/*===- TableGen'erated file -------------------------------------*- C++ -*-===*\ |* *| |* Interface Declarations *| |* *| |* Automatically generated file, do not edit! *| |* *| \*===----------------------------------------------------------------------===*/ namespace mlir { /// Ops that are in destination style have designated "init" operands, which act /// as initial tensor values for the results of the operation or the init /// buffers to which the results of the op will be written. /// /// Init operands must be tensors or memrefs. Input operands can have any type. /// All non-init operands are DPS inputs. /// /// The init operands of this op are specified by the MutableOperandRange that /// the `getDpsInitsMutable` interface methods returns. This implies that the /// init operands must be a consecutive range of operands. /// /// Each tensor init operand is tied to a corresponding tensor OpResult in a /// 1-to-1 fashion. The i-th init tensor is tied to the i-th OpResult. The op /// may not have any additional OpResults. Init operands and their tied /// OpResults have the same type. Dynamic dimension sizes also match at runtime. /// /// Note: This implies that a destination style op without any tensor inits must /// not have any OpResults. /// /// An op has "pure tensor semantics" if it has at least one tensor operand and /// no buffer (memref) operands. It has "pure buffer semantics" if it has at /// least one buffer (memref) operand and no tensor operands. /// /// Destination-passing style abstraction makes certain transformations easier. /// For example, tiling implementation can extract/insert slices from/into the /// destination of an op and use the resulting shaped value as an iter_arg in /// the surrounding loop structure. As another example, bufferization does not /// have to allocate new buffers for destinations (in case of in-place /// bufferization) and can directly reuse the existing destination buffer. /// /// Example of a destination style op: `%r = tensor.insert_slice %t into %d`, /// where `%t` is the single input and `%d` is the single init. `%d` is tied /// to `%r`. /// /// Example of an op that is not in destination style: `%r = tensor.pad %t`. /// This op is not in destination style because `%r` and `%t` have different /// shape. class DestinationStyleOpInterface; } // namespace mlir namespace mlir { /// Ops that are in destination style have designated "init" operands, which act /// as initial tensor values for the results of the operation or the init /// buffers to which the results of the op will be written. /// /// Init operands must be tensors or memrefs. Input operands can have any type. /// All non-init operands are DPS inputs. /// /// The init operands of this op are specified by the MutableOperandRange that /// the `getDpsInitsMutable` interface methods returns. This implies that the /// init operands must be a consecutive range of operands. /// /// Each tensor init operand is tied to a corresponding tensor OpResult in a /// 1-to-1 fashion. The i-th init tensor is tied to the i-th OpResult. The op /// may not have any additional OpResults. Init operands and their tied /// OpResults have the same type. Dynamic dimension sizes also match at runtime. /// /// Note: This implies that a destination style op without any tensor inits must /// not have any OpResults. /// /// An op has "pure tensor semantics" if it has at least one tensor operand and /// no buffer (memref) operands. It has "pure buffer semantics" if it has at /// least one buffer (memref) operand and no tensor operands. /// /// Destination-passing style abstraction makes certain transformations easier. /// For example, tiling implementation can extract/insert slices from/into the /// destination of an op and use the resulting shaped value as an iter_arg in /// the surrounding loop structure. As another example, bufferization does not /// have to allocate new buffers for destinations (in case of in-place /// bufferization) and can directly reuse the existing destination buffer. /// /// Example of a destination style op: `%r = tensor.insert_slice %t into %d`, /// where `%t` is the single input and `%d` is the single init. `%d` is tied /// to `%r`. /// /// Example of an op that is not in destination style: `%r = tensor.pad %t`. /// This op is not in destination style because `%r` and `%t` have different /// shape. namespace detail { struct DestinationStyleOpInterfaceInterfaceTraits { struct Concept { /// The methods defined by the interface. ::mlir::MutableOperandRange (*getDpsInitsMutable)(const Concept *impl, ::mlir::Operation *); }; template class Model : public Concept { public: using Interface = ::mlir::DestinationStyleOpInterface; Model() : Concept{getDpsInitsMutable} {} static inline ::mlir::MutableOperandRange getDpsInitsMutable(const Concept *impl, ::mlir::Operation *tablegen_opaque_val); }; template class FallbackModel : public Concept { public: using Interface = ::mlir::DestinationStyleOpInterface; FallbackModel() : Concept{getDpsInitsMutable} {} static inline ::mlir::MutableOperandRange getDpsInitsMutable(const Concept *impl, ::mlir::Operation *tablegen_opaque_val); }; template class ExternalModel : public FallbackModel { public: using ConcreteEntity = ConcreteOp; }; }; template struct DestinationStyleOpInterfaceTrait; } // namespace detail class DestinationStyleOpInterface : public ::mlir::OpInterface { public: using ::mlir::OpInterface::OpInterface; template struct Trait : public detail::DestinationStyleOpInterfaceTrait {}; /// Return start and end indices of the init operands range. ::mlir::MutableOperandRange getDpsInitsMutable(); ::mlir::OperandRange getDpsInits() { return (*this).getDpsInitsMutable(); } /// Return the number of DPS inits. int64_t getNumDpsInits() { return (*this).getDpsInits().size(); } /// Return the `i`-th DPS init. ::mlir::OpOperand *getDpsInitOperand(int64_t i) { return &(*this).getDpsInitsMutable()[i]; } /// Set the `i`-th DPS init. void setDpsInitOperand(int64_t i, Value value) { assert(i >= 0 && i < (*this).getNumDpsInits() && "invalid index"); (*this)->setOperand((*this).getDpsInits().getBeginOperandIndex() + i, value); } /// Return the number of DPS inputs. int64_t getNumDpsInputs() { return (*this)->getNumOperands() - (*this).getNumDpsInits(); } /// Return the DPS input operands. ::llvm::SmallVector<::mlir::OpOperand *> getDpsInputOperands() { ::llvm::SmallVector<::mlir::OpOperand *> result; int64_t numOperands = (*this)->getNumOperands(); ::mlir::OperandRange range = (*this).getDpsInits(); if (range.empty()) { result.reserve(numOperands); for (int64_t i = 0; i < numOperands; ++i) result.push_back(&(*this)->getOpOperand(i)); return result; } int64_t firstInitPos = range.getBeginOperandIndex(); int64_t numInits = range.size(); result.reserve(numOperands - numInits); for (int64_t i = 0; i < firstInitPos; ++i) result.push_back(&(*this)->getOpOperand(i)); for (int64_t i = firstInitPos + numInits; i < numOperands; ++i) result.push_back(&(*this)->getOpOperand(i)); return result; } /// Return the DPS input operands. ::llvm::SmallVector<::mlir::Value> getDpsInputs() { return ::llvm::to_vector(::llvm::map_range( (*this).getDpsInputOperands(), [](OpOperand *o) { return o->get(); })); } /// Return the `i`-th DPS input operand. ::mlir::OpOperand *getDpsInputOperand(int64_t i) { ::mlir::OperandRange range = (*this).getDpsInits(); if (range.empty()) return &(*this)->getOpOperand(i); int64_t firstInitPos = range.getBeginOperandIndex(); int64_t numInits = range.size(); assert(i >= 0 && i < (*this)->getNumOperands() - numInits && "invalid index"); return &(*this)->getOpOperand( i < firstInitPos ? i : i + firstInitPos + numInits); } /// Return "true" if `opOperand` is an "input". bool isDpsInput(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*this) && "invalid operand"); return !(*this).isDpsInit(opOperand); } /// Return "true" if `opOperand` is an "init". bool isDpsInit(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*this) && "invalid operand"); ::mlir::OperandRange range = (*this).getDpsInits(); if (range.empty()) return false; auto operandNumber = opOperand->getOperandNumber(); return operandNumber >= range.getBeginOperandIndex() && operandNumber < range.getBeginOperandIndex() + range.size(); } /// Return "true" if `opOperand` is a scalar value. A sclar is defined as /// neither a MemRef nor a tensor value. bool isScalar(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*this) && "invalid operand"); return !::llvm::isa( opOperand->get().getType()); } /// Return the OpResult that is tied to the given OpOperand. ::mlir::OpResult getTiedOpResult(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*this) && "invalid operand"); ::mlir::OperandRange range = (*this).getDpsInits(); assert(!range.empty() && "op has no inits"); int64_t resultIndex = opOperand->getOperandNumber() - range.getBeginOperandIndex(); assert(resultIndex >= 0 && resultIndex < (*this)->getNumResults()); return (*this)->getResult(resultIndex); } /// Return the OpOperand that is tied to the given OpResult. ::mlir::OpOperand *getTiedOpOperand(::mlir::OpResult opResult) { assert(opResult.getDefiningOp() == (*this) && "invalid opresult"); return (*this).getDpsInitOperand(opResult.getResultNumber()); } /// Return whether the op has pure buffer semantics. That is the case if the /// op has no tensor operands and at least one memref operand. bool hasPureBufferSemantics() { // No tensors. auto isTensor = [](Value v){ return ::llvm::isa<::mlir::TensorType>(v.getType()); }; if (::llvm::any_of((*this)->getOperands(), isTensor)) return false; // At least one memref. auto isMemref = [](Value v){ return ::llvm::isa<::mlir::BaseMemRefType>(v.getType()); }; return llvm::any_of((*this)->getOperands(), isMemref); } /// Return whether the op has pure tensor semantics. That is the case if the /// op has no memref operands and at least one tensor operand. bool hasPureTensorSemantics() { // No memrefs. auto isMemref = [](Value v){ return ::llvm::isa<::mlir::BaseMemRefType>(v.getType()); }; if (::llvm::any_of((*this)->getOperands(), isMemref)) return false; // At least one tensor. auto isTensor = [](Value v){ return ::llvm::isa<::mlir::TensorType>(v.getType()); }; return llvm::any_of((*this)->getOperands(), isTensor); } }; } // namespace mlir namespace mlir::detail { template struct DestinationStyleOpInterfaceTrait : public ::mlir::OpInterface::Trait { static ::llvm::LogicalResult verifyRegionTrait(::mlir::Operation *op) { return detail::verifyDestinationStyleOpInterface(op); } ::mlir::OperandRange getDpsInits() { return (*static_cast(this)).getDpsInitsMutable(); } /// Return the number of DPS inits. int64_t getNumDpsInits() { return (*static_cast(this)).getDpsInits().size(); } /// Return the `i`-th DPS init. ::mlir::OpOperand *getDpsInitOperand(int64_t i) { return &(*static_cast(this)).getDpsInitsMutable()[i]; } /// Set the `i`-th DPS init. void setDpsInitOperand(int64_t i, Value value) { assert(i >= 0 && i < (*static_cast(this)).getNumDpsInits() && "invalid index"); (*static_cast(this))->setOperand((*static_cast(this)).getDpsInits().getBeginOperandIndex() + i, value); } /// Return the number of DPS inputs. int64_t getNumDpsInputs() { return (*static_cast(this))->getNumOperands() - (*static_cast(this)).getNumDpsInits(); } /// Return the DPS input operands. ::llvm::SmallVector<::mlir::OpOperand *> getDpsInputOperands() { ::llvm::SmallVector<::mlir::OpOperand *> result; int64_t numOperands = (*static_cast(this))->getNumOperands(); ::mlir::OperandRange range = (*static_cast(this)).getDpsInits(); if (range.empty()) { result.reserve(numOperands); for (int64_t i = 0; i < numOperands; ++i) result.push_back(&(*static_cast(this))->getOpOperand(i)); return result; } int64_t firstInitPos = range.getBeginOperandIndex(); int64_t numInits = range.size(); result.reserve(numOperands - numInits); for (int64_t i = 0; i < firstInitPos; ++i) result.push_back(&(*static_cast(this))->getOpOperand(i)); for (int64_t i = firstInitPos + numInits; i < numOperands; ++i) result.push_back(&(*static_cast(this))->getOpOperand(i)); return result; } /// Return the DPS input operands. ::llvm::SmallVector<::mlir::Value> getDpsInputs() { return ::llvm::to_vector(::llvm::map_range( (*static_cast(this)).getDpsInputOperands(), [](OpOperand *o) { return o->get(); })); } /// Return the `i`-th DPS input operand. ::mlir::OpOperand *getDpsInputOperand(int64_t i) { ::mlir::OperandRange range = (*static_cast(this)).getDpsInits(); if (range.empty()) return &(*static_cast(this))->getOpOperand(i); int64_t firstInitPos = range.getBeginOperandIndex(); int64_t numInits = range.size(); assert(i >= 0 && i < (*static_cast(this))->getNumOperands() - numInits && "invalid index"); return &(*static_cast(this))->getOpOperand( i < firstInitPos ? i : i + firstInitPos + numInits); } /// Return "true" if `opOperand` is an "input". bool isDpsInput(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*static_cast(this)) && "invalid operand"); return !(*static_cast(this)).isDpsInit(opOperand); } /// Return "true" if `opOperand` is an "init". bool isDpsInit(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*static_cast(this)) && "invalid operand"); ::mlir::OperandRange range = (*static_cast(this)).getDpsInits(); if (range.empty()) return false; auto operandNumber = opOperand->getOperandNumber(); return operandNumber >= range.getBeginOperandIndex() && operandNumber < range.getBeginOperandIndex() + range.size(); } /// Return "true" if `opOperand` is a scalar value. A sclar is defined as /// neither a MemRef nor a tensor value. bool isScalar(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*static_cast(this)) && "invalid operand"); return !::llvm::isa( opOperand->get().getType()); } /// Return the OpResult that is tied to the given OpOperand. ::mlir::OpResult getTiedOpResult(::mlir::OpOperand *opOperand) { assert(opOperand->getOwner() == (*static_cast(this)) && "invalid operand"); ::mlir::OperandRange range = (*static_cast(this)).getDpsInits(); assert(!range.empty() && "op has no inits"); int64_t resultIndex = opOperand->getOperandNumber() - range.getBeginOperandIndex(); assert(resultIndex >= 0 && resultIndex < (*static_cast(this))->getNumResults()); return (*static_cast(this))->getResult(resultIndex); } /// Return the OpOperand that is tied to the given OpResult. ::mlir::OpOperand *getTiedOpOperand(::mlir::OpResult opResult) { assert(opResult.getDefiningOp() == (*static_cast(this)) && "invalid opresult"); return (*static_cast(this)).getDpsInitOperand(opResult.getResultNumber()); } /// Return whether the op has pure buffer semantics. That is the case if the /// op has no tensor operands and at least one memref operand. bool hasPureBufferSemantics() { // No tensors. auto isTensor = [](Value v){ return ::llvm::isa<::mlir::TensorType>(v.getType()); }; if (::llvm::any_of((*static_cast(this))->getOperands(), isTensor)) return false; // At least one memref. auto isMemref = [](Value v){ return ::llvm::isa<::mlir::BaseMemRefType>(v.getType()); }; return llvm::any_of((*static_cast(this))->getOperands(), isMemref); } /// Return whether the op has pure tensor semantics. That is the case if the /// op has no memref operands and at least one tensor operand. bool hasPureTensorSemantics() { // No memrefs. auto isMemref = [](Value v){ return ::llvm::isa<::mlir::BaseMemRefType>(v.getType()); }; if (::llvm::any_of((*static_cast(this))->getOperands(), isMemref)) return false; // At least one tensor. auto isTensor = [](Value v){ return ::llvm::isa<::mlir::TensorType>(v.getType()); }; return llvm::any_of((*static_cast(this))->getOperands(), isTensor); } }; } // namespace mlir::detail namespace mlir { template ::mlir::MutableOperandRange detail::DestinationStyleOpInterfaceInterfaceTraits::Model::getDpsInitsMutable(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return (llvm::cast(tablegen_opaque_val)).getDpsInitsMutable(); } template ::mlir::MutableOperandRange detail::DestinationStyleOpInterfaceInterfaceTraits::FallbackModel::getDpsInitsMutable(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) { return static_cast(impl)->getDpsInitsMutable(tablegen_opaque_val); } } // namespace mlir