| // 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/StreamExternalModels.h" |
| |
| #include "iree/compiler/Dialect/Flow/IR/FlowDialect.h" |
| #include "iree/compiler/Dialect/Flow/IR/FlowOps.h" |
| #include "iree/compiler/Dialect/HAL/IR/HALDialect.h" |
| #include "iree/compiler/Dialect/HAL/IR/HALOps.h" |
| #include "iree/compiler/Dialect/Stream/IR/StreamTypes.h" |
| #include "iree/compiler/Dialect/Util/IR/UtilDialect.h" |
| #include "iree/compiler/Dialect/Util/IR/UtilOps.h" |
| |
| namespace mlir::iree_compiler { |
| |
| namespace { |
| |
| template <typename OpT> |
| struct PreferCloneToConsumersStreamableOpExternalModel |
| : IREE::Stream::StreamableOpInterface::ExternalModel< |
| PreferCloneToConsumersStreamableOpExternalModel<OpT>, OpT> { |
| static void add(MLIRContext *context) { |
| OpT::template attachInterface< |
| PreferCloneToConsumersStreamableOpExternalModel<OpT>>(*context); |
| } |
| |
| bool preferCloneToConsumers(Operation *op) const { return true; } |
| }; |
| |
| struct FlowDispatchStreamableOpExternalModel |
| : IREE::Stream::StreamableOpInterface::ExternalModel< |
| FlowDispatchStreamableOpExternalModel, IREE::Flow::DispatchOp> { |
| static void add(MLIRContext *context) { |
| IREE::Flow::DispatchOp::attachInterface< |
| FlowDispatchStreamableOpExternalModel>(*context); |
| } |
| |
| bool preferCloneToConsumers(Operation *op) const { |
| // If the dispatch does not consume any resources then it is effectively a |
| // slow splat and should be treated like one. |
| const bool consumesAny = llvm::any_of( |
| op->getOperandTypes(), +[](Type type) { |
| return isa<IREE::Stream::AffinityTypeInterface>(type); |
| }); |
| return !consumesAny; |
| } |
| }; |
| |
| template <typename OpT> |
| struct OptionalOpAffinityAttrExternalModel |
| : IREE::Stream::AffinityOpInterface::ExternalModel< |
| OptionalOpAffinityAttrExternalModel<OpT>, OpT> { |
| static void add(MLIRContext *context) { |
| OpT::template attachInterface<OptionalOpAffinityAttrExternalModel<OpT>>( |
| *context); |
| } |
| |
| // Affinity only required for results that hold resources that |
| // require placement. |
| bool requiresAffinity(Operation *op) const { |
| auto resultType = cast<OpT>(op).getResult().getType(); |
| return isa<TensorType>(resultType); |
| } |
| |
| IREE::Stream::AffinityAttr getAffinityAttr(Operation *op) const { |
| return op->getAttrOfType<IREE::Stream::AffinityAttr>("stream.affinity"); |
| } |
| |
| void setAffinityAttr(Operation *op, IREE::Stream::AffinityAttr value) const { |
| if (value) { |
| op->setAttr("stream.affinity", value); |
| } else { |
| op->removeAttr("stream.affinity"); |
| } |
| } |
| |
| IREE::Stream::AffinityAttr getResultAffinityAttr(Operation *op) const { |
| return getAffinityAttr(op); |
| } |
| |
| void removeAffinityAttrs(Operation *op) const { |
| op->removeAttr("stream.affinity"); |
| } |
| }; |
| |
| struct FlowBarrierTargetAffinityAttrExternalModel |
| : IREE::Stream::AffinityOpInterface::ExternalModel< |
| FlowBarrierTargetAffinityAttrExternalModel, |
| IREE::Flow::TensorBarrierOp> { |
| static void add(MLIRContext *context) { |
| IREE::Flow::TensorBarrierOp::attachInterface< |
| FlowBarrierTargetAffinityAttrExternalModel>(*context); |
| } |
| |
| bool requiresAffinity(Operation *op) const { return true; } |
| |
| bool pinsValueAffinity(Operation *op) const { |
| return op->hasAttrOfType<IREE::Stream::AffinityAttr>("target"); |
| } |
| |
| IREE::Stream::AffinityAttr getAffinityAttr(Operation *op) const { |
| return op->getAttrOfType<IREE::Stream::AffinityAttr>("target"); |
| } |
| |
| void setAffinityAttr(Operation *op, IREE::Stream::AffinityAttr value) const { |
| op->setAttr("target", value); |
| } |
| |
| IREE::Stream::AffinityAttr getResultAffinityAttr(Operation *op) const { |
| return getAffinityAttr(op); |
| } |
| |
| void removeAffinityAttrs(Operation *op) const { op->removeAttr("target"); } |
| }; |
| |
| struct FlowTransferTargetAffinityAttrExternalModel |
| : IREE::Stream::AffinityOpInterface::ExternalModel< |
| FlowTransferTargetAffinityAttrExternalModel, |
| IREE::Flow::TensorTransferOp> { |
| static void add(MLIRContext *context) { |
| IREE::Flow::TensorTransferOp::attachInterface< |
| FlowTransferTargetAffinityAttrExternalModel>(*context); |
| } |
| |
| bool requiresAffinity(Operation *op) const { return true; } |
| |
| IREE::Stream::AffinityAttr getAffinityAttr(Operation *op) const { |
| return op->getAttrOfType<IREE::Stream::AffinityAttr>("target"); |
| } |
| |
| void setAffinityAttr(Operation *op, IREE::Stream::AffinityAttr value) const { |
| op->setAttr("target", value); |
| } |
| |
| IREE::Stream::AffinityAttr getResultAffinityAttr(Operation *op) const { |
| return getAffinityAttr(op); |
| } |
| |
| void removeAffinityAttrs(Operation *op) const { op->removeAttr("target"); } |
| }; |
| |
| template <typename OpT> |
| struct HALTensorAffinityAttrExternalModel |
| : IREE::Stream::AffinityOpInterface::ExternalModel< |
| HALTensorAffinityAttrExternalModel<OpT>, OpT> { |
| static void add(MLIRContext *context) { |
| OpT::template attachInterface<HALTensorAffinityAttrExternalModel<OpT>>( |
| *context); |
| } |
| |
| bool requiresAffinity(Operation *op) const { return false; } |
| |
| bool pinsValueAffinity(Operation *op) const { |
| return op->hasAttrOfType<IREE::Stream::AffinityAttr>("affinity"); |
| } |
| |
| IREE::Stream::AffinityAttr getAffinityAttr(Operation *op) const { |
| return op->getAttrOfType<IREE::Stream::AffinityAttr>("affinity"); |
| } |
| |
| void setAffinityAttr(Operation *op, IREE::Stream::AffinityAttr value) const { |
| if (value) { |
| op->setAttr("affinity", value); |
| } else { |
| op->removeAttr("affinity"); |
| } |
| } |
| |
| IREE::Stream::AffinityAttr getResultAffinityAttr(Operation *op) const { |
| return getAffinityAttr(op); |
| } |
| |
| void removeAffinityAttrs(Operation *op) const { op->removeAttr("affinity"); } |
| }; |
| |
| template <typename OpT> |
| struct GlobalOpAffinityAttrExternalModel |
| : IREE::Stream::AffinityOpInterface::ExternalModel< |
| GlobalOpAffinityAttrExternalModel<OpT>, OpT> { |
| static void add(MLIRContext *context) { |
| OpT::template attachInterface<GlobalOpAffinityAttrExternalModel<OpT>>( |
| *context); |
| } |
| |
| // Affinity only required for globals that hold resources that require |
| // placement. |
| bool requiresAffinity(Operation *op) const { |
| auto globalType = cast<IREE::Util::GlobalOpInterface>(op).getGlobalType(); |
| return isa<TensorType>(globalType); |
| } |
| |
| IREE::Stream::AffinityAttr getAffinityAttr(Operation *op) const { |
| return op->getAttrOfType<IREE::Stream::AffinityAttr>("stream.affinity"); |
| } |
| |
| void setAffinityAttr(Operation *op, IREE::Stream::AffinityAttr value) const { |
| if (value) { |
| op->setAttr("stream.affinity", value); |
| } else { |
| op->removeAttr("stream.affinity"); |
| } |
| } |
| |
| IREE::Stream::AffinityAttr getResultAffinityAttr(Operation *op) const { |
| return getAffinityAttr(op); |
| } |
| |
| void removeAffinityAttrs(Operation *op) const { |
| op->removeAttr("stream.affinity"); |
| } |
| }; |
| |
| template <typename OpT, bool kRequiresAffinity = true> |
| struct AffinityOpAttrExternalModel |
| : IREE::Stream::AffinityOpInterface::ExternalModel< |
| AffinityOpAttrExternalModel<OpT, kRequiresAffinity>, OpT> { |
| static void add(MLIRContext *context) { |
| OpT::template attachInterface< |
| AffinityOpAttrExternalModel<OpT, kRequiresAffinity>>(*context); |
| } |
| |
| // Most structural ops don't require affinities and after placement we don't |
| // use the affinities even if the ops still exist. |
| bool requiresAffinity(Operation *op) const { return kRequiresAffinity; } |
| |
| IREE::Stream::AffinityAttr getAffinityAttr(Operation *op) const { |
| return op->getAttrOfType<IREE::Stream::AffinityAttr>("stream.affinity"); |
| } |
| |
| void setAffinityAttr(Operation *op, IREE::Stream::AffinityAttr value) const { |
| if (value) { |
| op->setAttr("stream.affinity", value); |
| } else { |
| op->removeAttr("stream.affinity"); |
| } |
| } |
| |
| IREE::Stream::AffinityAttr getResultAffinityAttr(Operation *op) const { |
| return getAffinityAttr(op); |
| } |
| |
| void removeAffinityAttrs(Operation *op) const { |
| op->removeAttr("stream.affinity"); |
| } |
| }; |
| |
| struct TensorAffinityTypeExternalModel |
| : IREE::Stream::AffinityTypeInterface::ExternalModel< |
| TensorAffinityTypeExternalModel, RankedTensorType> { |
| static void add(MLIRContext *context) { |
| RankedTensorType::attachInterface<TensorAffinityTypeExternalModel>( |
| *context); |
| } |
| }; |
| |
| } // namespace |
| |
| void registerStreamExternalModels(DialectRegistry ®istry) { |
| registry.addExtension(+[](MLIRContext *context) { |
| TensorAffinityTypeExternalModel::add(context); |
| }); |
| |
| registry.insert<arith::ArithDialect>(); |
| registry.addExtension( |
| +[](MLIRContext *context, arith::ArithDialect *dialect) { |
| OptionalOpAffinityAttrExternalModel<arith::ConstantOp>::add(context); |
| }); |
| |
| registry.insert<IREE::Flow::FlowDialect>(); |
| registry.addExtension(+[](MLIRContext *context, |
| IREE::Flow::FlowDialect *dialect) { |
| PreferCloneToConsumersStreamableOpExternalModel< |
| IREE::Flow::TensorReshapeOp>::add(context); |
| PreferCloneToConsumersStreamableOpExternalModel< |
| IREE::Flow::TensorAllocaOp>::add(context); |
| PreferCloneToConsumersStreamableOpExternalModel< |
| IREE::Flow::TensorEmptyOp>::add(context); |
| PreferCloneToConsumersStreamableOpExternalModel< |
| IREE::Flow::TensorSplatOp>::add(context); |
| FlowDispatchStreamableOpExternalModel::add(context); |
| |
| FlowBarrierTargetAffinityAttrExternalModel::add(context); |
| FlowTransferTargetAffinityAttrExternalModel::add(context); |
| |
| AffinityOpAttrExternalModel<IREE::Flow::DispatchRegionOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::DispatchWorkgroupsOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::DispatchOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::CallOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorConstantOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorDynamicConstantOp>::add( |
| context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorAllocaOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorEmptyOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorSplatOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorCloneOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorEncodeOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorSliceOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::TensorUpdateOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::ChannelDefaultOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::CollectiveAllGatherOp>::add( |
| context); |
| AffinityOpAttrExternalModel<IREE::Flow::CollectiveAllReduceOp>::add( |
| context); |
| AffinityOpAttrExternalModel<IREE::Flow::CollectiveAllToAllOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Flow::CollectiveReduceScatterOp>::add( |
| context); |
| AffinityOpAttrExternalModel<IREE::Flow::CollectiveSendRecvOp>::add(context); |
| }); |
| |
| registry.insert<IREE::HAL::HALDialect>(); |
| registry.addExtension(+[](MLIRContext *context, |
| IREE::HAL::HALDialect *dialect) { |
| HALTensorAffinityAttrExternalModel<IREE::HAL::TensorImportOp>::add(context); |
| HALTensorAffinityAttrExternalModel<IREE::HAL::TensorExportOp>::add(context); |
| HALTensorAffinityAttrExternalModel<IREE::HAL::TensorAliasOp>::add(context); |
| HALTensorAffinityAttrExternalModel<IREE::HAL::TensorTransientsOp>::add( |
| context); |
| }); |
| |
| registry.insert<IREE::Util::UtilDialect>(); |
| registry.addExtension(+[](MLIRContext *context, |
| IREE::Util::UtilDialect *dialect) { |
| GlobalOpAffinityAttrExternalModel<IREE::Util::GlobalOp>::add(context); |
| AffinityOpAttrExternalModel<IREE::Util::InitializerOp, false>::add(context); |
| AffinityOpAttrExternalModel<IREE::Util::FuncOp, false>::add(context); |
| }); |
| } |
| |
| } // namespace mlir::iree_compiler |