Skip to content

Commit dd647e3

Browse files
authored
Rework the Option library to reduce dynamic relocations (#119198)
Apologies for the large change, I looked for ways to break this up and all of the ones I saw added real complexity. This change focuses on the option's prefixed names and the array of prefixes. These are present in every option and the dominant source of dynamic relocations for PIE or PIC users of LLVM and Clang tooling. In some cases, 100s or 1000s of them for the Clang driver which has a huge number of options. This PR addresses this by building a string table and a prefixes table that can be referenced with indices rather than pointers that require dynamic relocations. This removes almost 7k dynmaic relocations from the `clang` binary, roughly 8% of the remaining dynmaic relocations outside of vtables. For busy-boxing use cases where many different option tables are linked into the same binary, the savings add up a bit more. The string table is a straightforward mechanism, but the prefixes required some subtlety. They are encoded in a Pascal-string fashion with a size followed by a sequence of offsets. This works relatively well for the small realistic prefixes arrays in use. Lots of code has to change in order to land this though: both all the option library code has to be updated to use the string table and prefixes table, and all the users of the options library have to be updated to correctly instantiate the objects. Some follow-up patches in the works to provide an abstraction for this style of code, and to start using the same technique for some of the other strings here now that the infrastructure is in place.
1 parent 151901c commit dd647e3

File tree

52 files changed

+777
-541
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+777
-541
lines changed

clang-tools-extra/clangd/CompileCommands.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -458,20 +458,6 @@ llvm::ArrayRef<ArgStripper::Rule> ArgStripper::rulesFor(llvm::StringRef Arg) {
458458
PrevAlias[Self] = T;
459459
NextAlias[T] = Self;
460460
};
461-
// Also grab prefixes for each option, these are not fully exposed.
462-
llvm::ArrayRef<llvm::StringLiteral> Prefixes[DriverID::LastOption];
463-
464-
#define PREFIX(NAME, VALUE) \
465-
static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
466-
static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
467-
NAME##_init, std::size(NAME##_init) - 1);
468-
#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
469-
FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \
470-
METAVAR, VALUES) \
471-
Prefixes[DriverID::OPT_##ID] = PREFIX;
472-
#include "clang/Driver/Options.inc"
473-
#undef OPTION
474-
#undef PREFIX
475461

476462
struct {
477463
DriverID ID;
@@ -498,7 +484,9 @@ llvm::ArrayRef<ArgStripper::Rule> ArgStripper::rulesFor(llvm::StringRef Arg) {
498484
llvm::SmallVector<Rule> Rules;
499485
// Iterate over each alias, to add rules for parsing it.
500486
for (unsigned A = ID; A != DriverID::OPT_INVALID; A = NextAlias[A]) {
501-
if (!Prefixes[A].size()) // option groups.
487+
llvm::SmallVector<llvm::StringRef, 4> Prefixes;
488+
DriverTable.appendOptionPrefixes(A, Prefixes);
489+
if (Prefixes.empty()) // option groups.
502490
continue;
503491
auto Opt = DriverTable.getOption(A);
504492
// Exclude - and -foo pseudo-options.
@@ -507,7 +495,7 @@ llvm::ArrayRef<ArgStripper::Rule> ArgStripper::rulesFor(llvm::StringRef Arg) {
507495
auto Modes = getModes(Opt);
508496
std::pair<unsigned, unsigned> ArgCount = getArgCount(Opt);
509497
// Iterate over each spelling of the alias, e.g. -foo vs --foo.
510-
for (StringRef Prefix : Prefixes[A]) {
498+
for (StringRef Prefix : Prefixes) {
511499
llvm::SmallString<64> Buf(Prefix);
512500
Buf.append(Opt.getName());
513501
llvm::StringRef Spelling = Result->try_emplace(Buf).first->getKey();

clang/lib/Driver/DriverOptions.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,21 @@ using namespace clang::driver;
1414
using namespace clang::driver::options;
1515
using namespace llvm::opt;
1616

17+
#define OPTTABLE_STR_TABLE_CODE
18+
#include "clang/Driver/Options.inc"
19+
#undef OPTTABLE_STR_TABLE_CODE
20+
1721
#define OPTTABLE_VALUES_CODE
1822
#include "clang/Driver/Options.inc"
1923
#undef OPTTABLE_VALUES_CODE
2024

21-
#define PREFIX(NAME, VALUE) \
22-
static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
23-
static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
24-
NAME##_init, std::size(NAME##_init) - 1);
25+
#define OPTTABLE_PREFIXES_TABLE_CODE
2526
#include "clang/Driver/Options.inc"
26-
#undef PREFIX
27+
#undef OPTTABLE_PREFIXES_TABLE_CODE
2728

28-
static constexpr const llvm::StringLiteral PrefixTable_init[] =
29-
#define PREFIX_UNION(VALUES) VALUES
29+
#define OPTTABLE_PREFIXES_UNION_CODE
3030
#include "clang/Driver/Options.inc"
31-
#undef PREFIX_UNION
32-
;
33-
static constexpr const llvm::ArrayRef<llvm::StringLiteral>
34-
PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
31+
#undef OPTTABLE_PREFIXES_UNION_CODE
3532

3633
static constexpr OptTable::Info InfoTable[] = {
3734
#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
@@ -43,7 +40,9 @@ namespace {
4340

4441
class DriverOptTable : public PrecomputedOptTable {
4542
public:
46-
DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
43+
DriverOptTable()
44+
: PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
45+
OptionPrefixesUnion) {}
4746
};
4847
}
4948

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,14 @@ CowCompilerInvocation::getMutPreprocessorOutputOpts() {
277277

278278
using ArgumentConsumer = CompilerInvocation::ArgumentConsumer;
279279

280+
#define OPTTABLE_STR_TABLE_CODE
281+
#include "clang/Driver/Options.inc"
282+
#undef OPTTABLE_STR_TABLE_CODE
283+
284+
static llvm::StringRef lookupStrInTable(unsigned Offset) {
285+
return &OptionStrTable[Offset];
286+
}
287+
280288
#define SIMPLE_ENUM_VALUE_TABLE
281289
#include "clang/Driver/Options.inc"
282290
#undef SIMPLE_ENUM_VALUE_TABLE
@@ -303,6 +311,11 @@ static std::optional<bool> normalizeSimpleNegativeFlag(OptSpecifier Opt,
303311
/// denormalizeSimpleFlags never looks at it. Avoid bloating compile-time with
304312
/// unnecessary template instantiations and just ignore it with a variadic
305313
/// argument.
314+
static void denormalizeSimpleFlag(ArgumentConsumer Consumer,
315+
unsigned SpellingOffset, Option::OptionClass,
316+
unsigned, /*T*/...) {
317+
Consumer(lookupStrInTable(SpellingOffset));
318+
}
306319
static void denormalizeSimpleFlag(ArgumentConsumer Consumer,
307320
const Twine &Spelling, Option::OptionClass,
308321
unsigned, /*T*/...) {
@@ -343,10 +356,10 @@ static auto makeBooleanOptionNormalizer(bool Value, bool OtherValue,
343356
}
344357

345358
static auto makeBooleanOptionDenormalizer(bool Value) {
346-
return [Value](ArgumentConsumer Consumer, const Twine &Spelling,
359+
return [Value](ArgumentConsumer Consumer, unsigned SpellingOffset,
347360
Option::OptionClass, unsigned, bool KeyPath) {
348361
if (KeyPath == Value)
349-
Consumer(Spelling);
362+
Consumer(lookupStrInTable(SpellingOffset));
350363
};
351364
}
352365

@@ -371,6 +384,14 @@ static void denormalizeStringImpl(ArgumentConsumer Consumer,
371384
}
372385
}
373386

387+
template <typename T>
388+
static void
389+
denormalizeString(ArgumentConsumer Consumer, unsigned SpellingOffset,
390+
Option::OptionClass OptClass, unsigned TableIndex, T Value) {
391+
denormalizeStringImpl(Consumer, lookupStrInTable(SpellingOffset), OptClass,
392+
TableIndex, Twine(Value));
393+
}
394+
374395
template <typename T>
375396
static void denormalizeString(ArgumentConsumer Consumer, const Twine &Spelling,
376397
Option::OptionClass OptClass, unsigned TableIndex,
@@ -417,14 +438,14 @@ static std::optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
417438
}
418439

419440
static void denormalizeSimpleEnumImpl(ArgumentConsumer Consumer,
420-
const Twine &Spelling,
441+
unsigned SpellingOffset,
421442
Option::OptionClass OptClass,
422443
unsigned TableIndex, unsigned Value) {
423444
assert(TableIndex < SimpleEnumValueTablesSize);
424445
const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
425446
if (auto MaybeEnumVal = findValueTableByValue(Table, Value)) {
426-
denormalizeString(Consumer, Spelling, OptClass, TableIndex,
427-
MaybeEnumVal->Name);
447+
denormalizeString(Consumer, lookupStrInTable(SpellingOffset), OptClass,
448+
TableIndex, MaybeEnumVal->Name);
428449
} else {
429450
llvm_unreachable("The simple enum value was not correctly defined in "
430451
"the tablegen option description");
@@ -433,11 +454,11 @@ static void denormalizeSimpleEnumImpl(ArgumentConsumer Consumer,
433454

434455
template <typename T>
435456
static void denormalizeSimpleEnum(ArgumentConsumer Consumer,
436-
const Twine &Spelling,
457+
unsigned SpellingOffset,
437458
Option::OptionClass OptClass,
438459
unsigned TableIndex, T Value) {
439-
return denormalizeSimpleEnumImpl(Consumer, Spelling, OptClass, TableIndex,
440-
static_cast<unsigned>(Value));
460+
return denormalizeSimpleEnumImpl(Consumer, SpellingOffset, OptClass,
461+
TableIndex, static_cast<unsigned>(Value));
441462
}
442463

443464
static std::optional<std::string> normalizeString(OptSpecifier Opt,
@@ -473,7 +494,7 @@ normalizeStringVector(OptSpecifier Opt, int, const ArgList &Args,
473494
}
474495

475496
static void denormalizeStringVector(ArgumentConsumer Consumer,
476-
const Twine &Spelling,
497+
unsigned SpellingOffset,
477498
Option::OptionClass OptClass,
478499
unsigned TableIndex,
479500
const std::vector<std::string> &Values) {
@@ -487,15 +508,16 @@ static void denormalizeStringVector(ArgumentConsumer Consumer,
487508
CommaJoinedValue.append(Value);
488509
}
489510
}
490-
denormalizeString(Consumer, Spelling, Option::OptionClass::JoinedClass,
491-
TableIndex, CommaJoinedValue);
511+
denormalizeString(Consumer, SpellingOffset,
512+
Option::OptionClass::JoinedClass, TableIndex,
513+
CommaJoinedValue);
492514
break;
493515
}
494516
case Option::JoinedClass:
495517
case Option::SeparateClass:
496518
case Option::JoinedOrSeparateClass:
497519
for (const std::string &Value : Values)
498-
denormalizeString(Consumer, Spelling, OptClass, TableIndex, Value);
520+
denormalizeString(Consumer, SpellingOffset, OptClass, TableIndex, Value);
499521
break;
500522
default:
501523
llvm_unreachable("Cannot denormalize an option with option class "
@@ -532,10 +554,11 @@ static T extractMaskValue(T KeyPath) {
532554
}
533555

534556
#define PARSE_OPTION_WITH_MARSHALLING( \
535-
ARGS, DIAGS, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, \
536-
FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \
537-
SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, \
538-
IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \
557+
ARGS, DIAGS, PREFIX_TYPE, SPELLING_OFFSET, ID, KIND, GROUP, ALIAS, \
558+
ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \
559+
METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
560+
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, \
561+
TABLE_INDEX) \
539562
if ((VISIBILITY) & options::CC1Option) { \
540563
KEYPATH = MERGER(KEYPATH, DEFAULT_VALUE); \
541564
if (IMPLIED_CHECK) \
@@ -549,8 +572,8 @@ static T extractMaskValue(T KeyPath) {
549572
// Capture the extracted value as a lambda argument to avoid potential issues
550573
// with lifetime extension of the reference.
551574
#define GENERATE_OPTION_WITH_MARSHALLING( \
552-
CONSUMER, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
553-
VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \
575+
CONSUMER, PREFIX_TYPE, SPELLING_OFFSET, ID, KIND, GROUP, ALIAS, ALIASARGS, \
576+
FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \
554577
SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, \
555578
IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \
556579
if ((VISIBILITY) & options::CC1Option) { \
@@ -559,8 +582,8 @@ static T extractMaskValue(T KeyPath) {
559582
(Extracted != \
560583
static_cast<decltype(KEYPATH)>((IMPLIED_CHECK) ? (IMPLIED_VALUE) \
561584
: (DEFAULT_VALUE)))) \
562-
DENORMALIZER(CONSUMER, SPELLING, Option::KIND##Class, TABLE_INDEX, \
563-
Extracted); \
585+
DENORMALIZER(CONSUMER, SPELLING_OFFSET, Option::KIND##Class, \
586+
TABLE_INDEX, Extracted); \
564587
}(EXTRACTOR(KEYPATH)); \
565588
}
566589

clang/tools/clang-installapi/Options.cpp

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,41 +31,21 @@ namespace drv = clang::driver::options;
3131
namespace clang {
3232
namespace installapi {
3333

34-
/// Create prefix string literals used in InstallAPIOpts.td.
35-
#define PREFIX(NAME, VALUE) \
36-
static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
37-
static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
38-
NAME##_init, std::size(NAME##_init) - 1);
34+
#define OPTTABLE_STR_TABLE_CODE
3935
#include "InstallAPIOpts.inc"
40-
#undef PREFIX
36+
#undef OPTTABLE_STR_TABLE_CODE
4137

42-
static constexpr const llvm::StringLiteral PrefixTable_init[] =
43-
#define PREFIX_UNION(VALUES) VALUES
38+
#define OPTTABLE_PREFIXES_TABLE_CODE
4439
#include "InstallAPIOpts.inc"
45-
#undef PREFIX_UNION
46-
;
47-
static constexpr const ArrayRef<StringLiteral>
48-
PrefixTable(PrefixTable_init, std::size(PrefixTable_init) - 1);
40+
#undef OPTTABLE_PREFIXES_TABLE_CODE
41+
42+
#define OPTTABLE_PREFIXES_UNION_CODE
43+
#include "InstallAPIOpts.inc"
44+
#undef OPTTABLE_PREFIXES_UNION_CODE
4945

5046
/// Create table mapping all options defined in InstallAPIOpts.td.
5147
static constexpr OptTable::Info InfoTable[] = {
52-
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
53-
VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \
54-
VALUES) \
55-
{PREFIX, \
56-
NAME, \
57-
HELPTEXT, \
58-
HELPTEXTSFORVARIANTS, \
59-
METAVAR, \
60-
OPT_##ID, \
61-
Option::KIND##Class, \
62-
PARAM, \
63-
FLAGS, \
64-
VISIBILITY, \
65-
OPT_##GROUP, \
66-
OPT_##ALIAS, \
67-
ALIASARGS, \
68-
VALUES},
48+
#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
6949
#include "InstallAPIOpts.inc"
7050
#undef OPTION
7151
};
@@ -75,7 +55,9 @@ namespace {
7555
/// \brief Create OptTable class for parsing actual command line arguments.
7656
class DriverOptTable : public opt::PrecomputedOptTable {
7757
public:
78-
DriverOptTable() : PrecomputedOptTable(InfoTable, PrefixTable) {}
58+
DriverOptTable()
59+
: PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
60+
OptionPrefixesUnion) {}
7961
};
8062

8163
} // end anonymous namespace.

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,13 @@ enum ID {
174174
#undef OPTION
175175
};
176176

177-
#define PREFIX(NAME, VALUE) \
178-
static constexpr StringLiteral NAME##_init[] = VALUE; \
179-
static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
180-
std::size(NAME##_init) - 1);
177+
#define OPTTABLE_STR_TABLE_CODE
181178
#include "LinkerWrapperOpts.inc"
182-
#undef PREFIX
179+
#undef OPTTABLE_STR_TABLE_CODE
180+
181+
#define OPTTABLE_PREFIXES_TABLE_CODE
182+
#include "LinkerWrapperOpts.inc"
183+
#undef OPTTABLE_PREFIXES_TABLE_CODE
183184

184185
static constexpr OptTable::Info InfoTable[] = {
185186
#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
@@ -189,7 +190,8 @@ static constexpr OptTable::Info InfoTable[] = {
189190

190191
class WrapperOptTable : public opt::GenericOptTable {
191192
public:
192-
WrapperOptTable() : opt::GenericOptTable(InfoTable) {}
193+
WrapperOptTable()
194+
: opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
193195
};
194196

195197
const OptTable &getOptTable() {

clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,13 @@ enum ID {
109109
#undef OPTION
110110
};
111111

112-
#define PREFIX(NAME, VALUE) \
113-
static constexpr StringLiteral NAME##_init[] = VALUE; \
114-
static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
115-
std::size(NAME##_init) - 1);
112+
#define OPTTABLE_STR_TABLE_CODE
116113
#include "NVLinkOpts.inc"
117-
#undef PREFIX
114+
#undef OPTTABLE_STR_TABLE_CODE
115+
116+
#define OPTTABLE_PREFIXES_TABLE_CODE
117+
#include "NVLinkOpts.inc"
118+
#undef OPTTABLE_PREFIXES_TABLE_CODE
118119

119120
static constexpr OptTable::Info InfoTable[] = {
120121
#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
@@ -124,7 +125,8 @@ static constexpr OptTable::Info InfoTable[] = {
124125

125126
class WrapperOptTable : public opt::GenericOptTable {
126127
public:
127-
WrapperOptTable() : opt::GenericOptTable(InfoTable) {}
128+
WrapperOptTable()
129+
: opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
128130
};
129131

130132
const OptTable &getOptTable() {

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,13 @@ enum ID {
5050
#undef OPTION
5151
};
5252

53-
#define PREFIX(NAME, VALUE) \
54-
constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
55-
constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
56-
NAME##_init, std::size(NAME##_init) - 1);
53+
#define OPTTABLE_STR_TABLE_CODE
5754
#include "Opts.inc"
58-
#undef PREFIX
55+
#undef OPTTABLE_STR_TABLE_CODE
56+
57+
#define OPTTABLE_PREFIXES_TABLE_CODE
58+
#include "Opts.inc"
59+
#undef OPTTABLE_PREFIXES_TABLE_CODE
5960

6061
const llvm::opt::OptTable::Info InfoTable[] = {
6162
#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
@@ -65,7 +66,8 @@ const llvm::opt::OptTable::Info InfoTable[] = {
6566

6667
class ScanDepsOptTable : public llvm::opt::GenericOptTable {
6768
public:
68-
ScanDepsOptTable() : GenericOptTable(InfoTable) {
69+
ScanDepsOptTable()
70+
: GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
6971
setGroupedShortOptions(true);
7072
}
7173
};

0 commit comments

Comments
 (0)