#include "mlir/TableGen/GenInfo.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace llvm;
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);
for (Record *superClass : clauseSuperClasses) {
if (superClass == ompClause) {
clauseClassName = clause->getName();
break;
}
}
if (clauseClassName.empty()) {
for (auto [superClass, _] : clause->getSuperClasses()) {
if (superClass->isSubClassOf(ompClause)) {
clauseClassName = superClass->getName();
break;
}
}
}
assert(!clauseClassName.empty() && "clause name must be found");
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;
}
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();
}
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());
}
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.");
}
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;
}
static mlir::GenRegistration
verifyOpenmpOps("verify-openmp-ops",
"Verify OpenMP operations (produce no output file)",
verifyDecls);