[llvm] [PassBuilder] Table-drive pass name printing (PR #202656)

David Zbarsky via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 10:48:01 PDT 2026


https://github.com/dzbarsky updated https://github.com/llvm/llvm-project/pull/202656

>From 35d4ce60cf4cdfbf22954d6a4dad7c70e6ea9f40 Mon Sep 17 00:00:00 2001
From: David Zbarsky <dzbarsky at gmail.com>
Date: Mon, 8 Jun 2026 23:39:29 -0400
Subject: [PATCH 1/2] [PassBuilder] Table-drive pass name printing

Replace the macro-expanded raw_ostream operations in PassBuilder::printPassNames with static pass-name arrays and two shared noinline printing loops. Preserve the generated category order and the exact spelling of parameterized pass names.

The change only executes when a client requests the pass-name listing; normal pipeline parsing and optimization do not access the new tables or helpers.

A stripped opt binary shrinks from 115,493,720 to 115,394,640 bytes, saving 99,080 bytes. The linked __TEXT section shrinks by 98,304 bytes.

Validate byte-identical opt --print-passes output, compile PassBuilder.cpp, and compare the linked stripped opt binaries. Normal optimization performance is unaffected because printPassNames is not called by optimization pipelines.
---
 llvm/lib/Passes/PassBuilder.cpp | 111 +++++++++++++++++++++++++-------
 1 file changed, 88 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index f7db63ef8bf74..ab4ed2f19e5e3 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -2796,92 +2796,157 @@ PassBuilder::parseRegAllocFilter(StringRef FilterName) {
   return std::nullopt;
 }
 
-static void printPassName(StringRef PassName, raw_ostream &OS) {
-  OS << "  " << PassName << "\n";
+namespace {
+struct PassNameWithParams {
+  StringLiteral Name;
+  StringLiteral Params;
+};
+} // namespace
+
+LLVM_ATTRIBUTE_NOINLINE static void
+printPassNameList(ArrayRef<StringLiteral> PassNames, raw_ostream &OS) {
+  for (StringRef PassName : PassNames)
+    OS << "  " << PassName << '\n';
 }
-static void printPassName(StringRef PassName, StringRef Params,
-                          raw_ostream &OS) {
-  OS << "  " << PassName << "<" << Params << ">\n";
+
+LLVM_ATTRIBUTE_NOINLINE static void
+printPassNameList(ArrayRef<PassNameWithParams> PassNames, raw_ostream &OS) {
+  for (const PassNameWithParams &PassName : PassNames)
+    OS << "  " << PassName.Name << "<" << PassName.Params << ">\n";
 }
 
 void PassBuilder::printPassNames(raw_ostream &OS) {
   // TODO: print pass descriptions when they are available
 
   OS << "Module passes:\n";
-#define MODULE_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral ModulePassNames[] = {
+#define MODULE_PASS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(ModulePassNames, OS);
 
   OS << "Module passes with params:\n";
+  static constexpr PassNameWithParams ModulePassNamesWithParams[] = {
 #define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)      \
-  printPassName(NAME, PARAMS, OS);
+  {NAME, PARAMS},
 #include "PassRegistry.def"
+  };
+  printPassNameList(ModulePassNamesWithParams, OS);
 
   OS << "Module analyses:\n";
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral ModuleAnalysisNames[] = {
+#define MODULE_ANALYSIS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(ModuleAnalysisNames, OS);
 
   OS << "Module alias analyses:\n";
-#define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral ModuleAliasAnalysisNames[] = {
+#define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(ModuleAliasAnalysisNames, OS);
 
   OS << "CGSCC passes:\n";
-#define CGSCC_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral CGSCCPassNames[] = {
+#define CGSCC_PASS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(CGSCCPassNames, OS);
 
   OS << "CGSCC passes with params:\n";
+  static constexpr PassNameWithParams CGSCCPassNamesWithParams[] = {
 #define CGSCC_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)       \
-  printPassName(NAME, PARAMS, OS);
+  {NAME, PARAMS},
 #include "PassRegistry.def"
+  };
+  printPassNameList(CGSCCPassNamesWithParams, OS);
 
   OS << "CGSCC analyses:\n";
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral CGSCCAnalysisNames[] = {
+#define CGSCC_ANALYSIS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(CGSCCAnalysisNames, OS);
 
   OS << "Function passes:\n";
-#define FUNCTION_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral FunctionPassNames[] = {
+#define FUNCTION_PASS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(FunctionPassNames, OS);
 
   OS << "Function passes with params:\n";
+  static constexpr PassNameWithParams FunctionPassNamesWithParams[] = {
 #define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)    \
-  printPassName(NAME, PARAMS, OS);
+  {NAME, PARAMS},
 #include "PassRegistry.def"
+  };
+  printPassNameList(FunctionPassNamesWithParams, OS);
 
   OS << "Function analyses:\n";
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral FunctionAnalysisNames[] = {
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(FunctionAnalysisNames, OS);
 
   OS << "Function alias analyses:\n";
-#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral FunctionAliasAnalysisNames[] = {
+#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(FunctionAliasAnalysisNames, OS);
 
   OS << "LoopNest passes:\n";
-#define LOOPNEST_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral LoopNestPassNames[] = {
+#define LOOPNEST_PASS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(LoopNestPassNames, OS);
 
   OS << "Loop passes:\n";
-#define LOOP_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral LoopPassNames[] = {
+#define LOOP_PASS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(LoopPassNames, OS);
 
   OS << "Loop passes with params:\n";
+  static constexpr PassNameWithParams LoopPassNamesWithParams[] = {
 #define LOOP_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)        \
-  printPassName(NAME, PARAMS, OS);
+  {NAME, PARAMS},
 #include "PassRegistry.def"
+  };
+  printPassNameList(LoopPassNamesWithParams, OS);
 
   OS << "Loop analyses:\n";
-#define LOOP_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral LoopAnalysisNames[] = {
+#define LOOP_ANALYSIS(NAME, CREATE_PASS) NAME,
 #include "PassRegistry.def"
+  };
+  printPassNameList(LoopAnalysisNames, OS);
 
   OS << "Machine module passes (WIP):\n";
-#define MACHINE_MODULE_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral MachineModulePassNames[] = {
+#define MACHINE_MODULE_PASS(NAME, CREATE_PASS) NAME,
 #include "llvm/Passes/MachinePassRegistry.def"
+      ""};
+  printPassNameList(ArrayRef(MachineModulePassNames).drop_back(), OS);
 
   OS << "Machine function passes (WIP):\n";
-#define MACHINE_FUNCTION_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral MachineFunctionPassNames[] = {
+#define MACHINE_FUNCTION_PASS(NAME, CREATE_PASS) NAME,
 #include "llvm/Passes/MachinePassRegistry.def"
+  };
+  printPassNameList(MachineFunctionPassNames, OS);
 
   OS << "Machine function analyses (WIP):\n";
-#define MACHINE_FUNCTION_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
+  static constexpr StringLiteral MachineFunctionAnalysisNames[] = {
+#define MACHINE_FUNCTION_ANALYSIS(NAME, CREATE_PASS) NAME,
 #include "llvm/Passes/MachinePassRegistry.def"
+  };
+  printPassNameList(MachineFunctionAnalysisNames, OS);
 }
 
 void PassBuilder::registerParseTopLevelPipelineCallback(

>From d909e47d114fb15212bacb8fec405c19a87909f2 Mon Sep 17 00:00:00 2001
From: David Zbarsky <dzbarsky at gmail.com>
Date: Thu, 11 Jun 2026 13:47:12 -0400
Subject: [PATCH 2/2] [PassBuilder] Table-drive pass name printing

Replace the address-bearing StringLiteral arrays with character blobs and local
StringTable views. Preserve the shared noinline printing loops, generated
category order, and exact parameterized pass-name spelling.

Relative to the StringLiteral array implementation, PassBuilder.cpp.o shrinks
by 5,032 bytes and 578 relocations. Linked opt runtime rebases decrease by 603,
restoring the pre-change fixup count. The fully stripped opt binary gives back
16,496 bytes but still shrinks by 99,072 bytes from the pre-change baseline;
the linked __TEXT segment still shrinks by 98,304 bytes.

Validate byte-identical opt --print-passes output, compile PassBuilder.cpp, and
compare matched linked opt binaries and fixups.
---
 llvm/lib/Passes/PassBuilder.cpp | 139 ++++++++++++++++----------------
 1 file changed, 71 insertions(+), 68 deletions(-)

diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 7a71b5d58ec05..0f288a2124b7b 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -16,6 +16,7 @@
 
 #include "llvm/Passes/PassBuilder.h"
 #include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/StringTable.h"
 #include "llvm/Analysis/AliasAnalysisEvaluator.h"
 #include "llvm/Analysis/AliasSetTracker.h"
 #include "llvm/Analysis/AssumptionCache.h"
@@ -2850,157 +2851,159 @@ PassBuilder::parseRegAllocFilter(StringRef FilterName) {
   return std::nullopt;
 }
 
-namespace {
-struct PassNameWithParams {
-  StringLiteral Name;
-  StringLiteral Params;
-};
-} // namespace
-
-LLVM_ATTRIBUTE_NOINLINE static void
-printPassNameList(ArrayRef<StringLiteral> PassNames, raw_ostream &OS) {
-  for (StringRef PassName : PassNames)
+LLVM_ATTRIBUTE_NOINLINE static void printPassNameList(StringTable PassNames,
+                                                      raw_ostream &OS) {
+  for (StringRef PassName : drop_begin(PassNames))
     OS << "  " << PassName << '\n';
 }
 
 LLVM_ATTRIBUTE_NOINLINE static void
-printPassNameList(ArrayRef<PassNameWithParams> PassNames, raw_ostream &OS) {
-  for (const PassNameWithParams &PassName : PassNames)
-    OS << "  " << PassName.Name << "<" << PassName.Params << ">\n";
+printPassNameListWithParams(StringTable PassNames, raw_ostream &OS) {
+  auto I = PassNames.begin();
+  auto End = PassNames.end();
+  ++I;
+  while (I != End) {
+    StringRef Name = *I;
+    ++I;
+    assert(I != End);
+    StringRef Params = *I;
+    ++I;
+    OS << "  " << Name << '<' << Params << ">\n";
+  }
 }
 
 void PassBuilder::printPassNames(raw_ostream &OS) {
   // TODO: print pass descriptions when they are available
 
   OS << "Module passes:\n";
-  static constexpr StringLiteral ModulePassNames[] = {
-#define MODULE_PASS(NAME, CREATE_PASS) NAME,
+  static constexpr char ModulePassNames[] = {"\0"
+#define MODULE_PASS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(ModulePassNames, OS);
+  printPassNameList(StringTable(ModulePassNames), OS);
 
   OS << "Module passes with params:\n";
-  static constexpr PassNameWithParams ModulePassNamesWithParams[] = {
+  static constexpr char ModulePassNamesWithParams[] = {"\0"
 #define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)      \
-  {NAME, PARAMS},
+  NAME "\0" PARAMS "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(ModulePassNamesWithParams, OS);
+  printPassNameListWithParams(StringTable(ModulePassNamesWithParams), OS);
 
   OS << "Module analyses:\n";
-  static constexpr StringLiteral ModuleAnalysisNames[] = {
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) NAME,
+  static constexpr char ModuleAnalysisNames[] = {"\0"
+#define MODULE_ANALYSIS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(ModuleAnalysisNames, OS);
+  printPassNameList(StringTable(ModuleAnalysisNames), OS);
 
   OS << "Module alias analyses:\n";
-  static constexpr StringLiteral ModuleAliasAnalysisNames[] = {
-#define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) NAME,
+  static constexpr char ModuleAliasAnalysisNames[] = {"\0"
+#define MODULE_ALIAS_ANALYSIS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(ModuleAliasAnalysisNames, OS);
+  printPassNameList(StringTable(ModuleAliasAnalysisNames), OS);
 
   OS << "CGSCC passes:\n";
-  static constexpr StringLiteral CGSCCPassNames[] = {
-#define CGSCC_PASS(NAME, CREATE_PASS) NAME,
+  static constexpr char CGSCCPassNames[] = {"\0"
+#define CGSCC_PASS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(CGSCCPassNames, OS);
+  printPassNameList(StringTable(CGSCCPassNames), OS);
 
   OS << "CGSCC passes with params:\n";
-  static constexpr PassNameWithParams CGSCCPassNamesWithParams[] = {
+  static constexpr char CGSCCPassNamesWithParams[] = {"\0"
 #define CGSCC_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)       \
-  {NAME, PARAMS},
+  NAME "\0" PARAMS "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(CGSCCPassNamesWithParams, OS);
+  printPassNameListWithParams(StringTable(CGSCCPassNamesWithParams), OS);
 
   OS << "CGSCC analyses:\n";
-  static constexpr StringLiteral CGSCCAnalysisNames[] = {
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS) NAME,
+  static constexpr char CGSCCAnalysisNames[] = {"\0"
+#define CGSCC_ANALYSIS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(CGSCCAnalysisNames, OS);
+  printPassNameList(StringTable(CGSCCAnalysisNames), OS);
 
   OS << "Function passes:\n";
-  static constexpr StringLiteral FunctionPassNames[] = {
-#define FUNCTION_PASS(NAME, CREATE_PASS) NAME,
+  static constexpr char FunctionPassNames[] = {"\0"
+#define FUNCTION_PASS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(FunctionPassNames, OS);
+  printPassNameList(StringTable(FunctionPassNames), OS);
 
   OS << "Function passes with params:\n";
-  static constexpr PassNameWithParams FunctionPassNamesWithParams[] = {
+  static constexpr char FunctionPassNamesWithParams[] = {"\0"
 #define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)    \
-  {NAME, PARAMS},
+  NAME "\0" PARAMS "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(FunctionPassNamesWithParams, OS);
+  printPassNameListWithParams(StringTable(FunctionPassNamesWithParams), OS);
 
   OS << "Function analyses:\n";
-  static constexpr StringLiteral FunctionAnalysisNames[] = {
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) NAME,
+  static constexpr char FunctionAnalysisNames[] = {"\0"
+#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(FunctionAnalysisNames, OS);
+  printPassNameList(StringTable(FunctionAnalysisNames), OS);
 
   OS << "Function alias analyses:\n";
-  static constexpr StringLiteral FunctionAliasAnalysisNames[] = {
-#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) NAME,
+  static constexpr char FunctionAliasAnalysisNames[] = {"\0"
+#define FUNCTION_ALIAS_ANALYSIS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(FunctionAliasAnalysisNames, OS);
+  printPassNameList(StringTable(FunctionAliasAnalysisNames), OS);
 
   OS << "LoopNest passes:\n";
-  static constexpr StringLiteral LoopNestPassNames[] = {
-#define LOOPNEST_PASS(NAME, CREATE_PASS) NAME,
+  static constexpr char LoopNestPassNames[] = {"\0"
+#define LOOPNEST_PASS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(LoopNestPassNames, OS);
+  printPassNameList(StringTable(LoopNestPassNames), OS);
 
   OS << "Loop passes:\n";
-  static constexpr StringLiteral LoopPassNames[] = {
-#define LOOP_PASS(NAME, CREATE_PASS) NAME,
+  static constexpr char LoopPassNames[] = {"\0"
+#define LOOP_PASS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(LoopPassNames, OS);
+  printPassNameList(StringTable(LoopPassNames), OS);
 
   OS << "Loop passes with params:\n";
-  static constexpr PassNameWithParams LoopPassNamesWithParams[] = {
+  static constexpr char LoopPassNamesWithParams[] = {"\0"
 #define LOOP_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)        \
-  {NAME, PARAMS},
+  NAME "\0" PARAMS "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(LoopPassNamesWithParams, OS);
+  printPassNameListWithParams(StringTable(LoopPassNamesWithParams), OS);
 
   OS << "Loop analyses:\n";
-  static constexpr StringLiteral LoopAnalysisNames[] = {
-#define LOOP_ANALYSIS(NAME, CREATE_PASS) NAME,
+  static constexpr char LoopAnalysisNames[] = {"\0"
+#define LOOP_ANALYSIS(NAME, CREATE_PASS) NAME "\0"
 #include "PassRegistry.def"
   };
-  printPassNameList(LoopAnalysisNames, OS);
+  printPassNameList(StringTable(LoopAnalysisNames), OS);
 
   OS << "Machine module passes (WIP):\n";
-  static constexpr StringLiteral MachineModulePassNames[] = {
-#define MACHINE_MODULE_PASS(NAME, CREATE_PASS) NAME,
+  static constexpr char MachineModulePassNames[] = {"\0"
+#define MACHINE_MODULE_PASS(NAME, CREATE_PASS) NAME "\0"
 #include "llvm/Passes/MachinePassRegistry.def"
-      ""};
-  printPassNameList(ArrayRef(MachineModulePassNames).drop_back(), OS);
+  };
+  printPassNameList(StringTable(MachineModulePassNames), OS);
 
   OS << "Machine function passes (WIP):\n";
-  static constexpr StringLiteral MachineFunctionPassNames[] = {
-#define MACHINE_FUNCTION_PASS(NAME, CREATE_PASS) NAME,
+  static constexpr char MachineFunctionPassNames[] = {"\0"
+#define MACHINE_FUNCTION_PASS(NAME, CREATE_PASS) NAME "\0"
 #include "llvm/Passes/MachinePassRegistry.def"
   };
-  printPassNameList(MachineFunctionPassNames, OS);
+  printPassNameList(StringTable(MachineFunctionPassNames), OS);
 
   OS << "Machine function analyses (WIP):\n";
-  static constexpr StringLiteral MachineFunctionAnalysisNames[] = {
-#define MACHINE_FUNCTION_ANALYSIS(NAME, CREATE_PASS) NAME,
+  static constexpr char MachineFunctionAnalysisNames[] = {"\0"
+#define MACHINE_FUNCTION_ANALYSIS(NAME, CREATE_PASS) NAME "\0"
 #include "llvm/Passes/MachinePassRegistry.def"
   };
-  printPassNameList(MachineFunctionAnalysisNames, OS);
+  printPassNameList(StringTable(MachineFunctionAnalysisNames), OS);
 }
 
 void PassBuilder::registerParseTopLevelPipelineCallback(



More information about the llvm-commits mailing list