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