xref: /freebsd/contrib/llvm-project/llvm/include/llvm/TableGen/DirectiveEmitter.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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