[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:
Jan Svoboda 2020-12-07 14:22:23 +01:00
parent 41d0666391
commit 083e035c47
4 changed files with 48 additions and 122 deletions

View File

@ -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>;
}
/////////

View File

@ -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
}

View File

@ -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.

View File

@ -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 << "{";