Index: llvm/include/llvm/Transforms/InstCombine/InstCombine.h =================================================================== --- llvm/include/llvm/Transforms/InstCombine/InstCombine.h +++ llvm/include/llvm/Transforms/InstCombine/InstCombine.h @@ -25,13 +25,35 @@ namespace llvm { +static constexpr unsigned InstCombineDefaultMaxIterations = 1000; + +struct InstCombineOptions { + bool UseLoopInfo; + unsigned MaxIterations; + + InstCombineOptions() + : UseLoopInfo(false), MaxIterations(InstCombineDefaultMaxIterations) {} + + InstCombineOptions &setUseLoopInfo(bool Value) { + UseLoopInfo = Value; + return *this; + } + + InstCombineOptions &setMaxIterations(unsigned Value) { + MaxIterations = Value; + return *this; + } +}; + class InstCombinePass : public PassInfoMixin { +private: InstructionWorklist Worklist; - const unsigned MaxIterations; + InstCombineOptions Options; public: - explicit InstCombinePass(); - explicit InstCombinePass(unsigned MaxIterations); + explicit InstCombinePass(InstCombineOptions Opts = {}); + void printPipeline(raw_ostream &OS, + function_ref MapClassName2PassName); PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; Index: llvm/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/lib/Passes/PassBuilder.cpp +++ llvm/lib/Passes/PassBuilder.cpp @@ -778,6 +778,33 @@ return Result; } +Expected parseInstCombineOptions(StringRef Params) { + InstCombineOptions Result; + while (!Params.empty()) { + StringRef ParamName; + std::tie(ParamName, Params) = Params.split(';'); + + bool Enable = !ParamName.consume_front("no-"); + if (ParamName == "use-loop-info") { + Result.setUseLoopInfo(Enable); + } else if (Enable && ParamName.consume_front("max-iterations=")) { + APInt MaxIterations; + if (ParamName.getAsInteger(0, MaxIterations)) + return make_error( + formatv("invalid argument to InstCombine pass max-iterations " + "parameter: '{0}' ", + ParamName).str(), + inconvertibleErrorCode()); + Result.setMaxIterations((unsigned)MaxIterations.getZExtValue()); + } else { + return make_error( + formatv("invalid InstCombine pass parameter '{0}' ", ParamName).str(), + inconvertibleErrorCode()); + } + } + return Result; +} + /// Parser of parameters for LoopVectorize pass. Expected parseLoopVectorizeOptions(StringRef Params) { LoopVectorizeOptions Opts; Index: llvm/lib/Passes/PassRegistry.def =================================================================== --- llvm/lib/Passes/PassRegistry.def +++ llvm/lib/Passes/PassRegistry.def @@ -477,6 +477,15 @@ parseLoopVectorizeOptions, "no-interleave-forced-only;interleave-forced-only;" "no-vectorize-forced-only;vectorize-forced-only") +FUNCTION_PASS_WITH_PARAMS("instcombine", + "InstCombinePass", + [](InstCombineOptions Opts) { + return InstCombinePass(Opts); + }, + parseInstCombineOptions, + "no-use-loop-info;use-loop-info;" + "max-iterations=N" + ) FUNCTION_PASS_WITH_PARAMS("mldst-motion", "MergedLoadStoreMotionPass", [](MergedLoadStoreMotionOptions Opts) { Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -129,7 +129,6 @@ "Controls which instructions are visited"); // FIXME: these limits eventually should be as low as 2. -static constexpr unsigned InstCombineDefaultMaxIterations = 1000; #ifndef NDEBUG static constexpr unsigned InstCombineDefaultInfiniteLoopThreshold = 100; #else @@ -144,11 +143,6 @@ "instcombine-max-sink-users", cl::init(32), cl::desc("Maximum number of undroppable users for instruction sinking")); -static cl::opt LimitMaxIterations( - "instcombine-max-iterations", - cl::desc("Limit the maximum number of instruction combining iterations"), - cl::init(InstCombineDefaultMaxIterations)); - static cl::opt InfiniteLoopDetectionThreshold( "instcombine-infinite-loop-threshold", cl::desc("Number of instruction combining iterations considered an " @@ -4584,7 +4578,6 @@ DominatorTree &DT, OptimizationRemarkEmitter &ORE, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, unsigned MaxIterations, LoopInfo *LI) { auto &DL = F.getParent()->getDataLayout(); - MaxIterations = std::min(MaxIterations, LimitMaxIterations.getValue()); /// Builder - This is an IRBuilder that automatically inserts new /// instructions into the worklist when they are created. @@ -4646,10 +4639,17 @@ return MadeIRChange; } -InstCombinePass::InstCombinePass() : MaxIterations(LimitMaxIterations) {} +InstCombinePass::InstCombinePass(InstCombineOptions Opts) : Options(Opts) {} -InstCombinePass::InstCombinePass(unsigned MaxIterations) - : MaxIterations(MaxIterations) {} +void InstCombinePass::printPipeline( + raw_ostream &OS, function_ref MapClassName2PassName) { + static_cast *>(this)->printPipeline( + OS, MapClassName2PassName); + OS << '<'; + OS << "max-iterations=" << Options.MaxIterations << ";"; + OS << (Options.UseLoopInfo ? "" : "no-") << "use-loop-info"; + OS << '>'; +} PreservedAnalyses InstCombinePass::run(Function &F, FunctionAnalysisManager &AM) { @@ -4660,6 +4660,8 @@ auto &TTI = AM.getResult(F); auto *LI = AM.getCachedResult(F); + if (!LI && Options.UseLoopInfo) + LI = &AM.getResult(F); auto *AA = &AM.getResult(F); auto &MAMProxy = AM.getResult(F); @@ -4669,7 +4671,7 @@ &AM.getResult(F) : nullptr; if (!combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE, - BFI, PSI, MaxIterations, LI)) + BFI, PSI, Options.MaxIterations, LI)) // No changes, all analyses are preserved. return PreservedAnalyses::all(); Index: llvm/test/Other/new-pm-print-pipeline.ll =================================================================== --- llvm/test/Other/new-pm-print-pipeline.ll +++ llvm/test/Other/new-pm-print-pipeline.ll @@ -92,4 +92,8 @@ ;; Test SeparateConstOffsetFromGEPPass option. ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='separate-const-offset-from-gep' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-27 -; CHECK-27: function(separate-const-offset-from-gep) \ No newline at end of file +; CHECK-27: function(separate-const-offset-from-gep) + +;; Test InstCombine options - the first pass checks default settings, and the second checks customized options. +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='function(instcombine,instcombine)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-28 +; CHECK-28: function(instcombine,instcombine) Index: llvm/test/Transforms/InstCombine/gep-combine-loop-invariant.ll =================================================================== --- llvm/test/Transforms/InstCombine/gep-combine-loop-invariant.ll +++ llvm/test/Transforms/InstCombine/gep-combine-loop-invariant.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -opaque-pointers=0 < %s -passes='require,instcombine' -S | FileCheck %s +; RUN: opt -opaque-pointers=0 < %s -passes='instcombine' -S | FileCheck %s + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" Index: llvm/test/Transforms/InstCombine/statepoint-cleanup.ll =================================================================== --- llvm/test/Transforms/InstCombine/statepoint-cleanup.ll +++ llvm/test/Transforms/InstCombine/statepoint-cleanup.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=instcombine -instcombine-max-iterations=1 -S | FileCheck %s +; RUN: opt < %s -passes='instcombine' -S | FileCheck %s ; These tests check the optimizations specific to ; pointers being relocated at a statepoint. Index: llvm/test/Transforms/InstCombine/statepoint-iter.ll =================================================================== --- llvm/test/Transforms/InstCombine/statepoint-iter.ll +++ llvm/test/Transforms/InstCombine/statepoint-iter.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -passes=instcombine -instcombine-max-iterations=1 -S | FileCheck %s +; RUN: opt < %s -passes='instcombine' -S | FileCheck %s ; These tests check the optimizations specific to ; pointers being relocated at a statepoint.