diff --git a/llvm/include/llvm/Analysis/CGSCCPassManager.h b/llvm/include/llvm/Analysis/CGSCCPassManager.h --- a/llvm/include/llvm/Analysis/CGSCCPassManager.h +++ b/llvm/include/llvm/Analysis/CGSCCPassManager.h @@ -487,8 +487,16 @@ void printPipeline(raw_ostream &OS, function_ref MapClassName2PassName) { OS << "function"; - if (EagerlyInvalidate) - OS << ""; + if (EagerlyInvalidate || NoRerun) { + OS << "<"; + if (EagerlyInvalidate) + OS << "eager-inv"; + if (EagerlyInvalidate && NoRerun) + OS << ";"; + if (NoRerun) + OS << "no-rerun"; + OS << ">"; + } OS << '('; Pass->printPipeline(OS, MapClassName2PassName); OS << ')'; 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 @@ -486,6 +486,28 @@ return Count; } +static std::optional> +parseFunctionPipelineName(StringRef Name) { + std::pair Params; + if (!Name.consume_front("function")) + return std::nullopt; + if (Name.empty()) + return Params; + if (!Name.consume_front("<") || !Name.consume_back(">")) + return std::nullopt; + while (!Name.empty()) { + auto [Front, Back] = Name.split(';'); + Name = Back; + if (Front == "eager-inv") + Params.first = true; + else if (Front == "no-rerun") + Params.second = true; + else + return std::nullopt; + } + return Params; +} + static std::optional parseDevirtPassName(StringRef Name) { if (!Name.consume_front("devirt<") || !Name.consume_back(">")) return std::nullopt; @@ -1009,12 +1031,14 @@ if (startsWithDefaultPipelineAliasPrefix(Name)) return DefaultAliasRegex.match(Name); + StringRef NameNoBracket = Name.take_until([](char C) { return C == '<'; }); + // Explicitly handle pass manager names. if (Name == "module") return true; if (Name == "cgscc") return true; - if (Name == "function" || Name == "function") + if (NameNoBracket == "function") return true; if (Name == "coro-cond") return true; @@ -1040,9 +1064,10 @@ template static bool isCGSCCPassName(StringRef Name, CallbacksT &Callbacks) { // Explicitly handle pass manager names. + StringRef NameNoBracket = Name.take_until([](char C) { return C == '<'; }); if (Name == "cgscc") return true; - if (Name == "function" || Name == "function") + if (NameNoBracket == "function") return true; // Explicitly handle custom-parsed pass names. @@ -1068,7 +1093,8 @@ template static bool isFunctionPassName(StringRef Name, CallbacksT &Callbacks) { // Explicitly handle pass manager names. - if (Name == "function" || Name == "function") + StringRef NameNoBracket = Name.take_until([](char C) { return C == '<'; }); + if (NameNoBracket == "function") return true; if (Name == "loop" || Name == "loop-mssa") return true; @@ -1226,12 +1252,16 @@ MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); return Error::success(); } - if (Name == "function" || Name == "function") { + if (auto Params = parseFunctionPipelineName(Name)) { + if (Params->second) + return make_error( + "cannot have a no-rerun module to function adaptor", + inconvertibleErrorCode()); FunctionPassManager FPM; if (auto Err = parseFunctionPassPipeline(FPM, InnerPipeline)) return Err; - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM), - Name != "function")); + MPM.addPass( + createModuleToFunctionPassAdaptor(std::move(FPM), Params->first)); return Error::success(); } if (auto Count = parseRepeatPassName(Name)) { @@ -1394,13 +1424,13 @@ CGPM.addPass(std::move(NestedCGPM)); return Error::success(); } - if (Name == "function" || Name == "function") { + if (auto Params = parseFunctionPipelineName(Name)) { FunctionPassManager FPM; if (auto Err = parseFunctionPassPipeline(FPM, InnerPipeline)) return Err; // Add the nested pass manager with the appropriate adaptor. - CGPM.addPass( - createCGSCCToFunctionPassAdaptor(std::move(FPM), Name != "function")); + CGPM.addPass(createCGSCCToFunctionPassAdaptor( + std::move(FPM), Params->first, Params->second)); return Error::success(); } if (auto Count = parseRepeatPassName(Name)) { 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 @@ -101,3 +101,13 @@ ;; Test function-attrs ; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='cgscc(function-attrs)' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-29 ; CHECK-29: cgscc(function-attrs) + +;; Test cgscc -> function adaptor +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='cgscc(function(no-op-function))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-30 +; CHECK-30: cgscc(function(no-op-function)) + +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='cgscc(function(no-op-function))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-31 +; CHECK-31: cgscc(function(no-op-function)) + +; RUN: opt -disable-output -disable-verify -print-pipeline-passes -passes='cgscc(function(no-op-function))' < %s | FileCheck %s --match-full-lines --check-prefixes=CHECK-32 +; CHECK-32: cgscc(function(no-op-function)) diff --git a/llvm/test/Other/pass-pipeline-parsing.ll b/llvm/test/Other/pass-pipeline-parsing.ll --- a/llvm/test/Other/pass-pipeline-parsing.ll +++ b/llvm/test/Other/pass-pipeline-parsing.ll @@ -57,6 +57,10 @@ ; CHECK-DEFAULT-AA-DAG: Running analysis: BasicAA ; CHECK-DEFAULT-AA-DAG: Running analysis: TypeBasedAA +; RUN: not opt -passes='function(no-op-function)' %s 2>&1 \ +; RUN: | FileCheck %s --check-prefix=CHECK-RERUN-BAD +; CHECK-RERUN-BAD: cannot have a no-rerun module to function adaptor + ; RUN: not opt -disable-output -debug-pass-manager \ ; RUN: -passes='no-op-module)' %s 2>&1 \ ; RUN: | FileCheck %s --check-prefix=CHECK-UNBALANCED1