diff options
Diffstat (limited to 'llvm/utils/TableGen/OptParserEmitter.cpp')
-rw-r--r-- | llvm/utils/TableGen/OptParserEmitter.cpp | 269 |
1 files changed, 256 insertions, 13 deletions
diff --git a/llvm/utils/TableGen/OptParserEmitter.cpp b/llvm/utils/TableGen/OptParserEmitter.cpp index c1978ac7ac66..251533a8d154 100644 --- a/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/llvm/utils/TableGen/OptParserEmitter.cpp @@ -10,20 +10,22 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" #include <cctype> #include <cstring> #include <map> +#include <memory> using namespace llvm; static const std::string getOptionName(const Record &R) { // Use the record name unless EnumName is defined. if (isa<UnsetInit>(R.getValueInit("EnumName"))) - return R.getName(); + return std::string(R.getName()); - return R.getValueAsString("EnumName"); + return std::string(R.getValueAsString("EnumName")); } static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { @@ -33,6 +35,210 @@ static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { return OS; } +static const std::string getOptionSpelling(const Record &R, + size_t &PrefixLength) { + std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes"); + StringRef Name = R.getValueAsString("Name"); + if (Prefixes.empty()) { + PrefixLength = 0; + return Name.str(); + } + PrefixLength = Prefixes[0].size(); + return (Twine(Prefixes[0]) + Twine(Name)).str(); +} + +static const 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 << "&"; + write_cstring(OS, StringRef(getOptionSpelling(R, PrefixLength))); + OS << "[" << PrefixLength << "]"; +} + +class MarshallingKindInfo { +public: + 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"); + return Ret; + } + +private: + MarshallingFlagInfo(const Record &R) + : MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_FLAG") {} +}; + +class MarshallingStringInfo final : public MarshallingKindInfo { +public: + StringRef NormalizerRetTy; + StringRef Normalizer; + StringRef Denormalizer; + int TableIndex = -1; + std::vector<StringRef> Values; + std::vector<StringRef> NormalizedValues; + std::string ValueTableName; + + static constexpr const char *ValueTablePreamble = R"( +struct SimpleEnumValue { + const char *Name; + unsigned Value; +}; + +struct SimpleEnumValueTable { + const SimpleEnumValue *Table; + unsigned Size; +}; +)"; + + static constexpr const char *ValueTablesDecl = + "static const SimpleEnumValueTable SimpleEnumValueTables[] = "; + + void emitSpecific(raw_ostream &OS) const override { + emitScopedNormalizedValue(OS, NormalizerRetTy); + OS << ", "; + OS << Normalizer; + OS << ", "; + OS << Denormalizer; + OS << ", "; + OS << TableIndex; + } + + Optional<StringRef> emitValueTable(raw_ostream &OS) const override { + if (TableIndex == -1) + return {}; + OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n"; + for (unsigned I = 0, E = Values.size(); I != E; ++I) { + OS << "{"; + write_cstring(OS, Values[I]); + OS << ","; + OS << "static_cast<unsigned>("; + emitScopedNormalizedValue(OS, NormalizedValues[I]); + OS << ")},"; + } + OS << "};\n"; + return StringRef(ValueTableName); + } + + static std::unique_ptr<MarshallingKindInfo> create(const Record &R) { + assert(!isa<UnsetInit>(R.getValueInit("NormalizerRetTy")) && + "String options must have a type"); + + std::unique_ptr<MarshallingStringInfo> Ret(new MarshallingStringInfo(R)); + Ret->NormalizerRetTy = R.getValueAsString("NormalizerRetTy"); + + Ret->Normalizer = R.getValueAsString("Normalizer"); + Ret->Denormalizer = R.getValueAsString("Denormalizer"); + + 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: + MarshallingStringInfo(const Record &R) + : MarshallingKindInfo(R, "OPTION_WITH_MARSHALLING_STRING") {} + + 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; +} + /// OptParserEmitter - This tablegen backend takes an input .td file /// describing a list of options and emits a data structure for parsing and /// working with those options when given an input command line. @@ -102,7 +308,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << ", \"" << R.getValueAsString("Name") << '"'; // The option identifier name. - OS << ", "<< getOptionName(R); + OS << ", " << getOptionName(R); // The option kind. OS << ", Group"; @@ -135,21 +341,17 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "//////////\n"; OS << "// Options\n\n"; - for (unsigned i = 0, e = Opts.size(); i != e; ++i) { - const Record &R = *Opts[i]; - - // Start a single option entry. - OS << "OPTION("; + auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) { // The option prefix; std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; // The option string. - write_cstring(OS, R.getValueAsString("Name")); + emitNameUsingSpelling(OS, R); // The option identifier name. - OS << ", "<< getOptionName(R); + OS << ", " << getOptionName(R); // The option kind. OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); @@ -190,8 +392,7 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { int NumFlags = 0; const ListInit *LI = R.getValueAsListInit("Flags"); for (Init *I : *LI) - OS << (NumFlags++ ? " | " : "") - << cast<DefInit>(I)->getDef()->getName(); + OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName(); if (GroupFlags) { for (Init *I : *GroupFlags) OS << (NumFlags++ ? " | " : "") @@ -224,11 +425,52 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { write_cstring(OS, R.getValueAsString("Values")); else OS << "nullptr"; + }; + + std::vector<std::unique_ptr<MarshallingKindInfo>> OptsWithMarshalling; + for (unsigned I = 0, E = Opts.size(); I != E; ++I) { + const Record &R = *Opts[I]; + // Start a single option entry. + OS << "OPTION("; + WriteOptRecordFields(OS, R); OS << ")\n"; + if (!isa<UnsetInit>(R.getValueInit("MarshallingKind"))) + OptsWithMarshalling.push_back(MarshallingKindInfo::create(R)); } OS << "#endif // OPTION\n"; + for (const auto &KindInfo : OptsWithMarshalling) { + OS << "#ifdef " << KindInfo->MacroName << "\n"; + OS << KindInfo->MacroName << "("; + WriteOptRecordFields(OS, KindInfo->R); + OS << ", "; + KindInfo->emit(OS); + OS << ")\n"; + OS << "#endif // " << KindInfo->MacroName << "\n"; + } + + OS << "\n"; + OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE"; + OS << "\n"; + OS << MarshallingStringInfo::ValueTablePreamble; + std::vector<StringRef> ValueTableNames; + for (const auto &KindInfo : OptsWithMarshalling) + if (auto MaybeValueTableName = KindInfo->emitValueTable(OS)) + ValueTableNames.push_back(*MaybeValueTableName); + + OS << MarshallingStringInfo::ValueTablesDecl << "{"; + for (auto ValueTableName : ValueTableNames) + OS << "{" << ValueTableName << ", sizeof(" << ValueTableName + << ") / sizeof(SimpleEnumValue)" + << "},\n"; + OS << "};\n"; + OS << "static const unsigned SimpleEnumValueTablesSize = " + "sizeof(SimpleEnumValueTables) / sizeof(SimpleEnumValueTable);\n"; + + OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n"; + OS << "\n"; + OS << "\n"; OS << "#ifdef OPTTABLE_ARG_INIT\n"; OS << "//////////\n"; @@ -241,8 +483,9 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << "bool ValuesWereAdded;\n"; OS << R.getValueAsString("ValuesCode"); OS << "\n"; - for (std::string S : R.getValueAsListOfStrings("Prefixes")) { + for (StringRef Prefix : R.getValueAsListOfStrings("Prefixes")) { OS << "ValuesWereAdded = Opt.addValues("; + std::string S(Prefix); S += R.getValueAsString("Name"); write_cstring(OS, S); OS << ", Values);\n"; |