//===- DirectiveEmitter.h - Directive Language Emitter ----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // DirectiveEmitter uses the descriptions of directives and clauses to construct // common code declarations to be used in Frontends. // //===----------------------------------------------------------------------===// #ifndef LLVM_TABLEGEN_DIRECTIVEEMITTER_H #define LLVM_TABLEGEN_DIRECTIVEEMITTER_H #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Frontend/Directive/Spelling.h" #include "llvm/Support/MathExtras.h" #include "llvm/TableGen/Record.h" #include #include namespace llvm { // Wrapper class that contains DirectiveLanguage's information defined in // DirectiveBase.td and provides helper methods for accessing it. class DirectiveLanguage { public: explicit DirectiveLanguage(const RecordKeeper &Records) : Records(Records) { const auto &DirectiveLanguages = getDirectiveLanguages(); Def = DirectiveLanguages[0]; } StringRef getName() const { return Def->getValueAsString("name"); } StringRef getCppNamespace() const { return Def->getValueAsString("cppNamespace"); } StringRef getDirectivePrefix() const { return Def->getValueAsString("directivePrefix"); } StringRef getClausePrefix() const { return Def->getValueAsString("clausePrefix"); } StringRef getClauseEnumSetClass() const { return Def->getValueAsString("clauseEnumSetClass"); } StringRef getFlangClauseBaseClass() const { return Def->getValueAsString("flangClauseBaseClass"); } bool hasMakeEnumAvailableInNamespace() const { return Def->getValueAsBit("makeEnumAvailableInNamespace"); } bool hasEnableBitmaskEnumInNamespace() const { return Def->getValueAsBit("enableBitmaskEnumInNamespace"); } ArrayRef getAssociations() const { return Records.getAllDerivedDefinitions("Association"); } ArrayRef getCategories() const { return Records.getAllDerivedDefinitions("Category"); } ArrayRef getSourceLanguages() const { return Records.getAllDerivedDefinitions("SourceLanguage"); } ArrayRef getDirectives() const { return Records.getAllDerivedDefinitions("Directive"); } ArrayRef getClauses() const { return Records.getAllDerivedDefinitions("Clause"); } bool HasValidityErrors() const; private: const Record *Def; const RecordKeeper &Records; ArrayRef getDirectiveLanguages() const { return Records.getAllDerivedDefinitions("DirectiveLanguage"); } }; class Versioned { public: int getMinVersion(const Record *R) const { int64_t Min = R->getValueAsInt("minVersion"); assert(llvm::isInt(Min) && "Value out of range of 'int'"); return Min; } int getMaxVersion(const Record *R) const { int64_t Max = R->getValueAsInt("maxVersion"); assert(llvm::isInt(Max) && "Value out of range of 'int'"); return Max; } private: constexpr static int IntWidth = 8 * sizeof(int); }; class Spelling : public Versioned { public: using Value = directive::Spelling; Spelling(const Record *Def) : Def(Def) {} StringRef getText() const { return Def->getValueAsString("spelling"); } llvm::directive::VersionRange getVersions() const { return llvm::directive::VersionRange{getMinVersion(Def), getMaxVersion(Def)}; } Value get() const { return Value{getText(), getVersions()}; } private: const Record *Def; }; // Note: In all the classes below, allow implicit construction from Record *, // to allow writing code like: // for (const Directive D : getDirectives()) { // // instead of: // // for (const Record *R : getDirectives()) { // Directive D(R); // Base record class used for Directive and Clause class defined in // DirectiveBase.td. class BaseRecord { public: BaseRecord(const Record *Def) : Def(Def) {} std::vector getSpellings() const { std::vector List; llvm::transform(Def->getValueAsListOfDefs("spellings"), std::back_inserter(List), [](const Record *R) { return Spelling(R).get(); }); return List; } StringRef getSpellingForIdentifier() const { // From all spellings, pick the first one with the minimum version // (i.e. pick the first from all the oldest ones). This guarantees // that given several equivalent (in terms of versions) names, the // first one is used, e.g. given // Clause<[Spelling<"foo">, Spelling<"bar">]> ... // "foo" will be the selected spelling. // // This is a suitable spelling for generating an identifier name, // since it will remain unchanged when any potential new spellings // are added. Spelling::Value Oldest{"not found", {/*Min=*/INT_MAX, 0}}; for (auto V : getSpellings()) if (V.Versions.Min < Oldest.Versions.Min) Oldest = V; return Oldest.Name; } // Returns the name of the directive formatted for output. Whitespace are // replaced with underscores. static std::string getSnakeName(StringRef Name) { std::string N = Name.str(); llvm::replace(N, ' ', '_'); return N; } // Take a string Name with sub-words separated with characters from Sep, // and return a string with each of the sub-words capitalized, and the // separators removed, e.g. // Name = "some_directive^name", Sep = "_^" -> "SomeDirectiveName". static std::string getUpperCamelName(StringRef Name, StringRef Sep) { std::string Camel = Name.str(); // Convert to uppercase bool Cap = true; llvm::transform(Camel, Camel.begin(), [&](unsigned char C) { if (Sep.contains(C)) { assert(!Cap && "No initial or repeated separators"); Cap = true; } else if (Cap) { C = llvm::toUpper(C); Cap = false; } return C; }); size_t Out = 0; // Remove separators for (size_t In = 0, End = Camel.size(); In != End; ++In) { unsigned char C = Camel[In]; if (!Sep.contains(C)) Camel[Out++] = C; } Camel.resize(Out); return Camel; } std::string getFormattedName() const { if (auto maybeName = Def->getValueAsOptionalString("name")) return getSnakeName(*maybeName); return getSnakeName(getSpellingForIdentifier()); } bool isDefault() const { return Def->getValueAsBit("isDefault"); } // Returns the record name. StringRef getRecordName() const { return Def->getName(); } const Record *getRecord() const { return Def; } protected: const Record *Def; }; // Wrapper class that contains a Directive's information defined in // DirectiveBase.td and provides helper methods for accessing it. class Directive : public BaseRecord { public: Directive(const Record *Def) : BaseRecord(Def) {} std::vector getAllowedClauses() const { return Def->getValueAsListOfDefs("allowedClauses"); } std::vector getAllowedOnceClauses() const { return Def->getValueAsListOfDefs("allowedOnceClauses"); } std::vector getAllowedExclusiveClauses() const { return Def->getValueAsListOfDefs("allowedExclusiveClauses"); } std::vector getRequiredClauses() const { return Def->getValueAsListOfDefs("requiredClauses"); } std::vector getLeafConstructs() const { return Def->getValueAsListOfDefs("leafConstructs"); } const Record *getAssociation() const { return Def->getValueAsDef("association"); } const Record *getCategory() const { return Def->getValueAsDef("category"); } std::vector getSourceLanguages() const { return Def->getValueAsListOfDefs("languages"); } // Clang uses a different format for names of its directives enum. std::string getClangAccSpelling() const { StringRef Name = getSpellingForIdentifier(); // Clang calls the 'unknown' value 'invalid'. if (Name == "unknown") return "Invalid"; return BaseRecord::getUpperCamelName(Name, " _"); } }; // Wrapper class that contains Clause's information defined in DirectiveBase.td // and provides helper methods for accessing it. class Clause : public BaseRecord { public: Clause(const Record *Def) : BaseRecord(Def) {} // Optional field. StringRef getClangClass() const { return Def->getValueAsString("clangClass"); } // Optional field. StringRef getFlangClass() const { return Def->getValueAsString("flangClass"); } // Get the formatted name for Flang parser class. The generic formatted class // name is constructed from the name were the first letter of each word is // captitalized and the underscores are removed. // ex: async -> Async // num_threads -> NumThreads std::string getFormattedParserClassName() const { StringRef Name = getSpellingForIdentifier(); return BaseRecord::getUpperCamelName(Name, "_"); } // Clang uses a different format for names of its clause enum, which can be // overwritten with the `clangSpelling` value. So get the proper spelling // here. std::string getClangAccSpelling() const { if (StringRef ClangSpelling = Def->getValueAsString("clangAccSpelling"); !ClangSpelling.empty()) return ClangSpelling.str(); StringRef Name = getSpellingForIdentifier(); return BaseRecord::getUpperCamelName(Name, "_"); } // Optional field. StringRef getEnumName() const { return Def->getValueAsString("enumClauseValue"); } std::vector getClauseVals() const { return Def->getValueAsListOfDefs("allowedClauseValues"); } bool skipFlangUnparser() const { return Def->getValueAsBit("skipFlangUnparser"); } bool isValueOptional() const { return Def->getValueAsBit("isValueOptional"); } bool isValueList() const { return Def->getValueAsBit("isValueList"); } StringRef getDefaultValue() const { return Def->getValueAsString("defaultValue"); } bool isImplicit() const { return Def->getValueAsBit("isImplicit"); } std::vector getAliases() const { return Def->getValueAsListOfStrings("aliases"); } StringRef getPrefix() const { return Def->getValueAsString("prefix"); } bool isPrefixOptional() const { return Def->getValueAsBit("isPrefixOptional"); } }; // Wrapper class that contains VersionedClause's information defined in // DirectiveBase.td and provides helper methods for accessing it. class VersionedClause { public: VersionedClause(const Record *Def) : Def(Def) {} // Return the specific clause record wrapped in the Clause class. Clause getClause() const { return Clause(Def->getValueAsDef("clause")); } int64_t getMinVersion() const { return Def->getValueAsInt("minVersion"); } int64_t getMaxVersion() const { return Def->getValueAsInt("maxVersion"); } private: const Record *Def; }; class EnumVal : public BaseRecord { public: EnumVal(const Record *Def) : BaseRecord(Def) {} int getValue() const { return Def->getValueAsInt("value"); } bool isUserVisible() const { return Def->getValueAsBit("isUserValue"); } }; } // namespace llvm #endif // LLVM_TABLEGEN_DIRECTIVEEMITTER_H