Skip to content

Commit dd647e3

Browse files
authoredDec 11, 2024
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

+4-16
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

+11-12
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

0 commit comments

Comments
 (0)
Please sign in to comment.