[clang] [lld] [lldb] [llvm] [Option] Shrink Info from 40 to 24 bytes (PR #224807)
Fangrui Song via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 18 23:50:10 PDT 2026
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/224807
>From 8fccb784f2883bf9c65eacafb954b40fb8dfe078 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 18 Sep 2026 19:48:57 -0700
Subject: [PATCH 1/2] [Option] Replace the OptionTables object with a function.
NFC
The generated aggregate holds seven addresses, so it needs a relocation
per pointer and lives in .data.rel.ro (dynamic relocations in PIE and
shared library builds):
```
static constexpr llvm::opt::OptTable::Tables OptionTables = {
OptionStrTable, OptionPrefixesTable, OptionPrefixesUnion, ...};
...
FooOptTable() : OptTable(OptionTables) {}
```
Emit a function instead. The caller builds the aggregate on the stack
from PC-relative addresses, which the linker resolves:
```
static constexpr llvm::opt::OptTable::Tables optionTables() {
return {OptionStrTable, OptionPrefixesTable, OptionInfoTable, ...};
}
...
FooOptTable() : OptTable(optionTables()) {}
```
Derive the prefix union from the prefix table in the constructor and
drop the emitted OptionPrefixesUnion. Drop the redundant `static` on the
emitted tables: a namespace-scope const object has internal linkage.
Aided by Opus 5
---
clang/lib/Options/DriverOptions.cpp | 2 +-
clang/tools/clang-installapi/Options.cpp | 2 +-
.../ClangLinkerWrapper.cpp | 2 +-
.../ClangNVLinkWrapper.cpp | 2 +-
clang/tools/clang-scan-deps/ClangScanDeps.cpp | 4 +-
.../clang-sycl-linker/ClangSYCLLinker.cpp | 2 +-
lld/COFF/DriverUtils.cpp | 2 +-
lld/ELF/DriverUtils.cpp | 2 +-
lld/MachO/DriverUtils.cpp | 2 +-
lld/MinGW/Driver.cpp | 2 +-
lld/wasm/Driver.cpp | 2 +-
lldb/tools/driver/Driver.cpp | 2 +-
lldb/tools/lldb-dap/tool/lldb-dap.cpp | 2 +-
lldb/tools/lldb-server/lldb-gdbserver.cpp | 2 +-
lldb/tools/lldb-server/lldb-platform.cpp | 2 +-
.../examples/OptSubcommand/llvm-hello-sub.cpp | 2 +-
llvm/include/llvm/Option/OptTable.h | 4 +-
.../JITLink/COFFDirectiveParser.cpp | 3 +-
llvm/lib/Option/OptTable.cpp | 18 +++++---
.../llvm-dlltool/DlltoolDriver.cpp | 2 +-
llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp | 2 +-
llvm/tools/dsymutil/dsymutil.cpp | 2 +-
llvm/tools/llvm-cas/llvm-cas.cpp | 2 +-
llvm/tools/llvm-cgdata/llvm-cgdata.cpp | 2 +-
llvm/tools/llvm-cvtres/llvm-cvtres.cpp | 2 +-
llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp | 2 +-
.../llvm-debuginfod-find.cpp | 2 +-
.../tools/llvm-debuginfod/llvm-debuginfod.cpp | 2 +-
llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp | 2 +-
llvm/tools/llvm-dwp/llvm-dwp.cpp | 2 +-
llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp | 4 +-
llvm/tools/llvm-ifs/llvm-ifs.cpp | 4 +-
.../llvm-libtool-darwin.cpp | 2 +-
llvm/tools/llvm-lipo/llvm-lipo.cpp | 2 +-
llvm/tools/llvm-ml/llvm-ml.cpp | 2 +-
llvm/tools/llvm-mt/llvm-mt.cpp | 2 +-
llvm/tools/llvm-nm/llvm-nm.cpp | 2 +-
llvm/tools/llvm-objcopy/ObjcopyOptions.cpp | 11 +++--
llvm/tools/llvm-objdump/llvm-objdump.cpp | 4 +-
llvm/tools/llvm-rc/llvm-rc.cpp | 4 +-
llvm/tools/llvm-readobj/llvm-readobj.cpp | 2 +-
llvm/tools/llvm-readtapi/llvm-readtapi.cpp | 4 +-
llvm/tools/llvm-size/llvm-size.cpp | 2 +-
llvm/tools/llvm-strings/llvm-strings.cpp | 2 +-
.../tools/llvm-symbolizer/llvm-symbolizer.cpp | 2 +-
.../llvm-tli-checker/llvm-tli-checker.cpp | 2 +-
llvm/tools/sancov/sancov.cpp | 2 +-
llvm/unittests/Option/OptionParsingTest.cpp | 2 +-
.../Option/OptionSubCommandsTest.cpp | 2 +-
llvm/utils/TableGen/OptionParserEmitter.cpp | 46 ++++++-------------
50 files changed, 88 insertions(+), 96 deletions(-)
diff --git a/clang/lib/Options/DriverOptions.cpp b/clang/lib/Options/DriverOptions.cpp
index 50158f13a9653..4a1684cd3ce8c 100644
--- a/clang/lib/Options/DriverOptions.cpp
+++ b/clang/lib/Options/DriverOptions.cpp
@@ -23,7 +23,7 @@ namespace {
class DriverOptTable : public OptTable {
public:
- DriverOptTable() : OptTable(OptionTables) {
+ DriverOptTable() : OptTable(optionTables()) {
setValuesCodeFn(getOptionValuesCode);
}
};
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index c3bd0b14ce65a..8c9d1142d1510 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -38,7 +38,7 @@ namespace {
/// \brief Create OptTable class for parsing actual command line arguments.
class DriverOptTable : public opt::OptTable {
public:
- DriverOptTable() : OptTable(OptionTables) {}
+ DriverOptTable() : OptTable(optionTables()) {}
};
} // end anonymous namespace.
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 2e178aee196b6..0e71d0020c071 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -179,7 +179,7 @@ enum ID {
class WrapperOptTable : public opt::OptTable {
public:
- WrapperOptTable() : opt::OptTable(OptionTables) {}
+ WrapperOptTable() : opt::OptTable(optionTables()) {}
};
const OptTable &getOptTable() {
diff --git a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp
index 6df0af65e292b..84a3561fb9725 100644
--- a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp
+++ b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp
@@ -116,7 +116,7 @@ enum ID {
class WrapperOptTable : public opt::OptTable {
public:
- WrapperOptTable() : opt::OptTable(OptionTables) {}
+ WrapperOptTable() : opt::OptTable(optionTables()) {}
};
const OptTable &getOptTable() {
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 0cbc115f910df..778f73909665d 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -59,7 +59,9 @@ enum ID {
class ScanDepsOptTable : public llvm::opt::OptTable {
public:
- ScanDepsOptTable() : OptTable(OptionTables) { setGroupedShortOptions(true); }
+ ScanDepsOptTable() : OptTable(optionTables()) {
+ setGroupedShortOptions(true);
+ }
};
enum ResourceDirRecipeKind {
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index 84e0ead680d2b..b568c7e87ce7c 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -103,7 +103,7 @@ enum ID {
class LinkerOptTable : public opt::OptTable {
public:
- LinkerOptTable() : opt::OptTable(OptionTables) {}
+ LinkerOptTable() : opt::OptTable(optionTables()) {}
};
} // namespace
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 75530b405c692..265ddee6d8557 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -751,7 +751,7 @@ MemoryBufferRef LinkerDriver::convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
#define OPTTABLE_CODE
#include "Options.inc"
-COFFOptTable::COFFOptTable() : OptTable(OptionTables, true) {}
+COFFOptTable::COFFOptTable() : OptTable(optionTables(), true) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.
diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
index b2c760eeaf3ec..7bee46d8534bf 100644
--- a/lld/ELF/DriverUtils.cpp
+++ b/lld/ELF/DriverUtils.cpp
@@ -36,7 +36,7 @@ using namespace lld::elf;
#define OPTTABLE_CODE
#include "Options.inc"
-ELFOptTable::ELFOptTable() : OptTable(OptionTables) {}
+ELFOptTable::ELFOptTable() : OptTable(optionTables()) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.
diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
index 9b0f820634ad6..e097d2ce302c3 100644
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -35,7 +35,7 @@ using namespace lld::macho;
#define OPTTABLE_CODE
#include "Options.inc"
-MachOOptTable::MachOOptTable() : OptTable(OptionTables) {}
+MachOOptTable::MachOOptTable() : OptTable(optionTables()) {}
// Set color diagnostics according to --color-diagnostics={auto,always,never}
// or --no-color-diagnostics flags.
diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp
index b15d06b82146a..53cce5b5c0277 100644
--- a/lld/MinGW/Driver.cpp
+++ b/lld/MinGW/Driver.cpp
@@ -64,7 +64,7 @@ enum {
namespace {
class MinGWOptTable : public opt::OptTable {
public:
- MinGWOptTable() : opt::OptTable(OptionTables, false) {}
+ MinGWOptTable() : opt::OptTable(optionTables(), false) {}
opt::InputArgList parse(ArrayRef<const char *> argv);
};
} // namespace
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index a15c5cf0ad7ed..1de9851d5ed3e 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -151,7 +151,7 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
namespace {
class WasmOptTable : public opt::OptTable {
public:
- WasmOptTable() : opt::OptTable(OptionTables) {}
+ WasmOptTable() : opt::OptTable(optionTables()) {}
opt::InputArgList parse(ArrayRef<const char *> argv);
};
} // namespace
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index 69894370c07e8..529ec309445cf 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -84,7 +84,7 @@ enum ID {
class LLDBOptTable : public opt::OptTable {
public:
- LLDBOptTable() : opt::OptTable(OptionTables) {}
+ LLDBOptTable() : opt::OptTable(optionTables()) {}
};
} // namespace
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index 7dc367af45199..9444f77ae31ca 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -114,7 +114,7 @@ enum ID {
#include "Options.inc"
class LLDBDAPOptTable : public llvm::opt::OptTable {
public:
- LLDBDAPOptTable() : llvm::opt::OptTable(OptionTables, true) {}
+ LLDBDAPOptTable() : llvm::opt::OptTable(optionTables(), true) {}
};
} // anonymous namespace
diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp
index 853aee10ac4ec..98a79dedf65c0 100644
--- a/lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -307,7 +307,7 @@ enum ID {
class LLGSOptTable : public opt::OptTable {
public:
- LLGSOptTable() : opt::OptTable(OptionTables) {}
+ LLGSOptTable() : opt::OptTable(optionTables()) {}
void PrintHelp(llvm::StringRef Name) {
std::string Usage =
diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp
index 8a1e273435d92..29f065c33f409 100644
--- a/lldb/tools/lldb-server/lldb-platform.cpp
+++ b/lldb/tools/lldb-server/lldb-platform.cpp
@@ -73,7 +73,7 @@ enum ID {
class PlatformOptTable : public opt::OptTable {
public:
- PlatformOptTable() : opt::OptTable(OptionTables) {}
+ PlatformOptTable() : opt::OptTable(optionTables()) {}
void PrintHelp(llvm::StringRef Name) {
std::string Usage =
diff --git a/llvm/examples/OptSubcommand/llvm-hello-sub.cpp b/llvm/examples/OptSubcommand/llvm-hello-sub.cpp
index 485a3bfe89907..bc057002a4b36 100644
--- a/llvm/examples/OptSubcommand/llvm-hello-sub.cpp
+++ b/llvm/examples/OptSubcommand/llvm-hello-sub.cpp
@@ -24,7 +24,7 @@ enum ID {
class HelloSubOptTable : public OptTable {
public:
- HelloSubOptTable() : OptTable(OptionTables) {};
+ HelloSubOptTable() : OptTable(optionTables()) {};
};
} // namespace
diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h
index 1532f18b105bd..611cfe826a99f 100644
--- a/llvm/include/llvm/Option/OptTable.h
+++ b/llvm/include/llvm/Option/OptTable.h
@@ -159,7 +159,6 @@ class LLVM_ABI OptTable {
struct Tables {
const StringTable &StrTable;
ArrayRef<StringTable::Offset> PrefixesTable;
- ArrayRef<StringTable::Offset> PrefixesUnion;
ArrayRef<Info> Infos;
ArrayRef<HelpTextVariant> HelpTextVariants;
ArrayRef<SubCommand> SubCommands;
@@ -252,11 +251,10 @@ class LLVM_ABI OptTable {
unsigned &Index) const;
protected:
- OptTable(const Tables &Tables, bool IgnoreCase = false);
-
void setValuesCodeFn(ValuesCodeFnTy Fn) { ValuesCodeFn = Fn; }
public:
+ OptTable(const Tables &T, bool IgnoreCase = false);
virtual ~OptTable();
/// Return the string table used for option names.
diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
index 624ead6a8ea78..6300cfa56f133 100644
--- a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
@@ -17,14 +17,13 @@ using namespace jitlink;
#define DEBUG_TYPE "jitlink"
-// Create table mapping all options defined in COFFOptions.td
using namespace llvm::opt;
#define OPTTABLE_CODE
#include "COFFOptions.inc"
class COFFOptTable : public opt::OptTable {
public:
- COFFOptTable() : OptTable(OptionTables, true) {}
+ COFFOptTable() : OptTable(optionTables(), true) {}
};
static COFFOptTable optTable;
diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp
index c444235076586..87487d625f7e4 100644
--- a/llvm/lib/Option/OptTable.cpp
+++ b/llvm/lib/Option/OptTable.cpp
@@ -78,12 +78,18 @@ OptTable::OptTable(const Tables &T, bool IgnoreCase)
OptionInfos(T.Infos), IgnoreCase(IgnoreCase), SubCommands(T.SubCommands),
SubCommandIDsTable(T.SubCommandIDs),
HelpTextVariantsTable(T.HelpTextVariants) {
- for (StringTable::Offset PrefixOffset : T.PrefixesUnion) {
- StringRef Prefix = (*StrTable)[PrefixOffset];
- PrefixesUnion.push_back(Prefix);
- for (char C : Prefix)
- if (!is_contained(PrefixChars, C))
- PrefixChars.push_back(C);
+ // Each prefix set in PrefixesTable starts with its size.
+ for (unsigned I = 0, E = PrefixesTable.size(); I != E;) {
+ unsigned Size = PrefixesTable[I++].value();
+ for (unsigned J = 0; J != Size; ++J) {
+ StringRef Prefix = (*StrTable)[PrefixesTable[I++]];
+ if (is_contained(PrefixesUnion, Prefix))
+ continue;
+ PrefixesUnion.push_back(Prefix);
+ for (char C : Prefix)
+ if (!is_contained(PrefixChars, C))
+ PrefixChars.push_back(C);
+ }
}
// Find start of normal options.
diff --git a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
index cef8f5af611d8..d914b49747c32 100644
--- a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
+++ b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
@@ -45,7 +45,7 @@ using namespace llvm::opt;
class DllOptTable : public opt::OptTable {
public:
- DllOptTable() : opt::OptTable(OptionTables, false) {}
+ DllOptTable() : opt::OptTable(optionTables(), false) {}
};
// Opens a file. Path has to be resolved already.
diff --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
index 0cae27d4c2765..55e59aa6ac12d 100644
--- a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
+++ b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
@@ -50,7 +50,7 @@ using namespace llvm::opt;
class LibOptTable : public opt::OptTable {
public:
- LibOptTable() : opt::OptTable(OptionTables, true) {}
+ LibOptTable() : opt::OptTable(optionTables(), true) {}
};
} // namespace
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index 9adf846d1e1a3..0b30d3512d8d2 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -74,7 +74,7 @@ using namespace llvm::opt;
class DsymutilOptTable : public opt::OptTable {
public:
- DsymutilOptTable() : opt::OptTable(OptionTables) {}
+ DsymutilOptTable() : opt::OptTable(optionTables()) {}
};
} // namespace
diff --git a/llvm/tools/llvm-cas/llvm-cas.cpp b/llvm/tools/llvm-cas/llvm-cas.cpp
index 7ed4f4fc0846a..d4d79336b5d75 100644
--- a/llvm/tools/llvm-cas/llvm-cas.cpp
+++ b/llvm/tools/llvm-cas/llvm-cas.cpp
@@ -39,7 +39,7 @@ using namespace llvm::opt;
class LLVMCASOptTable : public opt::OptTable {
public:
- LLVMCASOptTable() : opt::OptTable(OptionTables) {}
+ LLVMCASOptTable() : opt::OptTable(optionTables()) {}
};
enum class CommandKind {
diff --git a/llvm/tools/llvm-cgdata/llvm-cgdata.cpp b/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
index 472805ec06053..f06119a24e6ff 100644
--- a/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
+++ b/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
@@ -57,7 +57,7 @@ using namespace llvm::opt;
class CGDataOptTable : public opt::OptTable {
public:
- CGDataOptTable() : OptTable(OptionTables) {}
+ CGDataOptTable() : OptTable(optionTables()) {}
};
} // end anonymous namespace
diff --git a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
index a6f1d42f433e9..e13c66c9ab1a7 100644
--- a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
+++ b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
@@ -48,7 +48,7 @@ using namespace llvm::opt;
class CvtResOptTable : public opt::OptTable {
public:
- CvtResOptTable() : opt::OptTable(OptionTables, true) {}
+ CvtResOptTable() : opt::OptTable(optionTables(), true) {}
};
}
diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
index 6584da5f9f41f..457623561e241 100644
--- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -37,7 +37,7 @@ using namespace llvm::opt;
class CxxfiltOptTable : public opt::OptTable {
public:
- CxxfiltOptTable() : opt::OptTable(OptionTables) {
+ CxxfiltOptTable() : opt::OptTable(optionTables()) {
setGroupedShortOptions(true);
}
};
diff --git a/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp b/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
index 447038f1601d7..483b14a841083 100644
--- a/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
+++ b/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
@@ -43,7 +43,7 @@ using namespace llvm::opt;
class DebuginfodFindOptTable : public opt::OptTable {
public:
- DebuginfodFindOptTable() : OptTable(OptionTables) {}
+ DebuginfodFindOptTable() : OptTable(optionTables()) {}
};
} // end anonymous namespace
diff --git a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
index 60c4ba164bc82..1ecb6e8c4bd3d 100644
--- a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
+++ b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
@@ -42,7 +42,7 @@ using namespace llvm::opt;
class DebuginfodOptTable : public opt::OptTable {
public:
- DebuginfodOptTable() : OptTable(OptionTables) {}
+ DebuginfodOptTable() : OptTable(optionTables()) {}
};
} // end anonymous namespace
diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
index 0d40bb7d75b79..2176db14f06f4 100644
--- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -45,7 +45,7 @@ using namespace llvm::opt;
class DwarfutilOptTable : public opt::OptTable {
public:
- DwarfutilOptTable() : opt::OptTable(OptionTables) {}
+ DwarfutilOptTable() : opt::OptTable(optionTables()) {}
};
} // namespace
diff --git a/llvm/tools/llvm-dwp/llvm-dwp.cpp b/llvm/tools/llvm-dwp/llvm-dwp.cpp
index c24164e3846e2..fac0051aa76e9 100644
--- a/llvm/tools/llvm-dwp/llvm-dwp.cpp
+++ b/llvm/tools/llvm-dwp/llvm-dwp.cpp
@@ -40,7 +40,7 @@ using namespace llvm::opt;
class DwpOptTable : public opt::OptTable {
public:
- DwpOptTable() : OptTable(OptionTables) {}
+ DwpOptTable() : OptTable(optionTables()) {}
};
} // end anonymous namespace
diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index 386af5186077e..e168c8141def9 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -75,7 +75,9 @@ enum ID {
class GSYMUtilOptTable : public llvm::opt::OptTable {
public:
- GSYMUtilOptTable() : OptTable(OptionTables) { setGroupedShortOptions(true); }
+ GSYMUtilOptTable() : OptTable(optionTables()) {
+ setGroupedShortOptions(true);
+ }
};
static bool Verbose;
diff --git a/llvm/tools/llvm-ifs/llvm-ifs.cpp b/llvm/tools/llvm-ifs/llvm-ifs.cpp
index 35f08b62ebacc..575a1117363fe 100644
--- a/llvm/tools/llvm-ifs/llvm-ifs.cpp
+++ b/llvm/tools/llvm-ifs/llvm-ifs.cpp
@@ -63,7 +63,9 @@ enum ID {
class IFSOptTable : public opt::OptTable {
public:
- IFSOptTable() : opt::OptTable(OptionTables) { setGroupedShortOptions(true); }
+ IFSOptTable() : opt::OptTable(optionTables()) {
+ setGroupedShortOptions(true);
+ }
};
struct DriverConfig {
diff --git a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
index ad3af47de7dde..b2e02173ee3b4 100644
--- a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
+++ b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
@@ -53,7 +53,7 @@ enum ID {
class LibtoolDarwinOptTable : public opt::OptTable {
public:
- LibtoolDarwinOptTable() : OptTable(OptionTables) {}
+ LibtoolDarwinOptTable() : OptTable(optionTables()) {}
};
} // end anonymous namespace
diff --git a/llvm/tools/llvm-lipo/llvm-lipo.cpp b/llvm/tools/llvm-lipo/llvm-lipo.cpp
index 486321657c3af..c5dd60d1107ad 100644
--- a/llvm/tools/llvm-lipo/llvm-lipo.cpp
+++ b/llvm/tools/llvm-lipo/llvm-lipo.cpp
@@ -77,7 +77,7 @@ using namespace llvm::opt;
class LipoOptTable : public opt::OptTable {
public:
- LipoOptTable() : opt::OptTable(lipo::OptionTables) {}
+ LipoOptTable() : opt::OptTable(lipo::optionTables()) {}
};
enum class LipoAction {
diff --git a/llvm/tools/llvm-ml/llvm-ml.cpp b/llvm/tools/llvm-ml/llvm-ml.cpp
index c6ce99cfc4da7..2a4e0537579d3 100644
--- a/llvm/tools/llvm-ml/llvm-ml.cpp
+++ b/llvm/tools/llvm-ml/llvm-ml.cpp
@@ -64,7 +64,7 @@ enum ID {
class MLOptTable : public opt::OptTable {
public:
- MLOptTable() : opt::OptTable(OptionTables, /*IgnoreCase=*/false) {}
+ MLOptTable() : opt::OptTable(optionTables(), /*IgnoreCase=*/false) {}
};
} // namespace
diff --git a/llvm/tools/llvm-mt/llvm-mt.cpp b/llvm/tools/llvm-mt/llvm-mt.cpp
index 3e651cf56e719..9e781ad2fedb3 100644
--- a/llvm/tools/llvm-mt/llvm-mt.cpp
+++ b/llvm/tools/llvm-mt/llvm-mt.cpp
@@ -46,7 +46,7 @@ using namespace llvm::opt;
class CvtResOptTable : public opt::OptTable {
public:
- CvtResOptTable() : opt::OptTable(OptionTables, true) {}
+ CvtResOptTable() : opt::OptTable(optionTables(), true) {}
};
} // namespace
diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp
index 2e9f865675234..e4e4dc6c83083 100644
--- a/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -72,7 +72,7 @@ enum ID {
class NmOptTable : public opt::OptTable {
public:
- NmOptTable() : opt::OptTable(OptionTables) { setGroupedShortOptions(true); }
+ NmOptTable() : opt::OptTable(optionTables()) { setGroupedShortOptions(true); }
};
enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 0bbaf95660329..4c0f9d1d09daf 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -46,7 +46,7 @@ namespace objcopy_opt {
class ObjcopyOptTable : public opt::OptTable {
public:
- ObjcopyOptTable() : opt::OptTable(objcopy_opt::OptionTables) {
+ ObjcopyOptTable() : opt::OptTable(objcopy_opt::optionTables()) {
setGroupedShortOptions(true);
setDashDashParsing(true);
}
@@ -67,7 +67,7 @@ namespace install_name_tool {
class InstallNameToolOptTable : public opt::OptTable {
public:
- InstallNameToolOptTable() : OptTable(install_name_tool::OptionTables) {}
+ InstallNameToolOptTable() : OptTable(install_name_tool::optionTables()) {}
};
enum BitcodeStripID {
@@ -85,7 +85,7 @@ namespace bitcode_strip {
class BitcodeStripOptTable : public opt::OptTable {
public:
- BitcodeStripOptTable() : opt::OptTable(bitcode_strip::OptionTables) {}
+ BitcodeStripOptTable() : opt::OptTable(bitcode_strip::optionTables()) {}
};
enum StripID {
@@ -102,7 +102,7 @@ namespace strip {
class StripOptTable : public opt::OptTable {
public:
- StripOptTable() : OptTable(strip::OptionTables) {
+ StripOptTable() : OptTable(strip::optionTables()) {
setGroupedShortOptions(true);
}
};
@@ -122,7 +122,8 @@ namespace extract_bundle_entry {
class ExtractBundleEntryOptTable : public opt::OptTable {
public:
- ExtractBundleEntryOptTable() : OptTable(extract_bundle_entry::OptionTables) {
+ ExtractBundleEntryOptTable()
+ : OptTable(extract_bundle_entry::optionTables()) {
setGroupedShortOptions(true);
}
};
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 77aac37506d4f..ed45af32fbd8f 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -121,7 +121,7 @@ namespace objdump_opt {
class ObjdumpOptTable : public CommonOptTable {
public:
ObjdumpOptTable()
- : CommonOptTable(objdump_opt::OptionTables,
+ : CommonOptTable(objdump_opt::optionTables(),
" [options] <input object files>",
"llvm object file dumper") {}
};
@@ -141,7 +141,7 @@ namespace otool {
class OtoolOptTable : public CommonOptTable {
public:
OtoolOptTable()
- : CommonOptTable(otool::OptionTables, " [option...] [file...]",
+ : CommonOptTable(otool::optionTables(), " [option...] [file...]",
"Mach-O object file displaying tool") {}
};
diff --git a/llvm/tools/llvm-rc/llvm-rc.cpp b/llvm/tools/llvm-rc/llvm-rc.cpp
index a091ae5ec6b5b..7be5b16dce3ba 100644
--- a/llvm/tools/llvm-rc/llvm-rc.cpp
+++ b/llvm/tools/llvm-rc/llvm-rc.cpp
@@ -63,7 +63,7 @@ namespace rc_opt {
class RcOptTable : public opt::OptTable {
public:
- RcOptTable() : OptTable(rc_opt::OptionTables, /* IgnoreCase = */ true) {}
+ RcOptTable() : OptTable(rc_opt::optionTables(), /* IgnoreCase = */ true) {}
};
enum Windres_ID {
@@ -81,7 +81,7 @@ namespace windres_opt {
class WindresOptTable : public opt::OptTable {
public:
WindresOptTable()
- : OptTable(windres_opt::OptionTables, /* IgnoreCase = */ false) {}
+ : OptTable(windres_opt::optionTables(), /* IgnoreCase = */ false) {}
};
static ExitOnError ExitOnErr;
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index 51f2fb326863f..6ec0563d6d327 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -64,7 +64,7 @@ enum ID {
class ReadobjOptTable : public opt::OptTable {
public:
- ReadobjOptTable() : opt::OptTable(OptionTables) {
+ ReadobjOptTable() : opt::OptTable(optionTables()) {
setGroupedShortOptions(true);
}
};
diff --git a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
index aea79e3c0872e..f032e90401d10 100644
--- a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
+++ b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
@@ -50,7 +50,9 @@ enum ID {
class TAPIOptTable : public opt::OptTable {
public:
- TAPIOptTable() : opt::OptTable(OptionTables) { setGroupedShortOptions(true); }
+ TAPIOptTable() : opt::OptTable(optionTables()) {
+ setGroupedShortOptions(true);
+ }
};
struct StubOptions {
diff --git a/llvm/tools/llvm-size/llvm-size.cpp b/llvm/tools/llvm-size/llvm-size.cpp
index b58306c780f82..66195fdbe4f56 100644
--- a/llvm/tools/llvm-size/llvm-size.cpp
+++ b/llvm/tools/llvm-size/llvm-size.cpp
@@ -50,7 +50,7 @@ enum ID {
class SizeOptTable : public opt::OptTable {
public:
- SizeOptTable() : OptTable(OptionTables) { setGroupedShortOptions(true); }
+ SizeOptTable() : OptTable(optionTables()) { setGroupedShortOptions(true); }
};
enum OutputFormatTy { berkeley, sysv, darwin };
diff --git a/llvm/tools/llvm-strings/llvm-strings.cpp b/llvm/tools/llvm-strings/llvm-strings.cpp
index 04c0f3a16454b..f2abd1c3271a8 100644
--- a/llvm/tools/llvm-strings/llvm-strings.cpp
+++ b/llvm/tools/llvm-strings/llvm-strings.cpp
@@ -44,7 +44,7 @@ using namespace llvm::opt;
class StringsOptTable : public opt::OptTable {
public:
- StringsOptTable() : OptTable(OptionTables) {
+ StringsOptTable() : OptTable(optionTables()) {
setGroupedShortOptions(true);
setDashDashParsing(true);
}
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index a820126cf265c..c82cb11ade1ca 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -62,7 +62,7 @@ using namespace llvm::opt;
class SymbolizerOptTable : public opt::OptTable {
public:
- SymbolizerOptTable() : OptTable(OptionTables) {
+ SymbolizerOptTable() : OptTable(optionTables()) {
setGroupedShortOptions(true);
}
};
diff --git a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
index 1b045d7291cf3..8e67d1a087d22 100644
--- a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
+++ b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
@@ -39,7 +39,7 @@ using namespace llvm::opt;
class TLICheckerOptTable : public opt::OptTable {
public:
- TLICheckerOptTable() : OptTable(OptionTables) {}
+ TLICheckerOptTable() : OptTable(optionTables()) {}
};
} // end anonymous namespace
diff --git a/llvm/tools/sancov/sancov.cpp b/llvm/tools/sancov/sancov.cpp
index 0d91ffb798bcb..2d20caee8355a 100644
--- a/llvm/tools/sancov/sancov.cpp
+++ b/llvm/tools/sancov/sancov.cpp
@@ -73,7 +73,7 @@ enum ID {
class SancovOptTable : public opt::OptTable {
public:
- SancovOptTable() : OptTable(OptionTables) {}
+ SancovOptTable() : OptTable(optionTables()) {}
};
} // namespace
diff --git a/llvm/unittests/Option/OptionParsingTest.cpp b/llvm/unittests/Option/OptionParsingTest.cpp
index 382de8ee7a195..6b45ea5ea8aa7 100644
--- a/llvm/unittests/Option/OptionParsingTest.cpp
+++ b/llvm/unittests/Option/OptionParsingTest.cpp
@@ -48,7 +48,7 @@ enum OptionVisibility {
namespace {
class TestOptTable : public OptTable {
public:
- TestOptTable(bool IgnoreCase = false) : OptTable(OptionTables, IgnoreCase) {
+ TestOptTable(bool IgnoreCase = false) : OptTable(optionTables(), IgnoreCase) {
setValuesCodeFn(getOptionValuesCode);
}
};
diff --git a/llvm/unittests/Option/OptionSubCommandsTest.cpp b/llvm/unittests/Option/OptionSubCommandsTest.cpp
index 8885ee2f83668..27405beeec0ef 100644
--- a/llvm/unittests/Option/OptionSubCommandsTest.cpp
+++ b/llvm/unittests/Option/OptionSubCommandsTest.cpp
@@ -37,7 +37,7 @@ enum ID {
class TestOptSubCommandTable : public OptTable {
public:
TestOptSubCommandTable(bool IgnoreCase = false)
- : OptTable(OptionTables, IgnoreCase) {}
+ : OptTable(optionTables(), IgnoreCase) {}
};
// Test fixture
diff --git a/llvm/utils/TableGen/OptionParserEmitter.cpp b/llvm/utils/TableGen/OptionParserEmitter.cpp
index e4a3313e67a42..59a681ff2dd52 100644
--- a/llvm/utils/TableGen/OptionParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptionParserEmitter.cpp
@@ -282,17 +282,10 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
SubCommandIDs.try_emplace(SubCommandKey, 0);
}
- DenseSet<StringRef> PrefixesUnionSet;
- for (const auto &[Prefix, _] : Prefixes)
- PrefixesUnionSet.insert_range(Prefix);
- SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),
- PrefixesUnionSet.end());
- array_pod_sort(PrefixesUnion.begin(), PrefixesUnion.end());
-
llvm::StringToOffsetTable Table;
- // We can add all the prefixes via the union.
- for (const auto &Prefix : PrefixesUnion)
- Table.GetOrAddStringOffset(Prefix);
+ for (const auto &[PrefixSet, _] : Prefixes)
+ for (const auto &Prefix : PrefixSet)
+ Table.GetOrAddStringOffset(Prefix);
for (const Record &R : llvm::make_pointee_range(Groups)) {
Table.GetOrAddStringOffset(R.getValueAsString("Name"));
Table.GetOrAddStringOffset(getHelpText(R));
@@ -346,8 +339,7 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
OS << "#ifdef OPTTABLE_CODE\n";
// Dump prefixes.
- OS << "static constexpr llvm::StringTable::Offset OptionPrefixesTable[] = "
- "{\n";
+ OS << "constexpr llvm::StringTable::Offset OptionPrefixesTable[] = {\n";
{
// Ensure the first prefix set is always empty.
assert(!Prefixes.empty() &&
@@ -370,20 +362,9 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
}
OS << "\n};\n\n";
- // Dump prefixes union.
- if (!PrefixesUnion.empty()) {
- OS << "static constexpr llvm::StringTable::Offset OptionPrefixesUnion[] = "
- "{\n";
- llvm::ListSeparator Sep(", ");
- for (auto Prefix : PrefixesUnion)
- OS << Sep << " " << *Table.GetStringOffset(Prefix) << " /* '" << Prefix
- << "' */";
- OS << "\n};\n\n";
- }
-
// Dump help text variants. Each option's variants form a run ended by a zero
// row; offset 0 is the empty run.
- OS << "static constexpr llvm::opt::OptTable::HelpTextVariant "
+ OS << "constexpr llvm::opt::OptTable::HelpTextVariant "
"OptionHelpTextVariantsTable[] = {\n";
DenseMap<const Record *, unsigned> HelpTextVariantsOffset;
unsigned NumVariantRows = 1;
@@ -413,8 +394,7 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
// Dump subcommands.
if (!SubCommands.empty()) {
- OS << "static constexpr llvm::opt::OptTable::SubCommand "
- "OptionSubCommands[] = {\n";
+ OS << "constexpr llvm::opt::OptTable::SubCommand OptionSubCommands[] = {\n";
for (const Record *SubCommand : SubCommands) {
OS << " { \"" << SubCommand->getValueAsString("Name") << "\", ";
OS << "\"" << SubCommand->getValueAsString("HelpText") << "\", ";
@@ -424,7 +404,7 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
}
// Dump subcommand IDs.
- OS << "static constexpr unsigned OptionSubCommandIDsTable[] = {\n";
+ OS << "constexpr unsigned OptionSubCommandIDsTable[] = {\n";
{
// Ensure the first subcommand set is always empty.
assert(!SubCommandIDs.empty() &&
@@ -454,7 +434,7 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
OS << "\n};\n\n";
// Dump the option table in OptTable::Info field order.
- OS << "static constexpr llvm::opt::OptTable::Info OptionInfoTable[] = {\n";
+ OS << "constexpr llvm::opt::OptTable::Info OptionInfoTable[] = {\n";
for (const Record &R : llvm::make_pointee_range(Groups)) {
OS << " {";
writeStrTableOffset(OS, Table, R.getValueAsString("Name"),
@@ -489,13 +469,13 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
}
OS << "};\n\n";
- OS << "static constexpr llvm::opt::OptTable::Tables OptionTables = {\n";
- OS << " OptionStrTable, OptionPrefixesTable, "
- << (PrefixesUnion.empty() ? "{}" : "OptionPrefixesUnion")
- << ", OptionInfoTable,\n";
- OS << " OptionHelpTextVariantsTable, "
+ // A function rather than an object: the object needs relocations.
+ OS << "static constexpr llvm::opt::OptTable::Tables optionTables() {\n";
+ OS << " return {OptionStrTable, OptionPrefixesTable, OptionInfoTable,\n";
+ OS << " OptionHelpTextVariantsTable, "
<< (SubCommands.empty() ? "{}" : "OptionSubCommands")
<< ", OptionSubCommandIDsTable};\n";
+ OS << "}\n";
OS << "#undef OPTTABLE_CODE\n";
OS << "#endif // OPTTABLE_CODE\n\n";
>From 080cc8090d9efaf54b2bd775b3e40d2f5b04b7ee Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Fri, 18 Sep 2026 19:49:07 -0700
Subject: [PATCH 2/2] [Option] Shrink Info from 40 to 24 bytes
Few options set MetaVar, AliasArgs, Values, help text variants, or
subcommands (12%, 4%, 4%, 0.1%, 0.06% of 6955 options), yet every entry
carries all five. Move them to a deduplicated InfoExtra side table
reached by a 16-bit offset; row 0 serves options that set none. Narrow
Visibility to 16 bits; clang uses seven.
clang's table shrinks from 155 KB to 93 KB plus 4 KB of extras.
Aided by Opus 5
---
llvm/include/llvm/Option/OptTable.h | 78 ++++++++++++---------
llvm/include/llvm/Option/Option.h | 9 +--
llvm/lib/Option/OptTable.cpp | 6 +-
llvm/utils/TableGen/OptionParserEmitter.cpp | 72 ++++++++++---------
4 files changed, 85 insertions(+), 80 deletions(-)
diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h
index 611cfe826a99f..6f8f9500f8fa6 100644
--- a/llvm/include/llvm/Option/OptTable.h
+++ b/llvm/include/llvm/Option/OptTable.h
@@ -73,6 +73,20 @@ class LLVM_ABI OptTable {
StringTable::Offset HelpTextOffset;
};
+ /// Fields few options set. Row 0 is all zero and serves the options that set
+ /// none.
+ struct InfoExtra {
+ StringTable::Offset MetaVarOffset;
+ StringTable::Offset AliasArgsOffset;
+ /// The possible values as a comma separated list, empty for an option whose
+ /// values only getOptionValuesCode() knows.
+ StringTable::Offset ValuesOffset;
+ // Offset into OptTable's HelpTextVariantsTable; 0 for none.
+ unsigned short HelpTextVariantsOffset;
+ // Offset into OptTable's SubCommandIDsTable.
+ unsigned short SubCommandIDsOffset;
+ };
+
/// Entry for a single option instance in the option data table. An option's
/// ID is its 1-based position in the table.
struct Info {
@@ -80,21 +94,14 @@ class LLVM_ABI OptTable {
/// Offset 0 means the .td supplied no HelpText. A HelpText<""> maps to a
/// distinct empty string, marking the option deliberately undocumented.
StringTable::Offset HelpTextOffset;
- StringTable::Offset MetaVarOffset;
- StringTable::Offset AliasArgsOffset;
- /// The possible values as a comma separated list, empty for an option whose
- /// values only getOptionValuesCode() knows.
- StringTable::Offset ValuesOffset;
unsigned Flags;
- unsigned Visibility;
+ unsigned short Visibility;
// Offset into OptTable's PrefixesTable.
unsigned short PrefixesOffset;
unsigned short GroupID;
unsigned short AliasID;
- // Offset into OptTable's HelpTextVariantsTable; 0 for none.
- unsigned short HelpTextVariantsOffset;
- // Offset into OptTable's SubCommandIDsTable.
- unsigned short SubCommandIDsOffset;
+ // Offset into OptTable's InfoExtrasTable.
+ unsigned short ExtraOffset;
unsigned char Kind;
unsigned char Param;
@@ -113,22 +120,6 @@ class LLVM_ABI OptTable {
}
bool hasHelpText() const { return HelpTextOffset.value() != 0; }
- bool hasAliasArgs() const { return AliasArgsOffset.value() != 0; }
-
- bool hasSubCommands() const { return SubCommandIDsOffset != 0; }
-
- unsigned getNumSubCommandIDs(ArrayRef<unsigned> SubCommandIDsTable) const {
- // We embed the number of subcommand IDs in the value of the first offset.
- return SubCommandIDsTable[SubCommandIDsOffset];
- }
-
- ArrayRef<unsigned>
- getSubCommandIDs(ArrayRef<unsigned> SubCommandIDsTable) const {
- return hasSubCommands() ? SubCommandIDsTable.slice(
- SubCommandIDsOffset + 1,
- getNumSubCommandIDs(SubCommandIDsTable))
- : ArrayRef<unsigned>();
- }
void appendPrefixes(const StringTable &StrTable,
ArrayRef<StringTable::Offset> PrefixesTable,
@@ -160,6 +151,7 @@ class LLVM_ABI OptTable {
const StringTable &StrTable;
ArrayRef<StringTable::Offset> PrefixesTable;
ArrayRef<Info> Infos;
+ ArrayRef<InfoExtra> InfoExtras;
ArrayRef<HelpTextVariant> HelpTextVariants;
ArrayRef<SubCommand> SubCommands;
ArrayRef<unsigned> SubCommandIDs;
@@ -174,7 +166,7 @@ class LLVM_ABI OptTable {
SubCommands, [&](const auto &C) { return SubCommand == C.Name; });
assert(SCIT != SubCommands.end() &&
"This helper is only for valid registered subcommands.");
- auto SubCommandIDs = CandidateInfo->getSubCommandIDs(SubCommandIDsTable);
+ auto SubCommandIDs = getSubCommandIDs(*CandidateInfo);
unsigned CurrentSubCommandID = SCIT - &SubCommands[0];
return llvm::is_contained(SubCommandIDs, CurrentSubCommandID);
}
@@ -193,6 +185,8 @@ class LLVM_ABI OptTable {
/// The option information table.
ArrayRef<Info> OptionInfos;
+ ArrayRef<InfoExtra> InfoExtrasTable;
+
bool IgnoreCase;
/// The subcommand information table.
@@ -229,24 +223,33 @@ class LLVM_ABI OptTable {
return OptionInfos[id - 1];
}
+ const InfoExtra &getExtra(const Info &I) const {
+ return InfoExtrasTable[I.ExtraOffset];
+ }
+
StringTable::Offset getHelpTextOffset(const Info &I,
Visibility VisibilityMask) const {
- if (I.HelpTextVariantsOffset)
- for (const HelpTextVariant *V =
- &HelpTextVariantsTable[I.HelpTextVariantsOffset];
- V->Visibility; ++V)
- if (VisibilityMask & V->Visibility)
- return V->HelpTextOffset;
+ for (const HelpTextVariant *V =
+ &HelpTextVariantsTable[getExtra(I).HelpTextVariantsOffset];
+ V->Visibility; ++V)
+ if (VisibilityMask & V->Visibility)
+ return V->HelpTextOffset;
return I.HelpTextOffset;
}
StringRef getOptionValues(const Info &I) const {
- StringRef Values = (*StrTable)[I.ValuesOffset];
+ StringRef Values = (*StrTable)[getExtra(I).ValuesOffset];
if (Values.empty() && ValuesCodeFn)
Values = ValuesCodeFn(getOptionID(I));
return Values;
}
+ ArrayRef<unsigned> getSubCommandIDs(const Info &I) const {
+ // A set starts with its size.
+ unsigned Offset = getExtra(I).SubCommandIDsOffset;
+ return SubCommandIDsTable.slice(Offset + 1, SubCommandIDsTable[Offset]);
+ }
+
std::unique_ptr<Arg> parseOneArgGrouped(InputArgList &Args,
unsigned &Index) const;
@@ -329,7 +332,12 @@ class LLVM_ABI OptTable {
/// Get the meta-variable name to use when describing
/// this options values in the help text.
StringRef getOptionMetaVar(OptSpecifier id) const {
- return (*StrTable)[getInfo(id).MetaVarOffset];
+ return (*StrTable)[getExtra(getInfo(id)).MetaVarOffset];
+ }
+
+ /// Get the alias arguments as a \0 separated list, e.g. "foo\0bar\0".
+ const char *getOptionAliasArgs(OptSpecifier id) const {
+ return StrTable->getCString(getExtra(getInfo(id)).AliasArgsOffset);
}
/// Specify the environment variable where initial options should be read.
diff --git a/llvm/include/llvm/Option/Option.h b/llvm/include/llvm/Option/Option.h
index 1233ca5a42228..dd91be2e4c527 100644
--- a/llvm/include/llvm/Option/Option.h
+++ b/llvm/include/llvm/Option/Option.h
@@ -117,15 +117,10 @@ class Option {
/// Get the alias arguments as a \0 separated list.
/// E.g. ["foo", "bar"] would be returned as "foo\0bar\0".
const char *getAliasArgs() const {
- assert(Info && "Must have a valid info!");
- assert(Owner && "Must have a valid owner!");
- return Owner->getStrTable().getCString(Info->AliasArgsOffset);
+ return Owner->getOptionAliasArgs(getID());
}
- bool hasAliasArgs() const {
- assert(Info && "Must have a valid info!");
- return Info->hasAliasArgs();
- }
+ bool hasAliasArgs() const { return *getAliasArgs() != '\0'; }
/// Get the default prefix for this option.
StringRef getPrefix() const { return Owner->getOptionPrefix(getID()); }
diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp
index 87487d625f7e4..ad7db113aa6e9 100644
--- a/llvm/lib/Option/OptTable.cpp
+++ b/llvm/lib/Option/OptTable.cpp
@@ -75,7 +75,8 @@ OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
OptTable::OptTable(const Tables &T, bool IgnoreCase)
: StrTable(&T.StrTable), PrefixesTable(T.PrefixesTable),
- OptionInfos(T.Infos), IgnoreCase(IgnoreCase), SubCommands(T.SubCommands),
+ OptionInfos(T.Infos), InfoExtrasTable(T.InfoExtras),
+ IgnoreCase(IgnoreCase), SubCommands(T.SubCommands),
SubCommandIDsTable(T.SubCommandIDs),
HelpTextVariantsTable(T.HelpTextVariants) {
// Each prefix set in PrefixesTable starts with its size.
@@ -770,8 +771,7 @@ void OptTable::internalPrintHelp(
auto DoesOptionBelongToSubcommand = [&](const Info &CandidateInfo) {
// Retrieve the SubCommandIDs registered to the given current CandidateInfo
// Option.
- ArrayRef<unsigned> SubCommandIDs =
- CandidateInfo.getSubCommandIDs(SubCommandIDsTable);
+ ArrayRef<unsigned> SubCommandIDs = getSubCommandIDs(CandidateInfo);
// If no registered subcommands, then only global options are to be printed.
// If no valid SubCommand (empty) in commandline then print the current
diff --git a/llvm/utils/TableGen/OptionParserEmitter.cpp b/llvm/utils/TableGen/OptionParserEmitter.cpp
index 59a681ff2dd52..ddc7e9f0f4ef4 100644
--- a/llvm/utils/TableGen/OptionParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptionParserEmitter.cpp
@@ -18,6 +18,7 @@
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/StringToOffsetTable.h"
#include "llvm/TableGen/TableGenBackend.h"
+#include <array>
#include <cstring>
#include <map>
@@ -258,18 +259,11 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
using SubCommandIDsT = std::map<SubCommandKeyT, unsigned>;
SubCommandIDsT SubCommandIDs;
- auto PrintSubCommandIdsOffset = [&SubCommandIDs, &OS](const Record &R) {
- if (R.getValue("SubCommands") != nullptr) {
- std::vector<const Record *> SubCommands =
- R.getValueAsListOfDefs("SubCommands");
- SubCommandKeyT SubCommandKey;
- for (const auto &SubCommand : SubCommands)
- SubCommandKey.push_back(SubCommand->getName());
- OS << SubCommandIDs[SubCommandKey];
- } else {
- // The option SubCommandIDsOffset (for default top level toolname is 0).
- OS << '0';
- }
+ auto GetSubCommandIDsOffset = [&SubCommandIDs](const Record &R) {
+ SubCommandKeyT SubCommandKey;
+ for (const Record *SubCommand : R.getValueAsListOfDefs("SubCommands"))
+ SubCommandKey.push_back(SubCommand->getName());
+ return SubCommandIDs[SubCommandKey];
};
SubCommandIDs.try_emplace(SubCommandKeyT(), 0);
@@ -433,6 +427,29 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
}
OS << "\n};\n\n";
+ // Rarely set fields, in OptTable::InfoExtra order. Options with equal values
+ // share a row; row 0 is all zero.
+ OS << "constexpr llvm::opt::OptTable::InfoExtra OptionInfoExtrasTable[] = "
+ "{\n {0, 0, 0, 0, 0},\n";
+ std::map<std::array<unsigned, 5>, unsigned> ExtraRows;
+ ExtraRows.try_emplace({}, 0);
+ DenseMap<const Record *, unsigned> ExtraOffset;
+ for (const Record &R : llvm::make_pointee_range(Opts)) {
+ std::array<unsigned, 5> Row = {
+ *Table.GetStringOffset(getOptionalString(R, "MetaVarName")),
+ *Table.GetStringOffset(getAliasArgsBlob(R)),
+ *Table.GetStringOffset(getOptionalString(R, "Values")),
+ HelpTextVariantsOffset.lookup(&R), GetSubCommandIDsOffset(R)};
+ auto [It, Inserted] = ExtraRows.try_emplace(Row, ExtraRows.size());
+ if (Inserted) {
+ OS << " {";
+ interleaveComma(Row, OS);
+ OS << "},\n";
+ }
+ ExtraOffset[&R] = It->second;
+ }
+ OS << "};\n\n";
+
// Dump the option table in OptTable::Info field order.
OS << "constexpr llvm::opt::OptTable::Info OptionInfoTable[] = {\n";
for (const Record &R : llvm::make_pointee_range(Groups)) {
@@ -441,9 +458,8 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
/*EmitComment=*/true);
OS << ", ";
writeStrTableOffset(OS, Table, getHelpText(R));
- OS << ", 0, 0, 0, 0, 0, 0, " << GetRefID(R, "Group") << ", 0, 0, ";
- PrintSubCommandIdsOffset(R);
- OS << ", llvm::opt::Option::GroupClass, 0},\n";
+ OS << ", 0, 0, 0, " << GetRefID(R, "Group")
+ << ", 0, 0, llvm::opt::Option::GroupClass, 0},\n";
}
for (const Record &R : llvm::make_pointee_range(Opts)) {
OS << " {";
@@ -451,28 +467,20 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
/*EmitComment=*/true);
OS << ", ";
writeStrTableOffset(OS, Table, getHelpText(R));
- OS << ", ";
- writeStrTableOffset(OS, Table, getOptionalString(R, "MetaVarName"));
- OS << ", ";
- writeStrTableOffset(OS, Table, getAliasArgsBlob(R));
- OS << ", ";
- writeStrTableOffset(OS, Table, getOptionalString(R, "Values"));
OS << ", " << GetMask(R, "Flags") << ", " << GetMask(R, "Visibility");
std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
OS << ", " << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())];
OS << ", " << GetRefID(R, "Group") << ", " << GetRefID(R, "Alias");
- OS << ", " << HelpTextVariantsOffset.lookup(&R) << ", ";
- PrintSubCommandIdsOffset(R);
- OS << ", llvm::opt::Option::"
+ OS << ", " << ExtraOffset.lookup(&R) << ", llvm::opt::Option::"
<< R.getValueAsDef("Kind")->getValueAsString("Name") << "Class, "
<< R.getValueAsInt("NumArgs") << "},\n";
}
OS << "};\n\n";
- // A function rather than an object: the object needs relocations.
+ // A function rather than an object: the object needs dynamic relocations.
OS << "static constexpr llvm::opt::OptTable::Tables optionTables() {\n";
OS << " return {OptionStrTable, OptionPrefixesTable, OptionInfoTable,\n";
- OS << " OptionHelpTextVariantsTable, "
+ OS << " OptionInfoExtrasTable, OptionHelpTextVariantsTable, "
<< (SubCommands.empty() ? "{}" : "OptionSubCommands")
<< ", OptionSubCommandIDsTable};\n";
OS << "}\n";
@@ -548,13 +556,8 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
// The option meta-variable name (unused).
OS << ", 0";
- // The option Values (unused for groups).
- OS << ", 0";
-
- // The option SubCommandIDsOffset.
- OS << ", ";
- PrintSubCommandIdsOffset(R);
- OS << ")\n";
+ // The option Values and SubCommandIDsOffset (unused for groups).
+ OS << ", 0, 0)\n";
}
OS << "\n";
@@ -619,8 +622,7 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
writeStrTableOffset(OS, Table, getOptionalString(R, "Values"));
// The option SubCommandIDsOffset.
- OS << ", ";
- PrintSubCommandIdsOffset(R);
+ OS << ", " << GetSubCommandIDsOffset(R);
};
auto IsMarshallingOption = [](const Record &R) {
More information about the cfe-commits
mailing list