mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 23:56:05 +00:00

After the introduction of `OpAsmAttrInterface` for alias in #124721, the natural thought to exercise it would be migrating the MLIR existing alias generation method, i.e. `OpAsmDialectInterface`, to use the new interface. There is a `BuiltinOpAsmDialectInterface` that generates aliases for `AffineMapAttr` and `IntegerSetAttr`, and these attributes could be migrated to use `OpAsmAttrInterface`. However, the tricky part is that `OpAsmAttrInterface` lives in `OpImplementation.h`. If `BuiltinAttributes.h` includes that, it would become a cyclic inclusion. Note that only BuiltinAttribute/Type would face such issue as outside user can just include `OpImplementation.h` (see downstream example https://github.com/google/heir/pull/1437) The dependency is introduced by the fact that `OpAsmAttrInterface` uses `OpAsmDialectInterface::AliasResult`. The solution to is: Put the `AliasResult` in `OpAsmSupport.h` that all interfaces can include that header safely. The API wont break as `mlir::OpAsmDialectInterface::AliasResult` is a typedef of this class.
241 lines
8.7 KiB
C++
241 lines
8.7 KiB
C++
//===- BuiltinDialect.cpp - MLIR Builtin Dialect --------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains the Builtin dialect that contains all of the attributes,
|
|
// operations, and types that are necessary for the validity of the IR.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/IR/BuiltinDialect.h"
|
|
#include "BuiltinDialectBytecode.h"
|
|
#include "mlir/IR/Builders.h"
|
|
#include "mlir/IR/BuiltinOps.h"
|
|
#include "mlir/IR/BuiltinTypes.h"
|
|
#include "mlir/IR/DialectResourceBlobManager.h"
|
|
#include "mlir/IR/IRMapping.h"
|
|
#include "mlir/IR/OpImplementation.h"
|
|
#include "mlir/IR/PatternMatch.h"
|
|
#include "mlir/IR/TypeRange.h"
|
|
|
|
using namespace mlir;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// TableGen'erated dialect
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/IR/BuiltinDialect.cpp.inc"
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// BuiltinBlobManagerInterface
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
using BuiltinBlobManagerInterface =
|
|
ResourceBlobManagerDialectInterfaceBase<DenseResourceElementsHandle>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// BuiltinOpAsmDialectInterface
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface {
|
|
BuiltinOpAsmDialectInterface(Dialect *dialect,
|
|
BuiltinBlobManagerInterface &mgr)
|
|
: OpAsmDialectInterface(dialect), blobManager(mgr) {}
|
|
|
|
AliasResult getAlias(Attribute attr, raw_ostream &os) const override {
|
|
if (llvm::isa<LocationAttr>(attr)) {
|
|
os << "loc";
|
|
return AliasResult::OverridableAlias;
|
|
}
|
|
if (auto distinct = llvm::dyn_cast<DistinctAttr>(attr))
|
|
if (!llvm::isa<UnitAttr>(distinct.getReferencedAttr())) {
|
|
os << "distinct";
|
|
return AliasResult::OverridableAlias;
|
|
}
|
|
return AliasResult::NoAlias;
|
|
}
|
|
|
|
AliasResult getAlias(Type type, raw_ostream &os) const final {
|
|
if (auto tupleType = llvm::dyn_cast<TupleType>(type)) {
|
|
if (tupleType.size() > 16) {
|
|
os << "tuple";
|
|
return AliasResult::OverridableAlias;
|
|
}
|
|
}
|
|
return AliasResult::NoAlias;
|
|
}
|
|
|
|
//===------------------------------------------------------------------===//
|
|
// Resources
|
|
//===------------------------------------------------------------------===//
|
|
|
|
std::string
|
|
getResourceKey(const AsmDialectResourceHandle &handle) const override {
|
|
return cast<DenseResourceElementsHandle>(handle).getKey().str();
|
|
}
|
|
FailureOr<AsmDialectResourceHandle>
|
|
declareResource(StringRef key) const final {
|
|
return blobManager.insert(key);
|
|
}
|
|
LogicalResult parseResource(AsmParsedResourceEntry &entry) const final {
|
|
FailureOr<AsmResourceBlob> blob = entry.parseAsBlob();
|
|
if (failed(blob))
|
|
return failure();
|
|
|
|
// Update the blob for this entry.
|
|
blobManager.update(entry.getKey(), std::move(*blob));
|
|
return success();
|
|
}
|
|
void
|
|
buildResources(Operation *op,
|
|
const SetVector<AsmDialectResourceHandle> &referencedResources,
|
|
AsmResourceBuilder &provider) const final {
|
|
blobManager.buildResources(provider, referencedResources.getArrayRef());
|
|
}
|
|
|
|
private:
|
|
/// The blob manager for the dialect.
|
|
BuiltinBlobManagerInterface &blobManager;
|
|
};
|
|
} // namespace
|
|
|
|
void BuiltinDialect::initialize() {
|
|
registerTypes();
|
|
registerAttributes();
|
|
registerLocationAttributes();
|
|
addOperations<
|
|
#define GET_OP_LIST
|
|
#include "mlir/IR/BuiltinOps.cpp.inc"
|
|
>();
|
|
|
|
auto &blobInterface = addInterface<BuiltinBlobManagerInterface>();
|
|
addInterface<BuiltinOpAsmDialectInterface>(blobInterface);
|
|
builtin_dialect_detail::addBytecodeInterface(this);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ModuleOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
void ModuleOp::build(OpBuilder &builder, OperationState &state,
|
|
std::optional<StringRef> name) {
|
|
state.addRegion()->emplaceBlock();
|
|
if (name) {
|
|
state.attributes.push_back(builder.getNamedAttr(
|
|
mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(*name)));
|
|
}
|
|
}
|
|
|
|
/// Construct a module from the given context.
|
|
ModuleOp ModuleOp::create(Location loc, std::optional<StringRef> name) {
|
|
OpBuilder builder(loc->getContext());
|
|
return builder.create<ModuleOp>(loc, name);
|
|
}
|
|
|
|
DataLayoutSpecInterface ModuleOp::getDataLayoutSpec() {
|
|
// Take the first and only (if present) attribute that implements the
|
|
// interface. This needs a linear search, but is called only once per data
|
|
// layout object construction that is used for repeated queries.
|
|
for (NamedAttribute attr : getOperation()->getAttrs())
|
|
if (auto spec = llvm::dyn_cast<DataLayoutSpecInterface>(attr.getValue()))
|
|
return spec;
|
|
return {};
|
|
}
|
|
|
|
TargetSystemSpecInterface ModuleOp::getTargetSystemSpec() {
|
|
// Take the first and only (if present) attribute that implements the
|
|
// interface. This needs a linear search, but is called only once per data
|
|
// layout object construction that is used for repeated queries.
|
|
for (NamedAttribute attr : getOperation()->getAttrs())
|
|
if (auto spec = llvm::dyn_cast<TargetSystemSpecInterface>(attr.getValue()))
|
|
return spec;
|
|
return {};
|
|
}
|
|
|
|
LogicalResult ModuleOp::verify() {
|
|
// Check that none of the attributes are non-dialect attributes, except for
|
|
// the symbol related attributes.
|
|
for (auto attr : (*this)->getAttrs()) {
|
|
if (!attr.getName().strref().contains('.') &&
|
|
!llvm::is_contained(
|
|
ArrayRef<StringRef>{mlir::SymbolTable::getSymbolAttrName(),
|
|
mlir::SymbolTable::getVisibilityAttrName()},
|
|
attr.getName().strref()))
|
|
return emitOpError() << "can only contain attributes with "
|
|
"dialect-prefixed names, found: '"
|
|
<< attr.getName().getValue() << "'";
|
|
}
|
|
|
|
// Check that there is at most one data layout spec attribute.
|
|
StringRef layoutSpecAttrName;
|
|
DataLayoutSpecInterface layoutSpec;
|
|
for (const NamedAttribute &na : (*this)->getAttrs()) {
|
|
if (auto spec = llvm::dyn_cast<DataLayoutSpecInterface>(na.getValue())) {
|
|
if (layoutSpec) {
|
|
InFlightDiagnostic diag =
|
|
emitOpError() << "expects at most one data layout attribute";
|
|
diag.attachNote() << "'" << layoutSpecAttrName
|
|
<< "' is a data layout attribute";
|
|
diag.attachNote() << "'" << na.getName().getValue()
|
|
<< "' is a data layout attribute";
|
|
}
|
|
layoutSpecAttrName = na.getName().strref();
|
|
layoutSpec = spec;
|
|
}
|
|
}
|
|
|
|
return success();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// UnrealizedConversionCastOp
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
LogicalResult
|
|
UnrealizedConversionCastOp::fold(FoldAdaptor adaptor,
|
|
SmallVectorImpl<OpFoldResult> &foldResults) {
|
|
OperandRange operands = getInputs();
|
|
ResultRange results = getOutputs();
|
|
|
|
if (operands.getType() == results.getType()) {
|
|
foldResults.append(operands.begin(), operands.end());
|
|
return success();
|
|
}
|
|
|
|
if (operands.empty())
|
|
return failure();
|
|
|
|
// Check that the input is a cast with results that all feed into this
|
|
// operation, and operand types that directly match the result types of this
|
|
// operation.
|
|
Value firstInput = operands.front();
|
|
auto inputOp = firstInput.getDefiningOp<UnrealizedConversionCastOp>();
|
|
if (!inputOp || inputOp.getResults() != operands ||
|
|
inputOp.getOperandTypes() != results.getTypes())
|
|
return failure();
|
|
|
|
// If everything matches up, we can fold the passthrough.
|
|
foldResults.append(inputOp->operand_begin(), inputOp->operand_end());
|
|
return success();
|
|
}
|
|
|
|
LogicalResult UnrealizedConversionCastOp::verify() {
|
|
// TODO: The verifier of external models is not called. This op verifier can
|
|
// be removed when that is fixed.
|
|
if (getNumResults() == 0)
|
|
return emitOpError() << "expected at least one result for cast operation";
|
|
return success();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// TableGen'd op method definitions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define GET_OP_CLASSES
|
|
#include "mlir/IR/BuiltinOps.cpp.inc"
|