forked from OSchip/llvm-project
[clang][cli] Unify boolean marshalling
Use lambdas with captures to replace the redundant infrastructure for marshalling of two boolean flags that control the same keypath. Reviewed By: dexonsmith Differential Revision: https://reviews.llvm.org/D92773
This commit is contained in:
parent
41d0666391
commit
083e035c47
|
@ -271,7 +271,7 @@ multiclass OptOutFFlag<string name, string pos_prefix, string neg_prefix,
|
|||
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)>;
|
||||
MarshallingInfoBooleanFlag<keypath, default_value, "fno_"#NAME, "-fno-"#name>;
|
||||
}
|
||||
|
||||
/////////
|
||||
|
|
|
@ -185,25 +185,21 @@ static FlagToValueNormalizer<T> makeFlagToValueNormalizer(T Value) {
|
|||
return FlagToValueNormalizer<T>{std::move(Value)};
|
||||
}
|
||||
|
||||
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 auto makeBooleanFlagNormalizer(OptSpecifier NegOpt) {
|
||||
return [NegOpt](OptSpecifier PosOpt, unsigned, const ArgList &Args,
|
||||
DiagnosticsEngine &) -> Optional<bool> {
|
||||
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 auto makeBooleanFlagDenormalizer(const char *NegSpelling) {
|
||||
return [NegSpelling](
|
||||
SmallVectorImpl<const char *> &Args, const char *PosSpelling,
|
||||
CompilerInvocation::StringAllocator, unsigned, unsigned Value) {
|
||||
Args.push_back(Value ? PosSpelling : NegSpelling);
|
||||
};
|
||||
}
|
||||
|
||||
static Optional<SimpleEnumValue>
|
||||
|
@ -3779,23 +3775,7 @@ bool CompilerInvocation::parseSimpleArgs(const ArgList &Args,
|
|||
this->KEYPATH, static_cast<decltype(this->KEYPATH)>(*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, \
|
||||
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, \
|
||||
TABLE_INDEX, NEG_ID, NEG_SPELLING) \
|
||||
{ \
|
||||
this->KEYPATH = MERGER(this->KEYPATH, DEFAULT_VALUE); \
|
||||
if (IMPLIED_CHECK) \
|
||||
this->KEYPATH = MERGER(this->KEYPATH, IMPLIED_VALUE); \
|
||||
if (auto MaybeValue = \
|
||||
NORMALIZER(OPT_##ID, OPT_##NEG_ID, TABLE_INDEX, Args, Diags)) \
|
||||
this->KEYPATH = MERGER( \
|
||||
this->KEYPATH, static_cast<decltype(this->KEYPATH)>(*MaybeValue)); \
|
||||
}
|
||||
|
||||
#include "clang/Driver/Options.inc"
|
||||
#undef OPTION_WITH_MARSHALLING_BOOLEAN
|
||||
#undef OPTION_WITH_MARSHALLING
|
||||
return true;
|
||||
}
|
||||
|
@ -4060,20 +4040,7 @@ void CompilerInvocation::generateCC1CommandLine(
|
|||
}(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, \
|
||||
IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, \
|
||||
TABLE_INDEX, NEG_ID, NEG_SPELLING) \
|
||||
if ((FLAGS)&options::CC1Option) { \
|
||||
bool Extracted = EXTRACTOR(this->KEYPATH); \
|
||||
if (ALWAYS_EMIT || \
|
||||
(Extracted != ((IMPLIED_CHECK) ? (IMPLIED_VALUE) : (DEFAULT_VALUE)))) \
|
||||
DENORMALIZER(Args, SPELLING, NEG_SPELLING, SA, TABLE_INDEX, Extracted); \
|
||||
}
|
||||
|
||||
#include "clang/Driver/Options.inc"
|
||||
#undef OPTION_WITH_MARSHALLING_BOOLEAN
|
||||
#undef OPTION_WITH_MARSHALLING
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ class Option<list<string> prefixes, string name, OptionKind kind> {
|
|||
OptionGroup Group = ?;
|
||||
Option Alias = ?;
|
||||
list<string> AliasArgs = [];
|
||||
string MarshallingInfoKind = ?;
|
||||
code KeyPath = ?;
|
||||
code DefaultValue = ?;
|
||||
code ImpliedValue = ?;
|
||||
|
@ -110,8 +109,6 @@ 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.
|
||||
|
@ -154,7 +151,6 @@ class ImpliedByAnyOf<list<Option> options, code value = "true"> {
|
|||
}
|
||||
|
||||
class MarshallingInfo<code keypath, code defaultvalue> {
|
||||
string MarshallingInfoKind = "Default";
|
||||
code KeyPath = keypath;
|
||||
code DefaultValue = defaultvalue;
|
||||
}
|
||||
|
@ -175,13 +171,11 @@ class MarshallingInfoBitfieldFlag<code keypath, code value>
|
|||
code ValueExtractor = "(extractMaskValue<unsigned, decltype("#value#"), "#value#">)";
|
||||
}
|
||||
|
||||
class MarshallingInfoBooleanFlag<code keypath, code defaultvalue, Option negopt>
|
||||
class MarshallingInfoBooleanFlag<code keypath, code defaultvalue, code neg_name, string neg_spelling>
|
||||
: MarshallingInfoFlag<keypath, defaultvalue> {
|
||||
bit ShouldAlwaysEmit = 1;
|
||||
string MarshallingInfoKind = "BooleanFlag";
|
||||
code Normalizer = "normalizeBooleanFlag";
|
||||
code Denormalizer = "denormalizeBooleanFlag";
|
||||
Option NegOption = negopt;
|
||||
code Normalizer = "makeBooleanFlagNormalizer(OPT_"#neg_name#")";
|
||||
code Denormalizer = "makeBooleanFlagDenormalizer(\""#neg_spelling#"\")";
|
||||
}
|
||||
|
||||
// Mixins for additional marshalling attributes.
|
||||
|
|
|
@ -63,9 +63,7 @@ static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
|
|||
|
||||
class MarshallingInfo {
|
||||
public:
|
||||
using Ptr = std::unique_ptr<MarshallingInfo>;
|
||||
|
||||
const char *MacroName;
|
||||
static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
|
||||
const Record &R;
|
||||
bool ShouldAlwaysEmit;
|
||||
StringRef KeyPath;
|
||||
|
@ -99,14 +97,9 @@ struct SimpleEnumValueTable {
|
|||
static constexpr const char *ValueTablesDecl =
|
||||
"static const SimpleEnumValueTable SimpleEnumValueTables[] = ";
|
||||
|
||||
MarshallingInfo(const Record &R)
|
||||
: MacroName("OPTION_WITH_MARSHALLING"), R(R) {}
|
||||
MarshallingInfo(const char *MacroName, const Record &R)
|
||||
: MacroName(MacroName), R(R){};
|
||||
MarshallingInfo(const Record &R) : R(R) {}
|
||||
|
||||
virtual ~MarshallingInfo() = default;
|
||||
|
||||
virtual void emit(raw_ostream &OS) const {
|
||||
void emit(raw_ostream &OS) const {
|
||||
write_cstring(OS, StringRef(getOptionSpelling(R)));
|
||||
OS << ", ";
|
||||
OS << ShouldAlwaysEmit;
|
||||
|
@ -157,59 +150,35 @@ private:
|
|||
|
||||
size_t MarshallingInfo::NextTableIndex = 0;
|
||||
|
||||
class MarshallingInfoBooleanFlag : public MarshallingInfo {
|
||||
public:
|
||||
const Record &NegOption;
|
||||
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
static MarshallingInfo::Ptr createMarshallingInfo(const Record &R) {
|
||||
static MarshallingInfo createMarshallingInfo(const Record &R) {
|
||||
assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
|
||||
!isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
|
||||
!isa<UnsetInit>(R.getValueInit("ValueMerger")) &&
|
||||
"MarshallingInfo must have a provide a keypath, default value and a "
|
||||
"value merger");
|
||||
|
||||
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"));
|
||||
}
|
||||
MarshallingInfo Ret(R);
|
||||
|
||||
Ret->ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
|
||||
Ret->KeyPath = R.getValueAsString("KeyPath");
|
||||
Ret->DefaultValue = R.getValueAsString("DefaultValue");
|
||||
Ret->NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
|
||||
Ret->ImpliedCheck = R.getValueAsString("ImpliedCheck");
|
||||
Ret->ImpliedValue =
|
||||
R.getValueAsOptionalString("ImpliedValue").getValueOr(Ret->DefaultValue);
|
||||
Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
|
||||
Ret.KeyPath = R.getValueAsString("KeyPath");
|
||||
Ret.DefaultValue = R.getValueAsString("DefaultValue");
|
||||
Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
|
||||
Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck");
|
||||
Ret.ImpliedValue =
|
||||
R.getValueAsOptionalString("ImpliedValue").getValueOr(Ret.DefaultValue);
|
||||
|
||||
Ret->Normalizer = R.getValueAsString("Normalizer");
|
||||
Ret->Denormalizer = R.getValueAsString("Denormalizer");
|
||||
Ret->ValueMerger = R.getValueAsString("ValueMerger");
|
||||
Ret->ValueExtractor = R.getValueAsString("ValueExtractor");
|
||||
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";
|
||||
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 (;;) {
|
||||
|
@ -217,22 +186,18 @@ static MarshallingInfo::Ptr createMarshallingInfo(const Record &R) {
|
|||
if (Idx == StringRef::npos)
|
||||
break;
|
||||
if (Idx > 0)
|
||||
Ret->Values.push_back(ValuesStr.slice(0, Idx));
|
||||
Ret.Values.push_back(ValuesStr.slice(0, Idx));
|
||||
ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos);
|
||||
}
|
||||
if (!ValuesStr.empty())
|
||||
Ret->Values.push_back(ValuesStr);
|
||||
Ret.Values.push_back(ValuesStr);
|
||||
|
||||
assert(Ret->Values.size() == Ret->NormalizedValues.size() &&
|
||||
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());
|
||||
return Ret;
|
||||
}
|
||||
|
||||
/// OptParserEmitter - This tablegen backend takes an input .td file
|
||||
|
@ -458,18 +423,18 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
|
|||
array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
|
||||
CmpMarshallingOpts);
|
||||
|
||||
std::vector<MarshallingInfo::Ptr> MarshallingInfos;
|
||||
std::vector<MarshallingInfo> MarshallingInfos;
|
||||
for (const auto *R : OptsWithMarshalling)
|
||||
MarshallingInfos.push_back(createMarshallingInfo(*R));
|
||||
|
||||
for (const auto &MI : MarshallingInfos) {
|
||||
OS << "#ifdef " << MI->MacroName << "\n";
|
||||
OS << MI->MacroName << "(";
|
||||
WriteOptRecordFields(OS, MI->R);
|
||||
OS << "#ifdef " << MarshallingInfo::MacroName << "\n";
|
||||
OS << MarshallingInfo::MacroName << "(";
|
||||
WriteOptRecordFields(OS, MI.R);
|
||||
OS << ", ";
|
||||
MI->emit(OS);
|
||||
MI.emit(OS);
|
||||
OS << ")\n";
|
||||
OS << "#endif // " << MI->MacroName << "\n";
|
||||
OS << "#endif // " << MarshallingInfo::MacroName << "\n";
|
||||
}
|
||||
|
||||
OS << "\n";
|
||||
|
@ -478,7 +443,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 << "{";
|
||||
|
|
Loading…
Reference in New Issue