| // Copyright 2024 The IREE Authors |
| // |
| // 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 "iree/compiler/ExternalInterfaces/TensorExtExternalModels.h" |
| |
| #include "iree/compiler/Dialect/Encoding/IR/EncodingTypes.h" |
| #include "iree/compiler/Dialect/TensorExt/IR/TensorExtOps.h" |
| #include "iree/compiler/Dialect/TensorExt/IR/TensorExtTypes.h" |
| #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h" |
| #include "mlir/Dialect/Bufferization/IR/BufferizationTypeInterfaces.h" |
| #include "mlir/Interfaces/ValueBoundsOpInterface.h" |
| |
| namespace mlir::iree_compiler { |
| namespace { |
| |
| //===----------------------------------------------------------------------===// |
| // Op Interfaces |
| //===----------------------------------------------------------------------===// |
| |
| struct DispatchTensorLoadOpInterface |
| : ValueBoundsOpInterface::ExternalModel< |
| DispatchTensorLoadOpInterface, |
| IREE::TensorExt::DispatchTensorLoadOp> { |
| void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim, |
| ValueBoundsConstraintSet &cstr) const { |
| auto loadOp = cast<IREE::TensorExt::DispatchTensorLoadOp>(op); |
| assert(value == loadOp.getResult() && "invalid value"); |
| cstr.bound(value)[dim] == loadOp.getMixedSizes()[dim]; |
| } |
| }; |
| |
| struct WorkloadOrdinalOpInterface |
| : ValueBoundsOpInterface::ExternalModel< |
| WorkloadOrdinalOpInterface, |
| IREE::TensorExt::DispatchWorkloadOrdinalOp> { |
| void populateBoundsForIndexValue(Operation *op, Value value, |
| ValueBoundsConstraintSet &cstr) const { |
| auto ordinalOp = cast<IREE::TensorExt::DispatchWorkloadOrdinalOp>(op); |
| assert(value == ordinalOp.getResult() && "value must be op result"); |
| cstr.bound(value) == ordinalOp.getOperand(); |
| } |
| }; |
| |
| //===----------------------------------------------------------------------===// |
| // Type Interfaces |
| //===----------------------------------------------------------------------===// |
| |
| struct EncodingTypeExternalModel |
| : IREE::Encoding::EncodingTypeInterface::ExternalModel< |
| EncodingTypeExternalModel, IREE::TensorExt::DispatchTensorType> { |
| |
| Type getEncodingType(Type type) const { |
| auto dispatchTensorType = cast<IREE::TensorExt::DispatchTensorType>(type); |
| return dispatchTensorType.getBoundType(); |
| } |
| |
| Type updateEncoding(Type type, Attribute encoding) const { |
| auto dispatchTensorType = cast<IREE::TensorExt::DispatchTensorType>(type); |
| return IREE::TensorExt::DispatchTensorType::get( |
| dispatchTensorType.getAccess(), dispatchTensorType.getShape(), |
| dispatchTensorType.getBoundElementType(), encoding); |
| } |
| }; |
| |
| struct TensorLikeTypeExternalModel |
| : bufferization::TensorLikeType::ExternalModel< |
| TensorLikeTypeExternalModel, IREE::TensorExt::DispatchTensorType> { |
| FailureOr<bufferization::BufferLikeType> getBufferType( |
| Type type, const bufferization::BufferizationOptions &options, |
| llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const { |
| auto dispatchTensorType = cast<IREE::TensorExt::DispatchTensorType>(type); |
| auto tensorType = cast<TensorType>(dispatchTensorType.asRankedTensorType()); |
| auto memSpace = options.defaultMemorySpaceFn( |
| cast<bufferization::TensorLikeType>(tensorType)); |
| if (!memSpace.has_value()) { |
| return emitError() << "could not infer memory space"; |
| } |
| return cast<bufferization::BufferLikeType>( |
| bufferization::getMemRefTypeWithStaticIdentityLayout(tensorType, |
| *memSpace)); |
| } |
| |
| LogicalResult verifyCompatibleBufferType( |
| Type type, bufferization::BufferLikeType bufferType, |
| llvm::function_ref<mlir::InFlightDiagnostic()> emitError) const { |
| auto dispatchTensorType = cast<IREE::TensorExt::DispatchTensorType>(type); |
| assert(isa<BaseMemRefType>(bufferType) && "expected memref type"); |
| auto memrefType = cast<ShapedType>(bufferType); |
| if (dispatchTensorType.getShape() != memrefType.getShape()) { |
| return emitError() << "shapes do not match"; |
| } |
| if (dispatchTensorType.getBoundElementType() != |
| memrefType.getElementType()) { |
| return emitError() << "element types do not match"; |
| } |
| return success(); |
| } |
| }; |
| |
| } // namespace |
| |
| void registerTensorExtExternalModels(DialectRegistry ®istry) { |
| registry.addExtension( |
| +[](MLIRContext *ctx, IREE::TensorExt::IREETensorExtDialect *dialect) { |
| IREE::TensorExt::DispatchTensorLoadOp::attachInterface< |
| DispatchTensorLoadOpInterface>(*ctx); |
| IREE::TensorExt::DispatchWorkloadOrdinalOp::attachInterface< |
| WorkloadOrdinalOpInterface>(*ctx); |
| IREE::TensorExt::DispatchTensorType::attachInterface< |
| EncodingTypeExternalModel, TensorLikeTypeExternalModel>(*ctx); |
| }); |
| } |
| |
| } // namespace mlir::iree_compiler |