10bd9a136SValentin Clement //===========- DirectiveCommonGen.cpp - Directive common info generator -=====// 20bd9a136SValentin Clement // 30bd9a136SValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40bd9a136SValentin Clement // See https://llvm.org/LICENSE.txt for license information. 50bd9a136SValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60bd9a136SValentin Clement // 70bd9a136SValentin Clement //===----------------------------------------------------------------------===// 80bd9a136SValentin Clement // 90bd9a136SValentin Clement // OpenMPCommonGen generates utility information from the single OpenMP source 100bd9a136SValentin Clement // of truth in llvm/lib/Frontend/OpenMP. 110bd9a136SValentin Clement // 120bd9a136SValentin Clement //===----------------------------------------------------------------------===// 130bd9a136SValentin Clement 140bd9a136SValentin Clement #include "mlir/TableGen/GenInfo.h" 150bd9a136SValentin Clement 160bd9a136SValentin Clement #include "llvm/ADT/Twine.h" 17aae51255SMogball #include "llvm/Support/CommandLine.h" 180bd9a136SValentin Clement #include "llvm/Support/raw_ostream.h" 190bd9a136SValentin Clement #include "llvm/TableGen/DirectiveEmitter.h" 20aae51255SMogball #include "llvm/TableGen/Error.h" 210bd9a136SValentin Clement #include "llvm/TableGen/Record.h" 220bd9a136SValentin Clement 230bd9a136SValentin Clement using llvm::Clause; 240bd9a136SValentin Clement using llvm::ClauseVal; 250bd9a136SValentin Clement using llvm::raw_ostream; 26b60c6cbcSRahul Joshi using llvm::Record; 270bd9a136SValentin Clement using llvm::RecordKeeper; 280bd9a136SValentin Clement 290bd9a136SValentin Clement // LLVM has multiple places (Clang, Flang, MLIR) where information about 300bd9a136SValentin Clement // the directives (OpenMP/OpenACC), and clauses are needed. It is good software 310bd9a136SValentin Clement // engineering to keep the common information in a single place to avoid 320bd9a136SValentin Clement // duplication, reduce engineering effort and prevent mistakes. 330bd9a136SValentin Clement // Currently that common place is llvm/include/llvm/Frontend/OpenMP/OMP.td for 340bd9a136SValentin Clement // OpenMP and llvm/include/llvm/Frontend/OpenACC/ACC.td for OpenACC. 350bd9a136SValentin Clement // We plan to use this tablegen source to generate all the required 360bd9a136SValentin Clement // declarations, functions etc. 370bd9a136SValentin Clement // 380bd9a136SValentin Clement // Some OpenMP/OpenACC clauses accept only a fixed set of values as inputs. 3960e34f8dSMogball // These can be represented as a Enum Attributes (EnumAttrDef) in MLIR 400bd9a136SValentin Clement // ODS. The emitDecls function below currently generates these enumerations. The 410bd9a136SValentin Clement // name of the enumeration is specified in the enumClauseValue field of 420bd9a136SValentin Clement // Clause record in OMP.td. This name can be used to specify the type of the 430bd9a136SValentin Clement // OpenMP operation's operand. The allowedClauseValues field provides the list 440bd9a136SValentin Clement // of ClauseValues which are part of the enumeration. 45*e8137503SRahul Joshi static bool emitDecls(const RecordKeeper &records, llvm::StringRef dialect, 46aae51255SMogball raw_ostream &os) { 47aae51255SMogball // A dialect must be selected for the generated attributes. 48aae51255SMogball if (dialect.empty()) { 49aae51255SMogball llvm::PrintFatalError("a dialect must be selected for the directives via " 50aae51255SMogball "'--directives-dialect'"); 51aae51255SMogball } 52aae51255SMogball 53b60c6cbcSRahul Joshi const auto directiveLanguages = 54*e8137503SRahul Joshi records.getAllDerivedDefinitions("DirectiveLanguage"); 555a1f6077SMehdi Amini assert(!directiveLanguages.empty() && "DirectiveLanguage missing."); 560bd9a136SValentin Clement 57*e8137503SRahul Joshi for (const Clause c : records.getAllDerivedDefinitions("Clause")) { 580bd9a136SValentin Clement const auto &clauseVals = c.getClauseVals(); 595a1f6077SMehdi Amini if (clauseVals.empty()) 600bd9a136SValentin Clement continue; 610bd9a136SValentin Clement 620bd9a136SValentin Clement const auto enumName = c.getEnumName(); 635a1f6077SMehdi Amini assert(!enumName.empty() && "enumClauseValue field not set."); 640bd9a136SValentin Clement 650bd9a136SValentin Clement std::vector<std::string> cvDefs; 66aae51255SMogball for (const auto &it : llvm::enumerate(clauseVals)) { 67fcb5905eSRahul Joshi const ClauseVal cval{it.value()}; 680bd9a136SValentin Clement if (!cval.isUserVisible()) 690bd9a136SValentin Clement continue; 700bd9a136SValentin Clement 717c385c4bSShraiysh Vaishay std::string name = cval.getFormattedName(); 727c385c4bSShraiysh Vaishay std::string enumValName(name.length(), ' '); 73fcb5905eSRahul Joshi llvm::transform(name, enumValName.begin(), llvm::toLower); 747c385c4bSShraiysh Vaishay enumValName[0] = llvm::toUpper(enumValName[0]); 750bd9a136SValentin Clement std::string cvDef{(enumName + llvm::Twine(name)).str()}; 767c385c4bSShraiysh Vaishay os << "def " << cvDef << " : I32EnumAttrCase<\"" << enumValName << "\", " 777c385c4bSShraiysh Vaishay << it.index() << ", \"" << name << "\">;\n"; 780bd9a136SValentin Clement cvDefs.push_back(cvDef); 790bd9a136SValentin Clement } 800bd9a136SValentin Clement 81aae51255SMogball os << "def " << enumName << ": I32EnumAttr<\n"; 820bd9a136SValentin Clement os << " \"Clause" << enumName << "\",\n"; 830bd9a136SValentin Clement os << " \"" << enumName << " Clause\",\n"; 840bd9a136SValentin Clement os << " ["; 85fcb5905eSRahul Joshi llvm::interleaveComma(cvDefs, os); 860bd9a136SValentin Clement os << "]> {\n"; 870bd9a136SValentin Clement os << " let cppNamespace = \"::mlir::" 880bd9a136SValentin Clement << directiveLanguages[0]->getValueAsString("cppNamespace") << "\";\n"; 89aae51255SMogball os << " let genSpecializedAttr = 0;\n"; 900bd9a136SValentin Clement os << "}\n"; 91aae51255SMogball llvm::SmallString<16> mnemonic; 92aae51255SMogball llvm::transform(enumName, std::back_inserter(mnemonic), llvm::toLower); 93aae51255SMogball os << "def " << enumName << "Attr : EnumAttr<" << dialect << "_Dialect, " 94aae51255SMogball << enumName << ", \"" << mnemonic << "\">;\n"; 950bd9a136SValentin Clement } 960bd9a136SValentin Clement return false; 970bd9a136SValentin Clement } 980bd9a136SValentin Clement 99aae51255SMogball static llvm::cl::OptionCategory 100aae51255SMogball directiveGenCat("Options for gen-directive-decl"); 101aae51255SMogball static llvm::cl::opt<std::string> 102aae51255SMogball dialect("directives-dialect", 103aae51255SMogball llvm::cl::desc("Generate directives for this dialect"), 104aae51255SMogball llvm::cl::cat(directiveGenCat), llvm::cl::CommaSeparated); 105aae51255SMogball 1060bd9a136SValentin Clement // Registers the generator to mlir-tblgen. 1070bd9a136SValentin Clement static mlir::GenRegistration genDirectiveDecls( 1080bd9a136SValentin Clement "gen-directive-decl", 1090bd9a136SValentin Clement "Generate declarations for directives (OpenMP/OpenACC etc.)", 1100bd9a136SValentin Clement [](const RecordKeeper &records, raw_ostream &os) { 111aae51255SMogball return emitDecls(records, dialect, os); 1120bd9a136SValentin Clement }); 113