1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[clang][cli] Port ObjCMTAction to new option parsing system

Merge existing marhsalling info kinds and add some primitives to
express flag options that contribute to a bitfield.

Depends on D82574

Reviewed By: Bigcheese

Differential Revision: https://reviews.llvm.org/D82860
This commit is contained in:
Jan Svoboda 2020-11-11 11:05:24 +01:00
parent 859b066624
commit 75210ece0c
4 changed files with 111 additions and 155 deletions

View File

@ -97,17 +97,15 @@ class Option<list<string> prefixes, string name, OptionKind kind> {
OptionGroup Group = ?;
Option Alias = ?;
list<string> AliasArgs = [];
string MarshallingKind = ?;
code KeyPath = ?;
code DefaultValue = ?;
bit ShouldAlwaysEmit = 0;
// Used by the Flag option kind.
bit IsPositive = 1;
// Used by the String option kind.
code NormalizerRetTy = ?;
code NormalizedValuesScope = "";
code Normalizer = "";
code Denormalizer = "";
code ValueMerger = "mergeForwardValue";
code ValueExtractor = "extractForwardValue";
list<code> NormalizedValues = ?;
}
@ -144,29 +142,39 @@ class ValuesCode<code valuecode> { code ValuesCode = valuecode; }
// Helpers for defining marshalling information.
class DefaultAnyOf<list<Option> defaults> {
code DefaultValue = !foldl("false", defaults, accumulator, option,
!strconcat(accumulator, " || ", !cast<string>(option.KeyPath)));
class DefaultAnyOf<list<Option> options, string default = "false", string separator = " || "> {
code DefaultValue = !foldl(default, options, accumulator, option,
!strconcat(accumulator, separator, !cast<string>(option.KeyPath)));
}
class MarshallingInfo<code keypath, code defaultvalue> {
code KeyPath = keypath;
code DefaultValue = defaultvalue;
}
class MarshallingInfoString<code keypath, code defaultvalue, code normalizerretty>
: MarshallingInfo<keypath, defaultvalue> {
string MarshallingKind = "string";
code NormalizerRetTy = normalizerretty;
}
class MarshallingInfoFlag<code keypath, DefaultAnyOf defaults = DefaultAnyOf<[]>>
class MarshallingInfoFlag<code keypath, DefaultAnyOf defaults = DefaultAnyOf<[]>, code ty="unsigned">
: MarshallingInfo<keypath, defaults.DefaultValue> {
string MarshallingKind = "flag";
code NormalizerRetTy = ty;
code Normalizer = "normalizeSimpleFlag";
}
class MarshallingInfoBitfieldFlag<code keypath, code value>
: MarshallingInfoFlag<keypath, DefaultAnyOf<[], "0u", " | ">, "unsigned"> {
code Normalizer = "(normalizeFlagToValue<unsigned, "#value#">)";
code ValueMerger = "mergeMaskValue";
code ValueExtractor = "(extractMaskValue<unsigned, decltype("#value#"), "#value#">)";
}
// Mixins for additional marshalling attributes.
class IsNegative { bit IsPositive = 0; }
class IsNegative {
// todo: create & apply a normalizer for negative flags
}
class AlwaysEmit { bit ShouldAlwaysEmit = 1; }
class Normalizer<code normalizer> { code Normalizer = normalizer; }
class Denormalizer<code denormalizer> { code Denormalizer = denormalizer; }
@ -177,6 +185,8 @@ class AutoNormalizeEnum {
code Normalizer = "normalizeSimpleEnum";
code Denormalizer = "denormalizeSimpleEnum";
}
class ValueMerger<code merger> { code ValueMerger = merger; }
class ValueExtractor<code extractor> { code ValueExtractor = extractor; }
// Predefined options.

View File

@ -15,33 +15,33 @@ struct OptionWithMarshallingInfo {
};
static const OptionWithMarshallingInfo MarshallingTable[] = {
#define OPTION_WITH_MARSHALLING_FLAG(PREFIX_TYPE, NAME, ID, KIND, GROUP, \
ALIAS, ALIASARGS, FLAGS, PARAM, HELPTEXT, \
METAVAR, VALUES, SPELLING, ALWAYS_EMIT, \
KEYPATH, DEFAULT_VALUE, IS_POSITIVE) \
{ NAME, #KEYPATH, #DEFAULT_VALUE },
#define OPTION_WITH_MARSHALLING( \
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) \
{NAME, #KEYPATH, #DEFAULT_VALUE},
#include "Opts.inc"
#undef OPTION_WITH_MARSHALLING_FLAG
#undef OPTION_WITH_MARSHALLING
};
TEST(OptionMarshalling, EmittedOrderSameAsDefinitionOrder) {
ASSERT_STREQ(MarshallingTable[0].Name, "marshalled-flag-0");
ASSERT_STREQ(MarshallingTable[1].Name, "marshalled-flag-1");
ASSERT_STREQ(MarshallingTable[2].Name, "marshalled-flag-2");
ASSERT_STREQ(MarshallingTable[3].Name, "marshalled-flag-3");
ASSERT_STREQ(MarshallingTable[0].Name, "marshalled-flag-d");
ASSERT_STREQ(MarshallingTable[1].Name, "marshalled-flag-c");
ASSERT_STREQ(MarshallingTable[2].Name, "marshalled-flag-b");
ASSERT_STREQ(MarshallingTable[3].Name, "marshalled-flag-a");
}
TEST(OptionMarshalling, EmittedSpecifiedKeyPath) {
ASSERT_STREQ(MarshallingTable[0].KeyPath, "MarshalledFlag0");
ASSERT_STREQ(MarshallingTable[1].KeyPath, "MarshalledFlag1");
ASSERT_STREQ(MarshallingTable[2].KeyPath, "MarshalledFlag2");
ASSERT_STREQ(MarshallingTable[3].KeyPath, "MarshalledFlag3");
ASSERT_STREQ(MarshallingTable[0].KeyPath, "MarshalledFlagD");
ASSERT_STREQ(MarshallingTable[1].KeyPath, "MarshalledFlagC");
ASSERT_STREQ(MarshallingTable[2].KeyPath, "MarshalledFlagB");
ASSERT_STREQ(MarshallingTable[3].KeyPath, "MarshalledFlagA");
}
TEST(OptionMarshalling, DefaultAnyOfConstructedDisjunctionOfKeypaths) {
ASSERT_STREQ(MarshallingTable[0].DefaultValue, "false");
ASSERT_STREQ(MarshallingTable[1].DefaultValue, "false || MarshalledFlag0");
ASSERT_STREQ(MarshallingTable[2].DefaultValue, "false || MarshalledFlag0");
ASSERT_STREQ(MarshallingTable[1].DefaultValue, "false || MarshalledFlagD");
ASSERT_STREQ(MarshallingTable[2].DefaultValue, "false || MarshalledFlagD");
ASSERT_STREQ(MarshallingTable[3].DefaultValue,
"false || MarshalledFlag1 || MarshalledFlag2");
"false || MarshalledFlagC || MarshalledFlagB");
}

View File

@ -45,11 +45,11 @@ def Blurmpq_eq : Flag<["--"], "blurmp=">;
def DashDash : Option<["--"], "", KIND_REMAINING_ARGS>;
def marshalled_flag_0 : Flag<["-"], "marshalled-flag-0">,
MarshallingInfoFlag<"MarshalledFlag0", DefaultAnyOf<[]>>;
def marshalled_flag_1 : Flag<["-"], "marshalled-flag-1">,
MarshallingInfoFlag<"MarshalledFlag1", DefaultAnyOf<[marshalled_flag_0]>>;
def marshalled_flag_2 : Flag<["-"], "marshalled-flag-2">,
MarshallingInfoFlag<"MarshalledFlag2", DefaultAnyOf<[marshalled_flag_0]>>;
def marshalled_flag_3 : Flag<["-"], "marshalled-flag-3">,
MarshallingInfoFlag<"MarshalledFlag3", DefaultAnyOf<[marshalled_flag_1, marshalled_flag_2]>>;
def marshalled_flag_d : Flag<["-"], "marshalled-flag-d">,
MarshallingInfoFlag<"MarshalledFlagD", DefaultAnyOf<[]>>;
def marshalled_flag_c : Flag<["-"], "marshalled-flag-c">,
MarshallingInfoFlag<"MarshalledFlagC", DefaultAnyOf<[marshalled_flag_d]>>;
def marshalled_flag_b : Flag<["-"], "marshalled-flag-b">,
MarshallingInfoFlag<"MarshalledFlagB", DefaultAnyOf<[marshalled_flag_d]>>;
def marshalled_flag_a : Flag<["-"], "marshalled-flag-a">,
MarshallingInfoFlag<"MarshalledFlagA", DefaultAnyOf<[marshalled_flag_c, marshalled_flag_b]>>;

View File

@ -61,74 +61,20 @@ static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
OS << "[" << PrefixLength << "]";
}
class MarshallingKindInfo {
class MarshallingInfo {
public:
static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
const Record &R;
const char *MacroName;
bool ShouldAlwaysEmit;
StringRef KeyPath;
StringRef DefaultValue;
StringRef NormalizedValuesScope;
void emit(raw_ostream &OS) const {
write_cstring(OS, StringRef(getOptionSpelling(R)));
OS << ", ";
OS << ShouldAlwaysEmit;
OS << ", ";
OS << KeyPath;
OS << ", ";
emitScopedNormalizedValue(OS, DefaultValue);
OS << ", ";
emitSpecific(OS);
}
virtual Optional<StringRef> emitValueTable(raw_ostream &OS) const {
return None;
}
virtual ~MarshallingKindInfo() = default;
static std::unique_ptr<MarshallingKindInfo> create(const Record &R);
protected:
void emitScopedNormalizedValue(raw_ostream &OS,
StringRef NormalizedValue) const {
if (!NormalizedValuesScope.empty())
OS << NormalizedValuesScope << "::";
OS << NormalizedValue;
}
virtual void emitSpecific(raw_ostream &OS) const = 0;
MarshallingKindInfo(const Record &R, const char *MacroName)
: R(R), MacroName(MacroName) {}
};
class MarshallingFlagInfo final : public MarshallingKindInfo {
public:
bool IsPositive;
void emitSpecific(raw_ostream &OS) const override { OS << IsPositive; }
static std::unique_ptr<MarshallingKindInfo> create(const Record &R) {
std::unique_ptr<MarshallingFlagInfo> Ret(new MarshallingFlagInfo(R));
Ret->IsPositive = R.getValueAsBit("IsPositive");
// 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 std::unique_ptr<MarshallingKindInfo>(Ret.release());
}
private:
MarshallingFlagInfo(const Record &R)
: MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_FLAG") {}
};
class MarshallingStringInfo final : public MarshallingKindInfo {
public:
StringRef NormalizerRetTy;
StringRef Normalizer;
StringRef Denormalizer;
StringRef ValueMerger;
StringRef ValueExtractor;
int TableIndex = -1;
std::vector<StringRef> Values;
std::vector<StringRef> NormalizedValues;
@ -149,17 +95,29 @@ struct SimpleEnumValueTable {
static constexpr const char *ValueTablesDecl =
"static const SimpleEnumValueTable SimpleEnumValueTables[] = ";
void emitSpecific(raw_ostream &OS) const override {
void emit(raw_ostream &OS) const {
write_cstring(OS, StringRef(getOptionSpelling(R)));
OS << ", ";
OS << ShouldAlwaysEmit;
OS << ", ";
OS << KeyPath;
OS << ", ";
emitScopedNormalizedValue(OS, DefaultValue);
OS << ", ";
emitScopedNormalizedValue(OS, NormalizerRetTy);
OS << ", ";
OS << Normalizer;
OS << ", ";
OS << Denormalizer;
OS << ", ";
OS << ValueMerger;
OS << ", ";
OS << ValueExtractor;
OS << ", ";
OS << TableIndex;
}
Optional<StringRef> emitValueTable(raw_ostream &OS) const override {
Optional<StringRef> emitValueTable(raw_ostream &OS) const {
if (TableIndex == -1)
return {};
OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n";
@ -175,23 +133,32 @@ struct SimpleEnumValueTable {
return StringRef(ValueTableName);
}
static std::unique_ptr<MarshallingKindInfo> create(const Record &R) {
assert(!isa<UnsetInit>(R.getValueInit("NormalizerRetTy")) &&
"String options must have a type");
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");
std::unique_ptr<MarshallingStringInfo> Ret(new MarshallingStringInfo(R));
Ret->NormalizerRetTy = R.getValueAsString("NormalizerRetTy");
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.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";
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 (;;) {
@ -199,55 +166,34 @@ struct SimpleEnumValueTable {
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 std::unique_ptr<MarshallingKindInfo>(Ret.release());
return Ret;
}
private:
MarshallingStringInfo(const Record &R)
: MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_STRING") {}
void emitScopedNormalizedValue(raw_ostream &OS,
StringRef NormalizedValue) const {
if (!NormalizedValuesScope.empty())
OS << NormalizedValuesScope << "::";
OS << NormalizedValue;
}
MarshallingInfo(const Record &R) : R(R){};
static size_t NextTableIndex;
};
size_t MarshallingStringInfo::NextTableIndex = 0;
std::unique_ptr<MarshallingKindInfo>
MarshallingKindInfo::create(const Record &R) {
assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
!isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
"Must provide at least a key-path and a default value for emitting "
"marshalling information");
std::unique_ptr<MarshallingKindInfo> Ret = nullptr;
StringRef MarshallingKindStr = R.getValueAsString("MarshallingKind");
if (MarshallingKindStr == "flag")
Ret = MarshallingFlagInfo::create(R);
else if (MarshallingKindStr == "string")
Ret = MarshallingStringInfo::create(R);
Ret->ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
Ret->KeyPath = R.getValueAsString("KeyPath");
Ret->DefaultValue = R.getValueAsString("DefaultValue");
if (!isa<UnsetInit>(R.getValueInit("NormalizedValuesScope")))
Ret->NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
return Ret;
}
size_t MarshallingInfo::NextTableIndex = 0;
/// OptParserEmitter - This tablegen backend takes an input .td file
/// describing a list of options and emits a data structure for parsing and
@ -438,7 +384,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
};
auto IsMarshallingOption = [](const Record &R) {
return !isa<UnsetInit>(R.getValueInit("MarshallingKind")) &&
return !isa<UnsetInit>(R.getValueInit("KeyPath")) &&
!R.getValueAsString("KeyPath").empty();
};
@ -472,30 +418,30 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
CmpMarshallingOpts);
std::vector<std::unique_ptr<MarshallingKindInfo>> MarshallingKindInfos;
std::vector<MarshallingInfo> MarshallingInfos;
for (const auto *R : OptsWithMarshalling)
MarshallingKindInfos.push_back(MarshallingKindInfo::create(*R));
MarshallingInfos.push_back(MarshallingInfo::create(*R));
for (const auto &KindInfo : MarshallingKindInfos) {
OS << "#ifdef " << KindInfo->MacroName << "\n";
OS << KindInfo->MacroName << "(";
WriteOptRecordFields(OS, KindInfo->R);
for (const auto &MI : MarshallingInfos) {
OS << "#ifdef " << MI.MacroName << "\n";
OS << MI.MacroName << "(";
WriteOptRecordFields(OS, MI.R);
OS << ", ";
KindInfo->emit(OS);
MI.emit(OS);
OS << ")\n";
OS << "#endif // " << KindInfo->MacroName << "\n";
OS << "#endif // " << MI.MacroName << "\n";
}
OS << "\n";
OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE";
OS << "\n";
OS << MarshallingStringInfo::ValueTablePreamble;
OS << MarshallingInfo::ValueTablePreamble;
std::vector<StringRef> ValueTableNames;
for (const auto &KindInfo : MarshallingKindInfos)
if (auto MaybeValueTableName = KindInfo->emitValueTable(OS))
for (const auto &MI : MarshallingInfos)
if (auto MaybeValueTableName = MI.emitValueTable(OS))
ValueTableNames.push_back(*MaybeValueTableName);
OS << MarshallingStringInfo::ValueTablesDecl << "{";
OS << MarshallingInfo::ValueTablesDecl << "{";
for (auto ValueTableName : ValueTableNames)
OS << "{" << ValueTableName << ", sizeof(" << ValueTableName
<< ") / sizeof(SimpleEnumValue)"