18#include "llvm/Support/Debug.h"
20#define DEBUG_TYPE "xegpu"
26static std::string
makeString(T array,
bool breakline =
false) {
29 llvm::raw_string_ostream os(buf);
31 for (
size_t i = 1; i < array.size(); i++) {
32 os << array[i - 1] <<
", ";
36 os << array.back() <<
"]";
42 if (
auto ty = llvm::dyn_cast<ShapedType>(type))
52 auto kind = attr.getValue();
53 return kind == CachePolicy::CACHED || kind == CachePolicy::UNCACHED ||
54 kind == CachePolicy::STREAMING || kind == CachePolicy::READ_INVALIDATE;
60 auto kind = attr.getValue();
61 return kind == CachePolicy::CACHED || kind == CachePolicy::UNCACHED ||
62 kind == CachePolicy::WRITE_BACK || kind == CachePolicy::WRITE_THROUGH;
67 VectorType valueTy,
int64_t chunkSize,
70 auto maskVecTy = dyn_cast<VectorType>(maskTy);
71 auto offsetsVecTy = dyn_cast<VectorType>(offsetsTy);
74 return emitError() <<
"Expecting chunk size == 1 for scalar result";
75 if (maskVecTy || offsetsVecTy)
76 return emitError() <<
"Expecting scalar mask and offsets.";
77 else if (maskVecTy && offsetsVecTy)
78 return emitError() <<
"Expecting a vector type result.";
82 auto valueSize = valueTy.getNumElements();
84 if (!maskVecTy && !offsetsVecTy) {
85 if (valueSize != chunkSize)
86 return emitError() <<
"value elements must match chunk size "
94 return emitError() <<
"Expecting a vector type mask.";
95 int64_t maskSize = maskVecTy.getNumElements();
98 if ((valueTy.getRank() == 1) && (valueSize != chunkSize))
99 return emitError() <<
"value elements must match chunk size "
102 if (valueSize != maskSize)
104 <<
"Mask should match value except the chunk size dim.";
110 expectedMaskShape.pop_back();
111 if (expectedMaskShape != maskShape)
112 return emitError() <<
"Mask should match value except the chunk size dim.";
125 auto offsetsVecTy = dyn_cast<VectorType>(offsetsTy);
127 return emitError() <<
"contiguity requires vector offsets (one per lane).";
129 int64_t inner = offsetsVecTy.getShape().back();
131 return emitError() <<
"contiguity = " << size <<
" (must be >= 2)";
132 if (inner % size != 0)
133 return emitError() <<
"contiguity = " << size
134 <<
" (must divide the innermost offsets dim " << inner
141 UnitAttr subgroup_block_io, DistributeLayoutAttr layout,
145 if (subgroup_block_io)
146 return emitError() <<
"subgroup_block_io "
147 "are only allowed when result is a VectorType.";
156 ArrayAttr strideAttr = mdescTy.getStrideAttr();
158 for (
Attribute attr : strideAttr.getValue()) {
159 strides.push_back(cast<IntegerAttr>(attr).getInt());
161 if (subgroup_block_io && layout) {
162 auto laneData = layout.getEffectiveLaneDataAsInt();
163 auto laneLayout = layout.getEffectiveLaneLayoutAsInt();
164 if (!laneData.empty()) {
165 bool isLaneDataContiguous =
166 std::all_of(laneData.begin(), std::prev(laneData.end()),
167 [](
int x) { return x == 1; });
168 if (!isLaneDataContiguous)
169 return emitError() <<
"With subgroup_block_io, accessed data must be "
170 "contiguous and coalesced.";
171 for (
size_t i = 0; i < laneData.size(); ++i) {
172 if (laneLayout[i] != blockShape[i])
173 return emitError() <<
"With subgroup_block_io, the block shape must "
174 "match the lane layout.";
175 if (laneLayout[i] != 1 && strides[i] != 1)
176 return emitError() <<
"With subgroup_block_io, the distributed "
177 "dimensions must be contiguous.";
182 if (layout && !layout.isDistributable(
184 return emitError() <<
"Value shape is not distributable with the layout";
186 if (dataShape.size() == mdescShape.size()) {
187 if (llvm::any_of(llvm::zip_equal(dataShape, mdescShape),
188 [](
auto p) {
return std::get<0>(p) > std::get<1>(p); }))
189 return emitError() <<
"data shape must not exceed mem_desc shape.";
193 if (subgroup_block_io && !blockShape.size())
194 return emitError() <<
"mem_desc must have block attribute when "
195 "subgroup_block_io is set.";
202LogicalResult CreateMemDescOp::verify() {
203 auto srcTy = getSource().getType();
205 return emitOpError(
"source memref must be contiguous.");
215 [[maybe_unused]]
auto ty = source.getType();
216 assert(ty.hasStaticShape() &&
"expecting a memref with static shape");
218 build(builder, state, tdesc, source,
ValueRange({}) ,
229 assert((isa<IntegerType, MemRefType>(srcTy)) &&
230 "Source has to be either int or memref.");
244 if (
auto memrefTy = dyn_cast<MemRefType>(srcTy)) {
245 auto memrefShape = memrefTy.getShape();
246 auto [memrefStrides, _] = memrefTy.getStridesAndOffset();
251 if (staticShape == memrefShape && staticStrides == memrefStrides &&
252 dynamicShape.empty() && dynamicStrides.empty()) {
258 build(builder, state, tdesc, source, dynamicShape, dynamicStrides,
259 staticShapeAttr, staticStridesAttr);
262LogicalResult CreateNdDescOp::verify() {
264 bool invalidRank = rank != getMixedStrides().size();
265 bool invalidElemTy =
false;
271 auto srcMemorySpace = getSourceMemorySpace();
272 auto tdescMemorySpace =
static_cast<unsigned>(
getType().getMemorySpace());
273 if (srcMemorySpace != tdescMemorySpace)
275 <<
" Source: " << srcMemorySpace
276 <<
", TensorDesc: " << tdescMemorySpace;
280 if (
auto memrefTy = dyn_cast<MemRefType>(getSourceType()))
283 if (llvm::isa<IntegerType>(getSourceType())) {
286 return emitOpError(
"expecting strides and shape to be present for "
292 "Expecting the rank of shape, strides, and source (if source "
293 "is a memref) should match with each other.");
297 return emitOpError(
"Expecting the TensorDesc rank is not greater than the "
298 "ranks of shape, strides or the memref source.");
301 return emitOpError(
"TensorDesc should have the same element "
302 "type with the source if it is a memref.\n");
313 xegpu::CachePolicyAttr l1_hint,
314 xegpu::CachePolicyAttr l2_hint,
315 xegpu::CachePolicyAttr l3_hint,
316 xegpu::DistributeLayoutAttr layout) {
323 build(builder, state, tensorDesc, dynamicOffsets, staticOffsetsAttr, l1_hint,
324 l2_hint, l3_hint, layout);
327LogicalResult PrefetchNdOp::verify() {
328 auto tdescTy = getTensorDescType();
331 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
334 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
337 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
339 int64_t tDescRank = tdescTy.getRank();
340 int64_t offsetSize = getMixedOffsets().size();
341 if (offsetSize != tDescRank)
343 "Mismatched ranks between offsets and tensor descriptor");
345 if (
auto layout = getAnchorLayout()) {
346 if (!layout.isDistributable(
getShapeOf(tdescTy)))
348 "TensorDesc shape is not distributable with the layout");
361 xegpu::CachePolicyAttr l1_hint,
362 xegpu::CachePolicyAttr l2_hint,
363 xegpu::CachePolicyAttr l3_hint,
364 xegpu::DistributeLayoutAttr layout) {
371 build(builder, state, retType, tensorDesc, dynamicOffsets, staticOffsetsAttr,
372 packed, transpose, l1_hint, l2_hint, l3_hint,
376LogicalResult LoadNdOp::verify() {
377 auto tdescTy = getTensorDescType();
381 return emitOpError(
"Invalid result, it should be a VectorType.\n");
384 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
387 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
390 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
392 int tdescElems = tdescTy.getNumElements() * tdescTy.getArrayLength();
393 int valueElems = valueTy.getNumElements();
398 if (valueElems < tdescElems && valueTy.getRank() == 1) {
400 if (tdescTy.getLayoutAttr())
402 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
407 if (tdescElems % valueElems)
410 <<
" is not a valid distribution for tensor descriptor "
420 if (getTranspose()) {
421 auto trans = getTranspose().value();
423 if (llvm::all_of(trans, [&](
size_t s) {
return s < tdescShape.size(); }))
430 if (tdescTy.getRank() == 2) {
432 auto vnni_factor = valueShape.back();
433 tdescShape[axis] /= vnni_factor;
434 tdescShape.push_back(vnni_factor);
437 <<
"Invalid Packed Attr. It is ignored (available for 2D "
447 auto array_len = tdescTy.getArrayLength();
450 if (array_len > 1 && !tdescShape.empty()) {
451 stacked2DShape[0] *= array_len;
452 threeDShape.insert(threeDShape.begin(), array_len);
455 if (valueShape != stacked2DShape && valueShape != threeDShape)
457 <<
" is not consistent with tensor descriptor "
460 int64_t tDescRank = tdescTy.getRank();
461 int64_t offsetSize = getMixedOffsets().size();
462 if (offsetSize != tDescRank)
464 "Mismatched ranks between offsets and tensor descriptor");
466 if (
auto layout = getAnchorLayout()) {
467 if (!layout.isDistributable(
getShapeOf(tdescTy)))
469 "TensorDesc shape is not distributable with the layout");
481 xegpu::CachePolicyAttr l1_hint,
482 xegpu::CachePolicyAttr l2_hint,
483 xegpu::CachePolicyAttr l3_hint,
484 xegpu::DistributeLayoutAttr layout) {
491 build(builder, state, value, tensorDesc, dynamicOffsets, staticOffsetsAttr,
492 l1_hint, l2_hint, l3_hint, layout);
495LogicalResult StoreNdOp::verify() {
496 auto dstTy = getTensorDescType();
500 return emitOpError(
"Expecting a VectorType result.\n");
503 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
506 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
509 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
511 auto array_len = dstTy.getArrayLength();
513 return emitOpError(
"array length is not supported by store_nd.\n");
515 auto tdescElems = dstTy.getNumElements();
516 auto valueElems = valTy.getNumElements();
521 if (valTy.getRank() == 1 && valueElems < tdescElems) {
523 if (dstTy.getLayoutAttr())
525 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
527 if (tdescElems % valueElems)
530 <<
" is not a valid distribution for tensor descriptor " << dstTy;
538 if (tdescShape != valueShape)
540 <<
" is not consistent with tensor descriptor "
543 int64_t tDescRank = dstTy.getRank();
544 int64_t offsetSize = getMixedOffsets().size();
545 if (offsetSize != tDescRank)
547 "Mismatched ranks between offsets and tensor descriptor");
549 if (
auto layout = getAnchorLayout()) {
550 if (!layout.isDistributable(tdescShape))
552 "TensorDesc shape is not distributable with the layout");
561LogicalResult PrefetchOp::verify() {
563 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
566 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
569 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
571 auto srcTy = getSourceType();
572 if (srcTy.
isInteger() && !getOffsetAlignByteAttr())
573 return emitOpError(
"offset_align_byte is required with integer source.");
575 if (getOffsetAlignByteAttr() && !srcTy.
isInteger())
576 return emitOpError(
"offset_align_byte only allowed with integer source.");
578 if (
auto layout = getAnchorLayout()) {
580 auto offsetsTy = getOffsets().getType();
581 if (llvm::isa<VectorType>(offsetsTy) &&
582 !layout.isDistributable(
getShapeOf(offsetsTy)))
583 return emitOpError(
"offset shape is not distributable with the layout");
592LogicalResult LoadGatherOp::verify() {
593 auto maskTy = getMaskType();
597 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
600 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
603 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
605 auto srcTy = getSourceType();
606 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
607 auto memTy = dyn_cast<MemRefType>(srcTy);
610 return emitError() <<
"Value should have the same element type as MemRef.";
612 if (
auto layout = getAnchorLayout()) {
613 if (!layout.isDistributable(
getShapeOf(valueTy)))
614 return emitOpError(
"Value shape is not distributable with the layout");
617 auto offsetsTy = getOffsets().getType();
628 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
629 xegpu::CachePolicyAttr l2_hint,
630 xegpu::CachePolicyAttr l3_hint) {
631 auto loc = source.
getLoc();
633 auto type = VectorType::get(size, builder.
getIndexType());
635 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
637 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
638 l2_hint, l3_hint,
nullptr,
645 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
646 xegpu::CachePolicyAttr l2_hint,
647 xegpu::CachePolicyAttr l3_hint,
648 DistributeLayoutAttr layout) {
649 auto loc = source.
getLoc();
651 auto type = VectorType::get(size, builder.
getIndexType());
653 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
655 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
656 l2_hint, l3_hint, layout,
nullptr);
662LogicalResult StoreScatterOp::verify() {
663 auto maskTy = getMaskType();
667 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
670 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
673 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
675 auto destTy = getDestType();
676 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
677 auto memTy = dyn_cast<MemRefType>(destTy);
680 return emitError() <<
"Value should have the same element type as MemRef.";
682 if (
auto layout = getAnchorLayout()) {
683 if (!layout.isDistributable(
getShapeOf(valueTy)))
684 return emitOpError(
"Value shape is not distributable with the layout");
687 auto offsetsTy = getOffsets().getType();
698 IntegerAttr chunk_size,
699 xegpu::CachePolicyAttr l1_hint,
700 xegpu::CachePolicyAttr l2_hint,
701 xegpu::CachePolicyAttr l3_hint) {
704 auto type = VectorType::get(size, builder.
getIndexType());
706 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
709 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
710 l3_hint,
nullptr,
nullptr);
713void StoreScatterOp::build(
716 xegpu::CachePolicyAttr l1_hint, xegpu::CachePolicyAttr l2_hint,
717 xegpu::CachePolicyAttr l3_hint, DistributeLayoutAttr layout) {
720 auto type = VectorType::get(size, builder.
getIndexType());
722 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
725 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
726 l3_hint, layout,
nullptr);
736 std::optional<DistributeLayoutAttr> layout,
738 if (layout && !layout->isDistributable(
741 <<
" shape is not distributable with the layout";
751 auto aRank = aShape.size();
752 auto bRank = bShape.size();
753 auto resRank = resShape.size();
754 if (aRank == 1 && bRank == 1 && resRank == 1)
760 return op->
emitOpError(
"A operand must be at least a 2D vector.");
762 return op->
emitOpError(
"B operand must be at least a 2D vector.");
764 return op->
emitOpError(
"Result must be at least a 2D vector.");
771 if (bRank == aRank + 1)
777 if (aRank != bRank || aRank != resRank)
778 return op->
emitOpError(
"Rank mismatch among A, B, and result.");
783 for (
int64_t i = 0; i < batchRank; ++i) {
784 if (aShape[i] != resShape[i])
785 return op->
emitOpError(
"Batch dimension mismatch at dim ")
786 << i <<
": A has " << aShape[i] <<
" but result has "
787 << resShape[i] <<
".";
788 if (aShape[i] != bShape[i])
789 return op->
emitOpError(
"Batch dimension mismatch at dim ")
790 << i <<
": A has " << aShape[i] <<
" but B has " << bShape[i]
795 int64_t aM = aShape[batchRank];
796 int64_t aK = aShape[batchRank + 1];
797 int64_t bK = bShape[batchRank];
798 int64_t bN = bShape[batchRank + 1];
799 int64_t resM = resShape[batchRank];
800 int64_t resN = resShape[batchRank + 1];
804 return op->
emitOpError(
"K-dimension mismatch: A has K=")
805 << aK <<
" but B has K=" << bK <<
".";
809 return op->
emitOpError(
"M-dimension mismatch: A has M=")
810 << aM <<
" but result has M=" << resM <<
".";
814 return op->
emitOpError(
"N-dimension mismatch: B has N=")
815 << bN <<
" but result has N=" << resN <<
".";
823 if (accType != resultType)
824 return op->
emitOpError(
"Accumulator type must match result type.");
831LogicalResult DpasOp::verify() {
832 auto lhsShape = getLhsType().getShape();
833 auto rhsShape = getRhsType().getShape();
834 auto resShape = getResultType().getShape();
856LogicalResult ConvertLayoutOp::verify() {
857 auto resLayout = getTargetLayout();
860 auto srcLayout = getEffectiveInputLayout();
864 if ((!srcLayout.isForWorkgroup() || !resLayout.isForWorkgroup()) &&
865 (!srcLayout.isForSubgroup() || !resLayout.isForSubgroup()))
866 return emitOpError(
"expected input layout and target layout be WgLayout or "
867 "SgLayout at the same time.");
869 Type srcType = getSource().getType();
870 if (llvm::isa<VectorType>(srcType)) {
872 if (!srcLayout.isDistributable(
shape))
874 "invalid input layout, data cannot be evenly distributed.");
876 if (!resLayout.isDistributable(
shape))
878 "invalid target layout, data cannot be evenly distributed.");
880 return mlir::success();
889 DistributeLayoutAttr layout) {
896 build(builder, state, res, memDesc, dynamicOffsets, staticOffsetsAttr,
900LogicalResult LoadMatrixOp::verify() {
902 auto resTy = dyn_cast<VectorType>(getRes().
getType());
903 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
904 MemDescType mdescTy = getMemDesc().getType();
907 getLayoutAttr(), [&]() {
return emitError(); });
916 DistributeLayoutAttr layout) {
921 build(builder, state, data, memDesc, dynamicOffsets, staticOffsetsAttr,
925LogicalResult StoreMatrixOp::verify() {
927 auto dataTy = dyn_cast<VectorType>(getData().
getType());
928 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
929 MemDescType mdescTy = getMemDesc().getType();
931 getLayoutAttr(), [&]() {
return emitError(); });
938LogicalResult TruncfOp::verify() {
939 auto sourceVecType = dyn_cast<VectorType>(getSource().
getType());
940 auto resultVecType = dyn_cast<VectorType>(getResult().
getType());
942 if (sourceVecType.getElementTypeBitWidth() <=
943 resultVecType.getElementTypeBitWidth())
944 return emitOpError(
"input type must be wider than result type.");
953LogicalResult LaneShuffleOp::verify() {
957 return emitOpError(
"requires a source vector with at least 2 elements.");
965 auto producer = getSource().getDefiningOp<LaneShuffleOp>();
966 if (producer && producer.getMode() != getMode())
967 return producer.getSource();
976LogicalResult DpasMxOp::verify() {
977 auto aShape = getAType().getShape();
978 auto bShape = getBType().getShape();
979 auto resShape = getResultType().getShape();
1000 int64_t aBatchRank = aShape.size() - 2;
1004 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
1006 if (scaleAVecType && scaleAVecType.getRank() > 1) {
1007 auto scaleAShape = scaleAVecType.getShape();
1009 if (scaleAVecType.getRank() < 2)
1010 return emitOpError(
"Scale A must be at least a 2D vector when not a "
1015 scaleAShape,
"ScaleA")))
1019 if (scaleAShape[scaleAShape.size() - 2] != aShape[aBatchRank])
1021 << scaleAShape[scaleAShape.size() - 2]
1022 <<
"] must match A M dimension [" << aShape[aBatchRank] <<
"].";
1028 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
1030 if (scaleBVecType && scaleBVecType.getRank() > 1) {
1031 auto scaleBShape = scaleBVecType.getShape();
1033 if (scaleBVecType.getRank() < 2)
1034 return emitOpError(
"Scale B must be at least a 2D vector when not a "
1039 scaleBShape,
"ScaleB")))
1044 if (scaleBShape.back() != bShape.back())
1046 << scaleBShape.back() <<
"] must match B N dimension ["
1047 << bShape.back() <<
"].";
1053 if (getScaleA() && getScaleB()) {
1054 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
1055 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
1057 if (scaleAVecType && scaleBVecType && scaleAVecType.getRank() > 1 &&
1058 scaleBVecType.getRank() > 1) {
1059 auto scaleAShape = scaleAVecType.getShape();
1060 auto scaleBShape = scaleBVecType.getShape();
1064 if (scaleAShape.back() != scaleBShape[scaleBShape.size() - 2])
1065 return emitOpError(
"Scale K dimension mismatch: scale_a has K=")
1066 << scaleAShape.back()
1067 <<
" but scale_b has K=" << scaleBShape[scaleBShape.size() - 2]
1076#include <mlir/Dialect/XeGPU/IR/XeGPUAttrInterface.cpp.inc>
1078#include <mlir/Dialect/XeGPU/IR/XeGPUEnums.cpp.inc>
1079#define GET_OP_CLASSES
1080#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 int64_t getNumElements(Type t)
Compute the total number of elements in the given type, also taking into account nested types.
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.
This class represents a single result from folding an operation.
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.
bool isStaticShapeAndContiguousRowMajor(MemRefType type)
Returns true, if the memref type has static shapes and represents a contiguous chunk of memory.
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.