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/raw_ostream.h"
18 #include "llvm/TableGen/DirectiveEmitter.h"
19 #include "llvm/TableGen/Record.h"
20 
21 using llvm::Clause;
22 using llvm::ClauseVal;
23 using llvm::raw_ostream;
24 using llvm::RecordKeeper;
25 using llvm::Twine;
26 
27 // LLVM has multiple places (Clang, Flang, MLIR) where information about
28 // the directives (OpenMP/OpenACC), and clauses are needed. It is good software
29 // engineering to keep the common information in a single place to avoid
30 // duplication, reduce engineering effort and prevent mistakes.
31 // Currently that common place is llvm/include/llvm/Frontend/OpenMP/OMP.td for
32 // OpenMP and llvm/include/llvm/Frontend/OpenACC/ACC.td for OpenACC.
33 // We plan to use this tablegen source to generate all the required
34 // declarations, functions etc.
35 //
36 // Some OpenMP/OpenACC clauses accept only a fixed set of values as inputs.
37 // These can be represented as a String Enum Attribute (StrEnumAttr) in MLIR
38 // ODS. The emitDecls function below currently generates these enumerations. The
39 // name of the enumeration is specified in the enumClauseValue field of
40 // Clause record in OMP.td. This name can be used to specify the type of the
41 // OpenMP operation's operand. The allowedClauseValues field provides the list
42 // of ClauseValues which are part of the enumeration.
43 static bool emitDecls(const RecordKeeper &recordKeeper, raw_ostream &os) {
44   const auto &directiveLanguages =
45       recordKeeper.getAllDerivedDefinitions("DirectiveLanguage");
46   assert(directiveLanguages.size() != 0 && "DirectiveLanguage missing.");
47 
48   const auto &clauses = recordKeeper.getAllDerivedDefinitions("Clause");
49 
50   for (const auto &r : clauses) {
51     Clause c{r};
52     const auto &clauseVals = c.getClauseVals();
53     if (clauseVals.size() <= 0)
54       continue;
55 
56     const auto enumName = c.getEnumName();
57     assert(enumName.size() != 0 && "enumClauseValue field not set.");
58 
59     std::vector<std::string> cvDefs;
60     for (const auto &cv : clauseVals) {
61       ClauseVal cval{cv};
62       if (!cval.isUserVisible())
63         continue;
64 
65       const auto name = cval.getFormattedName();
66       std::string cvDef{(enumName + llvm::Twine(name)).str()};
67       os << "def " << cvDef << " : StrEnumAttrCase<\"" << name << "\">;\n";
68       cvDefs.push_back(cvDef);
69     }
70 
71     os << "def " << enumName << ": StrEnumAttr<\n";
72     os << "  \"Clause" << enumName << "\",\n";
73     os << "  \"" << enumName << " Clause\",\n";
74     os << "  [";
75     for (unsigned int i = 0; i < cvDefs.size(); i++) {
76       os << cvDefs[i];
77       if (i != cvDefs.size() - 1)
78         os << ",";
79     }
80     os << "]> {\n";
81     os << "    let cppNamespace = \"::mlir::"
82        << directiveLanguages[0]->getValueAsString("cppNamespace") << "\";\n";
83     os << "}\n";
84   }
85   return false;
86 }
87 
88 // Registers the generator to mlir-tblgen.
89 static mlir::GenRegistration genDirectiveDecls(
90     "gen-directive-decl",
91     "Generate declarations for directives (OpenMP/OpenACC etc.)",
92     [](const RecordKeeper &records, raw_ostream &os) {
93       return emitDecls(records, os);
94     });
95