Skip to content

Commit

Permalink
[llvm] Construct option's prefixed name at compile-time
Browse files Browse the repository at this point in the history
Some Clang command-line handling code could benefit from the option's prefixed name being a `StringLiteral`. This patch changes the `llvm::opt` TableGen backend to generate and emit that into the .inc file.

Depends on D157028.

Reviewed By: MaskRay

Differential Revision: https://reviews.llvm.org/D157029
  • Loading branch information
jansvoboda11 committed Aug 9, 2023
1 parent 2f5a183 commit 501f92d
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 79 deletions.
8 changes: 4 additions & 4 deletions clang-tools-extra/clangd/CompileCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,8 @@ llvm::ArrayRef<ArgStripper::Rule> ArgStripper::rulesFor(llvm::StringRef Arg) {
static constexpr llvm::StringLiteral NAME##_init[] = VALUE; \
static constexpr llvm::ArrayRef<llvm::StringLiteral> NAME( \
NAME##_init, std::size(NAME##_init) - 1);
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELP, METAVAR, VALUES) \
#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
FLAGS, PARAM, HELP, METAVAR, VALUES) \
Prefixes[DriverID::OPT_##ID] = PREFIX;
#include "clang/Driver/Options.inc"
#undef OPTION
Expand All @@ -505,8 +505,8 @@ llvm::ArrayRef<ArgStripper::Rule> ArgStripper::rulesFor(llvm::StringRef Arg) {
DriverID AliasID;
const void *AliasArgs;
} AliasTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELP, METAVAR, VALUES) \
#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
FLAGS, PARAM, HELP, METAVAR, VALUES) \
{DriverID::OPT_##ID, DriverID::OPT_##ALIAS, ALIASARGS},
#include "clang/Driver/Options.inc"
#undef OPTION
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple,
}

void Driver::setDriverMode(StringRef Value) {
static const std::string OptName =
static StringRef OptName =
getOpts().getOption(options::OPT_driver_mode).getPrefixedName();
if (auto M = llvm::StringSwitch<std::optional<DriverMode>>(Value)
.Case("gcc", GCCMode)
Expand Down Expand Up @@ -6554,7 +6554,7 @@ bool clang::driver::willEmitRemarks(const ArgList &Args) {

llvm::StringRef clang::driver::getDriverMode(StringRef ProgName,
ArrayRef<const char *> Args) {
static const std::string OptName =
static StringRef OptName =
getDriverOptTable().getOption(options::OPT_driver_mode).getPrefixedName();
llvm::StringRef Opt;
for (StringRef Arg : Args) {
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,8 +422,8 @@ static T extractMaskValue(T KeyPath) {
}

#define PARSE_OPTION_WITH_MARSHALLING( \
ARGS, DIAGS, PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
PARAM, HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, \
ARGS, DIAGS, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, \
FLAGS, PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, \
KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \
DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \
if ((FLAGS)&options::CC1Option) { \
Expand All @@ -439,10 +439,10 @@ static T extractMaskValue(T KeyPath) {
// Capture the extracted value as a lambda argument to avoid potential issues
// with lifetime extension of the reference.
#define GENERATE_OPTION_WITH_MARSHALLING( \
CONSUMER, PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
PARAM, HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, \
KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \
DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \
CONSUMER, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
MERGER, EXTRACTOR, TABLE_INDEX) \
if ((FLAGS)&options::CC1Option) { \
[&](const auto &Extracted) { \
if (ALWAYS_EMIT || \
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/Tooling/Tooling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,14 +276,14 @@ void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
return;
const auto &Table = driver::getDriverOptTable();
// --target=X
const std::string TargetOPT =
StringRef TargetOPT =
Table.getOption(driver::options::OPT_target).getPrefixedName();
// -target X
const std::string TargetOPTLegacy =
StringRef TargetOPTLegacy =
Table.getOption(driver::options::OPT_target_legacy_spelling)
.getPrefixedName();
// --driver-mode=X
const std::string DriverModeOPT =
StringRef DriverModeOPT =
Table.getOption(driver::options::OPT_driver_mode).getPrefixedName();
auto TargetMode =
driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs);
Expand All @@ -303,7 +303,7 @@ void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
}
if (ShouldAddTarget) {
CommandLine.insert(++CommandLine.begin(),
TargetOPT + TargetMode.TargetPrefix);
(TargetOPT + TargetMode.TargetPrefix).str());
}
}

Expand Down
41 changes: 24 additions & 17 deletions llvm/include/llvm/Option/OptTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class OptTable {
/// A null terminated array of prefix strings to apply to name while
/// matching.
ArrayRef<StringLiteral> Prefixes;
StringRef Name;
StringLiteral PrefixedName;
const char *HelpText;
const char *MetaVar;
unsigned ID;
Expand All @@ -55,6 +55,11 @@ class OptTable {
unsigned short AliasID;
const char *AliasArgs;
const char *Values;

StringRef getName() const {
unsigned PrefixLength = Prefixes.empty() ? 0 : Prefixes[0].size();
return PrefixedName.drop_front(PrefixLength);
}
};

private:
Expand Down Expand Up @@ -111,7 +116,9 @@ class OptTable {
const Option getOption(OptSpecifier Opt) const;

/// Lookup the name of the given option.
StringRef getOptionName(OptSpecifier id) const { return getInfo(id).Name; }
StringRef getOptionName(OptSpecifier id) const {
return getInfo(id).getName();
}

/// Get the kind of the given option.
unsigned getOptionKind(OptSpecifier id) const {
Expand Down Expand Up @@ -298,31 +305,31 @@ class PrecomputedOptTable : public OptTable {

} // end namespace llvm

#define LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(ID_PREFIX, PREFIX, NAME, ID, KIND, \
GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
#define LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(ID_PREFIX, PREFIX, PREFIXED_NAME, ID, \
KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
PARAM, HELPTEXT, METAVAR, VALUES) \
ID_PREFIX##ID

#define LLVM_MAKE_OPT_ID(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
FLAGS, PARAM, HELPTEXT, METAVAR, VALUES) \
LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OPT_, PREFIX, NAME, ID, KIND, GROUP, ALIAS, \
ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, \
VALUE)
#define LLVM_MAKE_OPT_ID(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, \
ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, VALUES) \
LLVM_MAKE_OPT_ID_WITH_ID_PREFIX(OPT_, PREFIX, PREFIXED_NAME, ID, KIND, \
GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUE)

#define LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX( \
ID_PREFIX, PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
ID_PREFIX, PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
FLAGS, PARAM, HELPTEXT, METAVAR, VALUES) \
llvm::opt::OptTable::Info { \
PREFIX, NAME, HELPTEXT, METAVAR, ID_PREFIX##ID, \
PREFIX, PREFIXED_NAME, HELPTEXT, METAVAR, ID_PREFIX##ID, \
llvm::opt::Option::KIND##Class, PARAM, FLAGS, ID_PREFIX##GROUP, \
ID_PREFIX##ALIAS, ALIASARGS, VALUES \
}

#define LLVM_CONSTRUCT_OPT_INFO(PREFIX, NAME, ID, KIND, GROUP, ALIAS, \
#define LLVM_CONSTRUCT_OPT_INFO(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, \
ALIASARGS, FLAGS, PARAM, HELPTEXT, METAVAR, \
VALUES) \
LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OPT_, PREFIX, NAME, ID, KIND, GROUP, \
ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES)
LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OPT_, PREFIX, PREFIXED_NAME, ID, \
KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
PARAM, HELPTEXT, METAVAR, VALUES)

#endif // LLVM_OPTION_OPTTABLE_H
9 changes: 4 additions & 5 deletions llvm/include/llvm/Option/Option.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class Option {
/// Get the name of this option without any prefix.
StringRef getName() const {
assert(Info && "Must have a valid info!");
return Info->Name;
return Info->getName();
}

const Option getGroup() const {
Expand Down Expand Up @@ -130,10 +130,9 @@ class Option {
}

/// Get the name of this option with the default prefix.
std::string getPrefixedName() const {
std::string Ret(getPrefix());
Ret += getName();
return Ret;
StringLiteral getPrefixedName() const {
assert(Info && "Must have a valid info!");
return Info->PrefixedName;
}

/// Get the help text for this option.
Expand Down
20 changes: 10 additions & 10 deletions llvm/lib/Option/OptTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
if (&A == &B)
return false;

if (int N = StrCmpOptionName(A.Name, B.Name))
if (int N = StrCmpOptionName(A.getName(), B.getName()))
return N < 0;

for (size_t I = 0, K = std::min(A.Prefixes.size(), B.Prefixes.size()); I != K;
Expand All @@ -77,7 +77,7 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {

// Support lower_bound between info and an option name.
static inline bool operator<(const OptTable::Info &I, StringRef Name) {
return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0;
return StrCmpOptionNameIgnoreCase(I.getName(), Name) < 0;
}

} // end namespace opt
Expand Down Expand Up @@ -163,10 +163,10 @@ static unsigned matchOption(const OptTable::Info *I, StringRef Str,
for (auto Prefix : I->Prefixes) {
if (Str.startswith(Prefix)) {
StringRef Rest = Str.substr(Prefix.size());
bool Matched = IgnoreCase ? Rest.starts_with_insensitive(I->Name)
: Rest.startswith(I->Name);
bool Matched = IgnoreCase ? Rest.starts_with_insensitive(I->getName())
: Rest.startswith(I->getName());
if (Matched)
return Prefix.size() + StringRef(I->Name).size();
return Prefix.size() + StringRef(I->getName()).size();
}
}
return 0;
Expand All @@ -175,8 +175,8 @@ static unsigned matchOption(const OptTable::Info *I, StringRef Str,
// Returns true if one of the Prefixes + In.Names matches Option
static bool optionMatches(const OptTable::Info &In, StringRef Option) {
for (auto Prefix : In.Prefixes)
if (Option.endswith(In.Name))
if (Option.slice(0, Option.size() - In.Name.size()) == Prefix)
if (Option.endswith(In.getName()))
if (Option.slice(0, Option.size() - In.getName().size()) == Prefix)
return true;
return false;
}
Expand Down Expand Up @@ -215,7 +215,7 @@ OptTable::findByPrefix(StringRef Cur, unsigned int DisableFlags) const {
continue;

for (auto Prefix : In.Prefixes) {
std::string S = (Prefix + In.Name + "\t").str();
std::string S = (Prefix + In.getName() + "\t").str();
if (In.HelpText)
S += In.HelpText;
if (StringRef(S).startswith(Cur) && S != std::string(Cur) + "\t")
Expand All @@ -240,7 +240,7 @@ unsigned OptTable::findNearest(StringRef Option, std::string &NearestString,

for (const Info &CandidateInfo :
ArrayRef<Info>(OptionInfos).drop_front(FirstSearchableIndex)) {
StringRef CandidateName = CandidateInfo.Name;
StringRef CandidateName = CandidateInfo.getName();

// We can eliminate some option prefix/name pairs as candidates right away:
// * Ignore option candidates with empty names, such as "--", or names
Expand Down Expand Up @@ -529,7 +529,7 @@ InputArgList OptTable::parseArgs(int Argc, char *const *Argv,

static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
const Option O = Opts.getOption(Id);
std::string Name = O.getPrefixedName();
std::string Name = O.getPrefixedName().str();

// Add metavar, if used.
switch (O.getKind()) {
Expand Down
16 changes: 8 additions & 8 deletions llvm/unittests/Option/OptionMarshallingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,28 @@
#include "gtest/gtest.h"

struct OptionWithMarshallingInfo {
llvm::StringRef Name;
llvm::StringLiteral PrefixedName;
const char *KeyPath;
const char *ImpliedCheck;
const char *ImpliedValue;
};

static const OptionWithMarshallingInfo MarshallingTable[] = {
#define OPTION_WITH_MARSHALLING( \
PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES, SPELLING, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
PREFIX_TYPE, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, \
DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, \
MERGER, EXTRACTOR, TABLE_INDEX) \
{NAME, #KEYPATH, #IMPLIED_CHECK, #IMPLIED_VALUE},
{PREFIXED_NAME, #KEYPATH, #IMPLIED_CHECK, #IMPLIED_VALUE},
#include "Opts.inc"
#undef OPTION_WITH_MARSHALLING
};

TEST(OptionMarshalling, EmittedOrderSameAsDefinitionOrder) {
ASSERT_STREQ(MarshallingTable[0].Name.data(), "marshalled-flag-d");
ASSERT_STREQ(MarshallingTable[1].Name.data(), "marshalled-flag-c");
ASSERT_STREQ(MarshallingTable[2].Name.data(), "marshalled-flag-b");
ASSERT_STREQ(MarshallingTable[3].Name.data(), "marshalled-flag-a");
ASSERT_EQ(MarshallingTable[0].PrefixedName, "-marshalled-flag-d");
ASSERT_EQ(MarshallingTable[1].PrefixedName, "-marshalled-flag-c");
ASSERT_EQ(MarshallingTable[2].PrefixedName, "-marshalled-flag-b");
ASSERT_EQ(MarshallingTable[3].PrefixedName, "-marshalled-flag-a");
}

TEST(OptionMarshalling, EmittedSpecifiedKeyPath) {
Expand Down
28 changes: 5 additions & 23 deletions llvm/utils/TableGen/OptParserEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,14 @@ static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
return OS;
}

static std::string getOptionSpelling(const Record &R, size_t &PrefixLength) {
static std::string getOptionPrefixedName(const Record &R) {
std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes");
StringRef Name = R.getValueAsString("Name");

if (Prefixes.empty()) {
PrefixLength = 0;
if (Prefixes.empty())
return Name.str();
}

PrefixLength = Prefixes[0].size();
return (Twine(Prefixes[0]) + Twine(Name)).str();
}

static std::string getOptionSpelling(const Record &R) {
size_t PrefixLength;
return getOptionSpelling(R, PrefixLength);
}

static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
size_t PrefixLength;
OS << "llvm::StringLiteral(";
write_cstring(
OS, StringRef(getOptionSpelling(R, PrefixLength)).substr(PrefixLength));
OS << ")";
return (Prefixes[0] + Twine(Name)).str();
}

class MarshallingInfo {
Expand Down Expand Up @@ -105,8 +89,6 @@ struct SimpleEnumValueTable {
}

void emit(raw_ostream &OS) const {
write_cstring(OS, StringRef(getOptionSpelling(R)));
OS << ", ";
OS << ShouldParse;
OS << ", ";
OS << ShouldAlwaysEmit;
Expand Down Expand Up @@ -346,8 +328,8 @@ static void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";

// The option string.
emitNameUsingSpelling(OS, R);
// The option prefixed name.
write_cstring(OS, getOptionPrefixedName(R));

// The option identifier name.
OS << ", " << getOptionName(R);
Expand Down

0 comments on commit 501f92d

Please sign in to comment.