17#include "llvm/Support/Debug.h"
19#define DEBUG_TYPE "xegpu"
25static std::string
makeString(T array,
bool breakline =
false) {
28 llvm::raw_string_ostream os(buf);
30 for (
size_t i = 1; i < array.size(); i++) {
31 os << array[i - 1] <<
", ";
35 os << array.back() <<
"]";
41 if (
auto ty = llvm::dyn_cast<ShapedType>(type))
51 auto kind = attr.getValue();
52 return kind == CachePolicy::CACHED || kind == CachePolicy::UNCACHED ||
53 kind == CachePolicy::STREAMING || kind == CachePolicy::READ_INVALIDATE;
59 auto kind = attr.getValue();
60 return kind == CachePolicy::CACHED || kind == CachePolicy::UNCACHED ||
61 kind == CachePolicy::WRITE_BACK || kind == CachePolicy::WRITE_THROUGH;
66 VectorType valueTy,
int64_t chunkSize,
69 auto maskVecTy = dyn_cast<VectorType>(maskTy);
70 auto offsetsVecTy = dyn_cast<VectorType>(offsetsTy);
73 return emitError() <<
"Expecting chunk size == 1 for scalar result";
74 if (maskVecTy || offsetsVecTy)
75 return emitError() <<
"Expecting scalar mask and offsets.";
76 else if (maskVecTy && offsetsVecTy)
77 return emitError() <<
"Expecting a vector type result.";
81 auto valueSize = valueTy.getNumElements();
83 if (!maskVecTy && !offsetsVecTy) {
84 if (valueSize != chunkSize)
85 return emitError() <<
"value elements must match chunk size "
93 return emitError() <<
"Expecting a vector type mask.";
94 int64_t maskSize = maskVecTy.getNumElements();
97 if ((valueTy.getRank() == 1) && (valueSize != chunkSize))
98 return emitError() <<
"value elements must match chunk size "
101 if (valueSize != maskSize)
103 <<
"Mask should match value except the chunk size dim.";
109 expectedMaskShape.pop_back();
110 if (expectedMaskShape != maskShape)
111 return emitError() <<
"Mask should match value except the chunk size dim.";
124 auto offsetsVecTy = dyn_cast<VectorType>(offsetsTy);
126 return emitError() <<
"contiguity requires vector offsets (one per lane).";
128 int64_t inner = offsetsVecTy.getShape().back();
130 return emitError() <<
"contiguity = " << size <<
" (must be >= 2)";
131 if (inner % size != 0)
132 return emitError() <<
"contiguity = " << size
133 <<
" (must divide the innermost offsets dim " << inner
140 UnitAttr subgroup_block_io, DistributeLayoutAttr layout,
144 if (subgroup_block_io)
145 return emitError() <<
"subgroup_block_io "
146 "are only allowed when result is a VectorType.";
155 ArrayAttr strideAttr = mdescTy.getStrideAttr();
157 for (
Attribute attr : strideAttr.getValue()) {
158 strides.push_back(cast<IntegerAttr>(attr).getInt());
160 if (subgroup_block_io && layout) {
161 auto laneData = layout.getEffectiveLaneDataAsInt();
162 auto laneLayout = layout.getEffectiveLaneLayoutAsInt();
163 if (!laneData.empty()) {
164 bool isLaneDataContiguous =
165 std::all_of(laneData.begin(), std::prev(laneData.end()),
166 [](
int x) { return x == 1; });
167 if (!isLaneDataContiguous)
168 return emitError() <<
"With subgroup_block_io, accessed data must be "
169 "contiguous and coalesced.";
170 for (
size_t i = 0; i < laneData.size(); ++i) {
171 if (laneLayout[i] != blockShape[i])
172 return emitError() <<
"With subgroup_block_io, the block shape must "
173 "match the lane layout.";
174 if (laneLayout[i] != 1 && strides[i] != 1)
175 return emitError() <<
"With subgroup_block_io, the distributed "
176 "dimensions must be contiguous.";
181 if (layout && !layout.isDistributable(
183 return emitError() <<
"Value shape is not distributable with the layout";
185 if (dataShape.size() == mdescShape.size()) {
186 if (llvm::any_of(llvm::zip_equal(dataShape, mdescShape),
187 [](
auto p) {
return std::get<0>(p) > std::get<1>(p); }))
188 return emitError() <<
"data shape must not exceed mem_desc shape.";
192 if (subgroup_block_io && !blockShape.size())
193 return emitError() <<
"mem_desc must have block attribute when "
194 "subgroup_block_io is set.";
204 [[maybe_unused]]
auto ty = source.getType();
205 assert(ty.hasStaticShape() &&
"expecting a memref with static shape");
207 build(builder, state, tdesc, source,
ValueRange({}) ,
218 assert((isa<IntegerType, MemRefType>(srcTy)) &&
219 "Source has to be either int or memref.");
233 if (
auto memrefTy = dyn_cast<MemRefType>(srcTy)) {
234 auto memrefShape = memrefTy.getShape();
235 auto [memrefStrides, _] = memrefTy.getStridesAndOffset();
240 if (staticShape == memrefShape && staticStrides == memrefStrides &&
241 dynamicShape.empty() && dynamicStrides.empty()) {
247 build(builder, state, tdesc, source, dynamicShape, dynamicStrides,
248 staticShapeAttr, staticStridesAttr);
251LogicalResult CreateNdDescOp::verify() {
253 bool invalidRank = rank != getMixedStrides().size();
254 bool invalidElemTy =
false;
260 auto srcMemorySpace = getSourceMemorySpace();
261 auto tdescMemorySpace =
static_cast<unsigned>(
getType().getMemorySpace());
262 if (srcMemorySpace != tdescMemorySpace)
264 <<
" Source: " << srcMemorySpace
265 <<
", TensorDesc: " << tdescMemorySpace;
269 if (
auto memrefTy = dyn_cast<MemRefType>(getSourceType()))
272 if (llvm::isa<IntegerType>(getSourceType())) {
275 return emitOpError(
"expecting strides and shape to be present for "
281 "Expecting the rank of shape, strides, and source (if source "
282 "is a memref) should match with each other.");
286 return emitOpError(
"Expecting the TensorDesc rank is not greater than the "
287 "ranks of shape, strides or the memref source.");
290 return emitOpError(
"TensorDesc should have the same element "
291 "type with the source if it is a memref.\n");
302 xegpu::CachePolicyAttr l1_hint,
303 xegpu::CachePolicyAttr l2_hint,
304 xegpu::CachePolicyAttr l3_hint,
305 xegpu::DistributeLayoutAttr layout) {
312 build(builder, state, tensorDesc, dynamicOffsets, staticOffsetsAttr, l1_hint,
313 l2_hint, l3_hint, layout);
316LogicalResult PrefetchNdOp::verify() {
317 auto tdescTy = getTensorDescType();
320 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
323 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
326 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
328 int64_t tDescRank = tdescTy.getRank();
329 int64_t offsetSize = getMixedOffsets().size();
330 if (offsetSize != tDescRank)
332 "Mismatched ranks between offsets and tensor descriptor");
334 if (
auto layout = getAnchorLayout()) {
335 if (!layout.isDistributable(
getShapeOf(tdescTy)))
337 "TensorDesc shape is not distributable with the layout");
350 xegpu::CachePolicyAttr l1_hint,
351 xegpu::CachePolicyAttr l2_hint,
352 xegpu::CachePolicyAttr l3_hint,
353 xegpu::DistributeLayoutAttr layout) {
360 build(builder, state, retType, tensorDesc, dynamicOffsets, staticOffsetsAttr,
361 packed, transpose, l1_hint, l2_hint, l3_hint,
365LogicalResult LoadNdOp::verify() {
366 auto tdescTy = getTensorDescType();
370 return emitOpError(
"Invalid result, it should be a VectorType.\n");
373 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
376 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
379 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
381 int tdescElems = tdescTy.getNumElements() * tdescTy.getArrayLength();
382 int valueElems = valueTy.getNumElements();
387 if (valueElems < tdescElems && valueTy.getRank() == 1) {
389 if (tdescTy.getLayoutAttr())
391 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
396 if (tdescElems % valueElems)
399 <<
" is not a valid distribution for tensor descriptor "
409 if (getTranspose()) {
410 auto trans = getTranspose().value();
412 if (llvm::all_of(trans, [&](
size_t s) {
return s < tdescShape.size(); }))
419 if (tdescTy.getRank() == 2) {
421 auto vnni_factor = valueShape.back();
422 tdescShape[axis] /= vnni_factor;
423 tdescShape.push_back(vnni_factor);
426 <<
"Invalid Packed Attr. It is ignored (available for 2D "
436 auto array_len = tdescTy.getArrayLength();
439 if (array_len > 1 && !tdescShape.empty()) {
440 stacked2DShape[0] *= array_len;
441 threeDShape.insert(threeDShape.begin(), array_len);
444 if (valueShape != stacked2DShape && valueShape != threeDShape)
446 <<
" is not consistent with tensor descriptor "
449 int64_t tDescRank = tdescTy.getRank();
450 int64_t offsetSize = getMixedOffsets().size();
451 if (offsetSize != tDescRank)
453 "Mismatched ranks between offsets and tensor descriptor");
455 if (
auto layout = getAnchorLayout()) {
456 if (!layout.isDistributable(
getShapeOf(tdescTy)))
458 "TensorDesc shape is not distributable with the layout");
470 xegpu::CachePolicyAttr l1_hint,
471 xegpu::CachePolicyAttr l2_hint,
472 xegpu::CachePolicyAttr l3_hint,
473 xegpu::DistributeLayoutAttr layout) {
480 build(builder, state, value, tensorDesc, dynamicOffsets, staticOffsetsAttr,
481 l1_hint, l2_hint, l3_hint, layout);
484LogicalResult StoreNdOp::verify() {
485 auto dstTy = getTensorDescType();
489 return emitOpError(
"Expecting a VectorType result.\n");
492 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
495 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
498 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
500 auto array_len = dstTy.getArrayLength();
502 return emitOpError(
"array length is not supported by store_nd.\n");
504 auto tdescElems = dstTy.getNumElements();
505 auto valueElems = valTy.getNumElements();
510 if (valTy.getRank() == 1 && valueElems < tdescElems) {
512 if (dstTy.getLayoutAttr())
514 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
516 if (tdescElems % valueElems)
519 <<
" is not a valid distribution for tensor descriptor " << dstTy;
527 if (tdescShape != valueShape)
529 <<
" is not consistent with tensor descriptor "
532 int64_t tDescRank = dstTy.getRank();
533 int64_t offsetSize = getMixedOffsets().size();
534 if (offsetSize != tDescRank)
536 "Mismatched ranks between offsets and tensor descriptor");
538 if (
auto layout = getAnchorLayout()) {
539 if (!layout.isDistributable(tdescShape))
541 "TensorDesc shape is not distributable with the layout");
550LogicalResult PrefetchOp::verify() {
552 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
555 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
558 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
560 auto srcTy = getSourceType();
561 if (srcTy.
isInteger() && !getOffsetAlignByteAttr())
562 return emitOpError(
"offset_align_byte is required with integer source.");
564 if (getOffsetAlignByteAttr() && !srcTy.
isInteger())
565 return emitOpError(
"offset_align_byte only allowed with integer source.");
567 if (
auto layout = getAnchorLayout()) {
569 auto offsetsTy = getOffsets().getType();
570 if (llvm::isa<VectorType>(offsetsTy) &&
571 !layout.isDistributable(
getShapeOf(offsetsTy)))
572 return emitOpError(
"offset shape is not distributable with the layout");
581LogicalResult LoadGatherOp::verify() {
582 auto maskTy = getMaskType();
586 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
589 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
592 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
594 auto srcTy = getSourceType();
595 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
596 auto memTy = dyn_cast<MemRefType>(srcTy);
599 return emitError() <<
"Value should have the same element type as MemRef.";
601 if (
auto layout = getAnchorLayout()) {
602 if (!layout.isDistributable(
getShapeOf(valueTy)))
603 return emitOpError(
"Value shape is not distributable with the layout");
606 auto offsetsTy = getOffsets().getType();
617 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
618 xegpu::CachePolicyAttr l2_hint,
619 xegpu::CachePolicyAttr l3_hint) {
620 auto loc = source.
getLoc();
622 auto type = VectorType::get(size, builder.
getIndexType());
624 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
626 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
627 l2_hint, l3_hint,
nullptr,
634 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
635 xegpu::CachePolicyAttr l2_hint,
636 xegpu::CachePolicyAttr l3_hint,
637 DistributeLayoutAttr layout) {
638 auto loc = source.
getLoc();
640 auto type = VectorType::get(size, builder.
getIndexType());
642 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
644 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
645 l2_hint, l3_hint, layout,
nullptr);
651LogicalResult StoreScatterOp::verify() {
652 auto maskTy = getMaskType();
656 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
659 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
662 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
664 auto destTy = getDestType();
665 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
666 auto memTy = dyn_cast<MemRefType>(destTy);
669 return emitError() <<
"Value should have the same element type as MemRef.";
671 if (
auto layout = getAnchorLayout()) {
672 if (!layout.isDistributable(
getShapeOf(valueTy)))
673 return emitOpError(
"Value shape is not distributable with the layout");
676 auto offsetsTy = getOffsets().getType();
687 IntegerAttr chunk_size,
688 xegpu::CachePolicyAttr l1_hint,
689 xegpu::CachePolicyAttr l2_hint,
690 xegpu::CachePolicyAttr l3_hint) {
693 auto type = VectorType::get(size, builder.
getIndexType());
695 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
698 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
699 l3_hint,
nullptr,
nullptr);
702void StoreScatterOp::build(
705 xegpu::CachePolicyAttr l1_hint, xegpu::CachePolicyAttr l2_hint,
706 xegpu::CachePolicyAttr l3_hint, DistributeLayoutAttr layout) {
709 auto type = VectorType::get(size, builder.
getIndexType());
711 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
714 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
715 l3_hint, layout,
nullptr);
725 std::optional<DistributeLayoutAttr> layout,
727 if (layout && !layout->isDistributable(
730 <<
" shape is not distributable with the layout";
740 auto aRank = aShape.size();
741 auto bRank = bShape.size();
742 auto resRank = resShape.size();
743 if (aRank == 1 && bRank == 1 && resRank == 1)
749 return op->
emitOpError(
"A operand must be at least a 2D vector.");
751 return op->
emitOpError(
"B operand must be at least a 2D vector.");
753 return op->
emitOpError(
"Result must be at least a 2D vector.");
760 if (bRank == aRank + 1)
766 if (aRank != bRank || aRank != resRank)
767 return op->
emitOpError(
"Rank mismatch among A, B, and result.");
772 for (
int64_t i = 0; i < batchRank; ++i) {
773 if (aShape[i] != resShape[i])
774 return op->
emitOpError(
"Batch dimension mismatch at dim ")
775 << i <<
": A has " << aShape[i] <<
" but result has "
776 << resShape[i] <<
".";
777 if (aShape[i] != bShape[i])
778 return op->
emitOpError(
"Batch dimension mismatch at dim ")
779 << i <<
": A has " << aShape[i] <<
" but B has " << bShape[i]
784 int64_t aM = aShape[batchRank];
785 int64_t aK = aShape[batchRank + 1];
786 int64_t bK = bShape[batchRank];
787 int64_t bN = bShape[batchRank + 1];
788 int64_t resM = resShape[batchRank];
789 int64_t resN = resShape[batchRank + 1];
793 return op->
emitOpError(
"K-dimension mismatch: A has K=")
794 << aK <<
" but B has K=" << bK <<
".";
798 return op->
emitOpError(
"M-dimension mismatch: A has M=")
799 << aM <<
" but result has M=" << resM <<
".";
803 return op->
emitOpError(
"N-dimension mismatch: B has N=")
804 << bN <<
" but result has N=" << resN <<
".";
812 if (accType != resultType)
813 return op->
emitOpError(
"Accumulator type must match result type.");
820LogicalResult DpasOp::verify() {
821 auto lhsShape = getLhsType().getShape();
822 auto rhsShape = getRhsType().getShape();
823 auto resShape = getResultType().getShape();
845LogicalResult ConvertLayoutOp::verify() {
846 auto srcLayout = getInputLayout();
847 auto resLayout = getTargetLayout();
855 if ((!srcLayout.isForWorkgroup() || !resLayout.isForWorkgroup()) &&
856 (!srcLayout.isForSubgroup() || !resLayout.isForSubgroup()))
857 return emitOpError(
"expected input layout and target layout be WgLayout or "
858 "SgLayout at the same time.");
860 Type srcType = getSource().getType();
861 if (llvm::isa<VectorType>(srcType)) {
863 if (!srcLayout.isDistributable(
shape))
865 "invalid input layout, data cannot be evenly distributed.");
867 if (!resLayout.isDistributable(
shape))
869 "invalid target layout, data cannot be evenly distributed.");
871 return mlir::success();
880 DistributeLayoutAttr layout) {
887 build(builder, state, res, memDesc, dynamicOffsets, staticOffsetsAttr,
891LogicalResult LoadMatrixOp::verify() {
893 auto resTy = dyn_cast<VectorType>(getRes().
getType());
894 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
895 MemDescType mdescTy = getMemDesc().getType();
898 getLayoutAttr(), [&]() {
return emitError(); });
907 DistributeLayoutAttr layout) {
912 build(builder, state, data, memDesc, dynamicOffsets, staticOffsetsAttr,
916LogicalResult StoreMatrixOp::verify() {
918 auto dataTy = dyn_cast<VectorType>(getData().
getType());
919 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
920 MemDescType mdescTy = getMemDesc().getType();
922 getLayoutAttr(), [&]() {
return emitError(); });
929LogicalResult TruncfOp::verify() {
930 auto sourceVecType = dyn_cast<VectorType>(getSource().
getType());
931 auto resultVecType = dyn_cast<VectorType>(getResult().
getType());
933 if (sourceVecType.getElementTypeBitWidth() <=
934 resultVecType.getElementTypeBitWidth())
935 return emitOpError(
"input type must be wider than result type.");
944LogicalResult DpasMxOp::verify() {
945 auto aShape = getAType().getShape();
946 auto bShape = getBType().getShape();
947 auto resShape = getResultType().getShape();
968 int64_t aBatchRank = aShape.size() - 2;
972 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
974 if (scaleAVecType && scaleAVecType.getRank() > 1) {
975 auto scaleAShape = scaleAVecType.getShape();
977 if (scaleAVecType.getRank() < 2)
978 return emitOpError(
"Scale A must be at least a 2D vector when not a "
983 scaleAShape,
"ScaleA")))
987 if (scaleAShape[scaleAShape.size() - 2] != aShape[aBatchRank])
989 << scaleAShape[scaleAShape.size() - 2]
990 <<
"] must match A M dimension [" << aShape[aBatchRank] <<
"].";
996 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
998 if (scaleBVecType && scaleBVecType.getRank() > 1) {
999 auto scaleBShape = scaleBVecType.getShape();
1001 if (scaleBVecType.getRank() < 2)
1002 return emitOpError(
"Scale B must be at least a 2D vector when not a "
1007 scaleBShape,
"ScaleB")))
1012 if (scaleBShape.back() != bShape.back())
1014 << scaleBShape.back() <<
"] must match B N dimension ["
1015 << bShape.back() <<
"].";
1021 if (getScaleA() && getScaleB()) {
1022 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
1023 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
1025 if (scaleAVecType && scaleBVecType && scaleAVecType.getRank() > 1 &&
1026 scaleBVecType.getRank() > 1) {
1027 auto scaleAShape = scaleAVecType.getShape();
1028 auto scaleBShape = scaleBVecType.getShape();
1032 if (scaleAShape.back() != scaleBShape[scaleBShape.size() - 2])
1033 return emitOpError(
"Scale K dimension mismatch: scale_a has K=")
1034 << scaleAShape.back()
1035 <<
" but scale_b has K=" << scaleBShape[scaleBShape.size() - 2]
1044#include <mlir/Dialect/XeGPU/IR/XeGPUAttrInterface.cpp.inc>
1046#include <mlir/Dialect/XeGPU/IR/XeGPUEnums.cpp.inc>
1047#define GET_OP_CLASSES
1048#include <mlir/Dialect/XeGPU/IR/XeGPU.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 Type getElementType(Type type)
Determine the element type of type.
static Type getValueType(Attribute attr)
static ArrayRef< int64_t > getShape(Type type)
Returns the shape of the given type.
static SmallVector< int64_t > getShapeOf(Type type)
static LogicalResult verifyDpasAccumulator(Operation *op, Type accType, Type resultType)
LogicalResult IsValidMatrixOpParams(VectorType dataTy, MemDescType mdescTy, UnitAttr subgroup_block_io, DistributeLayoutAttr layout, function_ref< InFlightDiagnostic()> emitError)
static std::string makeString(T array, bool breakline=false)
static bool isWriteHintOrNone(const CachePolicyAttr &attr)
static bool isReadHintOrNone(const CachePolicyAttr &attr)
static LogicalResult isValidGatherScatterBufferParams(Type offsetsTy, Type maskTy, VectorType valueTy, int64_t chunkSize, function_ref< InFlightDiagnostic()> emitError)
static LogicalResult isValidContiguity(std::optional< uint64_t > contiguity, Type offsetsTy, function_ref< InFlightDiagnostic()> emitError)
static LogicalResult verifyDpasDimensions(Operation *op, ArrayRef< int64_t > aShape, ArrayRef< int64_t > bShape, ArrayRef< int64_t > resShape)
static LogicalResult verifyLayoutDistributable(Operation *op, std::optional< DistributeLayoutAttr > layout, ArrayRef< int64_t > shape, StringRef operandName)
Attributes are known-constant values of operations.
DenseI64ArrayAttr getDenseI64ArrayAttr(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 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).
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.
Location getLoc() const
Return the location of this value.
SmallVector< OpFoldResult > getMixedSizes(OpBuilder &builder, Location loc, Value value)
Return the dimensions of the given memref value.
Include the generated interface declarations.
InFlightDiagnostic emitWarning(Location loc)
Utility method to emit a warning message using this location.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
SmallVector< T > applyPermutation(ArrayRef< T > input, ArrayRef< int64_t > permutation)
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
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.
void dispatchIndexOpFoldResults(ArrayRef< OpFoldResult > ofrs, SmallVectorImpl< Value > &dynamicVec, SmallVectorImpl< int64_t > &staticVec)
Helper function to dispatch multiple OpFoldResults according to the behavior of dispatchIndexOpFoldRe...
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
llvm::function_ref< Fn > function_ref
This represents an operation in an abstracted form, suitable for use with the builder APIs.