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