blob: 561462c49b5382e8ded62e4bec59302765fffd90 [file] [edit]
// 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 &registry) {
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