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 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.
emitDecls(const RecordKeeper & recordKeeper,llvm::StringRef dialect,raw_ostream & os)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 std::string name = cval.getFormattedName();
74 std::string enumValName(name.length(), ' ');
75 std::transform(name.begin(), name.end(), enumValName.begin(),
76 llvm::toLower);
77 enumValName[0] = llvm::toUpper(enumValName[0]);
78 std::string cvDef{(enumName + llvm::Twine(name)).str()};
79 os << "def " << cvDef << " : I32EnumAttrCase<\"" << enumValName << "\", "
80 << it.index() << ", \"" << name << "\">;\n";
81 cvDefs.push_back(cvDef);
82 }
83
84 os << "def " << enumName << ": I32EnumAttr<\n";
85 os << " \"Clause" << enumName << "\",\n";
86 os << " \"" << enumName << " Clause\",\n";
87 os << " [";
88 for (unsigned int i = 0; i < cvDefs.size(); i++) {
89 os << cvDefs[i];
90 if (i != cvDefs.size() - 1)
91 os << ",";
92 }
93 os << "]> {\n";
94 os << " let cppNamespace = \"::mlir::"
95 << directiveLanguages[0]->getValueAsString("cppNamespace") << "\";\n";
96 os << " let genSpecializedAttr = 0;\n";
97 os << "}\n";
98 llvm::SmallString<16> mnemonic;
99 llvm::transform(enumName, std::back_inserter(mnemonic), llvm::toLower);
100 os << "def " << enumName << "Attr : EnumAttr<" << dialect << "_Dialect, "
101 << enumName << ", \"" << mnemonic << "\">;\n";
102 }
103 return false;
104 }
105
106 static llvm::cl::OptionCategory
107 directiveGenCat("Options for gen-directive-decl");
108 static llvm::cl::opt<std::string>
109 dialect("directives-dialect",
110 llvm::cl::desc("Generate directives for this dialect"),
111 llvm::cl::cat(directiveGenCat), llvm::cl::CommaSeparated);
112
113 // Registers the generator to mlir-tblgen.
114 static mlir::GenRegistration genDirectiveDecls(
115 "gen-directive-decl",
116 "Generate declarations for directives (OpenMP/OpenACC etc.)",
__anona2de94610102(const RecordKeeper &records, raw_ostream &os) 117 [](const RecordKeeper &records, raw_ostream &os) {
118 return emitDecls(records, dialect, os);
119 });
120