[flang-commits] [clang] [flang] [llvm] [Passes] Port -print-pipeline-passes to PassesOptions (PR #230220)
Fangrui Song via flang-commits
flang-commits at lists.llvm.org
Thu Oct 8 20:49:57 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/230220
>From 818b8d737747e2a28fb0dc5b219a3245255fb571 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 8 Oct 2026 00:55:49 -0700
Subject: [PATCH 1/3] [Passes] Declare command line options in TableGen
Move the LLVMPasses cl::opts into a private PassesOptions struct
(lib/Passes/PassesOptions.td). PassBuilder holds
`const PassesOptions &Opts`, forward-declared in PassBuilder.h.
-force-new-pm-codegen and -verify-analysis-invalidation become
BoolOrDefault members; the latter defaults to on with EXPENSIVE_CHECKS.
DotCfgChangeReporter keeps the expanded -dot-cfg-dir in a new OutputDir
member instead of writing it back to the option.
-print-{before,after}-pass-number (cl::list) and -print-pipeline-passes
(custom parser) stay cl::opt.
Aided by Opus 5.5
---
llvm/include/llvm/Passes/PassBuilder.h | 2 +
.../llvm/Passes/StandardInstrumentations.h | 6 +-
llvm/lib/Passes/CMakeLists.txt | 8 +
llvm/lib/Passes/PassBuilder.cpp | 4 +-
llvm/lib/Passes/PassBuilderPipelines.cpp | 299 ++++--------------
llvm/lib/Passes/PassesOptions.cpp | 15 +
llvm/lib/Passes/PassesOptions.h | 18 ++
llvm/lib/Passes/PassesOptions.td | 150 +++++++++
llvm/lib/Passes/RunCodeGen.cpp | 12 +-
llvm/lib/Passes/StandardInstrumentations.cpp | 210 +++++-------
.../gn/secondary/llvm/lib/Passes/BUILD.gn | 10 +
.../llvm-project-overlay/llvm/BUILD.bazel | 12 +
12 files changed, 364 insertions(+), 382 deletions(-)
create mode 100644 llvm/lib/Passes/PassesOptions.cpp
create mode 100644 llvm/lib/Passes/PassesOptions.h
create mode 100644 llvm/lib/Passes/PassesOptions.td
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 879e78fae4bf9b..245725f13ed8a4 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -36,6 +36,7 @@ class StringRef;
class AAManager;
class TargetMachine;
class ModuleSummaryIndex;
+struct PassesOptions;
/// Tunable parameters for passes in the default pipelines.
class PipelineTuningOptions {
@@ -112,6 +113,7 @@ class PipelineTuningOptions {
/// of the built-in passes, and those may reference these members during
/// construction.
class PassBuilder {
+ const PassesOptions &Opts;
TargetMachine *TM;
PipelineTuningOptions PTO;
std::optional<PGOOptions> PGOOpt;
diff --git a/llvm/include/llvm/Passes/StandardInstrumentations.h b/llvm/include/llvm/Passes/StandardInstrumentations.h
index 7c47a93f4e24d8..a25ef0ea4eec35 100644
--- a/llvm/include/llvm/Passes/StandardInstrumentations.h
+++ b/llvm/include/llvm/Passes/StandardInstrumentations.h
@@ -617,8 +617,8 @@ class LLVM_ABI DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
// Generate the pdf file into \p Dir / \p PDFFileName using \p DotFile as
// input and return the html <a> tag with \Text as the content.
- static std::string genHTML(StringRef Text, StringRef DotFile,
- StringRef PDFFileName);
+ std::string genHTML(StringRef Text, StringRef DotFile,
+ StringRef PDFFileName) const;
void handleFunctionCompare(StringRef Name, StringRef Prefix, StringRef PassID,
StringRef Divider, bool InModule, unsigned Minor,
@@ -626,6 +626,8 @@ class LLVM_ABI DotCfgChangeReporter : public ChangeReporter<IRDataT<DCData>> {
const FuncDataT<DCData> &After);
unsigned N = 0;
+ // -dot-cfg-dir with ~ expanded, made absolute.
+ std::string OutputDir;
std::unique_ptr<raw_fd_ostream> HTML;
};
diff --git a/llvm/lib/Passes/CMakeLists.txt b/llvm/lib/Passes/CMakeLists.txt
index 6a966d582b63b1..e4abb96cfd23b1 100644
--- a/llvm/lib/Passes/CMakeLists.txt
+++ b/llvm/lib/Passes/CMakeLists.txt
@@ -1,8 +1,14 @@
+set(LLVM_TABLEGEN_PROJECT LLVM_HEADERS)
+set(LLVM_TARGET_DEFINITIONS PassesOptions.td)
+tablegen(LLVM PassesOptions.inc -gen-opt-parser-defs)
+add_public_tablegen_target(PassesOptionsTableGen)
+
add_llvm_component_library(LLVMPasses
CodeGenPassBuilder.cpp
PassBuilder.cpp
PassBuilderBindings.cpp
PassBuilderPipelines.cpp
+ PassesOptions.cpp
RunCodeGen.cpp
StandardInstrumentations.cpp
TriggerCrashPasses.cpp
@@ -12,6 +18,7 @@ add_llvm_component_library(LLVMPasses
${LLVM_MAIN_INCLUDE_DIR}/llvm/Passes
DEPENDS
+ PassesOptionsTableGen
intrinsics_gen
LINK_COMPONENTS
@@ -28,6 +35,7 @@ add_llvm_component_library(LLVMPasses
InstCombine
IRPrinter
ObjCARC
+ Option
Scalar
Support
Target
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 30a6f75a1b86d5..4f973196eb951e 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Passes/PassBuilder.h"
+#include "PassesOptions.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/StringTable.h"
#include "llvm/Analysis/AliasAnalysisEvaluator.h"
@@ -593,7 +594,8 @@ PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO,
std::optional<PGOOptions> PGOOpt,
PassInstrumentationCallbacks *PIC,
IntrusiveRefCntPtr<vfs::FileSystem> FS)
- : TM(TM), PTO(PTO), PGOOpt(PGOOpt), PIC(PIC), FS(std::move(FS)) {
+ : Opts(PassesOptions::Global), TM(TM), PTO(PTO), PGOOpt(PGOOpt), PIC(PIC),
+ FS(std::move(FS)) {
if (TM)
TM->registerPassBuilderCallbacks(*this);
if (PIC) {
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index bd37fffc8e9914..c2ce33e8a4ad5a 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -14,6 +14,7 @@
///
//===----------------------------------------------------------------------===//
+#include "PassesOptions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
@@ -160,171 +161,6 @@
using namespace llvm;
namespace llvm {
-
-static cl::opt<InliningAdvisorMode> UseInlineAdvisor(
- "enable-ml-inliner", cl::init(InliningAdvisorMode::Default), cl::Hidden,
- cl::desc("Enable ML policy for inliner. Currently trained for -Oz only"),
- cl::values(clEnumValN(InliningAdvisorMode::Default, "default",
- "Heuristics-based inliner version"),
- clEnumValN(InliningAdvisorMode::Development, "development",
- "Use development mode (runtime-loadable model)"),
- clEnumValN(InliningAdvisorMode::Release, "release",
- "Use release mode (AOT-compiled model)")));
-
-/// Flag to enable inline deferral during PGO.
-static cl::opt<bool>
- EnablePGOInlineDeferral("enable-npm-pgo-inline-deferral", cl::init(true),
- cl::Hidden,
- cl::desc("Enable inline deferral during PGO"));
-
-static cl::opt<bool> EnableModuleInliner("enable-module-inliner",
- cl::init(false), cl::Hidden,
- cl::desc("Enable module inliner"));
-
-static cl::opt<bool> PerformMandatoryInliningsFirst(
- "mandatory-inlining-first", cl::init(false), cl::Hidden,
- cl::desc("Perform mandatory inlinings module-wide, before performing "
- "inlining"));
-
-static cl::opt<bool> EnableEagerlyInvalidateAnalyses(
- "eagerly-invalidate-analyses", cl::init(true), cl::Hidden,
- cl::desc("Eagerly invalidate more analyses in default pipelines"));
-
-static cl::opt<bool> EnableMergeFunctions(
- "enable-merge-functions", cl::init(false), cl::Hidden,
- cl::desc("Enable function merging as part of the optimization pipeline"));
-
-static cl::opt<bool> EnablePostPGOLoopRotation(
- "enable-post-pgo-loop-rotation", cl::init(true), cl::Hidden,
- cl::desc("Run the loop rotation transformation after PGO instrumentation"));
-
-static cl::opt<bool>
- TriggerCrash("opt-pipeline-trigger-crash", cl::init(false), cl::Hidden,
- cl::desc("Trigger crash in optimization pipeline"));
-
-static cl::opt<bool> EnableGlobalAnalyses(
- "enable-global-analyses", cl::init(true), cl::Hidden,
- cl::desc("Enable inter-procedural analyses"));
-
-static cl::opt<bool> RunPartialInlining("enable-partial-inlining",
- cl::init(false), cl::Hidden,
- cl::desc("Run Partial inlining pass"));
-
-static cl::opt<bool> ExtraVectorizerPasses(
- "extra-vectorizer-passes", cl::init(false), cl::Hidden,
- cl::desc("Run cleanup optimization passes after vectorization"));
-
-static cl::opt<bool> RunNewGVN("enable-newgvn", cl::init(false), cl::Hidden,
- cl::desc("Run the NewGVN pass"));
-
-static cl::opt<bool>
- EnableLoopInterchange("enable-loopinterchange", cl::init(true), cl::Hidden,
- cl::desc("Enable the LoopInterchange Pass"));
-
-static cl::opt<bool> EnableUnrollAndJam("enable-unroll-and-jam",
- cl::init(false), cl::Hidden,
- cl::desc("Enable Unroll And Jam Pass"));
-
-static cl::opt<bool> EnableLoopFlatten("enable-loop-flatten", cl::init(false),
- cl::Hidden,
- cl::desc("Enable the LoopFlatten Pass"));
-
-static cl::opt<bool>
- EnableInstrumentor("enable-instrumentor", cl::init(false), cl::Hidden,
- cl::desc("Enable the Instrumentor Pass"));
-
-static cl::opt<bool>
- EnableDFAJumpThreading("enable-dfa-jump-thread",
- cl::desc("Enable DFA jump threading"),
- cl::init(true), cl::Hidden);
-
-static cl::opt<bool>
- EnableHotColdSplit("hot-cold-split",
- cl::desc("Enable hot-cold splitting pass"));
-
-static cl::opt<bool>
- DisablePreInliner("disable-preinline", cl::init(false), cl::Hidden,
- cl::desc("Disable pre-instrumentation inliner"));
-
-static cl::opt<int> PreInlineThreshold(
- "preinline-threshold", cl::Hidden, cl::init(75),
- cl::desc("Control the amount of inlining in pre-instrumentation inliner "
- "(default = 75)"));
-
-static cl::opt<bool>
- EnableGVNHoist("enable-gvn-hoist",
- cl::desc("Enable the GVN hoisting pass (default = off)"));
-
-static cl::opt<bool>
- EnableGVNSink("enable-gvn-sink",
- cl::desc("Enable the GVN sinking pass (default = off)"));
-
-static cl::opt<bool> EnableJumpTableToSwitch(
- "enable-jump-table-to-switch", cl::init(true),
- cl::desc("Enable JumpTableToSwitch pass (default = true)"));
-
-// This option is used in simplifying testing SampleFDO optimizations for
-// profile loading.
-static cl::opt<bool>
- EnableCHR("enable-chr", cl::init(true), cl::Hidden,
- cl::desc("Enable control height reduction optimization (CHR)"));
-
-static cl::opt<bool> FlattenedProfileUsed(
- "flattened-profile-used", cl::init(false), cl::Hidden,
- cl::desc("Indicate the sample profile being used is flattened, i.e., "
- "no inline hierarchy exists in the profile"));
-
-static cl::opt<bool>
- EnableMatrix("enable-matrix", cl::init(false), cl::Hidden,
- cl::desc("Enable lowering of the matrix intrinsics"));
-
-static cl::opt<bool> EnableMergeICmps(
- "enable-mergeicmps", cl::init(true), cl::Hidden,
- cl::desc("Enable MergeICmps pass in the optimization pipeline"));
-
-static cl::opt<bool> EnableConstraintElimination(
- "enable-constraint-elimination", cl::init(true), cl::Hidden,
- cl::desc(
- "Enable pass to eliminate conditions based on linear constraints"));
-
-static cl::opt<AttributorRunOption> AttributorRun(
- "attributor-enable", cl::Hidden, cl::init(AttributorRunOption::NONE),
- cl::desc("Enable the attributor inter-procedural deduction pass"),
- cl::values(clEnumValN(AttributorRunOption::FULL, "full",
- "enable all full attributor runs"),
- clEnumValN(AttributorRunOption::LIGHT, "light",
- "enable all attributor-light runs"),
- clEnumValN(AttributorRunOption::MODULE, "module",
- "enable module-wide attributor runs"),
- clEnumValN(AttributorRunOption::MODULE_LIGHT, "module-light",
- "enable module-wide attributor-light runs"),
- clEnumValN(AttributorRunOption::CGSCC, "cgscc",
- "enable call graph SCC attributor runs"),
- clEnumValN(AttributorRunOption::CGSCC_LIGHT, "cgscc-light",
- "enable call graph SCC attributor-light runs"),
- clEnumValN(AttributorRunOption::NONE, "none",
- "disable attributor runs")));
-
-static cl::opt<bool> EnableSampledInstr(
- "enable-sampled-instrumentation", cl::init(false), cl::Hidden,
- cl::desc("Enable profile instrumentation sampling (default = off)"));
-static cl::opt<bool> UseLoopVersioningLICM(
- "enable-loop-versioning-licm", cl::init(false), cl::Hidden,
- cl::desc("Enable the experimental Loop Versioning LICM pass"));
-
-static cl::opt<std::string> InstrumentColdFuncOnlyPath(
- "instrument-cold-function-only-path", cl::init(""),
- cl::desc("File path for cold function only instrumentation(requires use "
- "with --pgo-instrument-cold-function-only)"),
- cl::Hidden);
-
-// TODO: There is a similar flag in WPD pass, we should consolidate them by
-// parsing the option only once in PassBuilder and share it across both places.
-static cl::opt<bool> EnableDevirtualizeSpeculatively(
- "enable-devirtualize-speculatively",
- cl::desc("Enable speculative devirtualization optimization"),
- cl::init(false));
-
extern cl::opt<std::string> UseCtxProfile;
extern cl::opt<bool> PGOInstrumentColdFunctionOnly;
@@ -332,21 +168,22 @@ extern cl::opt<bool> EnableMemProfContextDisambiguation;
} // namespace llvm
PipelineTuningOptions::PipelineTuningOptions() {
+ const PassesOptions &Opts = PassesOptions::Global;
LoopInterleaving = true;
LoopVectorization = true;
SLPVectorization = false;
LoopUnrolling = true;
- LoopInterchange = EnableLoopInterchange;
+ LoopInterchange = Opts.enable_loopinterchange;
LoopFusion = false;
ForgetAllSCEVInLoopUnroll = ForgetSCEVInLoopUnroll;
LicmMssaOptCap = SetLicmMssaOptCap;
LicmMssaNoAccForPromotionCap = SetLicmMssaNoAccForPromotionCap;
CallGraphProfile = true;
UnifiedLTO = false;
- MergeFunctions = EnableMergeFunctions;
+ MergeFunctions = Opts.enable_merge_functions;
InlinerThreshold = -1;
- EagerlyInvalidateAnalyses = EnableEagerlyInvalidateAnalyses;
- DevirtualizeSpeculatively = EnableDevirtualizeSpeculatively;
+ EagerlyInvalidateAnalyses = Opts.eagerly_invalidate_analyses;
+ DevirtualizeSpeculatively = Opts.enable_devirtualize_speculatively;
}
namespace llvm {
@@ -558,7 +395,7 @@ PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level,
LPM1.addPass(LICMPass(PTO.LicmMssaOptCap, PTO.LicmMssaNoAccForPromotionCap,
/*AllowSpeculation=*/true));
LPM1.addPass(SimpleLoopUnswitchPass());
- if (EnableLoopFlatten)
+ if (Opts.enable_loop_flatten)
LPM1.addPass(LoopFlattenPass());
LPM2.addPass(LoopIdiomRecognizePass());
@@ -653,11 +490,11 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
FPM.addPass(AssumeSimplifyPass());
// Hoisting of scalars and load expressions.
- if (EnableGVNHoist)
+ if (Opts.enable_gvn_hoist)
FPM.addPass(GVNHoistPass());
// Global value numbering based sinking.
- if (EnableGVNSink) {
+ if (Opts.enable_gvn_sink) {
FPM.addPass(GVNSinkPass());
FPM.addPass(
SimplifyCFGPass(SimplifyCFGOptions().convertSwitchRangeToICmp(true)));
@@ -671,7 +508,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
FPM.addPass(CorrelatedValuePropagationPass());
// Jump table to switch conversion.
- if (EnableJumpTableToSwitch)
+ if (Opts.enable_jump_table_to_switch)
FPM.addPass(JumpTableToSwitchPass(/*InLTO=*/isLTOPostLink(Phase)));
FPM.addPass(
@@ -697,7 +534,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
// minimal multiplication trees.
FPM.addPass(ReassociatePass());
- if (EnableConstraintElimination)
+ if (Opts.enable_constraint_elimination)
FPM.addPass(ConstraintEliminationPass());
// Add the primary loop simplification pipeline.
@@ -733,7 +570,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
/*AllowSpeculation=*/true));
LPM1.addPass(
SimpleLoopUnswitchPass(/* NonTrivial */ Level == OptimizationLevel::O3));
- if (EnableLoopFlatten)
+ if (Opts.enable_loop_flatten)
LPM1.addPass(LoopFlattenPass());
LPM2.addPass(LoopIdiomRecognizePass());
@@ -783,7 +620,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
// Eliminate redundancies.
FPM.addPass(MergedLoadStoreMotionPass());
- if (RunNewGVN)
+ if (Opts.enable_newgvn)
FPM.addPass(NewGVNPass());
else
FPM.addPass(GVNPass());
@@ -805,7 +642,7 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
// Re-consider control flow based optimizations after redundancy elimination,
// redo DCE, etc.
- if (EnableDFAJumpThreading)
+ if (Opts.enable_dfa_jump_thread)
FPM.addPass(DFAJumpThreadingPass());
FPM.addPass(JumpThreadingPass());
@@ -852,18 +689,18 @@ void PassBuilder::addPreInlinerPasses(ModulePassManager &MPM,
OptimizationLevel Level,
ThinOrFullLTOPhase LTOPhase) {
assert(Level != OptimizationLevel::O0 && "Not expecting O0 here!");
- if (DisablePreInliner)
+ if (Opts.disable_preinline)
return;
InlineParams IP;
- IP.DefaultThreshold = PreInlineThreshold;
+ IP.DefaultThreshold = Opts.preinline_threshold;
// FIXME: The hint threshold has the same value used by the regular inliner
// when not optimzing for size. This should probably be lowered after
// performance testing.
// FIXME: this comment is cargo culted from the old pass manager, revisit).
IP.HintThreshold = 325;
- IP.OptSizeHintThreshold = PreInlineThreshold;
+ IP.OptSizeHintThreshold = Opts.preinline_threshold;
ModuleInlinerWrapperPass MIWP(
IP, /* MandatoryFirst */ true,
InlineContext{LTOPhase, InlinePass::EarlyInliner});
@@ -890,7 +727,7 @@ void PassBuilder::addPreInlinerPasses(ModulePassManager &MPM,
void PassBuilder::addPostPGOLoopRotation(ModulePassManager &MPM,
OptimizationLevel Level) {
- if (EnablePostPGOLoopRotation) {
+ if (Opts.enable_post_pgo_loop_rotation) {
// Disable header duplication in loop rotation at -Oz.
MPM.addPass(createModuleToFunctionPassAdaptor(
createFunctionToLoopPassAdaptor(LoopRotatePass(),
@@ -928,7 +765,7 @@ void PassBuilder::addPGOInstrPasses(ModulePassManager &MPM,
// Do counter promotion at Level greater than O0.
Options.DoCounterPromotion = true;
Options.UseBFIInPromotion = IsCS;
- if (EnableSampledInstr) {
+ if (Opts.enable_sampled_instrumentation) {
Options.Sampling = true;
// With sampling, there is little beneifit to enable counter promotion.
// But note that sampling does work with counter promotion.
@@ -990,15 +827,15 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
IP.HotCallSiteThreshold = 0;
if (PGOOpt)
- IP.EnableDeferral = EnablePGOInlineDeferral;
+ IP.EnableDeferral = Opts.enable_npm_pgo_inline_deferral;
- ModuleInlinerWrapperPass MIWP(IP, PerformMandatoryInliningsFirst,
+ ModuleInlinerWrapperPass MIWP(IP, Opts.mandatory_inlining_first,
InlineContext{Phase, InlinePass::CGSCCInliner},
- UseInlineAdvisor, MaxDevirtIterations);
+ Opts.enable_ml_inliner, MaxDevirtIterations);
// Require the GlobalsAA analysis for the module so we can query it within
// the CGSCC pipeline.
- if (EnableGlobalAnalyses) {
+ if (Opts.enable_global_analyses) {
MIWP.addModulePass(RequireAnalysisPass<GlobalsAA, Module>());
// Invalidate AAManager so it can be recreated and pick up the newly
// available GlobalsAA.
@@ -1021,9 +858,9 @@ PassBuilder::buildInlinerPipeline(OptimizationLevel Level,
// valuable as the inliner doesn't currently care whether it is inlining an
// invoke or a call.
- if (AttributorRun & AttributorRunOption::CGSCC)
+ if (Opts.attributor_enable & AttributorRunOption::CGSCC)
MainCGPipeline.addPass(AttributorCGSCCPass());
- else if (AttributorRun & AttributorRunOption::CGSCC_LIGHT)
+ else if (Opts.attributor_enable & AttributorRunOption::CGSCC_LIGHT)
MainCGPipeline.addPass(AttributorLightCGSCCPass());
// Deduce function attributes. We do another run of this after the function
@@ -1089,7 +926,7 @@ PassBuilder::buildModuleInlinerPipeline(OptimizationLevel Level,
IP.HotCallSiteThreshold = 0;
if (PGOOpt)
- IP.EnableDeferral = EnablePGOInlineDeferral;
+ IP.EnableDeferral = Opts.enable_npm_pgo_inline_deferral;
// The inline deferral logic is used to avoid losing some
// inlining chance in future. It is helpful in SCC inliner, in which
@@ -1099,7 +936,7 @@ PassBuilder::buildModuleInlinerPipeline(OptimizationLevel Level,
// inline deferral logic in module inliner.
IP.EnableDeferral = false;
- MPM.addPass(ModuleInlinerPass(IP, UseInlineAdvisor, Phase));
+ MPM.addPass(ModuleInlinerPass(IP, Opts.enable_ml_inliner, Phase));
if (!UseCtxProfile.empty() && Phase == ThinOrFullLTOPhase::ThinLTOPostLink) {
MPM.addPass(GlobalOptPass());
MPM.addPass(GlobalDCEPass());
@@ -1142,8 +979,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
// In ThinLTO mode, when flattened profile is used, all the available
// profile information will be annotated in PreLink phase so there is
// no need to load the profile again in PostLink.
- bool LoadSampleProfile =
- HasSampleProfile && !(FlattenedProfileUsed && isThinLTOPostLink(Phase));
+ bool LoadSampleProfile = HasSampleProfile && !(Opts.flattened_profile_used &&
+ isThinLTOPostLink(Phase));
// During the ThinLTO backend phase we perform early indirect call promotion
// here, before globalopt. Otherwise imported available_externally functions
@@ -1209,9 +1046,9 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
// (quick!) no-op if there are no OpenMP runtime calls present in the module.
MPM.addPass(OpenMPOptPass(Phase));
- if (AttributorRun & AttributorRunOption::MODULE)
+ if (Opts.attributor_enable & AttributorRunOption::MODULE)
MPM.addPass(AttributorPass());
- else if (AttributorRun & AttributorRunOption::MODULE_LIGHT)
+ else if (Opts.attributor_enable & AttributorRunOption::MODULE_LIGHT)
MPM.addPass(AttributorLightPass());
// Lower type metadata and the type.test intrinsic in the ThinLTO
@@ -1266,13 +1103,13 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
"supported.");
const bool IsCtxProfUse = !UseCtxProfile.empty() && isThinLTOPreLink(Phase);
- assert(
- (InstrumentColdFuncOnlyPath.empty() || PGOInstrumentColdFunctionOnly) &&
- "--instrument-cold-function-only-path is provided but "
- "--pgo-instrument-cold-function-only is not enabled");
- const bool IsColdFuncOnlyInstrGen = PGOInstrumentColdFunctionOnly &&
- IsPGOPreLink &&
- !InstrumentColdFuncOnlyPath.empty();
+ assert((Opts.instrument_cold_function_only_path.empty() ||
+ PGOInstrumentColdFunctionOnly) &&
+ "--instrument-cold-function-only-path is provided but "
+ "--pgo-instrument-cold-function-only is not enabled");
+ const bool IsColdFuncOnlyInstrGen =
+ PGOInstrumentColdFunctionOnly && IsPGOPreLink &&
+ !Opts.instrument_cold_function_only_path.empty();
if (IsPGOInstrGen || IsPGOInstrUse || IsMemprofUse || IsCtxProfGen ||
IsCtxProfUse || IsColdFuncOnlyInstrGen)
@@ -1307,7 +1144,7 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
} else if (IsColdFuncOnlyInstrGen) {
addPGOInstrPasses(MPM, Level, /* RunProfileGen */ true, /* IsCS */ false,
/* AtomicCounterUpdate */ false,
- InstrumentColdFuncOnlyPath,
+ Opts.instrument_cold_function_only_path.str(),
/* ProfileRemappingFile */ "");
}
@@ -1315,8 +1152,8 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
MPM.addPass(PGOIndirectCallPromotion(false, false));
if (IsPGOPreLink && PGOOpt->CSAction == PGOOptions::CSIRInstr)
- MPM.addPass(PGOInstrumentationGenCreateVar(PGOOpt->CSProfileGenFile,
- EnableSampledInstr));
+ MPM.addPass(PGOInstrumentationGenCreateVar(
+ PGOOpt->CSProfileGenFile, Opts.enable_sampled_instrumentation));
if (IsMemprofUse)
MPM.addPass(MemProfUsePass(PGOOpt->MemoryProfile, FS));
@@ -1327,7 +1164,7 @@ PassBuilder::buildModuleSimplificationPipeline(OptimizationLevel Level,
MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/true));
- if (EnableModuleInliner)
+ if (Opts.enable_module_inliner)
MPM.addPass(buildModuleInlinerPipeline(Level, Phase));
else
MPM.addPass(buildInlinerPipeline(Level, Phase));
@@ -1371,7 +1208,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// combiner for cleanup here so that the unrolling and LICM can be pipelined
// across the loop nests.
// We do UnrollAndJam in a separate LPM to ensure it happens before unroll
- if (EnableUnrollAndJam && PTO.LoopUnrolling)
+ if (Opts.enable_unroll_and_jam && PTO.LoopUnrolling)
FPM.addPass(createFunctionToLoopPassAdaptor(
LoopUnrollAndJamPass(static_cast<int>(Level))));
FPM.addPass(LoopUnrollPass(LoopUnrollOptions(
@@ -1404,7 +1241,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// Cleanup after the loop optimization passes.
FPM.addPass(InstCombinePass());
- if (Level > OptimizationLevel::O1 && ExtraVectorizerPasses) {
+ if (Level > OptimizationLevel::O1 && Opts.extra_vectorizer_passes) {
ExtraFunctionPassManager<ShouldRunExtraVectorPasses> ExtraPasses;
// At higher optimization levels, try to clean up any runtime overlap and
// alignment checks inserted by the vectorizer. We want to track correlated
@@ -1455,7 +1292,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// Optimize parallel scalar instruction chains into SIMD instructions.
if (PTO.SLPVectorization) {
FPM.addPass(SLPVectorizerPass());
- if (Level >= OptimizationLevel::O2 && ExtraVectorizerPasses) {
+ if (Level >= OptimizationLevel::O2 && Opts.extra_vectorizer_passes) {
FPM.addPass(EarlyCSEPass());
}
}
@@ -1471,7 +1308,7 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
// combiner for cleanup here so that the unrolling and LICM can be pipelined
// across the loop nests.
// We do UnrollAndJam in a separate LPM to ensure it happens before unroll
- if (EnableUnrollAndJam && PTO.LoopUnrolling) {
+ if (Opts.enable_unroll_and_jam && PTO.LoopUnrolling) {
FPM.addPass(createFunctionToLoopPassAdaptor(
LoopUnrollAndJamPass(static_cast<int>(Level))));
}
@@ -1523,7 +1360,7 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
// Run partial inlining pass to partially inline functions that have
// large bodies.
- if (RunPartialInlining)
+ if (Opts.enable_partial_inlining)
MPM.addPass(PartialInlinerPass());
// Remove avail extern fns and globals definitions since we aren't compiling
@@ -1565,7 +1402,7 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
// information for all local globals here, the late loop passes and notably
// the vectorizer will be able to use them to help recognize vectorizable
// memory operations.
- if (EnableGlobalAnalyses)
+ if (Opts.enable_global_analyses)
MPM.addPass(RecomputeGlobalsAAPass());
invokeOptimizerEarlyEPCallbacks(MPM, Level, LTOPhase);
@@ -1583,7 +1420,7 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
// early versioning may prevent further inlining due to increase of code
// size. Other optimizations which runs later might get benefit of no-alias
// assumption in clone loop.
- if (UseLoopVersioningLICM) {
+ if (Opts.enable_loop_versioning_licm) {
OptimizePM.addPass(
createFunctionToLoopPassAdaptor(LoopVersioningLICMPass()));
// LoopVersioningLICM pass might increase new LICM opportunities.
@@ -1598,14 +1435,14 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
if (!isLTOPreLink(LTOPhase))
OptimizePM.addPass(LowerConstantIntrinsicsPass());
- if (EnableMatrix) {
+ if (Opts.enable_matrix) {
OptimizePM.addPass(LowerMatrixIntrinsicsPass());
OptimizePM.addPass(EarlyCSEPass());
}
// CHR pass should only be applied with the profile information.
// The check is to check the profile summary information in CHR.
- if (EnableCHR && Level == OptimizationLevel::O3)
+ if (Opts.enable_chr && Level == OptimizationLevel::O3)
OptimizePM.addPass(ControlHeightReductionPass());
// FIXME: We need to run some loop optimizations to re-rotate loops after
@@ -1670,7 +1507,7 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
// Merge adjacent icmps into memcmp, then expand memcmp to loads/compares.
// TODO: move this furter up so that it can be optimized by GVN, etc.
- if (EnableMergeICmps)
+ if (Opts.enable_mergeicmps)
OptimizePM.addPass(MergeICmpsPass());
OptimizePM.addPass(ExpandMemCmpPass());
@@ -1699,13 +1536,13 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
invokeOptimizerLastEPCallbacks(MPM, Level, LTOPhase);
// Run the Instrumentor pass late.
- if (EnableInstrumentor)
+ if (Opts.enable_instrumentor)
MPM.addPass(InstrumentorPass(FS));
// Split out cold code. Splitting is done late to avoid hiding context from
// other optimizations and inadvertently regressing performance. The tradeoff
// is that this has a higher code size cost than splitting early.
- if (EnableHotColdSplit && !isLTOPreLink(LTOPhase))
+ if (Opts.hot_cold_split && !isLTOPreLink(LTOPhase))
MPM.addPass(HotColdSplittingPass());
// Now we need to do some global optimization transforms.
@@ -1745,9 +1582,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
// Also, we can't run devirtualization before inlining because the
// devirtualization depends on the passes optimizing/eliminating vtable GVs
// and those passes are only effective after inlining.
- if (EnableModuleInliner) {
+ if (Opts.enable_module_inliner) {
MPM.addPass(ModuleInlinerPass(::getInlineParamsFromOptLevel(Level),
- UseInlineAdvisor,
+ Opts.enable_ml_inliner,
ThinOrFullLTOPhase::None));
} else {
MPM.addPass(ModuleInlinerWrapperPass(
@@ -1787,7 +1624,7 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
// Force any function attributes we want the rest of the pipeline to observe.
MPM.addPass(ForceFunctionAttrsPass());
- if (TriggerCrash)
+ if (Opts.opt_pipeline_trigger_crash)
MPM.addPass(createModuleToFunctionPassAdaptor(TriggerCrashFunctionPass()));
if (PGOOpt && PGOOpt->DebugInfoForProfiling)
@@ -1918,7 +1755,7 @@ PassBuilder::buildThinLTOPreLinkDefaultPipeline(OptimizationLevel Level) {
// phase that will run after the thin link, running this here ends up with
// less information than will be available later and it may grow functions in
// ways that aren't beneficial.
- if (RunPartialInlining)
+ if (Opts.enable_partial_inlining)
MPM.addPass(PartialInlinerPass());
if (PGOOpt && PGOOpt->PseudoProbeForProfiling &&
@@ -2207,9 +2044,9 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
// valuable as the inliner doesn't currently care whether it is inlining an
// invoke or a call.
// Run the inliner now.
- if (EnableModuleInliner) {
+ if (Opts.enable_module_inliner) {
MPM.addPass(ModuleInlinerPass(::getInlineParamsFromOptLevel(Level),
- UseInlineAdvisor,
+ Opts.enable_ml_inliner,
ThinOrFullLTOPhase::FullLTOPostLink));
} else {
MPM.addPass(ModuleInlinerWrapperPass(
@@ -2250,7 +2087,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
FPM.addPass(InstCombinePass());
invokePeepholeEPCallbacks(FPM, Level);
- if (EnableConstraintElimination)
+ if (Opts.enable_constraint_elimination)
FPM.addPass(ConstraintEliminationPass());
FPM.addPass(JumpThreadingPass());
@@ -2285,7 +2122,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
// Require the GlobalsAA analysis for the module so we can query it within
// MainFPM.
- if (EnableGlobalAnalyses) {
+ if (Opts.enable_global_analyses) {
MPM.addPass(RequireAnalysisPass<GlobalsAA, Module>());
// Invalidate AAManager so it can be recreated and pick up the newly
// available GlobalsAA.
@@ -2299,7 +2136,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
/*AllowSpeculation=*/true),
/*USeMemorySSA=*/true));
- if (RunNewGVN)
+ if (Opts.enable_newgvn)
MainFPM.addPass(NewGVNPass());
else
MainFPM.addPass(GVNPass());
@@ -2317,7 +2154,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
invokeVectorizerStartEPCallbacks(MainFPM, Level);
LoopPassManager LPM;
- if (EnableLoopFlatten && Level >= OptimizationLevel::O2)
+ if (Opts.enable_loop_flatten && Level >= OptimizationLevel::O2)
LPM.addPass(LoopFlattenPass());
LPM.addPass(IndVarSimplifyPass());
LPM.addPass(LoopDeletionPass());
@@ -2357,7 +2194,7 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
MPM.addPass(DropTypeTestsPass());
// Enable splitting late in the FullLTO post-link pipeline.
- if (EnableHotColdSplit)
+ if (Opts.hot_cold_split)
MPM.addPass(HotColdSplittingPass());
// Add late LTO optimization passes.
@@ -2471,7 +2308,7 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,
if (PTO.MergeFunctions)
MPM.addPass(MergeFunctionsPass());
- if (EnableMatrix)
+ if (Opts.enable_matrix)
MPM.addPass(
createModuleToFunctionPassAdaptor(LowerMatrixIntrinsicsPass(true)));
@@ -2529,7 +2366,7 @@ PassBuilder::buildO0DefaultPipeline(OptimizationLevel Level,
invokeOptimizerLastEPCallbacks(MPM, Level, Phase);
- if (EnableInstrumentor)
+ if (Opts.enable_instrumentor)
MPM.addPass(InstrumentorPass(FS));
// Attach !implicit.ref metadata from all functions to copyright strings.
@@ -2570,7 +2407,7 @@ AAManager PassBuilder::buildDefaultAAPipeline() {
// Because the `AAManager` is a function analysis and `GlobalsAA` is a module
// analysis, all that the `AAManager` can do is query for any *cached*
// results from `GlobalsAA` through a readonly proxy.
- if (EnableGlobalAnalyses)
+ if (Opts.enable_global_analyses)
AA.registerModuleAnalysis<GlobalsAA>();
// Add target-specific alias analyses.
diff --git a/llvm/lib/Passes/PassesOptions.cpp b/llvm/lib/Passes/PassesOptions.cpp
new file mode 100644
index 00000000000000..2afa77a597708c
--- /dev/null
+++ b/llvm/lib/Passes/PassesOptions.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "PassesOptions.h"
+#include "llvm/Option/LibraryOptions.h"
+
+#define OPTIONS_STRUCT_DEFS
+#include "PassesOptions.inc"
+
+static llvm::opt::RegisterLibraryOptions<llvm::PassesOptions> Registration;
diff --git a/llvm/lib/Passes/PassesOptions.h b/llvm/lib/Passes/PassesOptions.h
new file mode 100644
index 00000000000000..5fa83efdd9f0fe
--- /dev/null
+++ b/llvm/lib/Passes/PassesOptions.h
@@ -0,0 +1,18 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_PASSES_PASSESOPTIONS_H
+#define LLVM_LIB_PASSES_PASSESOPTIONS_H
+
+#include "llvm/Analysis/InlineAdvisor.h"
+#include "llvm/Transforms/IPO/Attributor.h"
+
+#define OPTIONS_STRUCT_DECL
+#include "PassesOptions.inc"
+
+#endif // LLVM_LIB_PASSES_PASSESOPTIONS_H
diff --git a/llvm/lib/Passes/PassesOptions.td b/llvm/lib/Passes/PassesOptions.td
new file mode 100644
index 00000000000000..add8c5c04165d8
--- /dev/null
+++ b/llvm/lib/Passes/PassesOptions.td
@@ -0,0 +1,150 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+include "llvm/Option/LibraryOptions.td"
+
+def PassesOptions : OptionsStruct;
+
+// PassBuilderPipelines.cpp
+defm : EnumField<"attributor-enable", "AttributorRunOption", "AttributorRunOption::NONE",
+ "full,light,module,module-light,cgscc,cgscc-light,none",
+ ["AttributorRunOption::FULL", "AttributorRunOption::LIGHT",
+ "AttributorRunOption::MODULE", "AttributorRunOption::MODULE_LIGHT",
+ "AttributorRunOption::CGSCC", "AttributorRunOption::CGSCC_LIGHT",
+ "AttributorRunOption::NONE"],
+ "Enable the attributor inter-procedural deduction pass">;
+defm : BoolField<"disable-preinline", "false",
+ "Disable pre-instrumentation inliner">;
+defm : BoolField<"eagerly-invalidate-analyses", "true",
+ "Eagerly invalidate more analyses in default pipelines">;
+// This option is used in simplifying testing SampleFDO optimizations for
+// profile loading.
+defm : BoolField<"enable-chr", "true",
+ "Enable control height reduction optimization (CHR)">;
+defm : BoolField<"enable-constraint-elimination", "true",
+ "Enable pass to eliminate conditions based on linear constraints">;
+// TODO: There is a similar flag in WPD pass, we should consolidate them by
+// parsing the option only once in PassBuilder and share it across both places.
+defm : BoolField<"enable-devirtualize-speculatively", "false",
+ "Enable speculative devirtualization optimization">;
+defm : BoolField<"enable-dfa-jump-thread", "true",
+ "Enable DFA jump threading">;
+defm : BoolField<"enable-global-analyses", "true",
+ "Enable inter-procedural analyses">;
+defm : BoolField<"enable-gvn-hoist", "false",
+ "Enable the GVN hoisting pass (default = off)">;
+defm : BoolField<"enable-gvn-sink", "false",
+ "Enable the GVN sinking pass (default = off)">;
+defm : BoolField<"enable-instrumentor", "false",
+ "Enable the Instrumentor Pass">;
+defm : BoolField<"enable-jump-table-to-switch", "true",
+ "Enable JumpTableToSwitch pass (default = true)">;
+defm : BoolField<"enable-loop-flatten", "false",
+ "Enable the LoopFlatten Pass">;
+defm : BoolField<"enable-loop-versioning-licm", "false",
+ "Enable the experimental Loop Versioning LICM pass">;
+defm : BoolField<"enable-loopinterchange", "true",
+ "Enable the LoopInterchange Pass">;
+defm : BoolField<"enable-matrix", "false",
+ "Enable lowering of the matrix intrinsics">;
+defm : BoolField<"enable-merge-functions", "false",
+ "Enable function merging as part of the optimization pipeline">;
+defm : BoolField<"enable-mergeicmps", "true",
+ "Enable MergeICmps pass in the optimization pipeline">;
+defm : EnumField<"enable-ml-inliner", "InliningAdvisorMode", "InliningAdvisorMode::Default",
+ "default,development,release",
+ ["InliningAdvisorMode::Default", "InliningAdvisorMode::Development",
+ "InliningAdvisorMode::Release"],
+ "Enable ML policy for inliner. Currently trained for -Oz only">;
+defm : BoolField<"enable-module-inliner", "false",
+ "Enable module inliner">;
+defm : BoolField<"enable-newgvn", "false",
+ "Run the NewGVN pass">;
+defm : BoolField<"enable-npm-pgo-inline-deferral", "true",
+ "Enable inline deferral during PGO">;
+defm : BoolField<"enable-partial-inlining", "false",
+ "Run Partial inlining pass">;
+defm : BoolField<"enable-post-pgo-loop-rotation", "true",
+ "Run the loop rotation transformation after PGO instrumentation">;
+defm : BoolField<"enable-sampled-instrumentation", "false",
+ "Enable profile instrumentation sampling (default = off)">;
+defm : BoolField<"enable-unroll-and-jam", "false",
+ "Enable Unroll And Jam Pass">;
+defm : BoolField<"extra-vectorizer-passes", "false",
+ "Run cleanup optimization passes after vectorization">;
+defm : BoolField<"flattened-profile-used", "false",
+ "Indicate the sample profile being used is flattened, i.e., no inline hierarchy exists in the profile">;
+defm : BoolField<"hot-cold-split", "false",
+ "Enable hot-cold splitting pass">;
+defm : ValueField<"instrument-cold-function-only-path", "StringRef", "",
+ "File path for cold function only instrumentation(requires use with --pgo-instrument-cold-function-only)">;
+defm : BoolField<"mandatory-inlining-first", "false",
+ "Perform mandatory inlinings module-wide, before performing inlining">;
+defm : BoolField<"opt-pipeline-trigger-crash", "false",
+ "Trigger crash in optimization pipeline">;
+defm : ValueField<"preinline-threshold", "int", "75",
+ "Control the amount of inlining in pre-instrumentation inliner (default = 75)">;
+
+// RunCodeGen.cpp
+defm : OptionalBoolField<"force-new-pm-codegen",
+ "Whether to force the NewPM on/off. Not setting the option will default to what the target prefers">;
+
+// StandardInstrumentations.cpp
+// An option that determines the colour used for elements that are only in the
+// after part. Must be a colour named in appendix J of
+// https://graphviz.org/pdf/dotguide.pdf
+defm : ValueField<"dot-cfg-after-color", "StringRef", "\"forestgreen\"",
+ "Color for dot-cfg after elements">;
+// An option that determines the colour used for elements that are only in the
+// before part. Must be a colour named in appendix J of
+// https://graphviz.org/pdf/dotguide.pdf
+defm : ValueField<"dot-cfg-before-color", "StringRef", "\"red\"",
+ "Color for dot-cfg before elements">;
+// An option that determines the colour used for elements that are in both the
+// before and after parts. Must be a colour named in appendix J of
+// https://graphviz.org/pdf/dotguide.pdf
+defm : ValueField<"dot-cfg-common-color", "StringRef", "\"black\"",
+ "Color for dot-cfg common elements">;
+// An option that determines where the generated website file (named
+// passes.html) and the associated pdf files (named diff_*.pdf) are saved.
+defm : ValueField<"dot-cfg-dir", "StringRef", "\"./\"",
+ "Generate dot files into specified directory for changed IRs">;
+defm : BoolField<"dropped-variable-stats", "false",
+ "Dump dropped debug variables stats">;
+// An option for specifying an executable that will be called with the IR
+// everytime it changes in the opt pipeline. It will also be called on the
+// initial IR as it enters the pipeline. The executable will be passed the name
+// of a temporary file containing the IR and the PassID. This may be used, for
+// example, to call llc on the IR and run a test to determine which pass makes a
+// change that changes the functioning of the IR. The usual modifier options
+// work as expected.
+defm : ValueField<"exec-on-ir-change", "StringRef", "",
+ "exe called with module IR after each pass that changes it">;
+let MetaVarName = "<filename>" in
+defm : ValueField<"ir-dump-directory", "StringRef", "",
+ "If specified, IR printed using the -print-[before|after]{-all} options will be dumped into files in this directory rather than written to stderr">;
+defm : ValueField<"opt-bisect-print-ir-path", "StringRef", "",
+ "Print IR to path when opt-bisect-limit is reached">;
+// An option that supports the -print-changed option. See the description for
+// -print-changed for an explanation of the use of this option. Note that this
+// option has no effect without -print-changed.
+defm : BoolField<"print-before-changed", "false",
+ "Print before passes that change them">;
+// An option for specifying the dot used by
+// print-changed=[dot-cfg | dot-cfg-quiet]
+defm : ValueField<"print-changed-dot-path", "StringRef", "\"dot\"",
+ "system dot used by change reporters">;
+// Options to print the IR that was being processed when a pass crashes.
+defm : BoolField<"print-on-crash", "false",
+ "Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)">;
+defm : ValueField<"print-on-crash-path", "StringRef", "",
+ "Print the last form of the IR before crash to a file">;
+defm : BoolField<"print-pass-numbers", "false",
+ "Print pass names and their ordinals">;
+defm : OptionalBoolField<"verify-analysis-invalidation",
+ "Verify that analyses a pass reports as preserved are unchanged (default: on with EXPENSIVE_CHECKS)">;
diff --git a/llvm/lib/Passes/RunCodeGen.cpp b/llvm/lib/Passes/RunCodeGen.cpp
index 0ba67d01c3a9b1..e52491dd187a07 100644
--- a/llvm/lib/Passes/RunCodeGen.cpp
+++ b/llvm/lib/Passes/RunCodeGen.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Passes/RunCodeGen.h"
+#include "PassesOptions.h"
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LoopAnalysisManager.h"
#include "llvm/Analysis/RuntimeLibcallInfo.h"
@@ -25,12 +26,6 @@
using namespace llvm;
-static cl::opt<cl::boolOrDefault>
- ForceNewPM("force-new-pm-codegen",
- cl::desc("Whether to force the NewPM on/off. Not setting the "
- "option will default to what the target prefers."),
- cl::init(cl::boolOrDefault::BOU_UNSET));
-
static Error
runCodeGenPipelineLegacy(TargetMachine &TM, Module &M, raw_pwrite_stream &OS,
std::unique_ptr<ToolOutputFile> &DwoOS,
@@ -100,9 +95,8 @@ Error llvm::runCodeGenPipeline(TargetMachine &TM, Module &M,
CodeGenFileType CGFT, bool PrintPipelinePasses,
bool DisableVerify, bool DisableSimplifyLibCalls,
IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
- if (ForceNewPM == cl::boolOrDefault::BOU_TRUE ||
- (TM.shouldDefaultToNewPM() &&
- ForceNewPM != cl::boolOrDefault::BOU_FALSE)) {
+ if (valueOr(PassesOptions::Global.force_new_pm_codegen,
+ TM.shouldDefaultToNewPM())) {
return runCodeGenPipelineNewPM(TM, M, OS, DwoOS, CGFT, DisableVerify, VFS);
}
diff --git a/llvm/lib/Passes/StandardInstrumentations.cpp b/llvm/lib/Passes/StandardInstrumentations.cpp
index 2dbbf23c9eeab6..750d9152484099 100644
--- a/llvm/lib/Passes/StandardInstrumentations.cpp
+++ b/llvm/lib/Passes/StandardInstrumentations.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Passes/StandardInstrumentations.h"
+#include "PassesOptions.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringRef.h"
@@ -49,77 +50,6 @@
using namespace llvm;
-static cl::opt<bool> VerifyAnalysisInvalidation("verify-analysis-invalidation",
- cl::Hidden,
-#ifdef EXPENSIVE_CHECKS
- cl::init(true)
-#else
- cl::init(false)
-#endif
-);
-
-// An option that supports the -print-changed option. See
-// the description for -print-changed for an explanation of the use
-// of this option. Note that this option has no effect without -print-changed.
-static cl::opt<bool>
- PrintChangedBefore("print-before-changed",
- cl::desc("Print before passes that change them"),
- cl::init(false), cl::Hidden);
-
-// An option for specifying the dot used by
-// print-changed=[dot-cfg | dot-cfg-quiet]
-static cl::opt<std::string>
- DotBinary("print-changed-dot-path", cl::Hidden, cl::init("dot"),
- cl::desc("system dot used by change reporters"));
-
-// An option that determines the colour used for elements that are only
-// in the before part. Must be a colour named in appendix J of
-// https://graphviz.org/pdf/dotguide.pdf
-static cl::opt<std::string>
- BeforeColour("dot-cfg-before-color",
- cl::desc("Color for dot-cfg before elements"), cl::Hidden,
- cl::init("red"));
-// An option that determines the colour used for elements that are only
-// in the after part. Must be a colour named in appendix J of
-// https://graphviz.org/pdf/dotguide.pdf
-static cl::opt<std::string>
- AfterColour("dot-cfg-after-color",
- cl::desc("Color for dot-cfg after elements"), cl::Hidden,
- cl::init("forestgreen"));
-// An option that determines the colour used for elements that are in both
-// the before and after parts. Must be a colour named in appendix J of
-// https://graphviz.org/pdf/dotguide.pdf
-static cl::opt<std::string>
- CommonColour("dot-cfg-common-color",
- cl::desc("Color for dot-cfg common elements"), cl::Hidden,
- cl::init("black"));
-
-// An option that determines where the generated website file (named
-// passes.html) and the associated pdf files (named diff_*.pdf) are saved.
-static cl::opt<std::string> DotCfgDir(
- "dot-cfg-dir",
- cl::desc("Generate dot files into specified directory for changed IRs"),
- cl::Hidden, cl::init("./"));
-
-// Options to print the IR that was being processed when a pass crashes.
-static cl::opt<std::string> PrintOnCrashPath(
- "print-on-crash-path",
- cl::desc("Print the last form of the IR before crash to a file"),
- cl::Hidden);
-
-static cl::opt<bool> PrintOnCrash(
- "print-on-crash",
- cl::desc("Print the last form of the IR before crash (use -print-on-crash-path to dump to a file)"),
- cl::Hidden);
-
-static cl::opt<std::string> OptBisectPrintIRPath(
- "opt-bisect-print-ir-path",
- cl::desc("Print IR to path when opt-bisect-limit is reached"), cl::Hidden);
-
-static cl::opt<bool> PrintPassNumbers(
- "print-pass-numbers", cl::init(false), cl::Hidden,
- cl::desc("Print pass names and their ordinals"));
-
static cl::list<unsigned> PrintBeforePassNumber(
"print-before-pass-number", cl::CommaSeparated, cl::Hidden,
cl::desc("Print IR before the passes with specified numbers as "
@@ -130,35 +60,11 @@ static cl::list<unsigned> PrintAfterPassNumber(
cl::desc("Print IR after the passes with specified numbers as "
"reported by print-pass-numbers"));
-static cl::opt<std::string> IRDumpDirectory(
- "ir-dump-directory",
- cl::desc("If specified, IR printed using the "
- "-print-[before|after]{-all} options will be dumped into "
- "files in this directory rather than written to stderr"),
- cl::Hidden, cl::value_desc("filename"));
-
-static cl::opt<bool>
- DroppedVarStats("dropped-variable-stats", cl::Hidden,
- cl::desc("Dump dropped debug variables stats"),
- cl::init(false));
-
static bool shouldGenerateData(const Function &F);
static bool shouldGenerateData(const MachineFunction &MF);
namespace {
-// An option for specifying an executable that will be called with the IR
-// everytime it changes in the opt pipeline. It will also be called on
-// the initial IR as it enters the pipeline. The executable will be passed
-// the name of a temporary file containing the IR and the PassID. This may
-// be used, for example, to call llc on the IR and run a test to determine
-// which pass makes a change that changes the functioning of the IR.
-// The usual modifier options work as expected.
-static cl::opt<std::string>
- TestChanged("exec-on-ir-change", cl::Hidden, cl::init(""),
- cl::desc("exe called with module IR after each pass that "
- "changes it"));
-
bool loopContainsPrintSourceLoc(const Loop &L) {
const Function *F = L.getHeader()->getParent();
bool SourceLocFilterEmpty = isSourceLocFilterEmpty();
@@ -547,7 +453,7 @@ void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
const std::string &Before,
const std::string &After, IRUnitRef) {
// Report the IR before the changes when requested.
- if (PrintChangedBefore)
+ if (PassesOptions::Global.print_before_changed)
Out << "*** IR Dump Before " << PassID << " on " << Name << " ***\n"
<< Before;
@@ -564,11 +470,12 @@ void IRChangedPrinter::handleAfter(StringRef PassID, std::string &Name,
IRChangedTester::~IRChangedTester() = default;
void IRChangedTester::registerCallbacks(PassInstrumentationCallbacks &PIC) {
- if (TestChanged != "")
+ if (PassesOptions::Global.exec_on_ir_change != "")
TextChangeReporter<std::string>::registerRequiredCallbacks(PIC);
}
void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
+ const PassesOptions &Opts = PassesOptions::Global;
// Store the body into a temporary file
static SmallVector<int> FD{-1};
SmallVector<StringRef> SR{S};
@@ -577,13 +484,14 @@ void IRChangedTester::handleIR(const std::string &S, StringRef PassID) {
dbgs() << "Unable to create temporary file.";
return;
}
- static ErrorOr<std::string> Exe = sys::findProgramByName(TestChanged);
+ static ErrorOr<std::string> Exe =
+ sys::findProgramByName(Opts.exec_on_ir_change);
if (!Exe) {
dbgs() << "Unable to find test-changed executable.";
return;
}
- StringRef Args[] = {TestChanged, FileName[0], PassID};
+ StringRef Args[] = {Opts.exec_on_ir_change, FileName[0], PassID};
int Result = sys::ExecuteAndWait(*Exe, Args);
if (Result < 0) {
dbgs() << "Error executing test-changed executable.";
@@ -839,7 +747,8 @@ StringRef PrintIRInstrumentation::getFileSuffix(IRDumpFileSuffixType Type) {
std::string PrintIRInstrumentation::fetchDumpFilename(
StringRef PassName, StringRef IRFileDisplayName, unsigned PassNumber,
IRDumpFileSuffixType SuffixType) {
- assert(!IRDumpDirectory.empty() &&
+ const PassesOptions &Opts = PassesOptions::Global;
+ assert(!Opts.ir_dump_directory.empty() &&
"The flag -ir-dump-directory must be passed to dump IR to files");
SmallString<64> Filename;
@@ -850,7 +759,7 @@ std::string PrintIRInstrumentation::fetchDumpFilename(
FilenameStream << getFileSuffix(SuffixType);
SmallString<128> ResultPath;
- sys::path::append(ResultPath, IRDumpDirectory, Filename);
+ sys::path::append(ResultPath, Opts.ir_dump_directory, Filename);
return std::string(ResultPath);
}
@@ -923,7 +832,7 @@ void PrintIRInstrumentation::printBeforePass(StringRef PassID, IRUnitRef IR) {
unwrapAndPrint(Stream, IR);
};
- if (!IRDumpDirectory.empty()) {
+ if (!PassesOptions::Global.ir_dump_directory.empty()) {
std::string DumpIRFilename =
fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
IRDumpFileSuffixType::Before);
@@ -958,7 +867,7 @@ void PrintIRInstrumentation::printAfterPass(StringRef PassID, IRUnitRef IR) {
unwrapAndPrint(Stream, IR);
};
- if (!IRDumpDirectory.empty()) {
+ if (!PassesOptions::Global.ir_dump_directory.empty()) {
std::string DumpIRFilename =
fetchDumpFilename(PassID, getIRFileDisplayName(IR), CurrentPassNumber,
IRDumpFileSuffixType::After);
@@ -996,7 +905,7 @@ void PrintIRInstrumentation::printAfterPassInvalidated(StringRef PassID) {
printIR(Stream, M);
};
- if (!IRDumpDirectory.empty()) {
+ if (!PassesOptions::Global.ir_dump_directory.empty()) {
std::string DumpIRFilename =
fetchDumpFilename(PassID, IRFileDisplayName, PassNumber,
IRDumpFileSuffixType::Invalidated);
@@ -1036,7 +945,7 @@ bool PrintIRInstrumentation::shouldPrintAfterCurrentPassNumber() {
}
bool PrintIRInstrumentation::shouldPrintPassNumbers() {
- return PrintPassNumbers;
+ return PassesOptions::Global.print_pass_numbers;
}
bool PrintIRInstrumentation::shouldPrintBeforeSomePassNumber() {
@@ -1097,19 +1006,21 @@ bool OptNoneInstrumentation::shouldRun(StringRef PassID, IRUnitRef IR) {
}
bool OptPassGateInstrumentation::shouldRun(StringRef PassName, IRUnitRef IR) {
+ const PassesOptions &Opts = PassesOptions::Global;
if (isIgnored(PassName))
return true;
bool ShouldRun = Context.getOptPassGate().shouldRunPass(
PassName, getIRName(IR, IRContext));
- if (!ShouldRun && !this->HasWrittenIR && !OptBisectPrintIRPath.empty()) {
+ if (!ShouldRun && !this->HasWrittenIR &&
+ !Opts.opt_bisect_print_ir_path.empty()) {
// FIXME: print IR if limit is higher than number of opt-bisect
// invocations
this->HasWrittenIR = true;
const Module *M = unwrapModule(IR, /*Force=*/true);
assert((M && &M->getContext() == &Context) && "Missing/Mismatching Module");
std::error_code EC;
- raw_fd_ostream OS(OptBisectPrintIRPath, EC);
+ raw_fd_ostream OS(Opts.opt_bisect_print_ir_path, EC);
if (EC)
report_fatal_error(errorCodeToError(EC));
M->print(OS, nullptr);
@@ -1403,7 +1314,13 @@ static SmallVector<Function *, 1> GetFunctions(IRUnitRef IR) {
void PreservedCFGCheckerInstrumentation::registerCallbacks(
PassInstrumentationCallbacks &PIC, ModuleAnalysisManager &MAM) {
- if (!VerifyAnalysisInvalidation)
+#ifdef EXPENSIVE_CHECKS
+ constexpr bool VerifyByDefault = true;
+#else
+ constexpr bool VerifyByDefault = false;
+#endif
+ if (!valueOr(PassesOptions::Global.verify_analysis_invalidation,
+ VerifyByDefault))
return;
bool Registered = false;
@@ -1864,12 +1781,13 @@ class DotCfgDiffNode {
void setCommon(const BlockDataT<DCData> &Other) {
assert(!Data[1] && "Expected only one block datum");
Data[1] = &Other;
- Colour = CommonColour;
+ Colour = PassesOptions::Global.dot_cfg_common_color;
}
// Add an edge to \p E of colour {\p Value, \p Colour}.
void addEdge(unsigned E, StringRef Value, StringRef Colour) {
// This is a new edge or it is an edge being made common.
- assert((EdgesMap.count(E) == 0 || Colour == CommonColour) &&
+ assert((EdgesMap.count(E) == 0 ||
+ Colour == PassesOptions::Global.dot_cfg_common_color) &&
"Unexpected edge count and color.");
EdgesMap[E] = {Value.str(), Colour};
}
@@ -1955,7 +1873,8 @@ class DotCfgDiff {
};
std::string DotCfgDiffNode::getBodyContent() const {
- if (Colour == CommonColour) {
+ const PassesOptions &Opts = PassesOptions::Global;
+ if (Colour == Opts.dot_cfg_common_color) {
assert(Data[1] && "Expected Data[1] to be set.");
StringRef SR[2];
@@ -1967,12 +1886,15 @@ std::string DotCfgDiffNode::getBodyContent() const {
SR[I] = SR[I].drop_until([](char C) { return C == '\n'; }).drop_front();
}
- SmallString<80> OldLineFormat = formatv(
- "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", BeforeColour);
- SmallString<80> NewLineFormat = formatv(
- "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", AfterColour);
- SmallString<80> UnchangedLineFormat = formatv(
- "<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>", CommonColour);
+ SmallString<80> OldLineFormat =
+ formatv("<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>",
+ Opts.dot_cfg_before_color);
+ SmallString<80> NewLineFormat =
+ formatv("<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>",
+ Opts.dot_cfg_after_color);
+ SmallString<80> UnchangedLineFormat =
+ formatv("<FONT COLOR=\"{0}\">%l</FONT><BR align=\"left\"/>",
+ Opts.dot_cfg_common_color);
std::string Diff = Data[0]->getLabel().str();
Diff += ":\n<BR align=\"left\"/>" +
doSystemDiff(makeHTMLReady(SR[0]), makeHTMLReady(SR[1]),
@@ -2029,13 +1951,14 @@ std::string DotCfgDiff::colourize(std::string S, StringRef Colour) const {
DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
const FuncDataT<DCData> &After)
: GraphName(Title.str()) {
+ const PassesOptions &Opts = PassesOptions::Global;
StringMap<StringRef> EdgesMap;
// Handle each basic block in the before IR.
for (auto &B : Before.getData()) {
StringRef Label = B.getKey();
const BlockDataT<DCData> &BD = B.getValue();
- createNode(Label, BD, BeforeColour);
+ createNode(Label, BD, Opts.dot_cfg_before_color);
// Create transitions with names made up of the from block label, the value
// on which the transition is made and the to block label.
@@ -2044,7 +1967,7 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
Sink != E; ++Sink) {
std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
BD.getData().getSuccessorLabel(Sink->getKey()).str();
- EdgesMap.insert({Key, BeforeColour});
+ EdgesMap.insert({Key, Opts.dot_cfg_before_color});
}
}
@@ -2055,7 +1978,7 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
auto It = NodePosition.find(Label);
if (It == NodePosition.end())
// This only exists in the after IR. Create the node.
- createNode(Label, BD, AfterColour);
+ createNode(Label, BD, Opts.dot_cfg_after_color);
else
Nodes[It->second].setCommon(BD);
// Add in the edges between the nodes (as common or only in after).
@@ -2064,9 +1987,9 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
Sink != E; ++Sink) {
std::string Key = (Label + " " + Sink->getKey().str()).str() + " " +
BD.getData().getSuccessorLabel(Sink->getKey()).str();
- auto [It, Inserted] = EdgesMap.try_emplace(Key, AfterColour);
+ auto [It, Inserted] = EdgesMap.try_emplace(Key, Opts.dot_cfg_after_color);
if (!Inserted)
- It->second = CommonColour;
+ It->second = Opts.dot_cfg_common_color;
}
}
@@ -2094,7 +2017,7 @@ DotCfgDiff::DotCfgDiff(StringRef Title, const FuncDataT<DCData> &Before,
else {
StringRef V = It->getValue();
std::string NV = colourize(V.str() + " " + Value.str(), Colour);
- Colour = CommonColour;
+ Colour = Opts.dot_cfg_common_color;
It->getValue() = NV;
}
SourceNode.addEdge(SinkNode, Value, Colour);
@@ -2311,14 +2234,17 @@ void DotCfgChangeReporter::handleFunctionCompare(
}
std::string DotCfgChangeReporter::genHTML(StringRef Text, StringRef DotFile,
- StringRef PDFFileName) {
- SmallString<20> PDFFile = formatv("{0}/{1}", DotCfgDir, PDFFileName);
+ StringRef PDFFileName) const {
+ const PassesOptions &Opts = PassesOptions::Global;
+ SmallString<20> PDFFile = formatv("{0}/{1}", OutputDir, PDFFileName);
// Create the PDF file.
- static ErrorOr<std::string> DotExe = sys::findProgramByName(DotBinary);
+ static ErrorOr<std::string> DotExe =
+ sys::findProgramByName(Opts.print_changed_dot_path);
if (!DotExe)
return "Unable to find dot executable.";
- StringRef Args[] = {DotBinary, "-Tpdf", "-o", PDFFile, DotFile};
+ StringRef Args[] = {Opts.print_changed_dot_path, "-Tpdf", "-o", PDFFile,
+ DotFile};
int Result = sys::ExecuteAndWait(*DotExe, Args, std::nullopt);
if (Result < 0)
return "Error executing system dot.";
@@ -2412,7 +2338,7 @@ void DotCfgChangeReporter::handleIgnored(StringRef PassID, std::string &Name) {
bool DotCfgChangeReporter::initializeHTML() {
std::error_code EC;
- HTML = std::make_unique<raw_fd_ostream>(DotCfgDir + "/passes.html", EC);
+ HTML = std::make_unique<raw_fd_ostream>(OutputDir + "/passes.html", EC);
if (EC) {
HTML = nullptr;
return false;
@@ -2475,11 +2401,11 @@ void DotCfgChangeReporter::registerCallbacks(
PassInstrumentationCallbacks &PIC) {
if (PrintChanged == ChangePrinter::DotCfgVerbose ||
PrintChanged == ChangePrinter::DotCfgQuiet) {
- SmallString<128> OutputDir;
- sys::fs::expand_tilde(DotCfgDir, OutputDir);
- sys::fs::make_absolute(OutputDir);
- assert(!OutputDir.empty() && "expected output dir to be non-empty");
- DotCfgDir = OutputDir.c_str();
+ SmallString<128> Dir;
+ sys::fs::expand_tilde(PassesOptions::Global.dot_cfg_dir, Dir);
+ sys::fs::make_absolute(Dir);
+ assert(!Dir.empty() && "expected output dir to be non-empty");
+ OutputDir = Dir.str();
if (initializeHTML()) {
ChangeReporter<IRDataT<DCData>>::registerRequiredCallbacks(PIC);
return;
@@ -2499,16 +2425,18 @@ StandardInstrumentations::StandardInstrumentations(
PrintChanged == ChangePrinter::ColourDiffVerbose ||
PrintChanged == ChangePrinter::ColourDiffQuiet),
WebsiteChangeReporter(PrintChanged == ChangePrinter::DotCfgVerbose),
- Verify(DebugLogging), DroppedStatsIR(DroppedVarStats),
+ Verify(DebugLogging),
+ DroppedStatsIR(PassesOptions::Global.dropped_variable_stats),
VerifyEach(VerifyEach) {}
PrintCrashIRInstrumentation *PrintCrashIRInstrumentation::CrashReporter =
nullptr;
void PrintCrashIRInstrumentation::reportCrashIR() {
- if (!PrintOnCrashPath.empty()) {
+ const PassesOptions &Opts = PassesOptions::Global;
+ if (!Opts.print_on_crash_path.empty()) {
std::error_code EC;
- raw_fd_ostream Out(PrintOnCrashPath, EC);
+ raw_fd_ostream Out(Opts.print_on_crash_path, EC);
if (EC)
report_fatal_error(errorCodeToError(EC));
Out << SavedIR;
@@ -2523,7 +2451,8 @@ void PrintCrashIRInstrumentation::SignalHandler(void *) {
if (!CrashReporter)
return;
- assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
+ assert((PassesOptions::Global.print_on_crash ||
+ !PassesOptions::Global.print_on_crash_path.empty()) &&
"Did not expect to get here without option set.");
CrashReporter->reportCrashIR();
}
@@ -2532,14 +2461,17 @@ PrintCrashIRInstrumentation::~PrintCrashIRInstrumentation() {
if (!CrashReporter)
return;
- assert((PrintOnCrash || !PrintOnCrashPath.empty()) &&
+ assert((PassesOptions::Global.print_on_crash ||
+ !PassesOptions::Global.print_on_crash_path.empty()) &&
"Did not expect to get here without option set.");
CrashReporter = nullptr;
}
void PrintCrashIRInstrumentation::registerCallbacks(
PassInstrumentationCallbacks &PIC) {
- if ((!PrintOnCrash && PrintOnCrashPath.empty()) || CrashReporter)
+ const PassesOptions &Opts = PassesOptions::Global;
+ if ((!Opts.print_on_crash && Opts.print_on_crash_path.empty()) ||
+ CrashReporter)
return;
sys::AddSignalHandler(SignalHandler, nullptr);
diff --git a/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn
index 7f60735acfd687..c99b3c50256e21 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Passes/BUILD.gn
@@ -1,12 +1,21 @@
+import("//llvm/utils/TableGen/tablegen.gni")
+
+tablegen("PassesOptions") {
+ visibility = [ ":Passes" ]
+ args = [ "-gen-opt-parser-defs" ]
+}
+
static_library("Passes") {
output_name = "LLVMPasses"
deps = [
+ ":PassesOptions",
"//llvm/lib/Analysis",
"//llvm/lib/CodeGen",
"//llvm/lib/CodeGen/AsmPrinter",
"//llvm/lib/CodeGen/GlobalISel",
"//llvm/lib/IR",
"//llvm/lib/IRPrinter",
+ "//llvm/lib/Option",
"//llvm/lib/Support",
"//llvm/lib/Target",
"//llvm/lib/Transforms/AggressiveInstCombine",
@@ -26,6 +35,7 @@ static_library("Passes") {
"PassBuilder.cpp",
"PassBuilderBindings.cpp",
"PassBuilderPipelines.cpp",
+ "PassesOptions.cpp",
"RunCodeGen.cpp",
"StandardInstrumentations.cpp",
"TriggerCrashPasses.cpp",
diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
index 5e803e902478f7..5491022ea7ab82 100644
--- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel
@@ -4391,10 +4391,20 @@ cc_library(
textual_hdrs = ["lib/Passes/PassRegistry.def"],
)
+gentbl_cc_library(
+ name = "PassesOptionsTableGen",
+ strip_include_prefix = "lib/Passes",
+ tbl_outs = {"lib/Passes/PassesOptions.inc": ["-gen-opt-parser-defs"]},
+ tblgen = ":llvm-min-tblgen",
+ td_file = "lib/Passes/PassesOptions.td",
+ deps = [":OptParserTdFiles"],
+)
+
cc_library(
name = "Passes",
srcs = glob([
"lib/Passes/*.cpp",
+ "lib/Passes/*.h",
]),
hdrs = glob([
"include/llvm/Passes/*.h",
@@ -4416,6 +4426,8 @@ cc_library(
":Instrumentation",
":MC",
":ObjCARC",
+ ":Option",
+ ":PassesOptionsTableGen",
":Plugins",
":Scalar",
":Support",
>From 0b9f6e0619f3485b92614ab572987fb88ea97bfd Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 8 Oct 2026 10:17:31 -0700
Subject: [PATCH 2/3] [Passes] Port -print-pipeline-passes to PassesOptions
-print-pipeline-passes takes an optional value (=text or =tree), which
LibraryOptions does not support. Split it into a bool
-print-pipeline-passes and -print-pipeline-passes-format=text|tree.
clang, flang, LTO, llc, and opt read the format through
getPrintPipelinePasses() instead of the exported cl::opt.
Aided by Opus 5.5
---
clang/lib/CodeGen/BackendUtil.cpp | 4 +--
flang/lib/Frontend/FrontendActions.cpp | 2 +-
llvm/include/llvm/Passes/PassBuilder.h | 14 ++-------
llvm/lib/LTO/LTOBackend.cpp | 2 +-
llvm/lib/Passes/PassBuilder.cpp | 32 +++-----------------
llvm/lib/Passes/PassesOptions.h | 1 +
llvm/lib/Passes/PassesOptions.td | 8 +++++
llvm/test/CodeGen/AMDGPU/llc-pipeline-npm.ll | 6 ++--
llvm/test/CodeGen/Lanai/llc-pipeline-npm.ll | 2 +-
llvm/test/CodeGen/NVPTX/llc-pipeline-npm.ll | 4 +--
llvm/test/CodeGen/RISCV/O0-newpm-pipeline.ll | 4 +--
llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll | 4 +--
llvm/test/CodeGen/X86/llc-pipeline-npm.ll | 8 ++---
llvm/test/tools/opt/print-pipeline-passes.ll | 2 +-
llvm/tools/llc/lib/NewPMDriver.cpp | 5 +--
llvm/tools/opt/NewPMDriver.cpp | 5 +--
16 files changed, 42 insertions(+), 61 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index c754c75aa59de5..2cdc655f99f066 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1185,7 +1185,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
// This should be done for both clang and flang simultaneously.
// Print a textual, '-passes=' compatible, representation of pipeline if
// requested.
- if (PrintPipelinePasses) {
+ if (getPrintPipelinePasses()) {
MPM.printPipeline(outs(), [&PIC](StringRef ClassName) {
auto PassName = PIC.getPassNameForClassName(ClassName);
return PassName.empty() ? ClassName : PassName;
@@ -1234,7 +1234,7 @@ void EmitAssemblyHelper::RunCodegenPipeline(
TimeCodegenPasses([&]() {
Error CodeGenError = runCodeGenPipeline(
- *TM, *TheModule, *OS, DwoOS, CGFT, PrintPipelinePasses.has_value(),
+ *TM, *TheModule, *OS, DwoOS, CGFT, getPrintPipelinePasses().has_value(),
!CodeGenOpts.VerifyModule, /*DisableSimplifyLibCalls=*/false,
CI.getVirtualFileSystemPtr());
if (CodeGenError)
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 06d67e9417bc44..92fb562a9b6a0c 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -1108,7 +1108,7 @@ void CodeGenAction::runOptimizationPipeline(llvm::raw_pwrite_stream &os) {
// Print a textual, '-passes=' compatible, representation of pipeline if
// requested. In this case, don't run the passes. This mimics the behavior of
// clang.
- if (llvm::PrintPipelinePasses) {
+ if (llvm::getPrintPipelinePasses()) {
mpm.printPipeline(llvm::outs(), [&pic](llvm::StringRef className) {
auto passName = pic.getPassNameForClassName(className);
return passName.empty() ? className : passName;
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 245725f13ed8a4..e77a05012a4d3f 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -1035,17 +1035,9 @@ enum class PrintPipelinePassesFormat {
Tree,
};
-struct PrintPipelinePassesFormatParser
- : public cl::parser<std::optional<PrintPipelinePassesFormat>> {
- using cl::parser<std::optional<PrintPipelinePassesFormat>>::parser;
- LLVM_ABI bool parse(cl::Option &O, StringRef ArgName, StringRef ArgValue,
- std::optional<PrintPipelinePassesFormat> &Val);
-};
-
-/// Common option used by multiple tools to print pipeline passes
-LLVM_ABI extern cl::opt<std::optional<PrintPipelinePassesFormat>, false,
- PrintPipelinePassesFormatParser>
- PrintPipelinePasses;
+/// The format -print-pipeline-passes requests, or std::nullopt if it is not
+/// given.
+LLVM_ABI std::optional<PrintPipelinePassesFormat> getPrintPipelinePasses();
LLVM_ABI void printFormattedPipelinePasses(
raw_ostream &OS, StringRef Pipeline,
diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp
index 1136d50e056559..454095ea5ac836 100644
--- a/llvm/lib/LTO/LTOBackend.cpp
+++ b/llvm/lib/LTO/LTOBackend.cpp
@@ -378,7 +378,7 @@ static void runNewPMPasses(const Config &Conf, Module &Mod, TargetMachine *TM,
if (!Conf.DisableVerify)
MPM.addPass(VerifierPass());
- if (PrintPipelinePasses) {
+ if (getPrintPipelinePasses()) {
std::string PipelineStr;
raw_string_ostream OS(PipelineStr);
MPM.printPipeline(OS, [&PIC](StringRef ClassName) {
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 4f973196eb951e..1d507a12069dbc 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -219,7 +219,6 @@
#include "llvm/Passes/OptimizationLevel.h"
#include "llvm/Passes/TriggerCrashPasses.h"
#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
@@ -425,32 +424,11 @@
using namespace llvm;
-cl::opt<std::optional<PrintPipelinePassesFormat>, false,
- PrintPipelinePassesFormatParser>
- llvm::PrintPipelinePasses(
- "print-pipeline-passes", cl::ValueOptional,
- cl::desc(
- "Print string describing the pipeline (best-effort only).\n"
- " - =text\tPrint a '-passes' compatible string describing the "
- "pipeline.\n"
- " - =tree\tPrint a tree-like structure describing the pipeline."));
-
-bool PrintPipelinePassesFormatParser::parse(
- cl::Option &O, StringRef ArgName, StringRef Arg,
- std::optional<PrintPipelinePassesFormat> &Val) {
- std::optional<PrintPipelinePassesFormat> Format =
- StringSwitch<std::optional<PrintPipelinePassesFormat>>(Arg)
- .Case("text", PrintPipelinePassesFormat::Text)
- .Case("", PrintPipelinePassesFormat::Text)
- .Case("tree", PrintPipelinePassesFormat::Tree)
- .Default(std::nullopt);
-
- if (!Format)
- return O.error(formatv(
- "'{0}' value invalid for print-pipeline-passes argument!", Arg));
-
- Val = Format;
- return false;
+std::optional<PrintPipelinePassesFormat> llvm::getPrintPipelinePasses() {
+ const PassesOptions &Opts = PassesOptions::Global;
+ if (!Opts.print_pipeline_passes)
+ return std::nullopt;
+ return Opts.print_pipeline_passes_format;
}
void llvm::printFormattedPipelinePasses(raw_ostream &OS, StringRef Pipeline,
diff --git a/llvm/lib/Passes/PassesOptions.h b/llvm/lib/Passes/PassesOptions.h
index 5fa83efdd9f0fe..5e434e5d25d17c 100644
--- a/llvm/lib/Passes/PassesOptions.h
+++ b/llvm/lib/Passes/PassesOptions.h
@@ -10,6 +10,7 @@
#define LLVM_LIB_PASSES_PASSESOPTIONS_H
#include "llvm/Analysis/InlineAdvisor.h"
+#include "llvm/Passes/PassBuilder.h"
#include "llvm/Transforms/IPO/Attributor.h"
#define OPTIONS_STRUCT_DECL
diff --git a/llvm/lib/Passes/PassesOptions.td b/llvm/lib/Passes/PassesOptions.td
index add8c5c04165d8..4a98d394d292d0 100644
--- a/llvm/lib/Passes/PassesOptions.td
+++ b/llvm/lib/Passes/PassesOptions.td
@@ -10,6 +10,14 @@ include "llvm/Option/LibraryOptions.td"
def PassesOptions : OptionsStruct;
+// PassBuilder.cpp
+defm : BoolField<"print-pipeline-passes", "false",
+ "Print string describing the pipeline (best-effort only)">;
+defm : EnumField<"print-pipeline-passes-format", "PrintPipelinePassesFormat",
+ "PrintPipelinePassesFormat::Text", "text,tree",
+ ["PrintPipelinePassesFormat::Text", "PrintPipelinePassesFormat::Tree"],
+ "The -print-pipeline-passes format: a '-passes' compatible string, or a tree-like structure">;
+
// PassBuilderPipelines.cpp
defm : EnumField<"attributor-enable", "AttributorRunOption", "AttributorRunOption::NONE",
"full,light,module,module-light,cgscc,cgscc-light,none",
diff --git a/llvm/test/CodeGen/AMDGPU/llc-pipeline-npm.ll b/llvm/test/CodeGen/AMDGPU/llc-pipeline-npm.ll
index 073d46d24ea8af..0e3f9eb7baadd5 100644
--- a/llvm/test/CodeGen/AMDGPU/llc-pipeline-npm.ll
+++ b/llvm/test/CodeGen/AMDGPU/llc-pipeline-npm.ll
@@ -1,10 +1,10 @@
-; RUN: llc -enable-new-pm -mtriple=amdgpu7.00--amdhsa -O0 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=amdgpu7.00--amdhsa -O0 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck -check-prefix=GCN-O0 %s
-; RUN: llc -enable-new-pm -mtriple=amdgpu7.00--amdhsa -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=amdgpu7.00--amdhsa -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck -check-prefix=GCN-O2 %s
-; RUN: llc -O3 -enable-new-pm -mtriple=amdgpu7.00--amdhsa -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -O3 -enable-new-pm -mtriple=amdgpu7.00--amdhsa -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck -check-prefix=GCN-O3 %s
; GCN-O0: require<MachineModuleAnalysis>
diff --git a/llvm/test/CodeGen/Lanai/llc-pipeline-npm.ll b/llvm/test/CodeGen/Lanai/llc-pipeline-npm.ll
index e0a80177683a43..33ec73ef7dd9f8 100644
--- a/llvm/test/CodeGen/Lanai/llc-pipeline-npm.ll
+++ b/llvm/test/CodeGen/Lanai/llc-pipeline-npm.ll
@@ -1,4 +1,4 @@
-; RUN: llc -enable-new-pm -mtriple=lanai -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=lanai -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck %s
; CHECK: require<MachineModuleAnalysis>
diff --git a/llvm/test/CodeGen/NVPTX/llc-pipeline-npm.ll b/llvm/test/CodeGen/NVPTX/llc-pipeline-npm.ll
index c8fc7952678fbe..5aae85ddb0c27c 100644
--- a/llvm/test/CodeGen/NVPTX/llc-pipeline-npm.ll
+++ b/llvm/test/CodeGen/NVPTX/llc-pipeline-npm.ll
@@ -1,7 +1,7 @@
; RUN: llc -enable-new-pm -mtriple=nvptx64-nvidia-cuda -mcpu=sm_90 -O0 \
-; RUN: -print-pipeline-passes=tree < %s 2>&1 | FileCheck %s --check-prefix=O0
+; RUN: -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 | FileCheck %s --check-prefix=O0
; RUN: llc -enable-new-pm -mtriple=nvptx64-nvidia-cuda -mcpu=sm_90 -O2 \
-; RUN: -print-pipeline-passes=tree < %s 2>&1 | FileCheck %s --check-prefix=O2
+; RUN: -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 | FileCheck %s --check-prefix=O2
; O0: require<MachineModuleAnalysis>
; O0-NEXT: require<profile-summary>
diff --git a/llvm/test/CodeGen/RISCV/O0-newpm-pipeline.ll b/llvm/test/CodeGen/RISCV/O0-newpm-pipeline.ll
index 713a977b3024f2..92bb328e2f1812 100644
--- a/llvm/test/CodeGen/RISCV/O0-newpm-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O0-newpm-pipeline.ll
@@ -1,7 +1,7 @@
-; RUN: llc -enable-new-pm -mtriple=riscv32 -O0 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=riscv32 -O0 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | grep -v verify \
; RUN: | FileCheck %s
-; RUN: llc -enable-new-pm -mtriple=riscv64 -O0 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=riscv64 -O0 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | grep -v verify \
; RUN: | FileCheck %s
diff --git a/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
index df952e3077de4c..8f9a57b14ec3d9 100644
--- a/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
@@ -1,7 +1,7 @@
-; RUN: llc -enable-new-pm -mtriple=riscv32 -O3 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=riscv32 -O3 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | grep -v verify \
; RUN: | FileCheck %s
-; RUN: llc -enable-new-pm -mtriple=riscv64 -O3 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=riscv64 -O3 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | grep -v verify \
; RUN: | FileCheck %s --check-prefixes=CHECK,RV64
diff --git a/llvm/test/CodeGen/X86/llc-pipeline-npm.ll b/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
index e5c2010840565e..64b17d8c53046d 100644
--- a/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
+++ b/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
@@ -1,13 +1,13 @@
-; RUN: llc -enable-new-pm -mtriple=x86_64 -O0 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=x86_64 -O0 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck -check-prefix=O0 %s
-; RUN: llc -enable-new-pm -mtriple=x86_64 -O2 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=x86_64 -O2 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck -check-prefix=O2 %s
-; RUN: llc -enable-new-pm -mtriple=x86_64-windows -O0 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=x86_64-windows -O0 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck -check-prefix=O0-WINDOWS %s
-; RUN: llc -enable-new-pm -mtriple=x86_64-windows -O3 -print-pipeline-passes=tree < %s 2>&1 \
+; RUN: llc -enable-new-pm -mtriple=x86_64-windows -O3 -print-pipeline-passes -print-pipeline-passes-format=tree < %s 2>&1 \
; RUN: | FileCheck -check-prefix=O3-WINDOWS %s
; O0: require<MachineModuleAnalysis>
diff --git a/llvm/test/tools/opt/print-pipeline-passes.ll b/llvm/test/tools/opt/print-pipeline-passes.ll
index e63ccf53f439ce..1b511a8240a71f 100644
--- a/llvm/test/tools/opt/print-pipeline-passes.ll
+++ b/llvm/test/tools/opt/print-pipeline-passes.ll
@@ -2,7 +2,7 @@
; RUN: FileCheck %s --check-prefix=TEXT
; RUN: opt -p 'no-op-module,function(no-op-function)' %s --filetype=null \
-; RUN: -S --print-pipeline-passes=tree | \
+; RUN: -S --print-pipeline-passes --print-pipeline-passes-format=tree | \
; RUN: FileCheck %s --strict-whitespace --match-full-lines --check-prefix=TREE
; TEXT: no-op-module,verify,print
diff --git a/llvm/tools/llc/lib/NewPMDriver.cpp b/llvm/tools/llc/lib/NewPMDriver.cpp
index 3eac9bd15355e0..46f08ce194ab7d 100644
--- a/llvm/tools/llc/lib/NewPMDriver.cpp
+++ b/llvm/tools/llc/lib/NewPMDriver.cpp
@@ -182,14 +182,15 @@ int llvm::compileModuleWithNewPM(
}
// If user only wants to print the pipeline, print it before parsing the MIR.
- if (PrintPipelinePasses) {
+ if (std::optional<PrintPipelinePassesFormat> Format =
+ getPrintPipelinePasses()) {
std::string PipelineStr;
raw_string_ostream OS(PipelineStr);
MPM.printPipeline(OS, [&PIC](StringRef ClassName) {
auto PassName = PIC.getPassNameForClassName(ClassName);
return PassName.empty() ? ClassName : PassName;
});
- printFormattedPipelinePasses(outs(), PipelineStr, *PrintPipelinePasses);
+ printFormattedPipelinePasses(outs(), PipelineStr, *Format);
outs() << '\n';
return 0;
}
diff --git a/llvm/tools/opt/NewPMDriver.cpp b/llvm/tools/opt/NewPMDriver.cpp
index e19dc61e772a31..5312da538a209c 100644
--- a/llvm/tools/opt/NewPMDriver.cpp
+++ b/llvm/tools/opt/NewPMDriver.cpp
@@ -571,14 +571,15 @@ bool llvm::runPassPipeline(
// Print a textual, '-passes=' compatible, representation of pipeline if
// requested.
- if (PrintPipelinePasses) {
+ if (std::optional<PrintPipelinePassesFormat> Format =
+ getPrintPipelinePasses()) {
std::string Pipeline;
raw_string_ostream SOS(Pipeline);
MPM.printPipeline(SOS, [&PIC](StringRef ClassName) {
auto PassName = PIC.getPassNameForClassName(ClassName);
return PassName.empty() ? ClassName : PassName;
});
- printFormattedPipelinePasses(outs(), Pipeline, *PrintPipelinePasses);
+ printFormattedPipelinePasses(outs(), Pipeline, *Format);
outs() << "\n";
if (!DisablePipelineVerification) {
>From 1f62e6fa7dd8c0eda21a2e58baf7d4355e82b60f Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 8 Oct 2026 20:49:45 -0700
Subject: [PATCH 3/3] Keep generated .inc files smaller
---
llvm/include/llvm/Option/LibraryOptions.td | 4 ++--
.../TableGen/Basic/OptionParserEmitter.cpp | 18 ++++++++++++------
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/Option/LibraryOptions.td b/llvm/include/llvm/Option/LibraryOptions.td
index 5bad10abcadce5..7bd708a7d8f3bb 100644
--- a/llvm/include/llvm/Option/LibraryOptions.td
+++ b/llvm/include/llvm/Option/LibraryOptions.td
@@ -41,7 +41,7 @@ class EnumValues<string values, list<code> enumerators>
// A bool member set by -<name> or -<name>=<true|false|1|0>.
multiclass BoolField<string name, code default, string help> {
def NAME : FlagOrEq<["-", "--"], name>, Field<NAME, "bool", default>,
- BareValue<"true">, HelpText<help>;
+ HelpText<help>;
}
// A BoolOrDefault member, Default unless -<name> or -<name>=<true|false|1|0>
@@ -49,7 +49,7 @@ multiclass BoolField<string name, code default, string help> {
multiclass OptionalBoolField<string name, string help> {
def NAME : FlagOrEq<["-", "--"], name>,
Field<NAME, "llvm::BoolOrDefault", "llvm::BoolOrDefault::Default">,
- BareValue<"llvm::BoolOrDefault::True">, HelpText<help>;
+ HelpText<help>;
}
// A member of the enumeration <type> set by -<name>=<value> or -<name> <value>,
diff --git a/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp b/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp
index 4c390b472ed1ae..23b73ee3d9f2f0 100644
--- a/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/OptionParserEmitter.cpp
@@ -282,8 +282,10 @@ static void emitOptionsStruct(const Record &Struct,
if (Kind != "FlagOrEq" && Kind != "SeparateOrEq")
PrintFatalError(R->getLoc(),
"a member is set by a FlagOrEq or SeparateOrEq");
- if (Kind == "FlagOrEq" && !R->getValue("BareValue"))
- PrintFatalError(R->getLoc(), "a FlagOrEq needs a BareValue");
+ StringRef Type = R->getValueAsString("FieldType");
+ if (Kind == "FlagOrEq" && Type != "bool" && Type != "llvm::BoolOrDefault" &&
+ !R->getValue("BareValue"))
+ PrintFatalError(R->getLoc(), "a FlagOrEq sets a bool or has a BareValue");
Fields.push_back(R);
}
// Members in declaration order.
@@ -344,9 +346,8 @@ static void emitOptionsStruct(const Record &Struct,
OS << " case OPT_" << getStructOptionID(*R) << ":\n";
std::string Member = getMemberName(*R, Prefix);
if (R->getValue("BareValue"))
- OS << " if (!A.getNumValues()) {\n " << Member << " = "
- << R->getValueAsString("BareValue")
- << ";\n return true;\n }\n";
+ OS << " if (!A.getNumValues()) { " << Member << " = "
+ << R->getValueAsString("BareValue") << "; return true; }\n";
if (!isa<UnsetInit>(R->getValueInit("NormalizedValues"))) {
SmallVector<StringRef> Values;
R->getValueAsString("Values").split(Values, ',');
@@ -362,7 +363,12 @@ static void emitOptionsStruct(const Record &Struct,
OS << " return false;\n }\n";
continue;
}
- OS << " return llvm::opt::parseArgValue(A.getValue(), " << Member
+ // A FlagOrEq without a value means =true.
+ StringRef Value =
+ R->getValueAsDef("Kind")->getValueAsString("Name") == "FlagOrEq"
+ ? "A.getNumValues() ? A.getValue() : \"true\""
+ : "A.getValue()";
+ OS << " return llvm::opt::parseArgValue(" << Value << ", " << Member
<< ");\n";
}
OS << " }\n llvm_unreachable(\"option without a member\");\n}\n";
More information about the flang-commits
mailing list