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
23using llvm::Clause;
24using llvm::EnumVal;
25using llvm::raw_ostream;
26using 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 Enum Attributes (EnumAttrDef) 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.
44static bool emitDecls(const RecordKeeper &records, llvm::StringRef dialect,
45 raw_ostream &os) {
46 // A dialect must be selected for the generated attributes.
47 if (dialect.empty()) {
48 llvm::PrintFatalError(Msg: "a dialect must be selected for the directives via "
49 "'--directives-dialect'");
50 }
51
52 const auto directiveLanguages =
53 records.getAllDerivedDefinitions(ClassName: "DirectiveLanguage");
54 assert(!directiveLanguages.empty() && "DirectiveLanguage missing.");
55
56 for (const Clause c : records.getAllDerivedDefinitions(ClassName: "Clause")) {
57 const auto &clauseVals = c.getClauseVals();
58 if (clauseVals.empty())
59 continue;
60
61 const auto enumName = c.getEnumName();
62 assert(!enumName.empty() && "enumClauseValue field not set.");
63
64 std::vector<std::string> cvDefs;
65 for (const auto &it : llvm::enumerate(First: clauseVals)) {
66 const EnumVal val{it.value()};
67 if (!val.isUserVisible())
68 continue;
69
70 std::string name = val.getFormattedName();
71 std::string enumValName(name.length(), ' ');
72 llvm::transform(Range&: name, d_first: enumValName.begin(), F: llvm::toLower);
73 enumValName[0] = llvm::toUpper(x: enumValName[0]);
74 std::string cvDef{(enumName + llvm::Twine(name)).str()};
75 os << "def " << cvDef << " : I32EnumAttrCase<\"" << enumValName << "\", "
76 << it.index() << ", \"" << name << "\">;\n";
77 cvDefs.push_back(x: cvDef);
78 }
79
80 os << "def " << enumName << ": I32EnumAttr<\n";
81 os << " \"Clause" << enumName << "\",\n";
82 os << " \"" << enumName << " Clause\",\n";
83 os << " [";
84 llvm::interleaveComma(c: cvDefs, os);
85 os << "]> {\n";
86 os << " let cppNamespace = \"::mlir::"
87 << directiveLanguages[0]->getValueAsString(FieldName: "cppNamespace") << "\";\n";
88 os << " let genSpecializedAttr = 0;\n";
89 os << "}\n";
90 llvm::SmallString<16> mnemonic;
91 llvm::transform(Range: enumName, d_first: std::back_inserter(x&: mnemonic), F: llvm::toLower);
92 os << "def " << enumName << "Attr : EnumAttr<" << dialect << "_Dialect, "
93 << enumName << ", \"" << mnemonic << "\">;\n";
94 }
95 return false;
96}
97
98static llvm::cl::OptionCategory
99 directiveGenCat("Options for gen-directive-decl");
100static llvm::cl::opt<std::string>
101 dialect("directives-dialect",
102 llvm::cl::desc("Generate directives for this dialect"),
103 llvm::cl::cat(directiveGenCat), llvm::cl::CommaSeparated);
104
105// Registers the generator to mlir-tblgen.
106static mlir::GenRegistration genDirectiveDecls(
107 "gen-directive-decl",
108 "Generate declarations for directives (OpenMP/OpenACC etc.)",
109 [](const RecordKeeper &records, raw_ostream &os) {
110 return emitDecls(records, dialect, os);
111 });
112

source code of mlir/tools/mlir-tblgen/DirectiveCommonGen.cpp