| //===========- DirectiveCommonGen.cpp - Directive common info generator -=====// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // OpenMPCommonGen generates utility information from the single OpenMP source |
| // of truth in llvm/lib/Frontend/OpenMP. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "mlir/TableGen/GenInfo.h" |
| |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/TableGen/DirectiveEmitter.h" |
| #include "llvm/TableGen/Error.h" |
| #include "llvm/TableGen/Record.h" |
| |
| using llvm::Clause; |
| using llvm::ClauseVal; |
| using llvm::raw_ostream; |
| using llvm::RecordKeeper; |
| |
| // LLVM has multiple places (Clang, Flang, MLIR) where information about |
| // the directives (OpenMP/OpenACC), and clauses are needed. It is good software |
| // engineering to keep the common information in a single place to avoid |
| // duplication, reduce engineering effort and prevent mistakes. |
| // Currently that common place is llvm/include/llvm/Frontend/OpenMP/OMP.td for |
| // OpenMP and llvm/include/llvm/Frontend/OpenACC/ACC.td for OpenACC. |
| // We plan to use this tablegen source to generate all the required |
| // declarations, functions etc. |
| // |
| // Some OpenMP/OpenACC clauses accept only a fixed set of values as inputs. |
| // These can be represented as a Enum Attributes (EnumAttrDef) in MLIR |
| // ODS. The emitDecls function below currently generates these enumerations. The |
| // name of the enumeration is specified in the enumClauseValue field of |
| // Clause record in OMP.td. This name can be used to specify the type of the |
| // OpenMP operation's operand. The allowedClauseValues field provides the list |
| // of ClauseValues which are part of the enumeration. |
| static bool emitDecls(const RecordKeeper &recordKeeper, llvm::StringRef dialect, |
| raw_ostream &os) { |
| // A dialect must be selected for the generated attributes. |
| if (dialect.empty()) { |
| llvm::PrintFatalError("a dialect must be selected for the directives via " |
| "'--directives-dialect'"); |
| } |
| |
| const auto &directiveLanguages = |
| recordKeeper.getAllDerivedDefinitions("DirectiveLanguage"); |
| assert(!directiveLanguages.empty() && "DirectiveLanguage missing."); |
| |
| const auto &clauses = recordKeeper.getAllDerivedDefinitions("Clause"); |
| |
| for (const auto &r : clauses) { |
| Clause c{r}; |
| const auto &clauseVals = c.getClauseVals(); |
| if (clauseVals.empty()) |
| continue; |
| |
| const auto enumName = c.getEnumName(); |
| assert(!enumName.empty() && "enumClauseValue field not set."); |
| |
| std::vector<std::string> cvDefs; |
| for (const auto &it : llvm::enumerate(clauseVals)) { |
| ClauseVal cval{it.value()}; |
| if (!cval.isUserVisible()) |
| continue; |
| |
| std::string name = cval.getFormattedName(); |
| std::string enumValName(name.length(), ' '); |
| std::transform(name.begin(), name.end(), enumValName.begin(), |
| llvm::toLower); |
| enumValName[0] = llvm::toUpper(enumValName[0]); |
| std::string cvDef{(enumName + llvm::Twine(name)).str()}; |
| os << "def " << cvDef << " : I32EnumAttrCase<\"" << enumValName << "\", " |
| << it.index() << ", \"" << name << "\">;\n"; |
| cvDefs.push_back(cvDef); |
| } |
| |
| os << "def " << enumName << ": I32EnumAttr<\n"; |
| os << " \"Clause" << enumName << "\",\n"; |
| os << " \"" << enumName << " Clause\",\n"; |
| os << " ["; |
| for (unsigned int i = 0; i < cvDefs.size(); i++) { |
| os << cvDefs[i]; |
| if (i != cvDefs.size() - 1) |
| os << ","; |
| } |
| os << "]> {\n"; |
| os << " let cppNamespace = \"::mlir::" |
| << directiveLanguages[0]->getValueAsString("cppNamespace") << "\";\n"; |
| os << " let genSpecializedAttr = 0;\n"; |
| os << "}\n"; |
| llvm::SmallString<16> mnemonic; |
| llvm::transform(enumName, std::back_inserter(mnemonic), llvm::toLower); |
| os << "def " << enumName << "Attr : EnumAttr<" << dialect << "_Dialect, " |
| << enumName << ", \"" << mnemonic << "\">;\n"; |
| } |
| return false; |
| } |
| |
| static llvm::cl::OptionCategory |
| directiveGenCat("Options for gen-directive-decl"); |
| static llvm::cl::opt<std::string> |
| dialect("directives-dialect", |
| llvm::cl::desc("Generate directives for this dialect"), |
| llvm::cl::cat(directiveGenCat), llvm::cl::CommaSeparated); |
| |
| // Registers the generator to mlir-tblgen. |
| static mlir::GenRegistration genDirectiveDecls( |
| "gen-directive-decl", |
| "Generate declarations for directives (OpenMP/OpenACC etc.)", |
| [](const RecordKeeper &records, raw_ostream &os) { |
| return emitDecls(records, dialect, os); |
| }); |