1 //===========- DirectiveCommonGen.cpp - Directive common info generator -=====// 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 // OpenMPCommonGen generates utility information from the single OpenMP source 10 // of truth in llvm/lib/Frontend/OpenMP. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "mlir/TableGen/GenInfo.h" 15 16 #include "llvm/ADT/Twine.h" 17 #include "llvm/Support/CommandLine.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include "llvm/TableGen/DirectiveEmitter.h" 20 #include "llvm/TableGen/Error.h" 21 #include "llvm/TableGen/Record.h" 22 23 using llvm::Clause; 24 using llvm::ClauseVal; 25 using llvm::raw_ostream; 26 using llvm::Record; 27 using llvm::RecordKeeper; 28 29 // LLVM has multiple places (Clang, Flang, MLIR) where information about 30 // the directives (OpenMP/OpenACC), and clauses are needed. It is good software 31 // engineering to keep the common information in a single place to avoid 32 // duplication, reduce engineering effort and prevent mistakes. 33 // Currently that common place is llvm/include/llvm/Frontend/OpenMP/OMP.td for 34 // OpenMP and llvm/include/llvm/Frontend/OpenACC/ACC.td for OpenACC. 35 // We plan to use this tablegen source to generate all the required 36 // declarations, functions etc. 37 // 38 // Some OpenMP/OpenACC clauses accept only a fixed set of values as inputs. 39 // These can be represented as a Enum Attributes (EnumAttrDef) in MLIR 40 // ODS. The emitDecls function below currently generates these enumerations. The 41 // name of the enumeration is specified in the enumClauseValue field of 42 // Clause record in OMP.td. This name can be used to specify the type of the 43 // OpenMP operation's operand. The allowedClauseValues field provides the list 44 // of ClauseValues which are part of the enumeration. 45 static bool emitDecls(const RecordKeeper &records, llvm::StringRef dialect, 46 raw_ostream &os) { 47 // A dialect must be selected for the generated attributes. 48 if (dialect.empty()) { 49 llvm::PrintFatalError("a dialect must be selected for the directives via " 50 "'--directives-dialect'"); 51 } 52 53 const auto directiveLanguages = 54 records.getAllDerivedDefinitions("DirectiveLanguage"); 55 assert(!directiveLanguages.empty() && "DirectiveLanguage missing."); 56 57 for (const Clause c : records.getAllDerivedDefinitions("Clause")) { 58 const auto &clauseVals = c.getClauseVals(); 59 if (clauseVals.empty()) 60 continue; 61 62 const auto enumName = c.getEnumName(); 63 assert(!enumName.empty() && "enumClauseValue field not set."); 64 65 std::vector<std::string> cvDefs; 66 for (const auto &it : llvm::enumerate(clauseVals)) { 67 const ClauseVal cval{it.value()}; 68 if (!cval.isUserVisible()) 69 continue; 70 71 std::string name = cval.getFormattedName(); 72 std::string enumValName(name.length(), ' '); 73 llvm::transform(name, enumValName.begin(), llvm::toLower); 74 enumValName[0] = llvm::toUpper(enumValName[0]); 75 std::string cvDef{(enumName + llvm::Twine(name)).str()}; 76 os << "def " << cvDef << " : I32EnumAttrCase<\"" << enumValName << "\", " 77 << it.index() << ", \"" << name << "\">;\n"; 78 cvDefs.push_back(cvDef); 79 } 80 81 os << "def " << enumName << ": I32EnumAttr<\n"; 82 os << " \"Clause" << enumName << "\",\n"; 83 os << " \"" << enumName << " Clause\",\n"; 84 os << " ["; 85 llvm::interleaveComma(cvDefs, os); 86 os << "]> {\n"; 87 os << " let cppNamespace = \"::mlir::" 88 << directiveLanguages[0]->getValueAsString("cppNamespace") << "\";\n"; 89 os << " let genSpecializedAttr = 0;\n"; 90 os << "}\n"; 91 llvm::SmallString<16> mnemonic; 92 llvm::transform(enumName, std::back_inserter(mnemonic), llvm::toLower); 93 os << "def " << enumName << "Attr : EnumAttr<" << dialect << "_Dialect, " 94 << enumName << ", \"" << mnemonic << "\">;\n"; 95 } 96 return false; 97 } 98 99 static llvm::cl::OptionCategory 100 directiveGenCat("Options for gen-directive-decl"); 101 static llvm::cl::opt<std::string> 102 dialect("directives-dialect", 103 llvm::cl::desc("Generate directives for this dialect"), 104 llvm::cl::cat(directiveGenCat), llvm::cl::CommaSeparated); 105 106 // Registers the generator to mlir-tblgen. 107 static mlir::GenRegistration genDirectiveDecls( 108 "gen-directive-decl", 109 "Generate declarations for directives (OpenMP/OpenACC etc.)", 110 [](const RecordKeeper &records, raw_ostream &os) { 111 return emitDecls(records, dialect, os); 112 }); 113