CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
474 lines
16 KiB
C++
474 lines
16 KiB
C++
//===- IRDL.cpp - IRDL dialect ----------------------------------*- C++ -*-===//
|
|
//
|
|
// This file is licensed 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/Dialect/IRDL/IR/IRDL.h"
|
|
#include "mlir/Dialect/IRDL/IRDLSymbols.h"
|
|
#include "mlir/IR/Builders.h"
|
|
#include "mlir/IR/BuiltinAttributes.h"
|
|
#include "mlir/IR/Diagnostics.h"
|
|
#include "mlir/IR/DialectImplementation.h"
|
|
#include "mlir/IR/ExtensibleDialect.h"
|
|
#include "mlir/IR/OpDefinition.h"
|
|
#include "mlir/IR/OpImplementation.h"
|
|
#include "mlir/IR/Operation.h"
|
|
#include "mlir/Support/LLVM.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SetOperations.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/ADT/TypeSwitch.h"
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
using namespace mlir;
|
|
using namespace mlir::irdl;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// IRDL dialect.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/Dialect/IRDL/IR/IRDL.cpp.inc"
|
|
|
|
#include "mlir/Dialect/IRDL/IR/IRDLDialect.cpp.inc"
|
|
|
|
void IRDLDialect::initialize() {
|
|
addOperations<
|
|
#define GET_OP_LIST
|
|
#include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"
|
|
>();
|
|
addTypes<
|
|
#define GET_TYPEDEF_LIST
|
|
#include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
|
|
>();
|
|
addAttributes<
|
|
#define GET_ATTRDEF_LIST
|
|
#include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"
|
|
>();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Parsing/Printing/Verifying
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Parse a region, and add a single block if the region is empty.
|
|
/// If no region is parsed, create a new region with a single empty block.
|
|
static ParseResult parseSingleBlockRegion(OpAsmParser &p, Region ®ion) {
|
|
auto regionParseRes = p.parseOptionalRegion(region);
|
|
if (regionParseRes.has_value() && failed(regionParseRes.value()))
|
|
return failure();
|
|
|
|
// If the region is empty, add a single empty block.
|
|
if (region.empty())
|
|
region.push_back(new Block());
|
|
|
|
return success();
|
|
}
|
|
|
|
static void printSingleBlockRegion(OpAsmPrinter &p, Operation *op,
|
|
Region ®ion) {
|
|
if (!region.getBlocks().front().empty())
|
|
p.printRegion(region);
|
|
}
|
|
static llvm::LogicalResult isValidName(llvm::StringRef in, mlir::Operation *loc,
|
|
const Twine &label) {
|
|
if (in.empty())
|
|
return loc->emitError("name of ") << label << " is empty";
|
|
|
|
bool allowUnderscore = false;
|
|
for (auto &elem : in) {
|
|
if (elem == '_') {
|
|
if (!allowUnderscore)
|
|
return loc->emitError("name of ")
|
|
<< label << " should not contain leading or double underscores";
|
|
} else {
|
|
if (!isalnum(elem))
|
|
return loc->emitError("name of ")
|
|
<< label
|
|
<< " must contain only lowercase letters, digits and "
|
|
"underscores";
|
|
|
|
if (llvm::isUpper(elem))
|
|
return loc->emitError("name of ")
|
|
<< label << " should not contain uppercase letters";
|
|
}
|
|
|
|
allowUnderscore = elem != '_';
|
|
}
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult DialectOp::verify() {
|
|
if (!Dialect::isValidNamespace(getName()))
|
|
return emitOpError("invalid dialect name");
|
|
if (failed(isValidName(getSymName(), getOperation(), "dialect")))
|
|
return failure();
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult OperationOp::verify() {
|
|
return isValidName(getSymName(), getOperation(), "operation");
|
|
}
|
|
|
|
LogicalResult TypeOp::verify() {
|
|
auto symName = getSymName();
|
|
if (!symName.empty() && symName.front() == '!')
|
|
symName = symName.substr(1);
|
|
return isValidName(symName, getOperation(), "type");
|
|
}
|
|
|
|
LogicalResult AttributeOp::verify() {
|
|
auto symName = getSymName();
|
|
if (!symName.empty() && symName.front() == '#')
|
|
symName = symName.substr(1);
|
|
return isValidName(symName, getOperation(), "attribute");
|
|
}
|
|
|
|
LogicalResult OperationOp::verifyRegions() {
|
|
// Stores pairs of value kinds and the list of names of values of this kind in
|
|
// the operation.
|
|
SmallVector<std::tuple<StringRef, llvm::SmallDenseSet<StringRef>>> valueNames;
|
|
|
|
auto insertNames = [&](StringRef kind, ArrayAttr names) {
|
|
llvm::SmallDenseSet<StringRef> nameSet;
|
|
nameSet.reserve(names.size());
|
|
for (auto name : names)
|
|
nameSet.insert(llvm::cast<StringAttr>(name).getValue());
|
|
valueNames.emplace_back(kind, std::move(nameSet));
|
|
};
|
|
|
|
for (Operation &op : getBody().getOps()) {
|
|
TypeSwitch<Operation *>(&op)
|
|
.Case([&](OperandsOp op) { insertNames("operands", op.getNames()); })
|
|
.Case([&](ResultsOp op) { insertNames("results", op.getNames()); })
|
|
.Case([&](RegionsOp op) { insertNames("regions", op.getNames()); });
|
|
}
|
|
|
|
// Verify that no two operand, result or region share the same name.
|
|
// The absence of duplicates within each value kind is checked by the
|
|
// associated operation's verifier.
|
|
for (size_t i : llvm::seq(valueNames.size())) {
|
|
for (size_t j : llvm::seq(i + 1, valueNames.size())) {
|
|
auto [lhs, lhsSet] = valueNames[i];
|
|
auto &[rhs, rhsSet] = valueNames[j];
|
|
llvm::set_intersect(lhsSet, rhsSet);
|
|
if (!lhsSet.empty())
|
|
return emitOpError("contains a value named '")
|
|
<< *lhsSet.begin() << "' for both its " << lhs << " and " << rhs;
|
|
}
|
|
}
|
|
|
|
return success();
|
|
}
|
|
|
|
static LogicalResult verifyNames(Operation *op, StringRef kindName,
|
|
ArrayAttr names, size_t numOperands) {
|
|
if (numOperands != names.size())
|
|
return op->emitOpError()
|
|
<< "the number of " << kindName
|
|
<< "s and their names must be "
|
|
"the same, but got "
|
|
<< numOperands << " and " << names.size() << " respectively";
|
|
|
|
DenseMap<StringRef, size_t> nameMap;
|
|
for (auto [i, name] : llvm::enumerate(names)) {
|
|
StringRef nameRef = llvm::cast<StringAttr>(name).getValue();
|
|
|
|
if (failed(isValidName(nameRef, op, Twine(kindName) + " #" + Twine(i))))
|
|
return failure();
|
|
|
|
if (nameMap.contains(nameRef))
|
|
return op->emitOpError() << "name of " << kindName << " #" << i
|
|
<< " is a duplicate of the name of " << kindName
|
|
<< " #" << nameMap[nameRef];
|
|
nameMap.insert({nameRef, i});
|
|
}
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult ParametersOp::verify() {
|
|
return verifyNames(*this, "parameter", getNames(), getNumOperands());
|
|
}
|
|
|
|
template <typename ValueListOp>
|
|
static LogicalResult verifyOperandsResultsCommon(ValueListOp op,
|
|
StringRef kindName) {
|
|
size_t numVariadicities = op.getVariadicity().size();
|
|
size_t numOperands = op.getNumOperands();
|
|
|
|
if (numOperands != numVariadicities)
|
|
return op.emitOpError()
|
|
<< "the number of " << kindName
|
|
<< "s and their variadicities must be "
|
|
"the same, but got "
|
|
<< numOperands << " and " << numVariadicities << " respectively";
|
|
|
|
return verifyNames(op, kindName, op.getNames(), numOperands);
|
|
}
|
|
|
|
LogicalResult OperandsOp::verify() {
|
|
return verifyOperandsResultsCommon(*this, "operand");
|
|
}
|
|
|
|
LogicalResult ResultsOp::verify() {
|
|
return verifyOperandsResultsCommon(*this, "result");
|
|
}
|
|
|
|
LogicalResult AttributesOp::verify() {
|
|
size_t namesSize = getAttributeValueNames().size();
|
|
size_t valuesSize = getAttributeValues().size();
|
|
|
|
if (namesSize != valuesSize)
|
|
return emitOpError()
|
|
<< "the number of attribute names and their constraints must be "
|
|
"the same but got "
|
|
<< namesSize << " and " << valuesSize << " respectively";
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult BaseOp::verify() {
|
|
std::optional<StringRef> baseName = getBaseName();
|
|
std::optional<SymbolRefAttr> baseRef = getBaseRef();
|
|
if (baseName.has_value() == baseRef.has_value())
|
|
return emitOpError() << "the base type or attribute should be specified by "
|
|
"either a name or a reference";
|
|
|
|
if (baseName &&
|
|
(baseName->empty() || ((*baseName)[0] != '!' && (*baseName)[0] != '#')))
|
|
return emitOpError() << "the base type or attribute name should start with "
|
|
"'!' or '#'";
|
|
|
|
return success();
|
|
}
|
|
|
|
/// Finds whether the provided symbol is an IRDL type or attribute definition.
|
|
/// The source operation must be within a DialectOp.
|
|
static LogicalResult
|
|
checkSymbolIsTypeOrAttribute(SymbolTableCollection &symbolTable,
|
|
Operation *source, SymbolRefAttr symbol) {
|
|
Operation *targetOp =
|
|
irdl::lookupSymbolNearDialect(symbolTable, source, symbol);
|
|
|
|
if (!targetOp)
|
|
return source->emitOpError() << "symbol '" << symbol << "' not found";
|
|
|
|
if (!isa<TypeOp, AttributeOp>(targetOp))
|
|
return source->emitOpError() << "symbol '" << symbol
|
|
<< "' does not refer to a type or attribute "
|
|
"definition (refers to '"
|
|
<< targetOp->getName() << "')";
|
|
|
|
return success();
|
|
}
|
|
|
|
LogicalResult BaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
|
|
std::optional<SymbolRefAttr> baseRef = getBaseRef();
|
|
if (!baseRef)
|
|
return success();
|
|
|
|
return checkSymbolIsTypeOrAttribute(symbolTable, *this, *baseRef);
|
|
}
|
|
|
|
LogicalResult
|
|
ParametricOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
|
|
std::optional<SymbolRefAttr> baseRef = getBaseType();
|
|
if (!baseRef)
|
|
return success();
|
|
|
|
return checkSymbolIsTypeOrAttribute(symbolTable, *this, *baseRef);
|
|
}
|
|
|
|
/// Parse a value with its variadicity first. By default, the variadicity is
|
|
/// single.
|
|
///
|
|
/// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
|
|
static ParseResult
|
|
parseValueWithVariadicity(OpAsmParser &p,
|
|
OpAsmParser::UnresolvedOperand &operand,
|
|
VariadicityAttr &variadicityAttr) {
|
|
MLIRContext *ctx = p.getBuilder().getContext();
|
|
|
|
// Parse the variadicity, if present
|
|
if (p.parseOptionalKeyword("single").succeeded()) {
|
|
variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);
|
|
} else if (p.parseOptionalKeyword("optional").succeeded()) {
|
|
variadicityAttr = VariadicityAttr::get(ctx, Variadicity::optional);
|
|
} else if (p.parseOptionalKeyword("variadic").succeeded()) {
|
|
variadicityAttr = VariadicityAttr::get(ctx, Variadicity::variadic);
|
|
} else {
|
|
variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);
|
|
}
|
|
|
|
// Parse the value
|
|
if (p.parseOperand(operand))
|
|
return failure();
|
|
return success();
|
|
}
|
|
|
|
static ParseResult parseNamedValueListImpl(
|
|
OpAsmParser &p, SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,
|
|
ArrayAttr &valueNamesAttr, VariadicityArrayAttr *variadicityAttr) {
|
|
Builder &builder = p.getBuilder();
|
|
MLIRContext *ctx = builder.getContext();
|
|
SmallVector<Attribute> valueNames;
|
|
SmallVector<VariadicityAttr> variadicities;
|
|
|
|
// Parse a single value with its variadicity
|
|
auto parseOne = [&] {
|
|
StringRef name;
|
|
OpAsmParser::UnresolvedOperand operand;
|
|
VariadicityAttr variadicity;
|
|
if (p.parseKeyword(&name) || p.parseColon())
|
|
return failure();
|
|
|
|
if (variadicityAttr) {
|
|
if (parseValueWithVariadicity(p, operand, variadicity))
|
|
return failure();
|
|
variadicities.push_back(variadicity);
|
|
} else {
|
|
if (p.parseOperand(operand))
|
|
return failure();
|
|
}
|
|
|
|
valueNames.push_back(StringAttr::get(ctx, name));
|
|
operands.push_back(operand);
|
|
return success();
|
|
};
|
|
|
|
if (p.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren, parseOne))
|
|
return failure();
|
|
valueNamesAttr = ArrayAttr::get(ctx, valueNames);
|
|
if (variadicityAttr)
|
|
*variadicityAttr = VariadicityArrayAttr::get(ctx, variadicities);
|
|
return success();
|
|
}
|
|
|
|
/// Parse a list of named values.
|
|
///
|
|
/// values ::=
|
|
/// `(` (named-value (`,` named-value)*)? `)`
|
|
/// named-value := bare-id `:` ssa-value
|
|
static ParseResult
|
|
parseNamedValueList(OpAsmParser &p,
|
|
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,
|
|
ArrayAttr &valueNamesAttr) {
|
|
return parseNamedValueListImpl(p, operands, valueNamesAttr, nullptr);
|
|
}
|
|
|
|
/// Parse a list of named values with their variadicities first. By default, the
|
|
/// variadicity is single.
|
|
///
|
|
/// values-with-variadicity ::=
|
|
/// `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
|
|
/// value-with-variadicity
|
|
/// ::= bare-id `:` ("single" | "optional" | "variadic")? ssa-value
|
|
static ParseResult parseNamedValueListWithVariadicity(
|
|
OpAsmParser &p, SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,
|
|
ArrayAttr &valueNamesAttr, VariadicityArrayAttr &variadicityAttr) {
|
|
return parseNamedValueListImpl(p, operands, valueNamesAttr, &variadicityAttr);
|
|
}
|
|
|
|
static void printNamedValueListImpl(OpAsmPrinter &p, Operation *op,
|
|
OperandRange operands,
|
|
ArrayAttr valueNamesAttr,
|
|
VariadicityArrayAttr variadicityAttr) {
|
|
p << "(";
|
|
interleaveComma(llvm::seq<int>(0, operands.size()), p, [&](int i) {
|
|
p << llvm::cast<StringAttr>(valueNamesAttr[i]).getValue() << ": ";
|
|
if (variadicityAttr) {
|
|
Variadicity variadicity = variadicityAttr[i].getValue();
|
|
if (variadicity != Variadicity::single) {
|
|
p << stringifyVariadicity(variadicity) << " ";
|
|
}
|
|
}
|
|
p << operands[i];
|
|
});
|
|
p << ")";
|
|
}
|
|
|
|
/// Print a list of named values.
|
|
///
|
|
/// values ::=
|
|
/// `(` (named-value (`,` named-value)*)? `)`
|
|
/// named-value := bare-id `:` ssa-value
|
|
static void printNamedValueList(OpAsmPrinter &p, Operation *op,
|
|
OperandRange operands,
|
|
ArrayAttr valueNamesAttr) {
|
|
printNamedValueListImpl(p, op, operands, valueNamesAttr, nullptr);
|
|
}
|
|
|
|
/// Print a list of named values with their variadicities first. By default, the
|
|
/// variadicity is single.
|
|
///
|
|
/// values-with-variadicity ::=
|
|
/// `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
|
|
/// value-with-variadicity ::=
|
|
/// bare-id `:` ("single" | "optional" | "variadic")? ssa-value
|
|
static void printNamedValueListWithVariadicity(
|
|
OpAsmPrinter &p, Operation *op, OperandRange operands,
|
|
ArrayAttr valueNamesAttr, VariadicityArrayAttr variadicityAttr) {
|
|
printNamedValueListImpl(p, op, operands, valueNamesAttr, variadicityAttr);
|
|
}
|
|
|
|
static ParseResult
|
|
parseAttributesOp(OpAsmParser &p,
|
|
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &attrOperands,
|
|
ArrayAttr &attrNamesAttr) {
|
|
Builder &builder = p.getBuilder();
|
|
SmallVector<Attribute> attrNames;
|
|
if (succeeded(p.parseOptionalLBrace())) {
|
|
auto parseOperands = [&]() {
|
|
if (p.parseAttribute(attrNames.emplace_back()) || p.parseEqual() ||
|
|
p.parseOperand(attrOperands.emplace_back()))
|
|
return failure();
|
|
return success();
|
|
};
|
|
if (p.parseCommaSeparatedList(parseOperands) || p.parseRBrace())
|
|
return failure();
|
|
}
|
|
attrNamesAttr = builder.getArrayAttr(attrNames);
|
|
return success();
|
|
}
|
|
|
|
static void printAttributesOp(OpAsmPrinter &p, AttributesOp op,
|
|
OperandRange attrArgs, ArrayAttr attrNames) {
|
|
if (attrNames.empty())
|
|
return;
|
|
p << "{";
|
|
interleaveComma(llvm::seq<int>(0, attrNames.size()), p,
|
|
[&](int i) { p << attrNames[i] << " = " << attrArgs[i]; });
|
|
p << '}';
|
|
}
|
|
|
|
LogicalResult RegionOp::verify() {
|
|
if (IntegerAttr numberOfBlocks = getNumberOfBlocksAttr())
|
|
if (int64_t number = numberOfBlocks.getInt(); number <= 0) {
|
|
return emitOpError("the number of blocks is expected to be >= 1 but got ")
|
|
<< number;
|
|
}
|
|
return success();
|
|
}
|
|
|
|
LogicalResult RegionsOp::verify() {
|
|
return verifyNames(*this, "region", getNames(), getNumOperands());
|
|
}
|
|
|
|
#include "mlir/Dialect/IRDL/IR/IRDLInterfaces.cpp.inc"
|
|
|
|
#define GET_TYPEDEF_CLASSES
|
|
#include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
|
|
|
|
#include "mlir/Dialect/IRDL/IR/IRDLEnums.cpp.inc"
|
|
|
|
#define GET_ATTRDEF_CLASSES
|
|
#include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"
|
|
|
|
#define GET_OP_CLASSES
|
|
#include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"
|