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.";
118 UnitAttr subgroup_block_io, DistributeLayoutAttr layout,
122 if (subgroup_block_io)
123 return emitError() <<
"subgroup_block_io "
124 "are only allowed when result is a VectorType.";
133 ArrayAttr strideAttr = mdescTy.getStrideAttr();
135 for (
Attribute attr : strideAttr.getValue()) {
136 strides.push_back(cast<IntegerAttr>(attr).getInt());
138 if (subgroup_block_io && layout) {
139 auto laneData = layout.getEffectiveLaneDataAsInt();
140 auto laneLayout = layout.getEffectiveLaneLayoutAsInt();
141 if (!laneData.empty()) {
142 bool isLaneDataContiguous =
143 std::all_of(laneData.begin(), std::prev(laneData.end()),
144 [](
int x) { return x == 1; });
145 if (!isLaneDataContiguous)
146 return emitError() <<
"With subgroup_block_io, accessed data must be "
147 "contiguous and coalesced.";
148 for (
size_t i = 0; i < laneData.size(); ++i) {
149 if (laneLayout[i] != blockShape[i])
150 return emitError() <<
"With subgroup_block_io, the block shape must "
151 "match the lane layout.";
152 if (laneLayout[i] != 1 && strides[i] != 1)
153 return emitError() <<
"With subgroup_block_io, the distributed "
154 "dimensions must be contiguous.";
159 if (layout && !layout.isDistributable(
161 return emitError() <<
"Value shape is not distributable with the layout";
163 if (dataShape.size() == mdescShape.size()) {
164 if (llvm::any_of(llvm::zip_equal(dataShape, mdescShape),
165 [](
auto p) {
return std::get<0>(p) > std::get<1>(p); }))
166 return emitError() <<
"data shape must not exceed mem_desc shape.";
170 if (subgroup_block_io && !blockShape.size())
171 return emitError() <<
"mem_desc must have block attribute when "
172 "subgroup_block_io is set.";
182 [[maybe_unused]]
auto ty = source.getType();
183 assert(ty.hasStaticShape() &&
"expecting a memref with static shape");
185 build(builder, state, tdesc, source,
ValueRange({}) ,
196 assert((isa<IntegerType, MemRefType>(srcTy)) &&
197 "Source has to be either int or memref.");
211 if (
auto memrefTy = dyn_cast<MemRefType>(srcTy)) {
212 auto memrefShape = memrefTy.getShape();
213 auto [memrefStrides, _] = memrefTy.getStridesAndOffset();
218 if (staticShape == memrefShape && staticStrides == memrefStrides &&
219 dynamicShape.empty() && dynamicStrides.empty()) {
225 build(builder, state, tdesc, source, dynamicShape, dynamicStrides,
226 staticShapeAttr, staticStridesAttr);
229LogicalResult CreateNdDescOp::verify() {
231 bool invalidRank = rank != getMixedStrides().size();
232 bool invalidElemTy =
false;
238 auto srcMemorySpace = getSourceMemorySpace();
239 auto tdescMemorySpace =
static_cast<unsigned>(
getType().getMemorySpace());
240 if (srcMemorySpace != tdescMemorySpace)
242 <<
" Source: " << srcMemorySpace
243 <<
", TensorDesc: " << tdescMemorySpace;
247 if (
auto memrefTy = dyn_cast<MemRefType>(getSourceType()))
250 if (llvm::isa<IntegerType>(getSourceType())) {
253 return emitOpError(
"expecting strides and shape to be present for "
259 "Expecting the rank of shape, strides, and source (if source "
260 "is a memref) should match with each other.");
264 return emitOpError(
"Expecting the TensorDesc rank is not greater than the "
265 "ranks of shape, strides or the memref source.");
268 return emitOpError(
"TensorDesc should have the same element "
269 "type with the source if it is a memref.\n");
280 xegpu::CachePolicyAttr l1_hint,
281 xegpu::CachePolicyAttr l2_hint,
282 xegpu::CachePolicyAttr l3_hint,
283 xegpu::DistributeLayoutAttr layout) {
290 build(builder, state, tensorDesc, dynamicOffsets, staticOffsetsAttr, l1_hint,
291 l2_hint, l3_hint, layout);
294LogicalResult PrefetchNdOp::verify() {
295 auto tdescTy = getTensorDescType();
298 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
301 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
304 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
306 int64_t tDescRank = tdescTy.getRank();
307 int64_t offsetSize = getMixedOffsets().size();
308 if (offsetSize != tDescRank)
310 "Mismatched ranks between offsets and tensor descriptor");
312 if (
auto layout = getAnchorLayout()) {
313 if (!layout.isDistributable(
getShapeOf(tdescTy)))
315 "TensorDesc shape is not distributable with the layout");
328 xegpu::CachePolicyAttr l1_hint,
329 xegpu::CachePolicyAttr l2_hint,
330 xegpu::CachePolicyAttr l3_hint,
331 xegpu::DistributeLayoutAttr layout) {
338 build(builder, state, retType, tensorDesc, dynamicOffsets, staticOffsetsAttr,
339 packed, transpose, l1_hint, l2_hint, l3_hint,
343LogicalResult LoadNdOp::verify() {
344 auto tdescTy = getTensorDescType();
348 return emitOpError(
"Invalid result, it should be a VectorType.\n");
351 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
354 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
357 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
359 int tdescElems = tdescTy.getNumElements() * tdescTy.getArrayLength();
360 int valueElems = valueTy.getNumElements();
365 if (valueElems < tdescElems && valueTy.getRank() == 1) {
367 if (tdescTy.getLayoutAttr())
369 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
374 if (tdescElems % valueElems)
377 <<
" is not a valid distribution for tensor descriptor "
387 if (getTranspose()) {
388 auto trans = getTranspose().value();
390 if (llvm::all_of(trans, [&](
size_t s) {
return s < tdescShape.size(); }))
397 if (tdescTy.getRank() == 2) {
399 auto vnni_factor = valueShape.back();
400 tdescShape[axis] /= vnni_factor;
401 tdescShape.push_back(vnni_factor);
404 <<
"Invalid Packed Attr. It is ignored (available for 2D "
414 auto array_len = tdescTy.getArrayLength();
417 if (array_len > 1 && !tdescShape.empty()) {
418 stacked2DShape[0] *= array_len;
419 threeDShape.insert(threeDShape.begin(), array_len);
422 if (valueShape != stacked2DShape && valueShape != threeDShape)
424 <<
" is not consistent with tensor descriptor "
427 int64_t tDescRank = tdescTy.getRank();
428 int64_t offsetSize = getMixedOffsets().size();
429 if (offsetSize != tDescRank)
431 "Mismatched ranks between offsets and tensor descriptor");
433 if (
auto layout = getAnchorLayout()) {
434 if (!layout.isDistributable(
getShapeOf(tdescTy)))
436 "TensorDesc shape is not distributable with the layout");
448 xegpu::CachePolicyAttr l1_hint,
449 xegpu::CachePolicyAttr l2_hint,
450 xegpu::CachePolicyAttr l3_hint,
451 xegpu::DistributeLayoutAttr layout) {
458 build(builder, state, value, tensorDesc, dynamicOffsets, staticOffsetsAttr,
459 l1_hint, l2_hint, l3_hint, layout);
462LogicalResult StoreNdOp::verify() {
463 auto dstTy = getTensorDescType();
467 return emitOpError(
"Expecting a VectorType result.\n");
470 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
473 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
476 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
478 auto array_len = dstTy.getArrayLength();
480 return emitOpError(
"array length is not supported by store_nd.\n");
482 auto tdescElems = dstTy.getNumElements();
483 auto valueElems = valTy.getNumElements();
488 if (valTy.getRank() == 1 && valueElems < tdescElems) {
490 if (dstTy.getLayoutAttr())
492 <<
"TensorDesc doesn't need LayoutAttr for SIMT code";
494 if (tdescElems % valueElems)
497 <<
" is not a valid distribution for tensor descriptor " << dstTy;
505 if (tdescShape != valueShape)
507 <<
" is not consistent with tensor descriptor "
510 int64_t tDescRank = dstTy.getRank();
511 int64_t offsetSize = getMixedOffsets().size();
512 if (offsetSize != tDescRank)
514 "Mismatched ranks between offsets and tensor descriptor");
516 if (
auto layout = getAnchorLayout()) {
517 if (!layout.isDistributable(tdescShape))
519 "TensorDesc shape is not distributable with the layout");
528LogicalResult PrefetchOp::verify() {
530 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
533 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
536 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
538 auto srcTy = getSourceType();
539 if (srcTy.
isInteger() && !getOffsetAlignByteAttr())
540 return emitOpError(
"offset_align_byte is required with integer source.");
542 if (getOffsetAlignByteAttr() && !srcTy.
isInteger())
543 return emitOpError(
"offset_align_byte only allowed with integer source.");
545 if (
auto layout = getAnchorLayout()) {
547 auto offsetsTy = getOffsets().getType();
548 if (llvm::isa<VectorType>(offsetsTy) &&
549 !layout.isDistributable(
getShapeOf(offsetsTy)))
550 return emitOpError(
"offset shape is not distributable with the layout");
559LogicalResult LoadGatherOp::verify() {
560 auto maskTy = getMaskType();
564 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
567 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
570 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
572 auto srcTy = getSourceType();
573 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
574 auto memTy = dyn_cast<MemRefType>(srcTy);
577 return emitError() <<
"Value should have the same element type as MemRef.";
579 if (
auto layout = getAnchorLayout()) {
580 if (!layout.isDistributable(
getShapeOf(valueTy)))
581 return emitOpError(
"Value shape is not distributable with the layout");
584 auto offsetsTy = getOffsets().getType();
592 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
593 xegpu::CachePolicyAttr l2_hint,
594 xegpu::CachePolicyAttr l3_hint) {
595 auto loc = source.
getLoc();
597 auto type = VectorType::get(size, builder.
getIndexType());
599 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
601 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
602 l2_hint, l3_hint,
nullptr);
608 IntegerAttr chunk_size, xegpu::CachePolicyAttr l1_hint,
609 xegpu::CachePolicyAttr l2_hint,
610 xegpu::CachePolicyAttr l3_hint,
611 DistributeLayoutAttr layout) {
612 auto loc = source.
getLoc();
614 auto type = VectorType::get(size, builder.
getIndexType());
616 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
618 build(builder, state, valueType, source, offset, mask, chunk_size, l1_hint,
619 l2_hint, l3_hint, layout);
625LogicalResult StoreScatterOp::verify() {
626 auto maskTy = getMaskType();
630 return emitOpError(
"invalid l1_hint: ") << getL1HintAttr();
633 return emitOpError(
"invalid l2_hint: ") << getL2HintAttr();
636 return emitOpError(
"invalid l3_hint: ") << getL3HintAttr();
638 auto destTy = getDestType();
639 uint64_t chunkSize =
static_cast<int64_t>(getChunkSize().value_or(1));
640 auto memTy = dyn_cast<MemRefType>(destTy);
643 return emitError() <<
"Value should have the same element type as MemRef.";
645 if (
auto layout = getAnchorLayout()) {
646 if (!layout.isDistributable(
getShapeOf(valueTy)))
647 return emitOpError(
"Value shape is not distributable with the layout");
650 auto offsetsTy = getOffsets().getType();
658 IntegerAttr chunk_size,
659 xegpu::CachePolicyAttr l1_hint,
660 xegpu::CachePolicyAttr l2_hint,
661 xegpu::CachePolicyAttr l3_hint) {
664 auto type = VectorType::get(size, builder.
getIndexType());
666 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
669 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
673void StoreScatterOp::build(
676 xegpu::CachePolicyAttr l1_hint, xegpu::CachePolicyAttr l2_hint,
677 xegpu::CachePolicyAttr l3_hint, DistributeLayoutAttr layout) {
680 auto type = VectorType::get(size, builder.
getIndexType());
682 auto offset = vector::FromElementsOp::create(builder, loc, type, values);
685 build(builder, state, value, dest, offset, mask, chunk_size, l1_hint, l2_hint,
696 std::optional<DistributeLayoutAttr> layout,
698 if (layout && !layout->isDistributable(
701 <<
" shape is not distributable with the layout";
711 auto aRank = aShape.size();
712 auto bRank = bShape.size();
713 auto resRank = resShape.size();
714 if (aRank == 1 && bRank == 1 && resRank == 1)
720 return op->
emitOpError(
"A operand must be at least a 2D vector.");
722 return op->
emitOpError(
"B operand must be at least a 2D vector.");
724 return op->
emitOpError(
"Result must be at least a 2D vector.");
731 if (bRank == aRank + 1)
737 if (aRank != bRank || aRank != resRank)
738 return op->
emitOpError(
"Rank mismatch among A, B, and result.");
743 for (
int64_t i = 0; i < batchRank; ++i) {
744 if (aShape[i] != resShape[i])
745 return op->
emitOpError(
"Batch dimension mismatch at dim ")
746 << i <<
": A has " << aShape[i] <<
" but result has "
747 << resShape[i] <<
".";
748 if (aShape[i] != bShape[i])
749 return op->
emitOpError(
"Batch dimension mismatch at dim ")
750 << i <<
": A has " << aShape[i] <<
" but B has " << bShape[i]
755 int64_t aM = aShape[batchRank];
756 int64_t aK = aShape[batchRank + 1];
757 int64_t bK = bShape[batchRank];
758 int64_t bN = bShape[batchRank + 1];
759 int64_t resM = resShape[batchRank];
760 int64_t resN = resShape[batchRank + 1];
764 return op->
emitOpError(
"K-dimension mismatch: A has K=")
765 << aK <<
" but B has K=" << bK <<
".";
769 return op->
emitOpError(
"M-dimension mismatch: A has M=")
770 << aM <<
" but result has M=" << resM <<
".";
774 return op->
emitOpError(
"N-dimension mismatch: B has N=")
775 << bN <<
" but result has N=" << resN <<
".";
783 if (accType != resultType)
784 return op->
emitOpError(
"Accumulator type must match result type.");
791LogicalResult DpasOp::verify() {
792 auto lhsShape = getLhsType().getShape();
793 auto rhsShape = getRhsType().getShape();
794 auto resShape = getResultType().getShape();
816LogicalResult ConvertLayoutOp::verify() {
817 auto srcLayout = getInputLayout();
818 auto resLayout = getTargetLayout();
826 if ((!srcLayout.isForWorkgroup() || !resLayout.isForWorkgroup()) &&
827 (!srcLayout.isForSubgroup() || !resLayout.isForSubgroup()))
828 return emitOpError(
"expected input layout and target layout be WgLayout or "
829 "SgLayout at the same time.");
831 Type srcType = getSource().getType();
832 if (llvm::isa<VectorType>(srcType)) {
834 if (!srcLayout.isDistributable(
shape))
836 "invalid input layout, data cannot be evenly distributed.");
838 if (!resLayout.isDistributable(
shape))
840 "invalid target layout, data cannot be evenly distributed.");
842 return mlir::success();
851 DistributeLayoutAttr layout) {
858 build(builder, state, res, memDesc, dynamicOffsets, staticOffsetsAttr,
862LogicalResult LoadMatrixOp::verify() {
864 auto resTy = dyn_cast<VectorType>(getRes().
getType());
865 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
866 MemDescType mdescTy = getMemDesc().getType();
869 getLayoutAttr(), [&]() {
return emitError(); });
878 DistributeLayoutAttr layout) {
883 build(builder, state, data, memDesc, dynamicOffsets, staticOffsetsAttr,
887LogicalResult StoreMatrixOp::verify() {
889 auto dataTy = dyn_cast<VectorType>(getData().
getType());
890 UnitAttr subgroup_block_io = getSubgroupBlockIoAttr();
891 MemDescType mdescTy = getMemDesc().getType();
893 getLayoutAttr(), [&]() {
return emitError(); });
900LogicalResult TruncfOp::verify() {
901 auto sourceVecType = dyn_cast<VectorType>(getSource().
getType());
902 auto resultVecType = dyn_cast<VectorType>(getResult().
getType());
904 if (sourceVecType.getElementTypeBitWidth() <=
905 resultVecType.getElementTypeBitWidth())
906 return emitOpError(
"input type must be wider than result type.");
915LogicalResult DpasMxOp::verify() {
916 auto aShape = getAType().getShape();
917 auto bShape = getBType().getShape();
918 auto resShape = getResultType().getShape();
939 int64_t aBatchRank = aShape.size() - 2;
943 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
945 if (scaleAVecType && scaleAVecType.getRank() > 1) {
946 auto scaleAShape = scaleAVecType.getShape();
948 if (scaleAVecType.getRank() < 2)
949 return emitOpError(
"Scale A must be at least a 2D vector when not a "
954 scaleAShape,
"ScaleA")))
958 if (scaleAShape[scaleAShape.size() - 2] != aShape[aBatchRank])
960 << scaleAShape[scaleAShape.size() - 2]
961 <<
"] must match A M dimension [" << aShape[aBatchRank] <<
"].";
967 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
969 if (scaleBVecType && scaleBVecType.getRank() > 1) {
970 auto scaleBShape = scaleBVecType.getShape();
972 if (scaleBVecType.getRank() < 2)
973 return emitOpError(
"Scale B must be at least a 2D vector when not a "
978 scaleBShape,
"ScaleB")))
983 if (scaleBShape.back() != bShape.back())
985 << scaleBShape.back() <<
"] must match B N dimension ["
986 << bShape.back() <<
"].";
992 if (getScaleA() && getScaleB()) {
993 auto scaleAVecType = dyn_cast<VectorType>(getScaleAType());
994 auto scaleBVecType = dyn_cast<VectorType>(getScaleBType());
996 if (scaleAVecType && scaleBVecType && scaleAVecType.getRank() > 1 &&
997 scaleBVecType.getRank() > 1) {
998 auto scaleAShape = scaleAVecType.getShape();
999 auto scaleBShape = scaleBVecType.getShape();
1003 if (scaleAShape.back() != scaleBShape[scaleBShape.size() - 2])
1004 return emitOpError(
"Scale K dimension mismatch: scale_a has K=")
1005 << scaleAShape.back()
1006 <<
" but scale_b has K=" << scaleBShape[scaleBShape.size() - 2]
1015#include <mlir/Dialect/XeGPU/IR/XeGPUAttrInterface.cpp.inc>
1017#include <mlir/Dialect/XeGPU/IR/XeGPUEnums.cpp.inc>
1018#define GET_OP_CLASSES
1019#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 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.