430 lines
19 KiB
C++
430 lines
19 KiB
C++
/*===- 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<typename ConcreteOp>
|
|
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<typename ConcreteOp>
|
|
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<typename ConcreteModel, typename ConcreteOp>
|
|
class ExternalModel : public FallbackModel<ConcreteModel> {
|
|
public:
|
|
using ConcreteEntity = ConcreteOp;
|
|
};
|
|
};
|
|
template <typename ConcreteOp>
|
|
struct DestinationStyleOpInterfaceTrait;
|
|
|
|
} // namespace detail
|
|
class DestinationStyleOpInterface : public ::mlir::OpInterface<DestinationStyleOpInterface, detail::DestinationStyleOpInterfaceInterfaceTraits> {
|
|
public:
|
|
using ::mlir::OpInterface<DestinationStyleOpInterface, detail::DestinationStyleOpInterfaceInterfaceTraits>::OpInterface;
|
|
template <typename ConcreteOp>
|
|
struct Trait : public detail::DestinationStyleOpInterfaceTrait<ConcreteOp> {};
|
|
|
|
/// 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<BaseMemRefType, TensorType>(
|
|
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 <typename ConcreteOp>
|
|
struct DestinationStyleOpInterfaceTrait : public ::mlir::OpInterface<DestinationStyleOpInterface, detail::DestinationStyleOpInterfaceInterfaceTraits>::Trait<ConcreteOp> {
|
|
static ::llvm::LogicalResult verifyRegionTrait(::mlir::Operation *op) {
|
|
return detail::verifyDestinationStyleOpInterface(op);
|
|
}
|
|
|
|
::mlir::OperandRange getDpsInits() {
|
|
return (*static_cast<ConcreteOp *>(this)).getDpsInitsMutable();
|
|
}
|
|
|
|
/// Return the number of DPS inits.
|
|
int64_t getNumDpsInits() { return (*static_cast<ConcreteOp *>(this)).getDpsInits().size(); }
|
|
|
|
/// Return the `i`-th DPS init.
|
|
::mlir::OpOperand *getDpsInitOperand(int64_t i) {
|
|
return &(*static_cast<ConcreteOp *>(this)).getDpsInitsMutable()[i];
|
|
}
|
|
|
|
/// Set the `i`-th DPS init.
|
|
void setDpsInitOperand(int64_t i, Value value) {
|
|
assert(i >= 0 && i < (*static_cast<ConcreteOp *>(this)).getNumDpsInits() && "invalid index");
|
|
(*static_cast<ConcreteOp *>(this))->setOperand((*static_cast<ConcreteOp *>(this)).getDpsInits().getBeginOperandIndex() + i, value);
|
|
}
|
|
|
|
/// Return the number of DPS inputs.
|
|
int64_t getNumDpsInputs() {
|
|
return (*static_cast<ConcreteOp *>(this))->getNumOperands() - (*static_cast<ConcreteOp *>(this)).getNumDpsInits();
|
|
}
|
|
|
|
/// Return the DPS input operands.
|
|
::llvm::SmallVector<::mlir::OpOperand *> getDpsInputOperands() {
|
|
::llvm::SmallVector<::mlir::OpOperand *> result;
|
|
int64_t numOperands = (*static_cast<ConcreteOp *>(this))->getNumOperands();
|
|
::mlir::OperandRange range = (*static_cast<ConcreteOp *>(this)).getDpsInits();
|
|
if (range.empty()) {
|
|
result.reserve(numOperands);
|
|
for (int64_t i = 0; i < numOperands; ++i)
|
|
result.push_back(&(*static_cast<ConcreteOp *>(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<ConcreteOp *>(this))->getOpOperand(i));
|
|
for (int64_t i = firstInitPos + numInits; i < numOperands; ++i)
|
|
result.push_back(&(*static_cast<ConcreteOp *>(this))->getOpOperand(i));
|
|
return result;
|
|
}
|
|
|
|
/// Return the DPS input operands.
|
|
::llvm::SmallVector<::mlir::Value> getDpsInputs() {
|
|
return ::llvm::to_vector(::llvm::map_range(
|
|
(*static_cast<ConcreteOp *>(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<ConcreteOp *>(this)).getDpsInits();
|
|
if (range.empty())
|
|
return &(*static_cast<ConcreteOp *>(this))->getOpOperand(i);
|
|
int64_t firstInitPos = range.getBeginOperandIndex();
|
|
int64_t numInits = range.size();
|
|
assert(i >= 0 && i < (*static_cast<ConcreteOp *>(this))->getNumOperands() - numInits
|
|
&& "invalid index");
|
|
return &(*static_cast<ConcreteOp *>(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<ConcreteOp *>(this)) && "invalid operand");
|
|
return !(*static_cast<ConcreteOp *>(this)).isDpsInit(opOperand);
|
|
}
|
|
|
|
/// Return "true" if `opOperand` is an "init".
|
|
bool isDpsInit(::mlir::OpOperand *opOperand) {
|
|
assert(opOperand->getOwner() == (*static_cast<ConcreteOp *>(this)) && "invalid operand");
|
|
::mlir::OperandRange range = (*static_cast<ConcreteOp *>(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<ConcreteOp *>(this)) && "invalid operand");
|
|
return !::llvm::isa<BaseMemRefType, TensorType>(
|
|
opOperand->get().getType());
|
|
}
|
|
|
|
/// Return the OpResult that is tied to the given OpOperand.
|
|
::mlir::OpResult getTiedOpResult(::mlir::OpOperand *opOperand) {
|
|
assert(opOperand->getOwner() == (*static_cast<ConcreteOp *>(this)) && "invalid operand");
|
|
::mlir::OperandRange range = (*static_cast<ConcreteOp *>(this)).getDpsInits();
|
|
assert(!range.empty() && "op has no inits");
|
|
int64_t resultIndex =
|
|
opOperand->getOperandNumber() - range.getBeginOperandIndex();
|
|
assert(resultIndex >= 0 &&
|
|
resultIndex < (*static_cast<ConcreteOp *>(this))->getNumResults());
|
|
return (*static_cast<ConcreteOp *>(this))->getResult(resultIndex);
|
|
}
|
|
|
|
/// Return the OpOperand that is tied to the given OpResult.
|
|
::mlir::OpOperand *getTiedOpOperand(::mlir::OpResult opResult) {
|
|
assert(opResult.getDefiningOp() == (*static_cast<ConcreteOp *>(this)) && "invalid opresult");
|
|
return (*static_cast<ConcreteOp *>(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<ConcreteOp *>(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<ConcreteOp *>(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<ConcreteOp *>(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<ConcreteOp *>(this))->getOperands(), isTensor); }
|
|
|
|
};
|
|
|
|
} // namespace mlir::detail
|
|
namespace mlir {
|
|
|
|
template<typename ConcreteOp>
|
|
::mlir::MutableOperandRange detail::DestinationStyleOpInterfaceInterfaceTraits::Model<ConcreteOp>::getDpsInitsMutable(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
|
|
return (llvm::cast<ConcreteOp>(tablegen_opaque_val)).getDpsInitsMutable();
|
|
}
|
|
template<typename ConcreteOp>
|
|
::mlir::MutableOperandRange detail::DestinationStyleOpInterfaceInterfaceTraits::FallbackModel<ConcreteOp>::getDpsInitsMutable(const Concept *impl, ::mlir::Operation *tablegen_opaque_val) {
|
|
return static_cast<const ConcreteOp *>(impl)->getDpsInitsMutable(tablegen_opaque_val);
|
|
}
|
|
|
|
} // namespace mlir
|