Index: include/llvm/Transforms/Scalar/LoopUnrollPass.h =================================================================== --- include/llvm/Transforms/Scalar/LoopUnrollPass.h +++ include/llvm/Transforms/Scalar/LoopUnrollPass.h @@ -16,6 +16,7 @@ namespace llvm { +class Error; class Function; class Loop; class LPMUpdater; @@ -83,6 +84,17 @@ OptLevel = O; return *this; } + + struct Parser; +}; + +struct LoopUnrollOptions::Parser { + using ParametersT = LoopUnrollOptions; + + LoopUnrollOptions UnrollOpts; + + Error parse(StringRef); + LoopUnrollOptions getParameters() { return UnrollOpts; } }; /// Loop unroll pass that will support both full and partial unrolling. Index: lib/Passes/PassBuilder.cpp =================================================================== --- lib/Passes/PassBuilder.cpp +++ lib/Passes/PassBuilder.cpp @@ -1223,6 +1223,42 @@ return Count; } +static bool checkParametrizedPassName(StringRef Name, StringRef PassName) { + if (!Name.consume_front(PassName)) + return false; + // normal pass name w/o parameters == default parameters + if (Name.empty()) + return true; + return Name.consume_front("<") && Name.consume_back(">"); +} + +namespace { + +template +Expected +parsePassParameters(ParserT &&Parser, StringRef Name, StringRef PassName) { + StringRef Params = Name; + if (!Params.consume_front(PassName)) { + assert(false && "unexpected failure to parse parametrized pass name"); + } + // default parameters + if (Params.empty()) + return typename ParserT::ParametersT{}; + + if (!Params.consume_front("<") || !Params.consume_back(">")) { + assert(false && "invalid format for parametrized pass name"); + } + + if (Error Err = Parser.parse(Params)) { + assert(Err.isA() && + "Pass parameter parser can only return StringErrors."); + return Err; + } + return Parser.getParameters(); +} + +} // namespace + /// Tests whether a pass name starts with a valid prefix for a default pipeline /// alias. static bool startsWithDefaultPipelineAliasPrefix(StringRef Name) { @@ -1318,6 +1354,9 @@ #define FUNCTION_PASS(NAME, CREATE_PASS) \ if (Name == NAME) \ return true; +#define FUNCTION_PASS_PARAMETRIZED(NAME, CREATE_PASS, PARSER) \ + if (checkParametrizedPassName(Name, NAME)) \ + return true; #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \ return true; @@ -1655,6 +1694,14 @@ FPM.addPass(CREATE_PASS); \ return Error::success(); \ } +#define FUNCTION_PASS_PARAMETRIZED(NAME, CREATE_PASS, PARSER) \ + if (checkParametrizedPassName(Name, NAME)) { \ + auto Params = parsePassParameters(PARSER, Name, NAME); \ + if (!Params) \ + return Params.takeError(); \ + FPM.addPass(CREATE_PASS(Params.get())); \ + return Error::success(); \ + } #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ if (Name == "require<" NAME ">") { \ FPM.addPass( \ Index: lib/Passes/PassRegistry.def =================================================================== --- lib/Passes/PassRegistry.def +++ lib/Passes/PassRegistry.def @@ -142,6 +142,9 @@ #ifndef FUNCTION_PASS #define FUNCTION_PASS(NAME, CREATE_PASS) #endif +#ifndef FUNCTION_PASS_PARAMETRIZED +#define FUNCTION_PASS_PARAMETRIZED(NAME, CREATE_PASS, PARSER) +#endif FUNCTION_PASS("aa-eval", AAEvaluator()) FUNCTION_PASS("adce", ADCEPass()) FUNCTION_PASS("add-discriminators", AddDiscriminatorsPass()) @@ -214,8 +217,9 @@ FUNCTION_PASS("sroa", SROA()) FUNCTION_PASS("tailcallelim", TailCallElimPass()) FUNCTION_PASS("unreachableblockelim", UnreachableBlockElimPass()) -FUNCTION_PASS("unroll", LoopUnrollPass()) -FUNCTION_PASS("unroll",LoopUnrollPass(LoopUnrollOptions().setPeeling(true).setRuntime(false))) +FUNCTION_PASS_PARAMETRIZED("unroll", \ + [](LoopUnrollOptions Opts) { return LoopUnrollPass(Opts); }, \ + LoopUnrollOptions::Parser()) FUNCTION_PASS("verify", VerifierPass()) FUNCTION_PASS("verify", DominatorTreeVerifierPass()) FUNCTION_PASS("verify", LoopVerifierPass()) @@ -224,6 +228,7 @@ FUNCTION_PASS("view-cfg", CFGViewerPass()) FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass()) #undef FUNCTION_PASS +#undef FUNCTION_PASS_PARAMETRIZED #ifndef LOOP_ANALYSIS #define LOOP_ANALYSIS(NAME, CREATE_PASS) Index: lib/Transforms/Scalar/LoopUnrollPass.cpp =================================================================== --- lib/Transforms/Scalar/LoopUnrollPass.cpp +++ lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/LoopAnalysisManager.h" @@ -50,6 +51,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" @@ -1291,6 +1293,39 @@ return Worklist; } +Error LoopUnrollOptions::Parser::parse(StringRef Params) { + while (!Params.empty()) { + StringRef ParamName; + std::tie(ParamName, Params) = Params.split(';'); + int OptLevel = StringSwitch(ParamName) + .Case("O0", 0) + .Case("O1", 1) + .Case("O2", 2) + .Case("O3", 3) + .Default(-1); + if (OptLevel >= 0) { + UnrollOpts.setOptLevel(OptLevel); + continue; + } + + bool Enable = !ParamName.consume_front("no-"); + if (ParamName == "partial") { + UnrollOpts.setPartial(Enable); + } else if (ParamName == "peeling") { + UnrollOpts.setPeeling(Enable); + } else if (ParamName == "runtime") { + UnrollOpts.setRuntime(Enable); + } else if (ParamName == "upperbound") { + UnrollOpts.setUpperBound(Enable); + } else { + return make_error( + formatv("invalid LoopUnrollPass parameter '{0}' ", ParamName).str(), + inconvertibleErrorCode()); + } + } + return Error::success(); +} + PreservedAnalyses LoopUnrollPass::run(Function &F, FunctionAnalysisManager &AM) { auto &SE = AM.getResult(F);