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 build(builder, state, tdesc, source,
ValueRange({}) ,
226 assert((isa<IntegerType, MemRefType>(srcTy)) &&
227 "Source has to be either int or memref.");
241 if (
auto memrefTy = dyn_cast<MemRefType>(srcTy)) {
242 auto memrefShape = memrefTy.getShape();
243 auto [memrefStrides, _] = memrefTy.getStridesAndOffset();
248 if (staticShape == memrefShape && staticStrides == memrefStrides &&
249 dynamicShape.empty() && dynamicStrides.empty()) {
255 build(builder, state, tdesc, source, dynamicShape, dynamicStrides,
256 staticShapeAttr, staticStridesAttr);
259LogicalResult CreateNdDescOp::verify() {
260 auto srcMemrefTy = dyn_cast<MemRefType>(getSourceType());
261 size_t rank = srcMemrefTy ? srcMemrefTy.getRank() :
getMixedSizes().size();
262 bool invalidElemTy =
false;
268 auto srcMemorySpace = getSourceMemorySpace();
269 auto tdescMemorySpace =
static_cast<unsigned>(
getType().getMemorySpace());
270 if (srcMemorySpace != tdescMemorySpace)
272 <<
" Source: " << srcMemorySpace
273 <<
", TensorDesc: " << tdescMemorySpace;
277 if (
auto memrefTy = dyn_cast<MemRefType>(getSourceType()))
280 bool hasExplicitShapeStrides =
281 !
getShape().empty() || !getStrides().empty() ||
282 (getConstShapeAttr() && !getConstShapeAttr().empty()) ||
283 (getConstStridesAttr() && !getConstStridesAttr().empty());
285 if (llvm::isa<IntegerType>(getSourceType())) {
288 return emitOpError(
"expecting strides and shape to be present for "
291 return emitOpError(
"Expecting the rank of shape and strides to match.");
292 }
else if (srcMemrefTy && hasExplicitShapeStrides) {
293 return emitOpError(
"shape and strides should not be specified for a memref "
294 "source; they are inferred from the memref.");
299 return emitOpError(
"Expecting the TensorDesc rank is not greater than the "
300 "ranks of shape, strides or the memref source.");
303 return emitOpError(
"TensorDesc should have the same element "
304 "type with the source if it is a memref.\n");
315 xegpu::CachePolicyAttr l1_hint,
316 xegpu::CachePolicyAttr l2_hint,
317 xegpu::CachePolicyAttr l3_hint,
318 xegpu::DistributeLayoutAttr layout) {
325 build(builder, state, tensorDesc, dynamicOffsets, staticOffsetsAttr, l1_hint,
326 l2_hint, l3_hint, layout);
329LogicalResult PrefetchNdOp::verify() {
330 auto tdescTy = getTensorDescType();
333 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
336 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
339 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
341 int64_t tDescRank = tdescTy.getRank();
342 int64_t offsetSize = getMixedOffsets().size();
343 if (offsetSize != tDescRank)
345 "Mismatched ranks between offsets and tensor descriptor");
347 if (
auto layout = getAnchorLayout()) {
348 if (!layout.isDistributable(
getShapeOf(tdescTy)))
350 "TensorDesc shape is not distributable with the layout");
363 xegpu::CachePolicyAttr l1_hint,
364 xegpu::CachePolicyAttr l2_hint,
365 xegpu::CachePolicyAttr l3_hint,
366 xegpu::DistributeLayoutAttr layout) {
373 build(builder, state, retType, tensorDesc, dynamicOffsets, staticOffsetsAttr,
374 packed, transpose, l1_hint, l2_hint, l3_hint,
378LogicalResult LoadNdOp::verify() {
379 auto tdescTy = getTensorDescType();
383 return emitOpError(
"Invalid result, it should be a VectorType.\n");
386 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
389 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
392 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
394 int tdescElems = tdescTy.getNumElements() * tdescTy.getArrayLength();
395 int valueElems = valueTy.getNumElements();
400 if (valueElems < tdescElems && valueTy.getRank() == 1) {
402 if (tdescTy.getLayoutAttr())
404 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
409 if (tdescElems % valueElems)
412 <<
" is not a valid distribution for tensor descriptor "
422 if (getTranspose()) {
423 auto trans = getTranspose().value();
425 if (llvm::all_of(trans, [&](
size_t s) {
return s < tdescShape.size(); }))
432 if (tdescTy.getRank() == 2) {
434 auto vnni_factor = valueShape.back();
435 tdescShape[axis] /= vnni_factor;
436 tdescShape.push_back(vnni_factor);
439 <<
"Invalid Packed Attr. It is ignored (available for 2D "
449 auto array_len = tdescTy.getArrayLength();
452 if (array_len > 1 && !tdescShape.empty()) {
453 stacked2DShape[0] *= array_len;
454 threeDShape.insert(threeDShape.begin(), array_len);
457 if (valueShape != stacked2DShape && valueShape != threeDShape)
459 <<
" is not consistent with tensor descriptor "
462 int64_t tDescRank = tdescTy.getRank();
463 int64_t offsetSize = getMixedOffsets().size();
464 if (offsetSize != tDescRank)
466 "Mismatched ranks between offsets and tensor descriptor");
468 if (
auto layout = getAnchorLayout()) {
469 if (!layout.isDistributable(
getShapeOf(tdescTy)))
471 "TensorDesc shape is not distributable with the layout");
483 xegpu::CachePolicyAttr l1_hint,
484 xegpu::CachePolicyAttr l2_hint,
485 xegpu::CachePolicyAttr l3_hint,
486 xegpu::DistributeLayoutAttr layout) {
493 build(builder, state, value, tensorDesc, dynamicOffsets, staticOffsetsAttr,
494 l1_hint, l2_hint, l3_hint, layout);
497LogicalResult StoreNdOp::verify() {
498 auto dstTy = getTensorDescType();
502 return emitOpError(
"Expecting a VectorType result.\n");
505 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
508 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
511 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
513 auto array_len = dstTy.getArrayLength();
515 return emitOpError(
"array length is not supported by store_nd.\n");
517 auto tdescElems = dstTy.getNumElements();
518 auto valueElems = valTy.getNumElements();
523 if (valTy.getRank() == 1 && valueElems < tdescElems) {
525 if (dstTy.getLayoutAttr())
527 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
529 if (tdescElems % valueElems)
532 <<
" is not a valid distribution for tensor descriptor " << dstTy;
540 if (tdescShape != valueShape)
542 <<
" is not consistent with tensor descriptor "
545 int64_t tDescRank = dstTy.getRank();
546 int64_t offsetSize = getMixedOffsets().size();
547 if (offsetSize != tDescRank)
549 "Mismatched ranks between offsets and tensor descriptor");
551 if (
auto layout = getAnchorLayout()) {
552 if (!layout.isDistributable(tdescShape))
554 "TensorDesc shape is not distributable with the layout");
563LogicalResult PrefetchOp::verify() {
565 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
568 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
571 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
573 auto srcTy = getSourceType();
574 if (srcTy.
isInteger() && !getOffsetAlignByteAttr())
575 return emitOpError(
"offset_align_byte is required with integer source.");
577 if (getOffsetAlignByteAttr() && !srcTy.
isInteger())
578 return emitOpError(
"offset_align_byte only allowed with integer source.");
580 if (
auto layout = getAnchorLayout()) {
582 auto offsetsTy = getOffsets().getType();
583 if (llvm::isa<VectorType>(offsetsTy) &&
584 !layout.isDistributable(
getShapeOf(offsetsTy)))
585 return emitOpError(
"offset shape is not distributable with the layout");
594LogicalResult LoadGatherOp::verify() {
595 auto maskTy = getMaskType();
599 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
602 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
605 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
607 auto srcTy = getSourceType();
608 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
609 auto memTy = dyn_cast<MemRefType>(srcTy);
612 return emitError() <<
"Value should have the same element type as MemRef.";
614 if (
auto layout = getAnchorLayout()) {
615 if (!layout.isDistributable(
getShapeOf(valueTy)))
616 return emitOpError(
"Value shape is not distributable with the layout");
619 auto offsetsTy = getOffsets().getType();
630 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
631 xegpu::CachePolicyAttr l2_hint,
632 xegpu::CachePolicyAttr l3_hint) {
633 auto loc = source.
getLoc();
635 auto type = VectorType::get(size, builder.
getIndexType());
637 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
639 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
640 l2_hint, l3_hint,
nullptr,
647 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
648 xegpu::CachePolicyAttr l2_hint,
649 xegpu::CachePolicyAttr l3_hint,
650 DistributeLayoutAttr layout) {
651 auto loc = source.
getLoc();
653 auto type = VectorType::get(size, builder.
getIndexType());
655 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
657 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
658 l2_hint, l3_hint, layout,
nullptr);
664LogicalResult StoreScatterOp::verify() {
665 auto maskTy = getMaskType();
669 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
672 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
675 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
677 auto destTy = getDestType();
678 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
679 auto memTy = dyn_cast<MemRefType>(destTy);
682 return emitError() <<
"Value should have the same element type as MemRef.";
684 if (
auto layout = getAnchorLayout()) {
685 if (!layout.isDistributable(
getShapeOf(valueTy)))
686 return emitOpError(
"Value shape is not distributable with the layout");
689 auto offsetsTy = getOffsets().getType();
700 IntegerAttr chunk_size,
701 xegpu::CachePolicyAttr l1_hint,
702 xegpu::CachePolicyAttr l2_hint,
703 xegpu::CachePolicyAttr l3_hint) {
706 auto type = VectorType::get(size, builder.
getIndexType());
708 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
711 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
712 l3_hint,
nullptr,
nullptr);
715void StoreScatterOp::build(
718 xegpu::CachePolicyAttr l1_hint, xegpu::CachePolicyAttr l2_hint,
719 xegpu::CachePolicyAttr l3_hint, DistributeLayoutAttr layout) {
722 auto type = VectorType::get(size, builder.
getIndexType());
724 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
727 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
728 l3_hint, layout,
nullptr);
738 std::optional<DistributeLayoutAttr> layout,
740 if (layout && !layout->isDistributable(
743 <<
" shape is not distributable with the layout";
753 auto aRank = aShape.size();
754 auto bRank = bShape.size();
755 auto resRank = resShape.size();
756 if (aRank == 1 && bRank == 1 && resRank == 1)
762 return op->
emitOpError(
"A operand must be at least a 2D vector.");
764 return op->
emitOpError(
"B operand must be at least a 2D vector.");
766 return op->
emitOpError(
"Result must be at least a 2D vector.");
773 if (bRank == aRank + 1)
779 if (aRank != bRank || aRank != resRank)
780 return op->
emitOpError(
"Rank mismatch among A, B, and result.");
785 for (
int64_t i = 0; i < batchRank; ++i) {
786 if (aShape[i] != resShape[i])
787 return op->
emitOpError(
"Batch dimension mismatch at dim ")
788 << i <<
": A has " << aShape[i] <<
" but result has "
789 << resShape[i] <<
".";
790 if (aShape[i] != bShape[i])
791 return op->
emitOpError(
"Batch dimension mismatch at dim ")
792 << i <<
": A has " << aShape[i] <<
" but B has " << bShape[i]
797 int64_t aM = aShape[batchRank];
798 int64_t aK = aShape[batchRank + 1];
799 int64_t bK = bShape[batchRank];
800 int64_t bN = bShape[batchRank + 1];
801 int64_t resM = resShape[batchRank];
802 int64_t resN = resShape[batchRank + 1];
806 return op->
emitOpError(
"K-dimension mismatch: A has K=")
807 << aK <<
" but B has K=" << bK <<
".";
811 return op->
emitOpError(
"M-dimension mismatch: A has M=")
812 << aM <<
" but result has M=" << resM <<
".";
816 return op->
emitOpError(
"N-dimension mismatch: B has N=")
817 << bN <<
" but result has N=" << resN <<
".";
825 if (accType != resultType)
826 return op->
emitOpError(
"Accumulator type must match result type.");
833LogicalResult DpasOp::verify() {
834 auto lhsShape = getLhsType().getShape();
835 auto rhsShape = getRhsType().getShape();
836 auto resShape = getResultType().getShape();
858LogicalResult ConvertLayoutOp::verify() {
859 auto resLayout = getTargetLayout();
862 auto srcLayout = getEffectiveInputLayout();
866 if ((!srcLayout.isForWorkgroup() || !resLayout.isForWorkgroup()) &&
867 (!srcLayout.isForSubgroup() || !resLayout.isForSubgroup()))
868 return emitOpError(
"expected input layout and target layout be WgLayout or "
869 "SgLayout at the same time.");
871 Type srcType = getSource().getType();
872 if (llvm::isa<VectorType>(srcType)) {
874 if (!srcLayout.isDistributable(
shape))
876 "invalid input layout, data cannot be evenly distributed.");
878 if (!resLayout.isDistributable(
shape))
880 "invalid target layout, data cannot be evenly distributed.");
882 return mlir::success();
891 DistributeLayoutAttr layout) {
898 build(builder, state, res, memDesc, dynamicOffsets, staticOffsetsAttr,
902LogicalResult LoadMatrixOp::verify() {
904 auto resTy = dyn_cast<VectorType>(getRes().
getType());
905 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
906 MemDescType mdescTy = getMemDesc().getType();
909 getLayoutAttr(), [&]() {
return emitError(); });
918 DistributeLayoutAttr layout) {
923 build(builder, state, data, memDesc, dynamicOffsets, staticOffsetsAttr,
927LogicalResult StoreMatrixOp::verify() {
929 auto dataTy = dyn_cast<VectorType>(getData().
getType());
930 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
931 MemDescType mdescTy = getMemDesc().getType();
933 getLayoutAttr(), [&]() {
return emitError(); });
940LogicalResult TruncfOp::verify() {
941 auto sourceVecType = dyn_cast<VectorType>(getSource().
getType());
942 auto resultVecType = dyn_cast<VectorType>(getResult().
getType());
944 if (sourceVecType.getElementTypeBitWidth() <=
945 resultVecType.getElementTypeBitWidth())
946 return emitOpError(
"input type must be wider than result type.");
955LogicalResult LaneShuffleOp::verify() {
959 return emitOpError(
"requires a source vector with at least 2 elements.");
967 auto producer = getSource().getDefiningOp<LaneShuffleOp>();
968 if (producer && producer.getMode() != getMode())
969 return producer.getSource();
978LogicalResult DpasMxOp::verify() {
979 auto aShape = getAType().getShape();
980 auto bShape = getBType().getShape();
981 auto resShape = getResultType().getShape();
1002 int64_t aBatchRank = aShape.size() - 2;
1006 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
1008 if (scaleAVecType && scaleAVecType.getRank() > 1) {
1009 auto scaleAShape = scaleAVecType.getShape();
1011 if (scaleAVecType.getRank() < 2)
1012 return emitOpError(
"Scale A must be at least a 2D vector when not a "
1017 scaleAShape,
"ScaleA")))
1021 if (scaleAShape[scaleAShape.size() - 2] != aShape[aBatchRank])
1023 << scaleAShape[scaleAShape.size() - 2]
1024 <<
"] must match A M dimension [" << aShape[aBatchRank] <<
"].";
1030 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
1032 if (scaleBVecType && scaleBVecType.getRank() > 1) {
1033 auto scaleBShape = scaleBVecType.getShape();
1035 if (scaleBVecType.getRank() < 2)
1036 return emitOpError(
"Scale B must be at least a 2D vector when not a "
1041 scaleBShape,
"ScaleB")))
1046 if (scaleBShape.back() != bShape.back())
1048 << scaleBShape.back() <<
"] must match B N dimension ["
1049 << bShape.back() <<
"].";
1055 if (getScaleA() && getScaleB()) {
1056 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
1057 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
1059 if (scaleAVecType && scaleBVecType && scaleAVecType.getRank() > 1 &&
1060 scaleBVecType.getRank() > 1) {
1061 auto scaleAShape = scaleAVecType.getShape();
1062 auto scaleBShape = scaleBVecType.getShape();
1066 if (scaleAShape.back() != scaleBShape[scaleBShape.size() - 2])
1067 return emitOpError(
"Scale K dimension mismatch: scale_a has K=")
1068 << scaleAShape.back()
1069 <<
" but scale_b has K=" << scaleBShape[scaleBShape.size() - 2]
1078#include <mlir/Dialect/XeGPU/IR/XeGPUAttrInterface.cpp.inc>
1080#include <mlir/Dialect/XeGPU/IR/XeGPUEnums.cpp.inc>
1081#define GET_OP_CLASSES
1082#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.