28#include "llvm/ADT/TypeSwitch.h"
34#define GEN_PASS_DEF_CONVERTVECTORTOXEGPU
35#include "mlir/Conversion/Passes.h.inc"
43static bool isZeroConstant(
Value val) {
49 .Case([](FloatAttr floatAttr) {
return floatAttr.getValue().isZero(); })
50 .Case([](IntegerAttr intAttr) {
return intAttr.getValue().isZero(); })
59static bool isZeroOrPoisonPadding(
Value val) {
60 return isZeroConstant(val) || val.
getDefiningOp<ub::PoisonOp>();
70static bool isInnermostTwoDimsTransposed(
AffineMap map) {
77 for (
unsigned i = 0; i + 2 < numResults; ++i)
87 VectorTransferOpInterface xferOp) {
90 "Masked transfer is not supported");
92 auto srcTy = dyn_cast<MemRefType>(xferOp.getShapedType());
99 if (
failed(srcTy.getStridesAndOffset(strides, offset)))
101 "The memref strides cannot be inferred");
104 if (strides.back() != 1)
106 xferOp,
"Buffer must be contiguous in the innermost dimension");
108 VectorType vecTy = xferOp.getVectorType();
109 unsigned vecRank = vecTy.getRank();
112 if (xferOp.hasOutOfBoundsDim() && vecRank < 2)
114 xferOp,
"Boundary check is available only for block instructions.");
121 auto dim = dyn_cast<AffineDimExpr>(expr);
122 if (dim.getPosition() < (numInputDims - vecRank))
124 xferOp,
"Only the innermost dimensions can be accessed");
147static void adjustStridesForPermutation(
AffineMap permMap,
162 typename = std::enable_if_t<llvm::is_one_of<
163 std::decay_t<OpType>, vector::TransferReadOp, vector::TransferWriteOp,
164 vector::GatherOp, vector::ScatterOp>::value>>
165static std::pair<SmallVector<Value>,
Value>
168 Value baseMemref = xferOp.getBase();
169 MemRefType memrefType = dyn_cast<MemRefType>(baseMemref.
getType());
172 Value offsetVal =
nullptr;
173 if (memrefType.hasStaticShape()) {
176 if (
failed(memrefType.getStridesAndOffset(intStrides, offset)))
177 return {{}, offsetVal};
178 bool hasDynamicStrides = llvm::any_of(intStrides, [](
int64_t strideVal) {
179 return ShapedType::isDynamic(strideVal);
182 if (!hasDynamicStrides)
186 if (!ShapedType::isDynamic(offset))
190 if (strides.empty() || !offsetVal) {
193 unsigned rank = memrefType.getRank();
199 resultTypes.push_back(MemRefType::get(
200 {}, memrefType.getElementType()));
201 resultTypes.push_back(indexType);
203 for (
unsigned i = 0; i < rank; ++i)
204 resultTypes.push_back(indexType);
206 for (
unsigned i = 0; i < rank; ++i)
207 resultTypes.push_back(indexType);
209 auto meta = memref::ExtractStridedMetadataOp::create(
210 rewriter, loc, resultTypes, baseMemref);
213 strides.append(meta.getStrides().begin(), meta.getStrides().end());
216 offsetVal = meta.getOffset();
221 return {strides, offsetVal};
252static Value computeOffsets(VectorTransferOpInterface xferOp,
256 VectorType vectorType = xferOp.getVectorType();
258 xferOp.getIndices().end());
264 auto stepType = VectorType::get({dim}, rewriter.
getIndexType());
265 auto stepOp = vector::StepOp::create(rewriter, loc, stepType);
266 stepVectors.push_back(stepOp);
273 adjustStridesForPermutation(xferOp.getPermutationMap(), permutedStrides);
276 size_t memrefRank = permutedStrides.size();
279 for (
size_t i = 0; i < vectorRank; ++i) {
280 size_t memrefDim = memrefRank - vectorRank + i;
281 Value strideValue = permutedStrides[memrefDim];
282 auto mulType = dyn_cast<VectorType>(stepVectors[i].
getType());
284 vector::BroadcastOp::create(rewriter, loc, mulType, strideValue);
285 auto mulOp = arith::MulIOp::create(rewriter, loc, stepVectors[i], bcastOp);
286 strideMultiplied.push_back(mulOp);
291 for (
size_t i = 0; i < vectorRank; ++i) {
294 auto newType = VectorType::get(newShape, rewriter.
getIndexType());
295 auto castOp = vector::ShapeCastOp::create(rewriter, loc, newType,
296 strideMultiplied[i]);
297 shapeCasted.push_back(castOp);
302 auto fullIndexVectorType =
304 for (
Value shapeCastVal : shapeCasted) {
305 auto broadcastOp = vector::BroadcastOp::create(
306 rewriter, loc, fullIndexVectorType, shapeCastVal);
307 broadcasted.push_back(broadcastOp);
311 Value localOffsets = broadcasted[0];
312 for (
size_t i = 1; i < broadcasted.size(); ++i)
314 arith::AddIOp::create(rewriter, loc, localOffsets, broadcasted[i]);
317 for (
size_t i = 0; i <
indices.size(); ++i) {
318 Value strideVal = strides[i];
319 Value offsetContrib =
320 arith::MulIOp::create(rewriter, loc,
indices[i], strideVal);
322 arith::AddIOp::create(rewriter, loc, baseOffset, offsetContrib);
325 Value bcastBase = vector::BroadcastOp::create(
326 rewriter, loc, fullIndexVectorType, baseOffset);
327 localOffsets = arith::AddIOp::create(rewriter, loc, bcastBase, localOffsets);
338 typename = std::enable_if_t<llvm::is_one_of<
339 std::decay_t<OpType>, vector::GatherOp, vector::ScatterOp>::value>>
344 for (
size_t i = 0; i < offsets.size(); ++i) {
345 Value offsetContrib =
346 arith::MulIOp::create(rewriter, loc, offsets[i], strides[i]);
348 arith::AddIOp::create(rewriter, loc, baseOffset, offsetContrib);
351 VectorType vecType = cast<VectorType>(
indices.getType());
354 vector::BroadcastOp::create(rewriter, loc, vecType, strides.back())
356 Value stridedIndices =
357 arith::MulIOp::create(rewriter, loc, strideVector,
indices).getResult();
360 vector::BroadcastOp::create(
362 VectorType::get(vecType.getShape(), rewriter.
getIndexType()),
365 return arith::AddIOp::create(rewriter, loc, baseVector, stridedIndices)
374static std::pair<Value, SmallVector<OpFoldResult>>
379 auto memrefType = cast<MemRefType>(
memref.getType());
380 unsigned rank = memrefType.getRank();
382 if (rank <= targetRank)
385 int64_t numCombinedDims = rank - targetRank;
391 for (
unsigned i = 0; i < numCombinedDims; ++i) {
392 subviewOffsets.push_back(offsets[i]);
399 auto originalShape = memrefType.getShape();
400 auto meta = memref::ExtractStridedMetadataOp::create(rewriter, loc,
memref);
401 for (
unsigned i = numCombinedDims; i < rank; ++i) {
403 if (ShapedType::isDynamic(originalShape[i])) {
404 subviewSizes.push_back(meta.getSizes()[i]);
405 resultShape.push_back(ShapedType::kDynamic);
408 resultShape.push_back(originalShape[i]);
413 auto resultType = memref::SubViewOp::inferRankReducedResultType(
414 resultShape, memrefType, subviewOffsets, subviewSizes, subviewStrides);
416 memref::SubViewOp::create(rewriter, loc, resultType,
memref,
417 subviewOffsets, subviewSizes, subviewStrides);
422 return {subviewOp.getResult(), newOffsets};
427 typename = std::enable_if_t<llvm::is_one_of<
428 std::decay_t<OpType>, vector::TransferReadOp, vector::TransferWriteOp,
429 vector::GatherOp, vector::ScatterOp>::value>>
433 auto indexPtr = memref::ExtractAlignedPointerAsIndexOp::create(
434 rewriter, loc, xferOp.getBase())
436 return arith::IndexCastOp::create(rewriter, loc, rewriter.
getI64Type(),
441static LogicalResult lowerToScatteredLoadOp(vector::TransferReadOp readOp,
445 VectorType vectorType = readOp.getVectorType();
447 auto memrefType = dyn_cast<MemRefType>(readOp.getShapedType());
451 auto meta = computeMemrefMeta(readOp, rewriter);
452 if (meta.first.empty())
456 computeOffsets(readOp, rewriter, meta.first, meta.second);
458 Value flatMemref = memrefToIndexPtr(readOp, rewriter);
460 Value mask = vector::ConstantMaskOp::create(
463 auto gatherOp = xegpu::LoadGatherOp::create(
464 rewriter, loc, vectorType, flatMemref, localOffsets, mask,
466 xegpu::CachePolicyAttr{},
467 xegpu::CachePolicyAttr{},
468 xegpu::CachePolicyAttr{},
471 rewriter.
replaceOp(readOp, gatherOp.getResult());
475static LogicalResult lowerToScatteredStoreOp(vector::TransferWriteOp writeOp,
479 VectorType vectorType = writeOp.getVectorType();
482 auto memrefType = dyn_cast<MemRefType>(writeOp.getShapedType());
486 auto meta = computeMemrefMeta(writeOp, rewriter);
487 if (meta.first.empty())
491 computeOffsets(writeOp, rewriter, meta.first, meta.second);
493 Value flatMemref = memrefToIndexPtr(writeOp, rewriter);
495 Value mask = vector::ConstantMaskOp::create(
498 xegpu::StoreScatterOp::create(rewriter, loc, writeOp.getVector(), flatMemref,
501 xegpu::CachePolicyAttr{},
502 xegpu::CachePolicyAttr{},
503 xegpu::CachePolicyAttr{},
509struct TransferReadLowering :
public OpRewritePattern<vector::TransferReadOp> {
512 LogicalResult matchAndRewrite(vector::TransferReadOp readOp,
513 PatternRewriter &rewriter)
const override {
514 Location loc = readOp.getLoc();
516 if (
failed(transferPreconditions(rewriter, readOp)))
518 auto readMemTy = cast<MemRefType>(readOp.getShapedType());
519 VectorType loadedVecTy = readOp.getVectorType();
520 bool isOutOfBounds = readOp.hasOutOfBoundsDim();
522 bool isSharedMemory = xegpu::XeGPUDialect::isSharedMemory(readMemTy);
526 if (loadedVecTy.getRank() != 1 && loadedVecTy.getRank() != 2)
528 readOp,
"Only 1D and 2D vector loads are supported for SLM");
529 AffineMap readMap = readOp.getPermutationMap();
533 "Non identity transposition is not supported for SLM loads.");
537 readOp,
"Out-of-bounds access is not supported for SLM loads");
541 xegpu::MemDescType::get(rewriter.
getContext(), readMemTy.getShape(),
542 readMemTy.getElementType(),
544 auto createMemDescOp = xegpu::CreateMemDescOp::create(
545 rewriter, loc, memDescType, readOp.getBase());
547 SmallVector<OpFoldResult>
indices =
549 auto loadMatrixOp = xegpu::LoadMatrixOp::create(
550 rewriter, loc, loadedVecTy, createMemDescOp.getResult(),
indices,
553 rewriter.
replaceOp(readOp, loadMatrixOp.getResult());
559 bool hasBlockLoadSupport =
560 (chip ==
"pvc" || chip ==
"bmg" || chip ==
"cri");
567 bool isTransposeLoad = isInnermostTwoDimsTransposed(readMap);
574 bool canLowerToLoadNd =
575 hasBlockLoadSupport && loadedVecTy.getRank() > 1 &&
577 readMemTy.getElementType().isIntOrFloat() &&
578 (!isOutOfBounds || isZeroOrPoisonPadding(readOp.getPadding()));
580 if (canLowerToLoadNd) {
581 auto elementType = loadedVecTy.getElementType();
583 SmallVector<int64_t> descShape(loadedVecTy.getShape());
584 if (isTransposeLoad) {
587 size_t rank = descShape.size();
588 assert(rank >= 2 &&
"Transpose requires at least 2 dimensions");
589 std::swap(descShape[rank - 1], descShape[rank - 2]);
590 loadedVecTy = VectorType::get(descShape, elementType);
592 auto descType = xegpu::TensorDescType::get(
593 descShape, elementType, 1,
594 isOutOfBounds, xegpu::MemorySpace::Global);
595 auto [src,
indices] = convertMemrefAndOffsetsToTargetRank(
596 rewriter, loc, readOp.getBase(),
599 xegpu::CachePolicyAttr hint =
nullptr;
600 xegpu::CreateNdDescOp ndDesc = xegpu::CreateNdDescOp::create(
603 Operation *loadedOp =
604 xegpu::LoadNdOp::create(rewriter, loc, loadedVecTy, ndDesc,
indices,
609 if (isTransposeLoad) {
613 int64_t rank = loadedVecTy.getRank();
614 SmallVector<int64_t> perm(llvm::to_vector(llvm::seq<int64_t>(0, rank)));
615 std::swap(perm[rank - 1], perm[rank - 2]);
616 loadedOp = vector::TransposeOp::create(rewriter, loc,
628 return lowerToScatteredLoadOp(readOp, rewriter);
632struct TransferWriteLowering
636 LogicalResult matchAndRewrite(vector::TransferWriteOp writeOp,
637 PatternRewriter &rewriter)
const override {
638 Location loc = writeOp.getLoc();
640 if (
failed(transferPreconditions(rewriter, writeOp)))
643 VectorType vecTy = writeOp.getVectorType();
644 auto writeMemTy = cast<MemRefType>(writeOp.getShapedType());
646 bool isSharedMemory = xegpu::XeGPUDialect::isSharedMemory(writeMemTy);
652 if (vecTy.getRank() != 1 && vecTy.getRank() != 2)
654 writeOp,
"Only 1D and 2D vector stores are supported for SLM");
657 xegpu::MemDescType::get(rewriter.
getContext(), writeMemTy.getShape(),
658 writeMemTy.getElementType(),
661 auto createMemDescOp = xegpu::CreateMemDescOp::create(
662 rewriter, loc, memDescType, writeOp.getBase());
665 SmallVector<OpFoldResult>
indices =
668 xegpu::StoreMatrixOp::create(rewriter, loc, writeOp.getVector(),
669 createMemDescOp.getResult(),
indices,
678 bool hasBlockStoreSupport =
679 (chip ==
"pvc" || chip ==
"bmg" || chip ==
"cri");
687 bool canLowerToStoreNd = hasBlockStoreSupport && vecTy.getRank() > 1 &&
689 writeMemTy.getElementType().isIntOrFloat();
691 if (canLowerToStoreNd) {
692 auto [src,
indices] = convertMemrefAndOffsetsToTargetRank(
693 rewriter, loc, writeOp.getBase(),
696 auto descType = xegpu::TensorDescType::get(
697 vecTy.getShape(), vecTy.getElementType(),
698 1, writeOp.hasOutOfBoundsDim(),
699 xegpu::MemorySpace::Global);
701 xegpu::CachePolicyAttr hint =
nullptr;
702 xegpu::CreateNdDescOp ndDesc = xegpu::CreateNdDescOp::create(
705 auto storeOp = xegpu::StoreNdOp::create(
706 rewriter, loc, writeOp.getVector(), ndDesc,
indices,
717 if (writeOp.hasOutOfBoundsDim())
719 return lowerToScatteredStoreOp(writeOp, rewriter);
726 LogicalResult matchAndRewrite(vector::GatherOp gatherOp,
727 PatternRewriter &rewriter)
const override {
728 auto srcTy = dyn_cast<MemRefType>(gatherOp.getBase().getType());
732 Location loc = gatherOp.getLoc();
733 VectorType vectorType = gatherOp.getVectorType();
735 auto meta = computeMemrefMeta(gatherOp, rewriter);
736 if (meta.first.empty())
740 computeOffsets(rewriter, gatherOp, meta.first, meta.second);
741 Value flatMemref = memrefToIndexPtr(gatherOp, rewriter);
743 auto xeGatherOp = xegpu::LoadGatherOp::create(
744 rewriter, loc, vectorType, flatMemref, localOffsets, gatherOp.getMask(),
746 xegpu::CachePolicyAttr{},
747 xegpu::CachePolicyAttr{},
748 xegpu::CachePolicyAttr{},
752 arith::SelectOp::create(rewriter, loc, gatherOp.getMask(),
753 xeGatherOp.getResult(), gatherOp.getPassThru());
754 rewriter.
replaceOp(gatherOp, selectOp.getResult());
762 LogicalResult matchAndRewrite(vector::ScatterOp scatterOp,
763 PatternRewriter &rewriter)
const override {
764 auto srcTy = dyn_cast<MemRefType>(scatterOp.getBase().getType());
768 Location loc = scatterOp.getLoc();
769 auto meta = computeMemrefMeta(scatterOp, rewriter);
770 if (meta.first.empty())
772 "Failed to compute strides");
775 computeOffsets(rewriter, scatterOp, meta.first, meta.second);
776 Value flatMemref = memrefToIndexPtr(scatterOp, rewriter);
778 xegpu::StoreScatterOp::create(rewriter, loc, scatterOp.getValueToStore(),
779 flatMemref, localOffsets, scatterOp.getMask(),
781 xegpu::CachePolicyAttr{},
782 xegpu::CachePolicyAttr{},
783 xegpu::CachePolicyAttr{},
794 LogicalResult matchAndRewrite(vector::LoadOp loadOp,
795 PatternRewriter &rewriter)
const override {
796 Location loc = loadOp.getLoc();
798 VectorType vecTy = loadOp.getResult().getType();
799 MemRefType memTy = loadOp.getBase().getType();
801 if (vecTy.getRank() != 1 && vecTy.getRank() != 2)
803 if (!memTy.getElementType().isIntOrFloat())
805 loadOp,
"Unsupported memref element type: expected integer or float");
808 bool boundaryCheck = vecTy.getRank() > 1;
810 xegpu::CachePolicyAttr hint =
nullptr;
812 auto [src,
indices] = convertMemrefAndOffsetsToTargetRank(
816 auto descType = xegpu::TensorDescType::get(
817 vecTy.getShape(), vecTy.getElementType(), 1,
818 boundaryCheck, xegpu::MemorySpace::Global);
820 xegpu::CreateNdDescOp ndDesc = xegpu::CreateNdDescOp::create(
823 xegpu::LoadNdOp::create(rewriter, loc, vecTy, ndDesc,
indices,
837 LogicalResult matchAndRewrite(vector::StoreOp storeOp,
838 PatternRewriter &rewriter)
const override {
839 Location loc = storeOp.getLoc();
842 VectorType vecTy = vector.getType();
843 MemRefType memTy = storeOp.getBase().getType();
845 if (vecTy.getRank() != 1 && vecTy.getRank() != 2)
847 if (!memTy.getElementType().isIntOrFloat())
850 "Unsupported memref element type: expected integer or float");
853 bool boundaryCheck = vecTy.getRank() > 1;
855 auto [src,
indices] = convertMemrefAndOffsetsToTargetRank(
856 rewriter, loc, storeOp.getBase(),
859 auto descType = xegpu::TensorDescType::get(
860 vecTy.getShape(), vecTy.getElementType(),
861 1, boundaryCheck, xegpu::MemorySpace::Global);
864 xegpu::CachePolicyAttr hint =
nullptr;
865 xegpu::CreateNdDescOp ndDesc = xegpu::CreateNdDescOp::create(
869 xegpu::StoreNdOp::create(rewriter, loc, vector, ndDesc,
indices,
884static std::optional<int64_t>
885getRowMajorMatmulBatchRank(
ArrayAttr indexingMaps) {
886 if (indexingMaps.size() != 3)
889 AffineMap mapA = cast<AffineMapAttr>(indexingMaps[0]).getValue();
890 AffineMap mapB = cast<AffineMapAttr>(indexingMaps[1]).getValue();
891 AffineMap mapC = cast<AffineMapAttr>(indexingMaps[2]).getValue();
900 unsigned numDims =
static_cast<unsigned>(batchRank) + 3;
901 unsigned numOperandResults =
static_cast<unsigned>(batchRank) + 2;
927 auto expected = ArrayAttr::get(
932 if (indexingMaps != expected)
937struct ContractionLowering :
public OpRewritePattern<vector::ContractionOp> {
940 LogicalResult matchAndRewrite(vector::ContractionOp contractOp,
941 PatternRewriter &rewriter)
const override {
942 Location loc = contractOp.getLoc();
944 if (contractOp.getKind() != vector::CombiningKind::ADD)
946 "Expects add combining kind");
951 VectorType accType = dyn_cast<VectorType>(acc.getType());
955 std::optional<int64_t> batchRank =
956 getRowMajorMatmulBatchRank(contractOp.getIndexingMapsAttr());
960 "Expects a (batched) row-major matmul: leading dims must "
961 "be batch dims shared by lhs, rhs, and acc; innermost two "
962 "dims must be (M, K), (K, N), and (M, N)");
967 "Expects operands of rank 4 or less");
969 auto dpasOp = xegpu::DpasOp::create(
970 rewriter, loc, contractOp.getResultType(),
lhs,
rhs, acc,
971 nullptr,
nullptr,
nullptr);
980static vector::ShapeCastOp getFlattenCast(
Value flat, VectorType ndType) {
982 if (shapeCast && shapeCast.getSourceVectorType() == ndType)
994static vector::BroadcastOp getSplatBroadcast(
Value flat) {
1003static bool canUnflatten(
Value flat, VectorType ndType) {
1004 return getFlattenCast(flat, ndType) || getDenseConstant(flat) ||
1005 getSplatBroadcast(flat);
1010 VectorType ndType) {
1011 assert(canUnflatten(flat, ndType) &&
"expected the cast to fold away");
1012 return vector::ShapeCastOp::create(rewriter, flat.
getLoc(), ndType, flat);
1036template <
typename OpTy>
1038 using OpRewritePattern<OpTy>::OpRewritePattern;
1040 LogicalResult matchAndRewrite(OpTy op,
1041 PatternRewriter &rewriter)
const override {
1042 constexpr bool isGather = std::is_same_v<OpTy, vector::GatherOp>;
1044 if (!isa<MemRefType>(op.getBase().getType()))
1047 if (op.getIndexVectorType().getRank() != 1)
1053 op.getIndices().template getDefiningOp<vector::ShapeCastOp>();
1054 if (!indexCast || indexCast.getSourceVectorType().getRank() < 2)
1056 op,
"index vector is not a shape_cast of an N-D vector");
1057 VectorType ndIndexType = indexCast.getSourceVectorType();
1058 VectorType ndMaskType =
1059 ndIndexType.cloneWith(std::nullopt, rewriter.
getI1Type());
1060 VectorType ndType = ndIndexType.cloneWith(
1061 std::nullopt, op.getVectorType().getElementType());
1065 if (!canUnflatten(op.getMask(), ndMaskType))
1068 if constexpr (isGather) {
1069 if (!canUnflatten(op.getPassThru(), ndType))
1071 "cannot un-flatten the pass-thru");
1073 Value mask = unflatten(rewriter, op.getMask(), ndMaskType);
1074 Value passThru = unflatten(rewriter, op.getPassThru(), ndType);
1075 auto ndGather = vector::GatherOp::create(
1076 rewriter, op.getLoc(), ndType, op.getBase(), op.getOffsets(),
1077 indexCast.getSource(), mask, passThru, op.getAlignmentAttr());
1078 ndGather->setDiscardableAttrs(op->getDiscardableAttrDictionary());
1082 if (!canUnflatten(op.getValueToStore(), ndType))
1084 op,
"cannot un-flatten the stored value");
1086 Value mask = unflatten(rewriter, op.getMask(), ndMaskType);
1087 Value valueToStore = unflatten(rewriter, op.getValueToStore(), ndType);
1091 op.getIndicesMutable().assign(indexCast.getSource());
1092 op.getMaskMutable().assign(mask);
1093 op.getValueToStoreMutable().assign(valueToStore);
1103static LogicalResult unflattenGatherScatter(
Operation *root) {
1106 patterns.add<UnflattenGatherScatter<vector::GatherOp>,
1107 UnflattenGatherScatter<vector::ScatterOp>>(ctx);
1108 vector::ShapeCastOp::getCanonicalizationPatterns(patterns, ctx);
1113static MemRefType withMemorySpace(MemRefType memrefTy,
Attribute newMemSpace) {
1114 return MemRefType::get(memrefTy.getShape(), memrefTy.getElementType(),
1115 memrefTy.getLayout(), newMemSpace);
1128static void promoteAllocasToSLM(
Operation *root) {
1130 Attribute slmAttr = IntegerAttr::get(IntegerType::get(ctx, 64), 3);
1136 auto isMemrefResultOp = [](
Operation *op) {
1139 return llvm::any_of(op->getResultTypes(),
1140 [](
Type t) { return isa<MemRefType>(t); });
1146 auto memrefTy = dyn_cast<MemRefType>(v.getType());
1147 if (!memrefTy || xegpu::XeGPUDialect::isSharedMemory(memrefTy))
1149 v.setType(withMemorySpace(memrefTy, slmAttr));
1151 if (!isMemrefResultOp(user))
1159 root->
walk([&](memref::AllocaOp op) {
1160 auto memrefTy = dyn_cast<MemRefType>(op.getResult().getType());
1161 if (!memrefTy || xegpu::XeGPUDialect::isSharedMemory(memrefTy))
1163 allocas.push_back(op);
1166 for (memref::AllocaOp alloca : allocas) {
1168 auto memrefTy = cast<MemRefType>(alloca.getResult().getType());
1169 auto newTy = withMemorySpace(memrefTy, slmAttr);
1170 auto newOp = memref::AllocaOp::create(
1171 builder, alloca.getLoc(), newTy, alloca.getDynamicSizes(),
1172 alloca.getSymbolOperands(), alloca.getAlignmentAttr());
1173 alloca.getResult().replaceAllUsesWith(newOp.getResult());
1177 if (!isMemrefResultOp(user))
1185struct ConvertVectorToXeGPUPass
1186 :
public impl::ConvertVectorToXeGPUBase<ConvertVectorToXeGPUPass> {
1187 void runOnOperation()
override {
1190 promoteAllocasToSLM(getOperation());
1194 if (
failed(unflattenGatherScatter(getOperation())))
1195 return signalPassFailure();
1201 return signalPassFailure();
1210 .
add<TransferReadLowering, TransferWriteLowering, LoadLowering,
1211 ScatterLowering, GatherLowering, StoreLowering, ContractionLowering>(
static std::optional< VectorShape > vectorShape(Type type)
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
static bool isSharedMemory(MemRefType type)
Return true if this is a shared memory memref type.
Base type for affine expression.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
MLIRContext * getContext() const
bool isMinorIdentity() const
Returns true if this affine map is a minor identity, i.e.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
bool isProjectedPermutation(bool allowZeroInResults=false) const
Returns true if the AffineMap represents a subset (i.e.
ArrayRef< AffineExpr > getResults() const
bool isPermutationOfMinorIdentityWithBroadcasting(SmallVectorImpl< unsigned > &permutedDims) const
Return true if this affine map can be converted to a minor identity with broadcast by doing a permute...
unsigned getNumResults() const
unsigned getNumInputs() const
AffineExpr getResult(unsigned idx) const
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
Attributes are known-constant values of operations.
IntegerAttr getI64IntegerAttr(int64_t value)
MLIRContext * getContext() const
An attribute that represents a reference to a dense vector or tensor object.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This class helps build Operations.
Operation is the basic unit of execution within MLIR.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
user_range getUsers()
Returns a range of all users.
MLIRContext * getContext()
Return the context this operation is associated with.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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.
user_range getUsers() const
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
std::optional< std::string > getChipStr(Operation *op)
Retrieves the chip string from the XeVM target attribute of the parent GPU module operation.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
void populatePrepareVectorToMMAPatterns(RewritePatternSet &patterns, bool useNvGpu=false)
Patterns to transform vector ops into a canonical form to convert to MMA matrix operations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map)
Return the reverse map of a projected permutation where the projected dimensions are transformed into...
SmallVector< T > applyPermutation(ArrayRef< T > input, ArrayRef< int64_t > permutation)
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
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 populateVectorToXeGPUConversionPatterns(RewritePatternSet &patterns)
Collect a set of patterns to convert from the vector to XeGPU ops.
llvm::TypeSwitch< T, ResultT > TypeSwitch
OpFoldResult getAsOpFoldResult(Value val)
Given a value, try to extract a constant Attribute.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...