diff --git a/llvm/include/llvm/Transforms/Scalar/LICM.h b/llvm/include/llvm/Transforms/Scalar/LICM.h --- a/llvm/include/llvm/Transforms/Scalar/LICM.h +++ b/llvm/include/llvm/Transforms/Scalar/LICM.h @@ -45,44 +45,57 @@ extern cl::opt SetLicmMssaOptCap; extern cl::opt SetLicmMssaNoAccForPromotionCap; +struct LICMOptions { + unsigned MssaOptCap; + unsigned MssaNoAccForPromotionCap; + bool AllowSpeculation; + + LICMOptions() + : MssaOptCap(SetLicmMssaOptCap), + MssaNoAccForPromotionCap(SetLicmMssaNoAccForPromotionCap), + AllowSpeculation(true) {} + + LICMOptions(unsigned MssaOptCap, unsigned MssaNoAccForPromotionCap, + bool AllowSpeculation) + : MssaOptCap(MssaOptCap), + MssaNoAccForPromotionCap(MssaNoAccForPromotionCap), + AllowSpeculation(AllowSpeculation) {} +}; + /// Performs Loop Invariant Code Motion Pass. class LICMPass : public PassInfoMixin { - unsigned LicmMssaOptCap; - unsigned LicmMssaNoAccForPromotionCap; - bool LicmAllowSpeculation; + LICMOptions Opts; public: - LICMPass() - : LicmMssaOptCap(SetLicmMssaOptCap), - LicmMssaNoAccForPromotionCap(SetLicmMssaNoAccForPromotionCap), - LicmAllowSpeculation(true) {} - LICMPass(unsigned LicmMssaOptCap, unsigned LicmMssaNoAccForPromotionCap, - bool LicmAllowSpeculation) - : LicmMssaOptCap(LicmMssaOptCap), - LicmMssaNoAccForPromotionCap(LicmMssaNoAccForPromotionCap), - LicmAllowSpeculation(LicmAllowSpeculation) {} + LICMPass(unsigned MssaOptCap, unsigned MssaNoAccForPromotionCap, + bool AllowSpeculation) + : LICMPass(LICMOptions(MssaOptCap, MssaNoAccForPromotionCap, + AllowSpeculation)) {} + LICMPass(LICMOptions Opts) : Opts(Opts) {} + PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U); + + void printPipeline(raw_ostream &OS, + function_ref MapClassName2PassName); }; /// Performs LoopNest Invariant Code Motion Pass. class LNICMPass : public PassInfoMixin { - unsigned LicmMssaOptCap; - unsigned LicmMssaNoAccForPromotionCap; - bool LicmAllowSpeculation; + LICMOptions Opts; public: - LNICMPass() - : LicmMssaOptCap(SetLicmMssaOptCap), - LicmMssaNoAccForPromotionCap(SetLicmMssaNoAccForPromotionCap), - LicmAllowSpeculation(true) {} - LNICMPass(unsigned LicmMssaOptCap, unsigned LicmMssaNoAccForPromotionCap, - bool LicmAllowSpeculation) - : LicmMssaOptCap(LicmMssaOptCap), - LicmMssaNoAccForPromotionCap(LicmMssaNoAccForPromotionCap), - LicmAllowSpeculation(LicmAllowSpeculation) {} + LNICMPass(unsigned MssaOptCap, unsigned MssaNoAccForPromotionCap, + bool AllowSpeculation) + : LNICMPass(LICMOptions(MssaOptCap, MssaNoAccForPromotionCap, + AllowSpeculation)) {} + LNICMPass(LICMOptions Opts) : Opts(Opts) {} + PreservedAnalyses run(LoopNest &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U); + + void printPipeline(raw_ostream &OS, + function_ref MapClassName2PassName); }; } // end namespace llvm diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -752,6 +752,24 @@ return Result; } +Expected parseLICMOptions(StringRef Params) { + LICMOptions Result; + while (!Params.empty()) { + StringRef ParamName; + std::tie(ParamName, Params) = Params.split(';'); + + bool Enable = !ParamName.consume_front("no-"); + if (ParamName == "allowspeculation") { + Result.AllowSpeculation = Enable; + } else { + return make_error( + formatv("invalid LICM pass parameter '{0}' ", ParamName).str(), + inconvertibleErrorCode()); + } + } + return Result; +} + Expected parseMergedLoadStoreMotionOptions(StringRef Params) { bool Result = false; while (!Params.empty()) { diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -463,7 +463,6 @@ #ifndef LOOPNEST_PASS #define LOOPNEST_PASS(NAME, CREATE_PASS) #endif -LOOPNEST_PASS("lnicm", LNICMPass()) LOOPNEST_PASS("loop-flatten", LoopFlattenPass()) LOOPNEST_PASS("loop-interchange", LoopInterchangePass()) LOOPNEST_PASS("loop-unroll-and-jam", LoopUnrollAndJamPass()) @@ -486,7 +485,6 @@ LOOP_PASS("canon-freeze", CanonicalizeFreezeInLoopsPass()) LOOP_PASS("dot-ddg", DDGDotPrinterPass()) LOOP_PASS("invalidate", InvalidateAllAnalysesPass()) -LOOP_PASS("licm", LICMPass()) LOOP_PASS("loop-idiom", LoopIdiomRecognizePass()) LOOP_PASS("loop-instsimplify", LoopInstSimplifyPass()) LOOP_PASS("loop-rotate", LoopRotatePass()) @@ -519,4 +517,18 @@ }, parseLoopUnswitchOptions, "nontrivial;no-nontrivial;trivial;no-trivial") + +LOOP_PASS_WITH_PARAMS("licm", "LICMPass", + [](LICMOptions Params) { + return LICMPass(Params); + }, + parseLICMOptions, + "allowspeculation"); + +LOOP_PASS_WITH_PARAMS("lnicm", "LNICMPass", + [](LICMOptions Params) { + return LNICMPass(Params); + }, + parseLICMOptions, + "allowspeculation"); #undef LOOP_PASS_WITH_PARAMS diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -270,8 +270,8 @@ // but ORE cannot be preserved (see comment before the pass definition). OptimizationRemarkEmitter ORE(L.getHeader()->getParent()); - LoopInvariantCodeMotion LICM(LicmMssaOptCap, LicmMssaNoAccForPromotionCap, - LicmAllowSpeculation); + LoopInvariantCodeMotion LICM(Opts.MssaOptCap, Opts.MssaNoAccForPromotionCap, + Opts.AllowSpeculation); if (!LICM.runOnLoop(&L, &AR.AA, &AR.LI, &AR.DT, AR.BFI, &AR.TLI, &AR.TTI, &AR.SE, AR.MSSA, &ORE)) return PreservedAnalyses::all(); @@ -285,6 +285,16 @@ return PA; } +void LICMPass::printPipeline( + raw_ostream &OS, function_ref MapClassName2PassName) { + static_cast *>(this)->printPipeline( + OS, MapClassName2PassName); + + OS << "<"; + OS << (Opts.AllowSpeculation ? "" : "no-") << "allowspeculation"; + OS << ">"; +} + PreservedAnalyses LNICMPass::run(LoopNest &LN, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &) { @@ -296,8 +306,8 @@ // but ORE cannot be preserved (see comment before the pass definition). OptimizationRemarkEmitter ORE(LN.getParent()); - LoopInvariantCodeMotion LICM(LicmMssaOptCap, LicmMssaNoAccForPromotionCap, - LicmAllowSpeculation); + LoopInvariantCodeMotion LICM(Opts.MssaOptCap, Opts.MssaNoAccForPromotionCap, + Opts.AllowSpeculation); Loop &OutermostLoop = LN.getOutermostLoop(); bool Changed = LICM.runOnLoop(&OutermostLoop, &AR.AA, &AR.LI, &AR.DT, AR.BFI, @@ -315,6 +325,16 @@ return PA; } +void LNICMPass::printPipeline( + raw_ostream &OS, function_ref MapClassName2PassName) { + static_cast *>(this)->printPipeline( + OS, MapClassName2PassName); + + OS << "<"; + OS << (Opts.AllowSpeculation ? "" : "no-") << "allowspeculation"; + OS << ">"; +} + char LegacyLICMPass::ID = 0; INITIALIZE_PASS_BEGIN(LegacyLICMPass, "licm", "Loop Invariant Code Motion", false, false) diff --git a/llvm/test/Other/new-pm-print-pipeline.ll b/llvm/test/Other/new-pm-print-pipeline.ll --- a/llvm/test/Other/new-pm-print-pipeline.ll +++ b/llvm/test/Other/new-pm-print-pipeline.ll @@ -69,9 +69,13 @@ ;; Test that the loop-nest-pass lnicm is printed with the other loop-passes in the pipeline. ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(loop-mssa(licm,loop-rotate,loop-deletion,lnicm,loop-rotate))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-23 -; CHECK-23: function(loop-mssa(licm,loop-rotate,loop-deletion,lnicm,loop-rotate)) +; CHECK-23: function(loop-mssa(licm,loop-rotate,loop-deletion,lnicm,loop-rotate)) ;; Test that -debugify and -check-debugify is printed correctly. ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='debugify,no-op-function,check-debugify' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-24 ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -enable-debugify -passes='no-op-function' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-24 ; CHECK-24: debugify,function(no-op-function),check-debugify + +;; Test that LICM & LNICM with options. +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(loop-mssa(licm,licm,lnicm,lnicm))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-25 +; CHECK-25: function(loop-mssa(licm,licm,lnicm,lnicm)) diff --git a/llvm/test/Transforms/LICM/allow-speculation-option.ll b/llvm/test/Transforms/LICM/allow-speculation-option.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/LICM/allow-speculation-option.ll @@ -0,0 +1,41 @@ +; RUN: opt -passes='loop-mssa(licm)' -S %s | FileCheck --check-prefixes=COMMON,SPEC_ON %s +; RUN: opt -passes='loop-mssa(licm)' -S %s | FileCheck --check-prefixes=COMMON,SPEC_OFF %s +; RUN: opt -passes='loop-mssa(lnicm)' -S %s | FileCheck --check-prefixes=COMMON,SPEC_ON %s +; RUN: opt -passes='loop-mssa(lnicm)' -S %s | FileCheck --check-prefixes=COMMON,SPEC_OFF %s + +define void @test([10 x i32]* %ptr, i32 %N) { +; COMMON-LABEL: @test( +; COMMON-NEXT: entry: +; SPEC_ON-NEXT: [[GEP:%.*]] = getelementptr [10 x i32], [10 x i32]* [[PTR:%.*]], i32 0, i32 0 +; COMMON-NEXT: br label [[LOOP_HEADER:%.*]] +; COMMON: loop.header: +; COMMON-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ] +; COMMON-NEXT: [[CMP:%.*]] = icmp ult i32 [[IV]], [[N:%.*]] +; COMMON-NEXT: br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT:%.*]] +; COMMON: loop.latch: +; SPEC_OFF-NEXT: [[GEP:%.*]] = getelementptr [10 x i32], [10 x i32]* [[PTR:%.*]], i32 0, i32 0 +; COMMON-NEXT: [[GEP_IV:%.*]] = getelementptr i32, i32* [[GEP]], i32 [[IV]] +; COMMON-NEXT: store i32 9999, i32* [[GEP_IV]], align 4 +; COMMON-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1 +; COMMON-NEXT: br label [[LOOP_HEADER]] +; COMMON: exit: +; COMMON-NEXT: ret void +; +entry: + br label %loop.header + +loop.header: + %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] + %cmp = icmp ult i32 %iv, %N + br i1 %cmp, label %loop.latch, label %exit + +loop.latch: + %gep = getelementptr [10 x i32], [10 x i32]* %ptr, i32 0, i32 0 + %gep.iv = getelementptr i32, i32* %gep, i32 %iv + store i32 9999, i32* %gep.iv + %iv.next = add i32 %iv, 1 + br label %loop.header + +exit: + ret void +}