From 017c62c41d4113b634f71edc81595c2383f8befb Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Fri, 20 Jan 2017 08:42:19 +0000 Subject: [PATCH] [PM] Port LoopSink to the new pass manager. Like several other loop passes (the vectorizer, etc) this pass doesn't really fit the model of a loop pass. The critical distinction is that it isn't intended to be pipelined together with other loop passes. I plan to add some documentation to the loop pass manager to make this more clear on that side. LoopSink is also different because it doesn't really need a lot of the infrastructure of our loop passes. For example, if there aren't loop invariant instructions causing a preheader to exist, there is no need to form a preheader. It also doesn't need LCSSA because this pass is only involved in sinking invariant instructions from a preheader into the loop, not reasoning about live-outs. This allows some nice simplifications to the pass in the new PM where we can directly walk the loops once without restructuring them. Differential Revision: https://reviews.llvm.org/D28921 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292589 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Transforms/Scalar/LoopSink.h | 40 +++++++++++++++++++++++ lib/Passes/PassBuilder.cpp | 1 + lib/Passes/PassRegistry.def | 1 + lib/Transforms/Scalar/LoopSink.cpp | 37 +++++++++++++++++++++ test/Transforms/LICM/loopsink.ll | 1 + test/Transforms/LICM/sink.ll | 2 ++ 6 files changed, 82 insertions(+) create mode 100644 include/llvm/Transforms/Scalar/LoopSink.h diff --git a/include/llvm/Transforms/Scalar/LoopSink.h b/include/llvm/Transforms/Scalar/LoopSink.h new file mode 100644 index 00000000000..371a7c8d2c4 --- /dev/null +++ b/include/llvm/Transforms/Scalar/LoopSink.h @@ -0,0 +1,40 @@ +//===- LoopSink.h - Loop Sink Pass ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface for the Loop Sink pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_LOOPSINK_H +#define LLVM_TRANSFORMS_SCALAR_LOOPSINK_H + +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" + +namespace llvm { + +/// A pass that does profile-guided sinking of instructions into loops. +/// +/// This is a function pass as it shouldn't be composed into any kind of +/// unified loop pass pipeline. The goal of it is to sink code into loops that +/// is loop invariant but only required within the loop body when doing so +/// reduces the global expected dynamic frequency with which it executes. +/// A classic example is an extremely cold branch within a loop body. +/// +/// We do this as a separate pass so that during normal optimization all +/// invariant operations can be held outside the loop body to simplify +/// fundamental analyses and transforms of the loop. +class LoopSinkPass : public PassInfoMixin { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); +}; +} + +#endif // LLVM_TRANSFORMS_SCALAR_LOOPSINK_H diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index 00f8a9dacbc..31b9ea2952d 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/lib/Passes/PassBuilder.cpp @@ -107,6 +107,7 @@ #include "llvm/Transforms/Scalar/LoopPassManager.h" #include "llvm/Transforms/Scalar/LoopRotation.h" #include "llvm/Transforms/Scalar/LoopSimplifyCFG.h" +#include "llvm/Transforms/Scalar/LoopSink.h" #include "llvm/Transforms/Scalar/LoopStrengthReduce.h" #include "llvm/Transforms/Scalar/LoopUnrollPass.h" #include "llvm/Transforms/Scalar/LowerAtomic.h" diff --git a/lib/Passes/PassRegistry.def b/lib/Passes/PassRegistry.def index a9939fddb98..d93fbdb2c72 100644 --- a/lib/Passes/PassRegistry.def +++ b/lib/Passes/PassRegistry.def @@ -159,6 +159,7 @@ FUNCTION_PASS("lower-guard-intrinsic", LowerGuardIntrinsicPass()) FUNCTION_PASS("guard-widening", GuardWideningPass()) FUNCTION_PASS("gvn", GVN()) FUNCTION_PASS("loop-simplify", LoopSimplifyPass()) +FUNCTION_PASS("loop-sink", LoopSinkPass()) FUNCTION_PASS("lowerinvoke", LowerInvokePass()) FUNCTION_PASS("mem2reg", PromotePass()) FUNCTION_PASS("memcpyopt", MemCpyOptPass()) diff --git a/lib/Transforms/Scalar/LoopSink.cpp b/lib/Transforms/Scalar/LoopSink.cpp index 6b1c81d7d97..c9d55b4594f 100644 --- a/lib/Transforms/Scalar/LoopSink.cpp +++ b/lib/Transforms/Scalar/LoopSink.cpp @@ -31,6 +31,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Scalar/LoopSink.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasSetTracker.h" @@ -298,6 +299,42 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI, return Changed; } +PreservedAnalyses LoopSinkPass::run(Function &F, FunctionAnalysisManager &FAM) { + LoopInfo &LI = FAM.getResult(F); + // Nothing to do if there are no loops. + if (LI.empty()) + return PreservedAnalyses::all(); + + AAResults &AA = FAM.getResult(F); + DominatorTree &DT = FAM.getResult(F); + BlockFrequencyInfo &BFI = FAM.getResult(F); + + // We want to do a postorder walk over the loops. Since loops are a tree this + // is equivalent to a reversed preorder walk and preorder is easy to compute + // without recursion. Since we reverse the preorder, we will visit siblings + // in reverse program order. This isn't expected to matter at all but is more + // consistent with sinking algorithms which generally work bottom-up. + SmallVector PreorderLoops = LI.getLoopsInPreorder(); + + bool Changed = false; + do { + Loop &L = *PreorderLoops.pop_back_val(); + + // Note that we don't pass SCEV here because it is only used to invalidate + // loops in SCEV and we don't preserve (or request) SCEV at all making that + // unnecessary. + Changed |= sinkLoopInvariantInstructions(L, AA, LI, DT, BFI, + /*ScalarEvolution*/ nullptr); + } while (!PreorderLoops.empty()); + + if (!Changed) + return PreservedAnalyses::all(); + + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} + namespace { struct LegacyLoopSinkPass : public LoopPass { static char ID; diff --git a/test/Transforms/LICM/loopsink.ll b/test/Transforms/LICM/loopsink.ll index 5004752d103..b203ea8b51a 100644 --- a/test/Transforms/LICM/loopsink.ll +++ b/test/Transforms/LICM/loopsink.ll @@ -1,4 +1,5 @@ ; RUN: opt -S -loop-sink < %s | FileCheck %s +; RUN: opt -S -passes=loop-sink < %s | FileCheck %s @g = global i32 0, align 4 diff --git a/test/Transforms/LICM/sink.ll b/test/Transforms/LICM/sink.ll index cf169ddc12a..70fa6fa13e3 100644 --- a/test/Transforms/LICM/sink.ll +++ b/test/Transforms/LICM/sink.ll @@ -1,5 +1,7 @@ ; RUN: opt -S -licm < %s | FileCheck %s --check-prefix=CHECK-LICM ; RUN: opt -S -licm < %s | opt -S -loop-sink | FileCheck %s --check-prefix=CHECK-SINK +; RUN: opt -S < %s -passes='require,loop(licm),loop-sink' \ +; RUN: | FileCheck %s --check-prefix=CHECK-SINK ; Original source code: ; int g;