[clang] 2f3055c - [clang][cli] Add support for options with two flags for controlling the same field.
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Mon Nov 16 01:24:11 PST 2020
Author: Jan Svoboda
Date: 2020-11-16T10:21:54+01:00
New Revision: 2f3055c543f8f5e8cd975350fae5f4b0ac4871c3
URL: https://github.com/llvm/llvm-project/commit/2f3055c543f8f5e8cd975350fae5f4b0ac4871c3
DIFF: https://github.com/llvm/llvm-project/commit/2f3055c543f8f5e8cd975350fae5f4b0ac4871c3.diff
LOG: [clang][cli] Add support for options with two flags for controlling the same field.
This enables automatically parsing and generating CC1 arguments for options where two flags control the same field, e.g. -fexperimental-new-pass-manager and -fno-experimental new pass manager.
Reviewed By: Bigcheese, dexonsmith
Original patch by Daniel Grumberg.
Differential Revision: https://reviews.llvm.org/D83071
Added:
Modified:
clang/include/clang/Driver/Options.td
clang/lib/Frontend/CompilerInvocation.cpp
llvm/include/llvm/Option/OptParser.td
llvm/utils/TableGen/OptParserEmitter.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 0b0def564cf3..ec86c5e07ab6 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -266,6 +266,12 @@ multiclass OptOutFFlag<string name, string pos_prefix, string neg_prefix,
MarshallingInfoFlag<keypath, defaults>;
}
+multiclass BooleanMarshalledFFlag<string name, code keypath, code default_value, string pos_help = "", string neg_help=""> {
+ def fno_#NAME : Flag<["-"], "fno-"#name>, HelpText<neg_help>;
+ def f#NAME : Flag<["-"], "f"#name>, HelpText<pos_help>,
+ MarshallingInfoBooleanFlag<keypath, default_value, !cast<Option>("fno_"#NAME)>;
+}
+
/////////
// Options
@@ -1320,9 +1326,9 @@ def fglobal_isel : Flag<["-"], "fglobal-isel">, Group<f_clang_Group>,
HelpText<"Enables the global instruction selector">;
def fexperimental_isel : Flag<["-"], "fexperimental-isel">, Group<f_clang_Group>,
Alias<fglobal_isel>;
-def fexperimental_new_pass_manager : Flag<["-"], "fexperimental-new-pass-manager">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
- HelpText<"Enables an experimental new pass manager in LLVM.">;
+defm experimental_new_pass_manager : BooleanMarshalledFFlag<"experimental-new-pass-manager", "CodeGenOpts.ExperimentalNewPassManager",
+ "static_cast<unsigned>(ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER)", "Enables an experimental new pass manager in LLVM.",
+ "Disables an experimental new pass manager in LLVM.">, Group<f_clang_Group>, Flags<[CC1Option]>;
def fexperimental_strict_floating_point : Flag<["-"], "fexperimental-strict-floating-point">,
Group<f_clang_Group>, Flags<[CC1Option]>,
HelpText<"Enables experimental strict floating point in LLVM.">,
@@ -1624,9 +1630,6 @@ def fno_global_isel : Flag<["-"], "fno-global-isel">, Group<f_clang_Group>,
HelpText<"Disables the global instruction selector">;
def fno_experimental_isel : Flag<["-"], "fno-experimental-isel">, Group<f_clang_Group>,
Alias<fno_global_isel>;
-def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-manager">,
- Group<f_clang_Group>, Flags<[CC1Option]>,
- HelpText<"Disables an experimental new pass manager in LLVM.">;
def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use the given vector functions library">, Values<"Accelerate,libmvec,MASSV,SVML,none">;
def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 2e20ecea3334..c4133ec1bcd8 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -134,6 +134,13 @@ static llvm::Optional<bool> normalizeSimpleFlag(OptSpecifier Opt,
return None;
}
+void denormalizeSimpleFlag(SmallVectorImpl<const char *> &Args,
+ const char *Spelling,
+ CompilerInvocation::StringAllocator SA,
+ unsigned TableIndex, unsigned Value) {
+ Args.push_back(Spelling);
+}
+
template <typename T, T Value>
static llvm::Optional<T>
normalizeFlagToValue(OptSpecifier Opt, unsigned TableIndex, const ArgList &Args,
@@ -143,6 +150,27 @@ normalizeFlagToValue(OptSpecifier Opt, unsigned TableIndex, const ArgList &Args,
return None;
}
+static Optional<bool> normalizeBooleanFlag(OptSpecifier PosOpt,
+ OptSpecifier NegOpt,
+ unsigned TableIndex,
+ const ArgList &Args,
+ DiagnosticsEngine &Diags) {
+ if (const Arg *A = Args.getLastArg(PosOpt, NegOpt))
+ return A->getOption().matches(PosOpt);
+ return None;
+}
+
+static void denormalizeBooleanFlag(SmallVectorImpl<const char *> &Args,
+ const char *Spelling,
+ const char *NegSpelling,
+ CompilerInvocation::StringAllocator SA,
+ unsigned TableIndex, unsigned Value) {
+ if (Value)
+ Args.push_back(Spelling);
+ else
+ Args.push_back(NegSpelling);
+}
+
static llvm::Optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
unsigned TableIndex,
const ArgList &Args,
@@ -165,12 +193,14 @@ static llvm::Optional<unsigned> normalizeSimpleEnum(OptSpecifier Opt,
}
static void denormalizeSimpleEnum(SmallVectorImpl<const char *> &Args,
+ const char *Spelling,
CompilerInvocation::StringAllocator SA,
unsigned TableIndex, unsigned Value) {
assert(TableIndex < SimpleEnumValueTablesSize);
const SimpleEnumValueTable &Table = SimpleEnumValueTables[TableIndex];
for (int I = 0, E = Table.Size; I != E; ++I) {
if (Value == Table.Table[I].Value) {
+ Args.push_back(Spelling);
Args.push_back(Table.Table[I].Name);
return;
}
@@ -181,8 +211,10 @@ static void denormalizeSimpleEnum(SmallVectorImpl<const char *> &Args,
}
static void denormalizeString(SmallVectorImpl<const char *> &Args,
+ const char *Spelling,
CompilerInvocation::StringAllocator SA,
unsigned TableIndex, const std::string &Value) {
+ Args.push_back(Spelling);
Args.push_back(SA(Value));
}
@@ -777,10 +809,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
}
}
- Opts.ExperimentalNewPassManager = Args.hasFlag(
- OPT_fexperimental_new_pass_manager, OPT_fno_experimental_new_pass_manager,
- /* Default */ ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER);
-
Opts.DebugPassManager =
Args.hasFlag(OPT_fdebug_pass_manager, OPT_fno_debug_pass_manager,
/* Default */ false);
@@ -3741,7 +3769,21 @@ bool CompilerInvocation::parseSimpleArgs(const ArgList &Args,
this->KEYPATH = MERGER(this->KEYPATH, static_cast<TYPE>(*MaybeValue)); \
}
+#define OPTION_WITH_MARSHALLING_BOOLEAN( \
+ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
+ TYPE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX, NEG_ID, \
+ NEG_SPELLING) \
+ { \
+ if (auto MaybeValue = \
+ NORMALIZER(OPT_##ID, OPT_##NEG_ID, TABLE_INDEX, Args, Diags)) \
+ this->KEYPATH = MERGER(this->KEYPATH, static_cast<TYPE>(*MaybeValue)); \
+ else \
+ this->KEYPATH = MERGER(this->KEYPATH, DEFAULT_VALUE); \
+ }
+
#include "clang/Driver/Options.inc"
+#undef OPTION_WITH_MARSHALLING_BOOLEAN
#undef OPTION_WITH_MARSHALLING
return true;
}
@@ -4000,16 +4042,22 @@ void CompilerInvocation::generateCC1CommandLine(
TYPE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \
if (((FLAGS) & options::CC1Option) && \
(ALWAYS_EMIT || EXTRACTOR(this->KEYPATH) != (DEFAULT_VALUE))) { \
- if (Option::KIND##Class == Option::FlagClass) { \
- Args.push_back(SPELLING); \
- } \
- if (Option::KIND##Class == Option::SeparateClass) { \
- Args.push_back(SPELLING); \
- DENORMALIZER(Args, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH)); \
- } \
+ DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH)); \
+ }
+
+#define OPTION_WITH_MARSHALLING_BOOLEAN( \
+ PREFIX_TYPE, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES, SPELLING, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, \
+ TYPE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX, NEG_ID, \
+ NEG_SPELLING) \
+ if (((FLAGS)&options::CC1Option) && \
+ (ALWAYS_EMIT || EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE)) { \
+ DENORMALIZER(Args, SPELLING, NEG_SPELLING, SA, TABLE_INDEX, \
+ EXTRACTOR(this->KEYPATH)); \
}
#include "clang/Driver/Options.inc"
+#undef OPTION_WITH_MARSHALLING_BOOLEAN
#undef OPTION_WITH_MARSHALLING
}
diff --git a/llvm/include/llvm/Option/OptParser.td b/llvm/include/llvm/Option/OptParser.td
index b2a07b05673a..85874478e59e 100644
--- a/llvm/include/llvm/Option/OptParser.td
+++ b/llvm/include/llvm/Option/OptParser.td
@@ -97,6 +97,7 @@ class Option<list<string> prefixes, string name, OptionKind kind> {
OptionGroup Group = ?;
Option Alias = ?;
list<string> AliasArgs = [];
+ string MarshallingInfoKind = ?;
code KeyPath = ?;
code DefaultValue = ?;
bit ShouldAlwaysEmit = false;
@@ -107,6 +108,8 @@ class Option<list<string> prefixes, string name, OptionKind kind> {
code ValueMerger = "mergeForwardValue";
code ValueExtractor = "extractForwardValue";
list<code> NormalizedValues = ?;
+ // Used for BooleanFlagKind
+ Option NegOption = ?;
}
// Helpers for defining options.
@@ -148,6 +151,7 @@ class DefaultAnyOf<list<Option> options, string default = "false", string separa
}
class MarshallingInfo<code keypath, code defaultvalue> {
+ string MarshallingInfoKind = "Default";
code KeyPath = keypath;
code DefaultValue = defaultvalue;
}
@@ -161,6 +165,7 @@ class MarshallingInfoFlag<code keypath, DefaultAnyOf defaults = DefaultAnyOf<[]>
: MarshallingInfo<keypath, defaults.DefaultValue> {
code NormalizerRetTy = ty;
code Normalizer = "normalizeSimpleFlag";
+ code Denormalizer = "denormalizeSimpleFlag";
}
class MarshallingInfoBitfieldFlag<code keypath, code value>
@@ -170,6 +175,15 @@ class MarshallingInfoBitfieldFlag<code keypath, code value>
code ValueExtractor = "(extractMaskValue<unsigned, decltype("#value#"), "#value#">)";
}
+class MarshallingInfoBooleanFlag<code keypath, code defaultvalue, Option negopt>
+ : MarshallingInfoFlag<keypath, DefaultAnyOf<[], defaultvalue>> {
+ bit ShouldAlwaysEmit = 1;
+ string MarshallingInfoKind = "BooleanFlag";
+ code Normalizer = "normalizeBooleanFlag";
+ code Denormalizer = "denormalizeBooleanFlag";
+ Option NegOption = negopt;
+}
+
// Mixins for additional marshalling attributes.
class IsNegative {
diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp
index f2e0a70ad417..88f5dd3658c9 100644
--- a/llvm/utils/TableGen/OptParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptParserEmitter.cpp
@@ -63,8 +63,9 @@ static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
class MarshallingInfo {
public:
- static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
+ using Ptr = std::unique_ptr<MarshallingInfo>;
+ const char *MacroName;
const Record &R;
bool ShouldAlwaysEmit;
StringRef KeyPath;
@@ -80,6 +81,8 @@ class MarshallingInfo {
std::vector<StringRef> NormalizedValues;
std::string ValueTableName;
+ static size_t NextTableIndex;
+
static constexpr const char *ValueTablePreamble = R"(
struct SimpleEnumValue {
const char *Name;
@@ -95,7 +98,14 @@ struct SimpleEnumValueTable {
static constexpr const char *ValueTablesDecl =
"static const SimpleEnumValueTable SimpleEnumValueTables[] = ";
- void emit(raw_ostream &OS) const {
+ MarshallingInfo(const Record &R)
+ : MacroName("OPTION_WITH_MARSHALLING"), R(R) {}
+ MarshallingInfo(const char *MacroName, const Record &R)
+ : MacroName(MacroName), R(R){};
+
+ virtual ~MarshallingInfo() = default;
+
+ virtual void emit(raw_ostream &OS) const {
write_cstring(OS, StringRef(getOptionSpelling(R)));
OS << ", ";
OS << ShouldAlwaysEmit;
@@ -133,53 +143,6 @@ struct SimpleEnumValueTable {
return StringRef(ValueTableName);
}
- static MarshallingInfo create(const Record &R) {
- assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
- !isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
- !isa<UnsetInit>(R.getValueInit("NormalizerRetTy")) &&
- !isa<UnsetInit>(R.getValueInit("ValueMerger")) &&
- "MarshallingInfo must have a type");
-
- MarshallingInfo Ret(R);
- Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
- Ret.KeyPath = R.getValueAsString("KeyPath");
- Ret.DefaultValue = R.getValueAsString("DefaultValue");
- Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
- Ret.NormalizerRetTy = R.getValueAsString("NormalizerRetTy");
-
- Ret.Normalizer = R.getValueAsString("Normalizer");
- Ret.Denormalizer = R.getValueAsString("Denormalizer");
- Ret.ValueMerger = R.getValueAsString("ValueMerger");
- Ret.ValueExtractor = R.getValueAsString("ValueExtractor");
-
- if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) {
- assert(!isa<UnsetInit>(R.getValueInit("Values")) &&
- "Cannot provide normalized values for value-less options");
- Ret.TableIndex = NextTableIndex++;
- Ret.NormalizedValues = R.getValueAsListOfStrings("NormalizedValues");
- Ret.Values.reserve(Ret.NormalizedValues.size());
- Ret.ValueTableName = getOptionName(R) + "ValueTable";
-
- StringRef ValuesStr = R.getValueAsString("Values");
- for (;;) {
- size_t Idx = ValuesStr.find(',');
- if (Idx == StringRef::npos)
- break;
- if (Idx > 0)
- Ret.Values.push_back(ValuesStr.slice(0, Idx));
- ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos);
- }
- if (!ValuesStr.empty())
- Ret.Values.push_back(ValuesStr);
-
- assert(Ret.Values.size() == Ret.NormalizedValues.size() &&
- "The number of normalized values doesn't match the number of "
- "values");
- }
-
- return Ret;
- }
-
private:
void emitScopedNormalizedValue(raw_ostream &OS,
StringRef NormalizedValue) const {
@@ -187,13 +150,85 @@ struct SimpleEnumValueTable {
OS << NormalizedValuesScope << "::";
OS << NormalizedValue;
}
+};
+
+size_t MarshallingInfo::NextTableIndex = 0;
- MarshallingInfo(const Record &R) : R(R){};
+class MarshallingInfoBooleanFlag : public MarshallingInfo {
+public:
+ const Record &NegOption;
- static size_t NextTableIndex;
+ MarshallingInfoBooleanFlag(const Record &Option, const Record &NegOption)
+ : MarshallingInfo("OPTION_WITH_MARSHALLING_BOOLEAN", Option),
+ NegOption(NegOption) {}
+
+ void emit(raw_ostream &OS) const override {
+ MarshallingInfo::emit(OS);
+ OS << ", ";
+ OS << getOptionName(NegOption);
+ OS << ", ";
+ write_cstring(OS, getOptionSpelling(NegOption));
+ }
};
-size_t MarshallingInfo::NextTableIndex = 0;
+static MarshallingInfo::Ptr createMarshallingInfo(const Record &R) {
+ assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
+ !isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
+ !isa<UnsetInit>(R.getValueInit("NormalizerRetTy")) &&
+ !isa<UnsetInit>(R.getValueInit("ValueMerger")) &&
+ "MarshallingInfo must have a type");
+
+ MarshallingInfo::Ptr Ret;
+ StringRef KindString = R.getValueAsString("MarshallingInfoKind");
+ if (KindString == "Default") {
+ Ret = std::make_unique<MarshallingInfo>(R);
+ } else if (KindString == "BooleanFlag") {
+ Ret = std::make_unique<MarshallingInfoBooleanFlag>(
+ R, *R.getValueAsDef("NegOption"));
+ }
+
+ Ret->ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
+ Ret->KeyPath = R.getValueAsString("KeyPath");
+ Ret->DefaultValue = R.getValueAsString("DefaultValue");
+ Ret->NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
+ Ret->NormalizerRetTy = R.getValueAsString("NormalizerRetTy");
+
+ Ret->Normalizer = R.getValueAsString("Normalizer");
+ Ret->Denormalizer = R.getValueAsString("Denormalizer");
+ Ret->ValueMerger = R.getValueAsString("ValueMerger");
+ Ret->ValueExtractor = R.getValueAsString("ValueExtractor");
+
+ if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) {
+ assert(!isa<UnsetInit>(R.getValueInit("Values")) &&
+ "Cannot provide normalized values for value-less options");
+ Ret->TableIndex = MarshallingInfo::NextTableIndex++;
+ Ret->NormalizedValues = R.getValueAsListOfStrings("NormalizedValues");
+ Ret->Values.reserve(Ret->NormalizedValues.size());
+ Ret->ValueTableName = getOptionName(R) + "ValueTable";
+
+ StringRef ValuesStr = R.getValueAsString("Values");
+ for (;;) {
+ size_t Idx = ValuesStr.find(',');
+ if (Idx == StringRef::npos)
+ break;
+ if (Idx > 0)
+ Ret->Values.push_back(ValuesStr.slice(0, Idx));
+ ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos);
+ }
+ if (!ValuesStr.empty())
+ Ret->Values.push_back(ValuesStr);
+
+ assert(Ret->Values.size() == Ret->NormalizedValues.size() &&
+ "The number of normalized values doesn't match the number of "
+ "values");
+ }
+
+ // FIXME: This is a workaround for a bug in older versions of clang (< 3.9)
+ // The constructor that is supposed to allow for Derived to Base
+ // conversion does not work. Remove this if we drop support for such
+ // configurations.
+ return MarshallingInfo::Ptr(Ret.release());
+}
/// OptParserEmitter - This tablegen backend takes an input .td file
/// describing a list of options and emits a data structure for parsing and
@@ -418,18 +453,18 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
CmpMarshallingOpts);
- std::vector<MarshallingInfo> MarshallingInfos;
+ std::vector<MarshallingInfo::Ptr> MarshallingInfos;
for (const auto *R : OptsWithMarshalling)
- MarshallingInfos.push_back(MarshallingInfo::create(*R));
+ MarshallingInfos.push_back(createMarshallingInfo(*R));
for (const auto &MI : MarshallingInfos) {
- OS << "#ifdef " << MarshallingInfo::MacroName << "\n";
- OS << MarshallingInfo::MacroName << "(";
- WriteOptRecordFields(OS, MI.R);
+ OS << "#ifdef " << MI->MacroName << "\n";
+ OS << MI->MacroName << "(";
+ WriteOptRecordFields(OS, MI->R);
OS << ", ";
- MI.emit(OS);
+ MI->emit(OS);
OS << ")\n";
- OS << "#endif // " << MarshallingInfo::MacroName << "\n";
+ OS << "#endif // " << MI->MacroName << "\n";
}
OS << "\n";
@@ -438,7 +473,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
OS << MarshallingInfo::ValueTablePreamble;
std::vector<StringRef> ValueTableNames;
for (const auto &MI : MarshallingInfos)
- if (auto MaybeValueTableName = MI.emitValueTable(OS))
+ if (auto MaybeValueTableName = MI->emitValueTable(OS))
ValueTableNames.push_back(*MaybeValueTableName);
OS << MarshallingInfo::ValueTablesDecl << "{";
More information about the cfe-commits
mailing list