23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/TypeSwitch.h"
29#include "mlir/Dialect/NVGPU/IR/NVGPUDialect.cpp.inc"
31void NVGPUDialect::initialize() {
33#define GET_TYPEDEF_LIST
34#include "mlir/Dialect/NVGPU/IR/NVGPUTypeDefs.cpp.inc"
37#define GET_ATTRDEF_LIST
38#include "mlir/Dialect/NVGPU/IR/NVGPUAttrDefs.cpp.inc"
42#include "mlir/Dialect/NVGPU/IR/NVGPUOps.cpp.inc"
44 declarePromisedInterfaces<memref::IndexedAccessOpInterface, LdMatrixOp>();
45 declarePromisedInterfaces<memref::IndexedMemCopyOpInterface,
49bool NVGPUDialect::isSharedMemoryAddressSpace(
Attribute memorySpace) {
52 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(memorySpace))
53 return intAttr.getValue().getZExtValue() ==
54 NVGPUDialect::kSharedMemoryAddressSpace;
55 if (
auto gpuAttr = llvm::dyn_cast<gpu::AddressSpaceAttr>(memorySpace))
56 return gpuAttr.getValue() == gpu::AddressSpace::Workgroup;
60bool NVGPUDialect::hasSharedMemoryAddressSpace(MemRefType type) {
61 Attribute memorySpace = type.getMemorySpace();
62 return isSharedMemoryAddressSpace(memorySpace);
69LogicalResult DeviceAsyncCopyOp::verify() {
70 auto srcMemref = llvm::cast<MemRefType>(getSrc().
getType());
71 auto dstMemref = llvm::cast<MemRefType>(getDst().
getType());
73 if (!srcMemref.isLastDimUnitStride())
74 return emitError(
"source memref most minor dim must have unit stride");
75 if (!dstMemref.isLastDimUnitStride())
76 return emitError(
"destination memref most minor dim must have unit stride");
77 if (!NVGPUDialect::hasSharedMemoryAddressSpace(dstMemref))
79 <<
"destination memref must have a memory space attribute of "
81 << NVGPUDialect::kSharedMemoryAddressSpace
82 <<
") or gpu::AddressSpaceAttr(Workgroup)";
83 if (dstMemref.getElementType() != srcMemref.getElementType())
84 return emitError(
"source and destination must have the same element type");
85 if (
size_t(srcMemref.getRank()) != getSrcIndices().size())
86 return emitOpError() <<
"expected " << srcMemref.getRank()
87 <<
" source indices, got " << getSrcIndices().size();
88 if (
size_t(dstMemref.getRank()) != getDstIndices().size())
89 return emitOpError() <<
"expected " << dstMemref.getRank()
90 <<
" destination indices, got "
91 << getDstIndices().size();
92 int64_t dstElements = getDstElements().getZExtValue();
93 int64_t sizeInBytes = (dstMemref.getElementTypeBitWidth() * dstElements) / 8;
94 if (sizeInBytes != 4 && sizeInBytes != 8 && sizeInBytes != 16) {
95 unsigned dstWidth = dstMemref.getElementTypeBitWidth();
97 diag <<
"Requested copy elements is " << dstElements <<
" with width "
98 << dstMemref.getElementTypeBitWidth()
99 <<
". But copy elements could be one of ";
100 if ((32 / dstWidth) > 0)
101 diag << (32 / dstWidth) <<
", ";
102 if ((64 / dstWidth) > 0)
103 diag << (64 / dstWidth) <<
", ";
104 if ((128 / dstWidth) > 0)
105 diag << (128 / dstWidth) <<
".";
108 if (getBypassL1().has_value()) {
109 int64_t req = 16 * 8 / dstMemref.getElementTypeBitWidth();
110 if (getBypassL1().value() && sizeInBytes != 16) {
111 return emitOpError() <<
"bypassL1 does not satify alignment for "
112 << dstMemref <<
" with destination element "
114 <<
". Unset bypassL1, or set "
115 "destination element to "
128 build(odsBuilder, odsState, matrixC.
getType(), matrixA, matrixB, matrixC,
129 mmaShape, UnitAttr());
136 build(odsBuilder, odsState, matrixC.
getType(), matrixA, matrixB, matrixC,
138 tf32Enabled ? odsBuilder.
getUnitAttr() : UnitAttr());
146 const std::array<int64_t, 3> &mmaShape,
147 bool tf32Enabled,
bool sparse =
false) {
165 auto aVector = matrixA.getType();
166 auto bVector = matrixB.getType();
167 auto cVector = matrixC.getType();
175 Type aType = aVector.getElementType();
178 if (sparse && aType.
isF64())
179 return op->
emitError() <<
"f64 is not supported for sparse mode";
191 shapeK = 128 / operandBitwidth;
193 numElementA = 32 / operandBitwidth;
194 numElementB = 32 / operandBitwidth;
197 <<
"expected input data type (i4,i8,f16,bf16,tf32,f64,"
198 "f8E4M3FN,f8E5M2) supported by "
206 if (aShape.size() != 2) {
207 return op->
emitError() <<
"matrixA must be 2 dimensional vector";
210 if (bShape.size() != 2) {
211 return op->
emitError() <<
"matrixB must be 2 dimensional vector";
214 if (cShape.size() != 2) {
215 return op->
emitError() <<
"matrixC must be 2 dimensional vector";
218 auto [m, n, k] = mmaShape;
221 int64_t sparseFactor = sparse ? 2 : 1;
222 if (aShape[0] * aShape[1] *
kWarpSize != m * k / sparseFactor)
224 <<
"expected " << m * k <<
" warp-wide matrix A elements";
227 if (bShape[0] * bShape[1] *
kWarpSize != k * n)
229 <<
"expected " << k * n <<
" warp-wide matrix B elements";
232 if (cShape[0] * cShape[1] *
kWarpSize != m * n)
234 <<
"expected " << m * n <<
" warp-wide matrix C elements";
237 if (tf32Enabled && !(aType.
isF32()))
239 <<
"expected tf32 tensor cores only for F32 operands";
251 if ((aShape[0] != mTile * kTile / (sparse ? 2 : 1)) ||
252 (aShape[1] != numElementA))
253 return op->
emitOpError() <<
"expected matrix A to be shaped ("
254 << mTile * kTile <<
" x " << numElementA <<
")";
257 if ((bShape[0] != kTile * nTile) || (bShape[1] != numElementB))
258 return op->
emitOpError() <<
"expected matrix B to be shaped ("
259 << kTile * nTile <<
" x " << numElementB <<
")";
262 if ((cShape[0] != mTile * nTile) || (cShape[1] != numElementC))
263 return op->
emitOpError() <<
"expected matrix C to be shaped ("
264 << mTile * nTile <<
" x " << numElementC <<
")";
269LogicalResult MmaSyncOp::verify() {
270 if (getMmaShape().size() != 3)
271 return emitOpError() <<
"mmaShape must have exactly 3 elements";
273 return verifyMmaSyncOp(this->getOperation(), getMatrixA(), getMatrixB(),
274 getMatrixC(), getMmaShapeAsArray(),
275 getOperation()->hasAttr(getTf32EnabledAttrName()));
285 build(odsBuilder, odsState, matrixC.
getType(), matrixA, matrixB, matrixC,
289LogicalResult MmaSparseSyncOp::verify() {
290 unsigned sparsitySelector = getSparsitySelector();
291 if (sparsitySelector > 1)
292 return emitOpError() <<
"sparsity selector should be 0 or 1";
294 if (getMmaShape().size() != 3)
295 return emitOpError() <<
"mmaShape must have exactly 3 elements";
297 return verifyMmaSyncOp(this->getOperation(), getMatrixA(), getMatrixB(),
298 getMatrixC(), getMmaShapeAsArray(),
299 getOperation()->hasAttr(getTf32EnabledAttrName()),
306LogicalResult LdMatrixOp::verify() {
308 auto srcMemref = llvm::cast<MemRefType>(getSrcMemref().
getType());
311 auto resVector = llvm::cast<VectorType>(getRes().
getType());
315 Type resType = resVector.getElementType();
319 int64_t numElementsPer32b = 32 / elementBitWidth;
322 int64_t numTiles = getNumTiles();
325 bool isTranspose = getTranspose();
331 if (!NVGPUDialect::hasSharedMemoryAddressSpace(srcMemref))
333 <<
"expected nvgpu.ldmatrix srcMemref must have a memory space "
334 "attribute of IntegerAttr("
335 << NVGPUDialect::kSharedMemoryAddressSpace
336 <<
") or gpu::AddressSpaceAttr(Workgroup)";
337 if (elementBitWidth > 32)
338 return emitError() <<
"nvgpu.ldmatrix works for 32b or lower";
339 if (isTranspose && !(elementBitWidth == 16))
341 <<
"nvgpu.ldmatrix transpose works only at 16b granularity";
342 if (resShape.size() != 2) {
343 return emitError() <<
"results must be 2 dimensional vector";
345 if (!(resShape[1] == numElementsPer32b))
346 return emitError() <<
"expected vector register shape[1] = "
347 << numElementsPer32b;
348 if (!(resShape[0] == numTiles))
350 <<
"expected vector register shape[0] and numTiles to match";
361 case TensorMapSwizzleKind::SWIZZLE_32B:
363 case TensorMapSwizzleKind::SWIZZLE_64B:
365 case TensorMapSwizzleKind::SWIZZLE_128B:
373 Operation *op, TensorMapDescriptorType descType,
374 std::optional<MemRefType> memrefType = std::nullopt) {
375 MemRefType descMemref = descType.getTensor();
377 if (descType.getInterleave() != TensorMapInterleaveKind::INTERLEAVE_NONE)
378 return op->
emitError() <<
"Interleave options are not supported yet.";
381 if (!NVGPUDialect::hasSharedMemoryAddressSpace(descMemref)) {
382 return op->
emitError() <<
"the tensor map descriptor has incorrect address "
383 "space, it must be shared memory address space.";
386 if (!descMemref.hasStaticShape())
387 return op->
emitError() <<
"the tensor map descriptor must be static shaped";
389 for (
auto dim : descMemref.getShape()) {
391 return op->
emitError() <<
"the tensor map descriptor must have "
392 "dimensions between 1 and "
396 if (descMemref.getRank() > 1 &&
397 descType.getSwizzle() != TensorMapSwizzleKind::SWIZZLE_NONE) {
398 unsigned lastDimensionByte =
399 descMemref.getElementTypeBitWidth() * descMemref.getShape().back() / 8;
401 if (lastDimensionByte != expectByte)
402 return op->
emitError() <<
"the tensormap descriptor must have last "
404 << expectByte <<
" bytes but it is "
405 << lastDimensionByte <<
" bytes";
409 if (!memrefType.has_value())
412 MemRefType dstMemref = memrefType.value();
415 if (descMemref.getElementType() != dstMemref.getElementType()) {
416 return op->
emitError() <<
"the element type of tensor map descriptor and "
417 "memref must be same";
420 if (!NVGPUDialect::hasSharedMemoryAddressSpace(dstMemref)) {
421 return op->
emitError() <<
"the destination memref has incorrect address "
422 "space, it must be shared memory address space.";
424 if (!dstMemref.hasStaticShape())
425 return op->
emitError() <<
"the destination memref must be static shaped";
427 if (dstMemref.getRank() != descMemref.getRank()) {
428 return op->
emitError() <<
"the shape of tensor map descriptor and "
429 "memref must have same rank";
431 if (!descMemref.getShape().equals(dstMemref.getShape())) {
432 return op->
emitError() <<
"memref and tensor map shapes mismatch "
433 << descMemref <<
" != " << dstMemref;
437 descMemref.getShape().back() * descMemref.getElementTypeBitWidth() / 8;
439 return op->
emitError() <<
"the bytes in the last dimension of the tensor "
440 "map must be a multiple of 16";
445LogicalResult TmaAsyncLoadOp::verify() {
448 if (error.has_value())
449 return error.value();
453 <<
" coordinates are supported.";
456 size_t(getTensorMapDescriptor().
getType().getTensor().getRank())) {
457 return emitError() <<
"number of coordinates do not match with the rank of "
458 "tensor descriptor map.";
468LogicalResult TmaAsyncStoreOp::verify() {
471 if (error.has_value())
472 return error.value();
476 <<
" coordinates are supported.";
479 size_t(getTensorMapDescriptor().
getType().getTensor().getRank())) {
480 return emitError() <<
"number of coordinates do not match with the rank of "
481 "tensor descriptor map.";
487LogicalResult TmaCreateDescriptorOp::verify() {
490 <<
" coordinates are supported.";
493 std::optional<InFlightDiagnostic> error =
495 if (error.has_value())
496 return error.value();
505LogicalResult WarpgroupGenerateDescriptorOp::verify() {
506 std::optional<InFlightDiagnostic> error =
508 if (error.has_value())
509 return error.value();
511 if (getTensorMap().
getType().getSwizzle() !=
512 TensorMapSwizzleKind::SWIZZLE_128B) {
514 << stringifyTensorMapSwizzleKind(
515 TensorMapSwizzleKind::SWIZZLE_128B)
516 <<
" is supported for the time being";
519 if (getTensorMap().
getType().getInterleave() !=
520 TensorMapInterleaveKind::INTERLEAVE_NONE) {
522 << stringifyTensorMapInterleaveKind(
523 TensorMapInterleaveKind::INTERLEAVE_NONE)
524 <<
" is supported for the time being";
554 if (isa<Float8E5M2Type, Float8E4M3FNType>(typeA) &&
555 isa<Float8E5M2Type, Float8E4M3FNType>(typeB) &&
570 72, 80, 88, 96, 104, 112, 120, 128,
571 136, 144, 152, 160, 168, 176, 184, 192,
572 200, 208, 216, 224, 232, 240, 248, 256};
574 80, 96, 112, 128, 144, 160,
575 176, 192, 208, 224, 240, 256};
577 isa<Float8E5M2Type, Float8E4M3FNType>(typeA))
578 if (llvm::is_contained(allowedN, sizeN))
582 if (llvm::is_contained(allowedNshort, sizeN))
587LogicalResult WarpgroupMmaOp::verify() {
588 if (getTransposeA() && !getTransposeB())
590 <<
"supports non-transpose A (Row Major) "
591 "and transpose B (Column Major) for the time being ";
592 MemRefType matrixA = getDescriptorA().
getType().getTensor();
593 MemRefType matrixB = getDescriptorB().
getType().getTensor();
594 VectorType matrixC = getMatrixC().
getType().getFragmented();
595 VectorType matrixD = getMatrixD().getType().getFragmented();
597 if (matrixC != matrixD)
598 return emitOpError() <<
"type of matrix C and matrix D must be the same";
600 if (matrixA.getRank() != 2 || matrixB.getRank() != 2 ||
601 matrixC.getRank() != 2 || matrixD.getRank() != 2) {
603 <<
"has matrices A, B, C and D, they must be 2 dimensional";
606 if (matrixA.getShape()[1] != matrixB.getShape()[0])
607 return emitOpError() <<
"2nd dim matrix-A (" << matrixA.getShape()[1]
608 <<
")!= 1st dim matrix-B (" << matrixB.getShape()[0]
610 if (matrixA.getShape()[0] != matrixC.getShape()[0])
611 return emitOpError() <<
"1st dim matrix-A ( " << matrixA.getShape()[0]
612 <<
" )!= 1st dim matrix-C ( " << matrixC.getShape()[0]
614 if (matrixB.getShape()[1] != matrixC.getShape()[1])
615 return emitOpError() <<
"2nd dim matrix-B ( " << matrixB.getShape()[1]
616 <<
" ) != 2nd dim matrix-C ( " << matrixC.getShape()[1]
620 matrixA.getElementType(),
621 matrixB.getElementType())))
623 <<
" += " << matrixA.getElementType() <<
" * "
624 << matrixB.getElementType()
625 <<
", it is not supported.";
628 return emitOpError() <<
"has input type " << matrixB <<
" n is set to "
629 << matrixB.getDimSize(1) <<
", it is not supported";
633 if (!matrixC.getElementType().isF32() && !matrixA.getElementType().isF16() &&
634 !matrixA.getElementType().isBF16()) {
635 return emitOpError() <<
"hit a limitation: " << matrixC.getElementType()
636 <<
" += " << matrixA.getElementType() <<
" * "
637 << matrixB.getElementType()
638 <<
", it is not supported yet";
644LogicalResult WarpgroupMmaStoreOp::verify() {
645 MemRefType dstMemrefType = getDstMemref().getType();
646 VectorType vtype = getMatrixD().getType().getFragmented();
649 if (!vtype.getElementType().isF32()) {
651 <<
"hit a limitation: only f32 results for the time being";
653 if (vtype.getDimSize(0) != dstMemrefType.getDimSize(0) ||
654 vtype.getDimSize(1) != dstMemrefType.getDimSize(1)) {
655 return emitOpError() <<
"results [" << vtype <<
"][" << vtype.getDimSize(1)
656 <<
"] values. However, destination memref["
657 << dstMemrefType.getDimSize(0) <<
"]["
658 << dstMemrefType.getDimSize(1)
659 <<
"] does not have same size as results";
668LogicalResult WarpgroupMmaInitAccumulatorOp::verify() {
669 WarpgroupAccumulatorType accType = getMatrixC().getType();
670 int64_t sizeM = accType.getFragmented().getDimSize(0);
671 int64_t sizeN = accType.getFragmented().getDimSize(1);
672 Type elemType = accType.getFragmented().getElementType();
676 return emitOpError() <<
"has type " << accType.getFragmented()
677 <<
". It does not fit into warp-group "
678 "level (wgmma) matrix multiplication instruction "
679 "(or not supported yet)";
688LogicalResult RcpOp::verify() {
690 bool approx = getApprox();
691 mlir::NVVM::FPRoundingModeAttr rnd = getRoundingAttr();
693 if (!approx || !ftz) {
695 <<
"has a limitation. non-approx or non-ftz is not supported yet.";
697 if (rnd.getValue() != mlir::NVVM::FPRoundingMode::NONE) {
698 return emitOpError() <<
"has a limitation. " << rnd
699 <<
" is not supported yet.";
710 bool srcIsVector = llvm::isa<VectorType>(inType);
711 bool dstIsVector = llvm::isa<VectorType>(outType);
712 if (srcIsVector != dstIsVector)
713 return op->
emitOpError(
"input and output must both be scalars or both be "
715 << inType <<
" and " << outType;
717 auto srcVector = llvm::cast<VectorType>(inType);
718 auto dstVector = llvm::cast<VectorType>(outType);
719 if (srcVector.getShape() != dstVector.getShape())
720 return op->
emitOpError(
"input and output shapes must match, got ")
721 << inType <<
" and " << outType;
726LogicalResult TruncfOp::verify() {
727 Type inType = getIn().getType();
739 if (srcBitWidth <= dstBitWidth)
741 << dstType <<
" must be narrower than operand type " << srcType;
743 if (!(srcBitWidth == 64 || srcBitWidth == 32 || srcBitWidth == 16))
744 return emitOpError(
"input type must be 64/32/16 bitwidth, but got ")
747 if (llvm::isa<Float8E8M0FNUType>(dstType)) {
748 if (rnd != mlir::NVVM::FPRoundingMode::RZ &&
749 rnd != mlir::NVVM::FPRoundingMode::RP)
750 return emitOpError(
"expects RZ or RP rounding mode when result type is "
753 }
else if (rnd == mlir::NVVM::FPRoundingMode::RS) {
756 if (!(srcBitWidth == 32 && dstBitWidth == 16))
757 return emitOpError(
"RS (stochastic) rounding is only supported for "
758 "f32->f16/bf16, got ")
759 << srcType <<
" -> " << dstType;
760 if (!getRandomBits())
761 return emitOpError(
"random_bits operand is required with RS rounding");
762 }
else if (srcType.isF64() && dstBitWidth >= 16) {
763 if (rnd != mlir::NVVM::FPRoundingMode::RN)
764 return emitOpError(
"expects RN rounding mode for f64 input, but got ")
766 }
else if (srcBitWidth == 32 && dstBitWidth == 16) {
767 if (rnd != mlir::NVVM::FPRoundingMode::RN &&
768 rnd != mlir::NVVM::FPRoundingMode::RZ)
769 return emitOpError(
"expects RN or RZ rounding mode for f32 to f16/bf16, "
772 }
else if (rnd != mlir::NVVM::FPRoundingMode::RN) {
773 return emitOpError(
"expects RN rounding mode, but got ") << getRndAttr();
776 if (getRandomBits() && rnd != mlir::NVVM::FPRoundingMode::RS)
777 return emitOpError(
"random_bits can only be used with RS rounding mode");
786LogicalResult ExtfOp::verify() {
787 Type inType = getIn().getType();
798 if (srcBitWidth >= dstBitWidth)
800 << dstType <<
" must be wider than operand type " << srcType;
802 if (dstBitWidth != 16 && dstBitWidth != 32 && dstBitWidth != 64)
803 return emitOpError(
"result type must be 16, 32, or 64 bitwidth, but got ")
806 if (llvm::isa<Float8E8M0FNUType>(srcType) &&
807 !llvm::isa<BFloat16Type>(dstType) && !dstType.
isF32())
808 return emitOpError(
"expects bf16 or f32 output type when input type is "
811 if (rnd != mlir::NVVM::FPRoundingMode::RN)
812 return emitOpError(
"expects RN rounding mode, but got ") << getRndAttr();
814 if (getRelu() && llvm::isa<BFloat16Type>(dstType))
815 return emitOpError(
"relu is not supported for bf16 destination");
824#define GET_ATTRDEF_CLASSES
825#include "mlir/Dialect/NVGPU/IR/NVGPUAttrDefs.cpp.inc"
827#include "mlir/Dialect/NVGPU/IR/NVGPUEnums.cpp.inc"
829#define GET_OP_CLASSES
830#include "mlir/Dialect/NVGPU/IR/NVGPUOps.cpp.inc"
832#define GET_TYPEDEF_CLASSES
833#include "mlir/Dialect/NVGPU/IR/NVGPUTypeDefs.cpp.inc"
p<< " : "<< getMemRefType()<< ", "<< getType();}static LogicalResult verifyVectorMemoryOp(Operation *op, MemRefType memrefType, VectorType vectorType) { if(memrefType.getElementType() !=vectorType.getElementType()) return op-> emitOpError("requires memref and vector types of the same elemental type")
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
static std::string diag(const llvm::Value &value)
LogicalResult isAllowedSizeM(int sizeM)
static LogicalResult verifyMmaSyncOp(Operation *op, TypedValue< VectorType > matrixA, TypedValue< VectorType > matrixB, TypedValue< VectorType > matrixC, const std::array< int64_t, 3 > &mmaShape, bool tf32Enabled, bool sparse=false)
Performs verification for MmaSyncOp and MmaSparseSyncOp.
std::optional< InFlightDiagnostic > verifyTmaDescriptorWithMemref(Operation *op, TensorMapDescriptorType descType, std::optional< MemRefType > memrefType=std::nullopt)
LogicalResult isAllowedSizeN(int sizeN, Type typeA)
LogicalResult isAllowedWGMMADataType(Type typeD, Type typeA, Type typeB)
static LogicalResult verifyConversionShapes(Operation *op, Type inType, Type outType)
static unsigned getSwizzleBytes(TensorMapSwizzleKind kind)
constexpr unsigned kTMALastdimByte
The bytes in the last dimension of the tensor map must be a multiple of 16.
constexpr int kWgmmaSizeM
M size of wgmma.mma_async instruction.
constexpr unsigned kMaxTMATensorDimension
Maximum TMA tile dimension (tensorRank) must be non-zero and less than or equal to the maximum suppor...
constexpr unsigned kMaxTMADimension
Maximum TMA tile size (boxDim), which specifies number of elements to be traversed along each of the ...
Attributes are known-constant values of operations.
ArrayAttr getI64ArrayAttr(ArrayRef< int64_t > values)
This class represents a diagnostic that is inflight and set to be reported.
This class helps build Operations.
Operation is the basic unit of execution within MLIR.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
OperationName getName()
The name of an operation is the key identifier for it.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isInteger() const
Return true if this is an integer type (with the specified width).
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
SmallVector< int64_t, 4 > getCoordinates(ArrayRef< int64_t > basis, unsigned linearIndex)
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
This represents an operation in an abstracted form, suitable for use with the builder APIs.