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