[Infra] Fix version-check workflow (#100090)
[llvm-project.git] / mlir / tools / mlir-tblgen / OmpOpGen.cpp
blob51eb43f322e6ad9ab7c0e312c6e1d5055589f166
1 //===- OmpOpGen.cpp - OpenMP dialect op specific generators ---------------===//
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 // OmpOpGen defines OpenMP dialect operation specific generators.
11 //===----------------------------------------------------------------------===//
13 #include "mlir/TableGen/GenInfo.h"
15 #include "llvm/TableGen/Error.h"
16 #include "llvm/TableGen/Record.h"
18 using namespace llvm;
20 /// Obtain the name of the OpenMP clause a given record inheriting
21 /// `OpenMP_Clause` refers to.
22 ///
23 /// It supports direct and indirect `OpenMP_Clause` superclasses. Once the
24 /// `OpenMP_Clause` class the record is based on is found, the optional
25 /// "OpenMP_" prefix and "Skip" and "Clause" suffixes are removed to return only
26 /// the clause name, i.e. "OpenMP_CollapseClauseSkip" is returned as "Collapse".
27 static StringRef extractOmpClauseName(Record *clause) {
28 Record *ompClause = clause->getRecords().getClass("OpenMP_Clause");
29 assert(ompClause && "base OpenMP records expected to be defined");
31 StringRef clauseClassName;
32 SmallVector<Record *, 1> clauseSuperClasses;
33 clause->getDirectSuperClasses(clauseSuperClasses);
35 // Check if OpenMP_Clause is a direct superclass.
36 for (Record *superClass : clauseSuperClasses) {
37 if (superClass == ompClause) {
38 clauseClassName = clause->getName();
39 break;
43 // Support indirectly-inherited OpenMP_Clauses.
44 if (clauseClassName.empty()) {
45 for (auto [superClass, _] : clause->getSuperClasses()) {
46 if (superClass->isSubClassOf(ompClause)) {
47 clauseClassName = superClass->getName();
48 break;
53 assert(!clauseClassName.empty() && "clause name must be found");
55 // Keep only the OpenMP clause name itself for reporting purposes.
56 StringRef prefix = "OpenMP_";
57 StringRef suffixes[] = {"Skip", "Clause"};
59 if (clauseClassName.starts_with(prefix))
60 clauseClassName = clauseClassName.substr(prefix.size());
62 for (StringRef suffix : suffixes) {
63 if (clauseClassName.ends_with(suffix))
64 clauseClassName =
65 clauseClassName.substr(0, clauseClassName.size() - suffix.size());
68 return clauseClassName;
71 /// Check that the given argument, identified by its name and initialization
72 /// value, is present in the \c arguments `dag`.
73 static bool verifyArgument(DagInit *arguments, StringRef argName,
74 Init *argInit) {
75 auto range = zip_equal(arguments->getArgNames(), arguments->getArgs());
76 return std::find_if(
77 range.begin(), range.end(),
78 [&](std::tuple<llvm::StringInit *const &, llvm::Init *const &> v) {
79 return std::get<0>(v)->getAsUnquotedString() == argName &&
80 std::get<1>(v) == argInit;
81 }) != range.end();
84 /// Check that the given string record value, identified by its name \c value,
85 /// is either undefined or empty in both the given operation and clause record
86 /// or its contents for the clause record are contained in the operation record.
87 static bool verifyStringValue(StringRef value, Record *op, Record *clause) {
88 auto opValue = op->getValueAsOptionalString(value);
89 auto clauseValue = clause->getValueAsOptionalString(value);
91 bool opHasValue = opValue && !opValue->trim().empty();
92 bool clauseHasValue = clauseValue && !clauseValue->trim().empty();
94 if (!opHasValue)
95 return !clauseHasValue;
97 return !clauseHasValue || opValue->contains(clauseValue->trim());
100 /// Verify that all fields of the given clause not explicitly ignored are
101 /// present in the corresponding operation field.
103 /// Print warnings or errors where this is not the case.
104 static void verifyClause(Record *op, Record *clause) {
105 StringRef clauseClassName = extractOmpClauseName(clause);
107 if (!clause->getValueAsBit("ignoreArgs")) {
108 DagInit *opArguments = op->getValueAsDag("arguments");
109 DagInit *arguments = clause->getValueAsDag("arguments");
111 for (auto [name, arg] :
112 zip(arguments->getArgNames(), arguments->getArgs())) {
113 if (!verifyArgument(opArguments, name->getAsUnquotedString(), arg))
114 PrintWarning(
115 op->getLoc(),
116 "'" + clauseClassName + "' clause-defined argument '" +
117 arg->getAsUnquotedString() + ":$" +
118 name->getAsUnquotedString() +
119 "' not present in operation. Consider `dag arguments = "
120 "!con(clausesArgs, ...)` or explicitly skipping this field.");
124 if (!clause->getValueAsBit("ignoreAsmFormat") &&
125 !verifyStringValue("assemblyFormat", op, clause))
126 PrintWarning(
127 op->getLoc(),
128 "'" + clauseClassName +
129 "' clause-defined `assemblyFormat` not present in operation. "
130 "Consider concatenating `clausesAssemblyFormat` or explicitly "
131 "skipping this field.");
133 if (!clause->getValueAsBit("ignoreDesc") &&
134 !verifyStringValue("description", op, clause))
135 PrintError(op->getLoc(),
136 "'" + clauseClassName +
137 "' clause-defined `description` not present in operation. "
138 "Consider concatenating `clausesDescription` or explicitly "
139 "skipping this field.");
141 if (!clause->getValueAsBit("ignoreExtraDecl") &&
142 !verifyStringValue("extraClassDeclaration", op, clause))
143 PrintWarning(
144 op->getLoc(),
145 "'" + clauseClassName +
146 "' clause-defined `extraClassDeclaration` not present in "
147 "operation. Consider concatenating `clausesExtraClassDeclaration` "
148 "or explicitly skipping this field.");
151 /// Verify that all properties of `OpenMP_Clause`s of records deriving from
152 /// `OpenMP_Op`s have been inherited by the latter.
153 static bool verifyDecls(const RecordKeeper &recordKeeper, raw_ostream &) {
154 for (Record *op : recordKeeper.getAllDerivedDefinitions("OpenMP_Op")) {
155 for (Record *clause : op->getValueAsListOfDefs("clauseList"))
156 verifyClause(op, clause);
159 return false;
162 // Registers the generator to mlir-tblgen.
163 static mlir::GenRegistration
164 verifyOpenmpOps("verify-openmp-ops",
165 "Verify OpenMP operations (produce no output file)",
166 verifyDecls);