1 //===- DirectiveEmitter.h - Directive Language Emitter ----------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // DirectiveEmitter uses the descriptions of directives and clauses to construct 10 // common code declarations to be used in Frontends. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_TABLEGEN_DIRECTIVEEMITTER_H 15 #define LLVM_TABLEGEN_DIRECTIVEEMITTER_H 16 17 #include "llvm/ADT/STLExtras.h" 18 #include "llvm/ADT/StringExtras.h" 19 #include "llvm/ADT/StringRef.h" 20 #include "llvm/Frontend/Directive/Spelling.h" 21 #include "llvm/Support/MathExtras.h" 22 #include "llvm/TableGen/Record.h" 23 #include <algorithm> 24 #include <string> 25 #include <vector> 26 27 namespace llvm { 28 29 // Wrapper class that contains DirectiveLanguage's information defined in 30 // DirectiveBase.td and provides helper methods for accessing it. 31 class DirectiveLanguage { 32 public: DirectiveLanguage(const RecordKeeper & Records)33 explicit DirectiveLanguage(const RecordKeeper &Records) : Records(Records) { 34 const auto &DirectiveLanguages = getDirectiveLanguages(); 35 Def = DirectiveLanguages[0]; 36 } 37 getName()38 StringRef getName() const { return Def->getValueAsString("name"); } 39 getCppNamespace()40 StringRef getCppNamespace() const { 41 return Def->getValueAsString("cppNamespace"); 42 } 43 getDirectivePrefix()44 StringRef getDirectivePrefix() const { 45 return Def->getValueAsString("directivePrefix"); 46 } 47 getClausePrefix()48 StringRef getClausePrefix() const { 49 return Def->getValueAsString("clausePrefix"); 50 } 51 getClauseEnumSetClass()52 StringRef getClauseEnumSetClass() const { 53 return Def->getValueAsString("clauseEnumSetClass"); 54 } 55 getFlangClauseBaseClass()56 StringRef getFlangClauseBaseClass() const { 57 return Def->getValueAsString("flangClauseBaseClass"); 58 } 59 hasMakeEnumAvailableInNamespace()60 bool hasMakeEnumAvailableInNamespace() const { 61 return Def->getValueAsBit("makeEnumAvailableInNamespace"); 62 } 63 hasEnableBitmaskEnumInNamespace()64 bool hasEnableBitmaskEnumInNamespace() const { 65 return Def->getValueAsBit("enableBitmaskEnumInNamespace"); 66 } 67 getAssociations()68 ArrayRef<const Record *> getAssociations() const { 69 return Records.getAllDerivedDefinitions("Association"); 70 } 71 getCategories()72 ArrayRef<const Record *> getCategories() const { 73 return Records.getAllDerivedDefinitions("Category"); 74 } 75 getSourceLanguages()76 ArrayRef<const Record *> getSourceLanguages() const { 77 return Records.getAllDerivedDefinitions("SourceLanguage"); 78 } 79 getDirectives()80 ArrayRef<const Record *> getDirectives() const { 81 return Records.getAllDerivedDefinitions("Directive"); 82 } 83 getClauses()84 ArrayRef<const Record *> getClauses() const { 85 return Records.getAllDerivedDefinitions("Clause"); 86 } 87 88 bool HasValidityErrors() const; 89 90 private: 91 const Record *Def; 92 const RecordKeeper &Records; 93 getDirectiveLanguages()94 ArrayRef<const Record *> getDirectiveLanguages() const { 95 return Records.getAllDerivedDefinitions("DirectiveLanguage"); 96 } 97 }; 98 99 class Versioned { 100 public: getMinVersion(const Record * R)101 int getMinVersion(const Record *R) const { 102 int64_t Min = R->getValueAsInt("minVersion"); 103 assert(llvm::isInt<IntWidth>(Min) && "Value out of range of 'int'"); 104 return Min; 105 } 106 getMaxVersion(const Record * R)107 int getMaxVersion(const Record *R) const { 108 int64_t Max = R->getValueAsInt("maxVersion"); 109 assert(llvm::isInt<IntWidth>(Max) && "Value out of range of 'int'"); 110 return Max; 111 } 112 113 private: 114 constexpr static int IntWidth = 8 * sizeof(int); 115 }; 116 117 class Spelling : public Versioned { 118 public: 119 using Value = directive::Spelling; 120 Spelling(const Record * Def)121 Spelling(const Record *Def) : Def(Def) {} 122 getText()123 StringRef getText() const { return Def->getValueAsString("spelling"); } getVersions()124 llvm::directive::VersionRange getVersions() const { 125 return llvm::directive::VersionRange{getMinVersion(Def), 126 getMaxVersion(Def)}; 127 } 128 get()129 Value get() const { return Value{getText(), getVersions()}; } 130 131 private: 132 const Record *Def; 133 }; 134 135 // Note: In all the classes below, allow implicit construction from Record *, 136 // to allow writing code like: 137 // for (const Directive D : getDirectives()) { 138 // 139 // instead of: 140 // 141 // for (const Record *R : getDirectives()) { 142 // Directive D(R); 143 144 // Base record class used for Directive and Clause class defined in 145 // DirectiveBase.td. 146 class BaseRecord { 147 public: BaseRecord(const Record * Def)148 BaseRecord(const Record *Def) : Def(Def) {} 149 getSpellings()150 std::vector<Spelling::Value> getSpellings() const { 151 std::vector<Spelling::Value> List; 152 llvm::transform(Def->getValueAsListOfDefs("spellings"), 153 std::back_inserter(List), 154 [](const Record *R) { return Spelling(R).get(); }); 155 return List; 156 } 157 getSpellingForIdentifier()158 StringRef getSpellingForIdentifier() const { 159 // From all spellings, pick the first one with the minimum version 160 // (i.e. pick the first from all the oldest ones). This guarantees 161 // that given several equivalent (in terms of versions) names, the 162 // first one is used, e.g. given 163 // Clause<[Spelling<"foo">, Spelling<"bar">]> ... 164 // "foo" will be the selected spelling. 165 // 166 // This is a suitable spelling for generating an identifier name, 167 // since it will remain unchanged when any potential new spellings 168 // are added. 169 Spelling::Value Oldest{"not found", {/*Min=*/INT_MAX, 0}}; 170 for (auto V : getSpellings()) 171 if (V.Versions.Min < Oldest.Versions.Min) 172 Oldest = V; 173 return Oldest.Name; 174 } 175 176 // Returns the name of the directive formatted for output. Whitespace are 177 // replaced with underscores. getSnakeName(StringRef Name)178 static std::string getSnakeName(StringRef Name) { 179 std::string N = Name.str(); 180 llvm::replace(N, ' ', '_'); 181 return N; 182 } 183 184 // Take a string Name with sub-words separated with characters from Sep, 185 // and return a string with each of the sub-words capitalized, and the 186 // separators removed, e.g. 187 // Name = "some_directive^name", Sep = "_^" -> "SomeDirectiveName". getUpperCamelName(StringRef Name,StringRef Sep)188 static std::string getUpperCamelName(StringRef Name, StringRef Sep) { 189 std::string Camel = Name.str(); 190 // Convert to uppercase 191 bool Cap = true; 192 llvm::transform(Camel, Camel.begin(), [&](unsigned char C) { 193 if (Sep.contains(C)) { 194 assert(!Cap && "No initial or repeated separators"); 195 Cap = true; 196 } else if (Cap) { 197 C = llvm::toUpper(C); 198 Cap = false; 199 } 200 return C; 201 }); 202 size_t Out = 0; 203 // Remove separators 204 for (size_t In = 0, End = Camel.size(); In != End; ++In) { 205 unsigned char C = Camel[In]; 206 if (!Sep.contains(C)) 207 Camel[Out++] = C; 208 } 209 Camel.resize(Out); 210 return Camel; 211 } 212 getFormattedName()213 std::string getFormattedName() const { 214 if (auto maybeName = Def->getValueAsOptionalString("name")) 215 return getSnakeName(*maybeName); 216 return getSnakeName(getSpellingForIdentifier()); 217 } 218 isDefault()219 bool isDefault() const { return Def->getValueAsBit("isDefault"); } 220 221 // Returns the record name. getRecordName()222 StringRef getRecordName() const { return Def->getName(); } 223 getRecord()224 const Record *getRecord() const { return Def; } 225 226 protected: 227 const Record *Def; 228 }; 229 230 // Wrapper class that contains a Directive's information defined in 231 // DirectiveBase.td and provides helper methods for accessing it. 232 class Directive : public BaseRecord { 233 public: Directive(const Record * Def)234 Directive(const Record *Def) : BaseRecord(Def) {} 235 getAllowedClauses()236 std::vector<const Record *> getAllowedClauses() const { 237 return Def->getValueAsListOfDefs("allowedClauses"); 238 } 239 getAllowedOnceClauses()240 std::vector<const Record *> getAllowedOnceClauses() const { 241 return Def->getValueAsListOfDefs("allowedOnceClauses"); 242 } 243 getAllowedExclusiveClauses()244 std::vector<const Record *> getAllowedExclusiveClauses() const { 245 return Def->getValueAsListOfDefs("allowedExclusiveClauses"); 246 } 247 getRequiredClauses()248 std::vector<const Record *> getRequiredClauses() const { 249 return Def->getValueAsListOfDefs("requiredClauses"); 250 } 251 getLeafConstructs()252 std::vector<const Record *> getLeafConstructs() const { 253 return Def->getValueAsListOfDefs("leafConstructs"); 254 } 255 getAssociation()256 const Record *getAssociation() const { 257 return Def->getValueAsDef("association"); 258 } 259 getCategory()260 const Record *getCategory() const { return Def->getValueAsDef("category"); } 261 getSourceLanguages()262 std::vector<const Record *> getSourceLanguages() const { 263 return Def->getValueAsListOfDefs("languages"); 264 } 265 266 // Clang uses a different format for names of its directives enum. getClangAccSpelling()267 std::string getClangAccSpelling() const { 268 StringRef Name = getSpellingForIdentifier(); 269 270 // Clang calls the 'unknown' value 'invalid'. 271 if (Name == "unknown") 272 return "Invalid"; 273 274 return BaseRecord::getUpperCamelName(Name, " _"); 275 } 276 }; 277 278 // Wrapper class that contains Clause's information defined in DirectiveBase.td 279 // and provides helper methods for accessing it. 280 class Clause : public BaseRecord { 281 public: Clause(const Record * Def)282 Clause(const Record *Def) : BaseRecord(Def) {} 283 284 // Optional field. getClangClass()285 StringRef getClangClass() const { 286 return Def->getValueAsString("clangClass"); 287 } 288 289 // Optional field. getFlangClass()290 StringRef getFlangClass() const { 291 return Def->getValueAsString("flangClass"); 292 } 293 294 // Get the formatted name for Flang parser class. The generic formatted class 295 // name is constructed from the name were the first letter of each word is 296 // captitalized and the underscores are removed. 297 // ex: async -> Async 298 // num_threads -> NumThreads getFormattedParserClassName()299 std::string getFormattedParserClassName() const { 300 StringRef Name = getSpellingForIdentifier(); 301 return BaseRecord::getUpperCamelName(Name, "_"); 302 } 303 304 // Clang uses a different format for names of its clause enum, which can be 305 // overwritten with the `clangSpelling` value. So get the proper spelling 306 // here. getClangAccSpelling()307 std::string getClangAccSpelling() const { 308 if (StringRef ClangSpelling = Def->getValueAsString("clangAccSpelling"); 309 !ClangSpelling.empty()) 310 return ClangSpelling.str(); 311 312 StringRef Name = getSpellingForIdentifier(); 313 return BaseRecord::getUpperCamelName(Name, "_"); 314 } 315 316 // Optional field. getEnumName()317 StringRef getEnumName() const { 318 return Def->getValueAsString("enumClauseValue"); 319 } 320 getClauseVals()321 std::vector<const Record *> getClauseVals() const { 322 return Def->getValueAsListOfDefs("allowedClauseValues"); 323 } 324 skipFlangUnparser()325 bool skipFlangUnparser() const { 326 return Def->getValueAsBit("skipFlangUnparser"); 327 } 328 isValueOptional()329 bool isValueOptional() const { return Def->getValueAsBit("isValueOptional"); } 330 isValueList()331 bool isValueList() const { return Def->getValueAsBit("isValueList"); } 332 getDefaultValue()333 StringRef getDefaultValue() const { 334 return Def->getValueAsString("defaultValue"); 335 } 336 isImplicit()337 bool isImplicit() const { return Def->getValueAsBit("isImplicit"); } 338 getAliases()339 std::vector<StringRef> getAliases() const { 340 return Def->getValueAsListOfStrings("aliases"); 341 } 342 getPrefix()343 StringRef getPrefix() const { return Def->getValueAsString("prefix"); } 344 isPrefixOptional()345 bool isPrefixOptional() const { 346 return Def->getValueAsBit("isPrefixOptional"); 347 } 348 }; 349 350 // Wrapper class that contains VersionedClause's information defined in 351 // DirectiveBase.td and provides helper methods for accessing it. 352 class VersionedClause { 353 public: VersionedClause(const Record * Def)354 VersionedClause(const Record *Def) : Def(Def) {} 355 356 // Return the specific clause record wrapped in the Clause class. getClause()357 Clause getClause() const { return Clause(Def->getValueAsDef("clause")); } 358 getMinVersion()359 int64_t getMinVersion() const { return Def->getValueAsInt("minVersion"); } 360 getMaxVersion()361 int64_t getMaxVersion() const { return Def->getValueAsInt("maxVersion"); } 362 363 private: 364 const Record *Def; 365 }; 366 367 class EnumVal : public BaseRecord { 368 public: EnumVal(const Record * Def)369 EnumVal(const Record *Def) : BaseRecord(Def) {} 370 getValue()371 int getValue() const { return Def->getValueAsInt("value"); } 372 isUserVisible()373 bool isUserVisible() const { return Def->getValueAsBit("isUserValue"); } 374 }; 375 376 } // namespace llvm 377 378 #endif // LLVM_TABLEGEN_DIRECTIVEEMITTER_H 379