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,42 +45,49 @@ 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); }; /// 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) + : Opts(LICMOptions(MssaOptCap, MssaNoAccForPromotionCap, + AllowSpeculation)) {} + LNICMPass() {} + PreservedAnalyses run(LoopNest &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U); }; 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 @@ -751,6 +751,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 @@ -485,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()) @@ -518,4 +517,11 @@ }, parseLoopUnswitchOptions, "nontrivial;no-nontrivial;trivial;no-trivial") + +LOOP_PASS_WITH_PARAMS("licm", "LICMPass", + [](LICMOptions Params) { + return LICMPass(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(); @@ -296,8 +296,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, 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,39 @@ +; 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 + +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 +}