1 //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===// 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 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/TableGen/Error.h" 18 #include "llvm/TableGen/Record.h" 19 #include "llvm/TableGen/TableGenBackend.h" 20 21 namespace llvm { 22 void EmitDirectivesEnums(RecordKeeper &Records, raw_ostream &OS) { 23 24 const auto &DirectiveLanguages = 25 Records.getAllDerivedDefinitions("DirectiveLanguage"); 26 27 if (DirectiveLanguages.size() != 1) { 28 PrintError("A single definition of DirectiveLanguage is needed."); 29 return; 30 } 31 32 const auto &DirectiveLanguage = DirectiveLanguages[0]; 33 StringRef languageName = DirectiveLanguage->getValueAsString("name"); 34 StringRef DirectivePrefix = 35 DirectiveLanguage->getValueAsString("directivePrefix"); 36 StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); 37 StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); 38 bool MakeEnumAvailableInNamespace = 39 DirectiveLanguage->getValueAsBit("makeEnumAvailableInNamespace"); 40 bool EnableBitmaskEnumInNamespace = 41 DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace"); 42 43 OS << "#ifndef LLVM_" << languageName << "_INC\n"; 44 OS << "#define LLVM_" << languageName << "_INC\n"; 45 46 if (EnableBitmaskEnumInNamespace) 47 OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; 48 49 OS << "namespace llvm {\n"; 50 51 // Open namespaces defined in the directive language 52 llvm::SmallVector<StringRef, 2> Namespaces; 53 llvm::SplitString(CppNamespace, Namespaces, "::"); 54 for (auto Ns : Namespaces) 55 OS << "namespace " << Ns << " {\n"; 56 57 if (EnableBitmaskEnumInNamespace) 58 OS << "LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 59 60 // Emit Directive enumeration 61 OS << "enum class Directive {\n"; 62 const auto &Directives = Records.getAllDerivedDefinitions("Directive"); 63 for (const auto &D : Directives) { 64 const auto Name = D->getValueAsString("name"); 65 std::string N = Name.str(); 66 std::replace(N.begin(), N.end(), ' ', '_'); 67 OS << DirectivePrefix << N << ",\n"; 68 } 69 OS << "};\n"; 70 71 OS << "static constexpr std::size_t Directive_enumSize = " 72 << Directives.size() << ";\n"; 73 74 // Emit Clause enumeration 75 OS << "enum class Clause {\n"; 76 const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); 77 for (const auto &C : Clauses) { 78 const auto Name = C->getValueAsString("name"); 79 OS << ClausePrefix << Name << ",\n"; 80 } 81 OS << "};\n"; 82 83 OS << "static constexpr std::size_t Clause_enumSize = " << Clauses.size() 84 << ";\n"; 85 86 // Make the enum values available in the defined namespace. This allows us to 87 // write something like Enum_X if we have a `using namespace <CppNamespace>`. 88 // At the same time we do not loose the strong type guarantees of the enum 89 // class, that is we cannot pass an unsigned as Directive without an explicit 90 // cast. 91 if (MakeEnumAvailableInNamespace) { 92 for (const auto &D : Directives) { 93 const auto Name = D->getValueAsString("name"); 94 std::string N = Name.str(); 95 std::replace(N.begin(), N.end(), ' ', '_'); 96 OS << "constexpr auto " << DirectivePrefix << N << " = " << CppNamespace 97 << "::Directive::" << DirectivePrefix << N << ";\n"; 98 } 99 100 for (const auto &C : Clauses) { 101 const auto Name = C->getValueAsString("name"); 102 OS << "constexpr auto " << ClausePrefix << Name << " = " << CppNamespace 103 << "::Clause::" << ClausePrefix << Name << ";\n"; 104 } 105 } 106 107 // Closing namespaces 108 for (auto Ns : llvm::reverse(Namespaces)) 109 OS << "} // namespace " << Ns << "\n"; 110 111 OS << "} // namespace llvm\n"; 112 113 OS << "#endif"; 114 } 115 } // namespace llvm 116