23#include "llvm/ADT/STLExtras.h"
24#include "llvm/Support/DebugLog.h"
28#define GEN_PASS_DEF_XEGPUUNROLL
29#include "mlir/Dialect/XeGPU/Transforms/Passes.h.inc"
33#define DEBUG_TYPE "xegpu-unroll"
46template <
typename SourceOp>
56 LDBG() <<
"Get unroll shape for: " << *op;
58 if (
options.filterConstraint && failed(
options.filterConstraint(op))) {
59 LDBG() <<
"--no filter constraint -> BAIL";
64 "expects the native shape for native shape call back function.");
65 auto nativeShape =
options.nativeShape(op);
71 return options.getUnrolledTypes(type, tileShape);
78 if (
auto vecTy = dyn_cast<VectorType>(destTy)) {
79 auto shape = vecTy.getShape();
83 if (isa<xegpu::TensorDescType>(destTy)) {
88 auto castOp = UnrealizedConversionCastOp::create(
89 rewriter, loc, destTy, srcs,
91 return castOp.getResult(0);
94 llvm_unreachable(
"Unexpected destTy.");
103 if (
auto vecTy = dyn_cast<VectorType>(src.
getType())) {
108 if (isa<xegpu::TensorDescType>(src.
getType())) {
113 auto castOp = UnrealizedConversionCastOp::create(
114 rewriter, loc, destTypes, src,
116 return castOp.getResults();
119 llvm_unreachable(
"Unexpected src type.");
129 auto vecType = cast<VectorType>(operand.
getType());
130 std::optional<SmallVector<int64_t>> grids =
132 assert(grids &&
"Expecting grids to be computed.");
136 VectorType newVecTy =
137 vecType.cloneWith(blockSize, vecType.getElementType());
139 return pack(operand, convertedTypes, blockSize, loc, rewriter);
143 const char *
const packAttrName =
"__xegpu_blocking_pack__";
144 const char *
const unpackAttrName =
"__xegpu_blocking_unpack__";
145 const char *
const blockAttrName =
"__xegpu_blocking_tile_shape__";
159 int64_t rank = tdescTy.getRank();
167 auto aV = llvm::cast<Value>(a);
169 return rewriter.
createOrFold<arith::AddIOp>(loc, aV, bV);
174 llvm::drop_begin(mixedOffsets, mixedOffsets.size() - rank));
176 llvm::seq<int64_t>(mixedOffsets.size() - rank, mixedOffsets.size());
182 for (
auto [idx, oldOff, offset] :
183 llvm::zip(validIdxes, oldOffsets, offsets))
184 mixedOffsets[idx] = addi(oldOff, offset);
186 auto newOp = createOp(mixedOffsets);
187 newOps.push_back(newOp);
192struct UnrollCreateNdOp :
public UnrollPattern<xegpu::CreateNdDescOp> {
193 using UnrollPattern<xegpu::CreateNdDescOp>::UnrollPattern;
194 LogicalResult matchAndRewrite(xegpu::CreateNdDescOp op,
197 xegpu::TensorDescType tdescTy = op.getType();
199 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
204 Value src = op.getSource();
205 auto makeCreateNd = [&](
Type tdesc) ->
Value {
206 auto ndTy = cast<xegpu::TensorDescType>(tdesc);
207 if (isa<MemRefType>(src.
getType()))
208 return xegpu::CreateNdDescOp::create(rewriter, loc, ndTy,
210 return xegpu::CreateNdDescOp::create(
211 rewriter, loc, ndTy, src, op.getMixedSizes(), op.getMixedStrides());
216 if (tdescTy.getRank() <= 2) {
218 newOps.push_back(makeCreateNd(newTdescTys[0]));
221 for (
Type t : newTdescTys)
222 newOps.push_back(makeCreateNd(t));
224 Value castOp = unpack(newOps, tdescTy, *targetShape, loc, rewriter);
230struct UnrollPrefetchNdOp :
public UnrollPattern<xegpu::PrefetchNdOp> {
231 using UnrollPattern<xegpu::PrefetchNdOp>::UnrollPattern;
232 LogicalResult matchAndRewrite(xegpu::PrefetchNdOp op,
235 xegpu::TensorDescType tdescTy = op.getTensorDescType();
237 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
241 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
243 layout = layout.dropInstData();
247 getUnrolledTypes(tdescTy, *targetShape);
249 op.getTensorDesc(), convertedTdescTypes, *targetShape, loc, rewriter);
252 xegpu::PrefetchNdOp::create(rewriter, loc, convertedTdesc[0], offsets,
253 op.getL1HintAttr(), op.getL2HintAttr(),
254 op.getL3HintAttr(), layout);
257 unrollByTile(op.getMixedOffsets(), tdescTy, *targetShape, createPrefetch,
265struct UnrollLoadNdOp :
public UnrollPattern<xegpu::LoadNdOp> {
266 using UnrollPattern<xegpu::LoadNdOp>::UnrollPattern;
267 LogicalResult matchAndRewrite(xegpu::LoadNdOp op,
271 VectorType valueTy = op.getType();
272 xegpu::TensorDescType tdescTy = op.getTensorDescType();
274 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
278 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
280 layout = layout.dropInstData();
282 Type elemTy = tdescTy.getElementType();
283 VectorType newValueTy = valueTy.cloneWith(*targetShape, elemTy);
289 getUnrolledTypes(tdescTy, *targetShape);
291 op.getTensorDesc(), convertedTdescTypes, *targetShape, loc, rewriter);
294 return xegpu::LoadNdOp::create(
295 rewriter, loc, newValueTy, convertedTdescs[0], offsets,
296 op.getPackedAttr(), op.getTransposeAttr(), op.getL1HintAttr(),
297 op.getL2HintAttr(), op.getL3HintAttr(), layout);
299 newOps = unrollByTile(op.getMixedOffsets(), tdescTy, *targetShape,
300 createLoad, loc, rewriter);
302 Value castOp = unpack(newOps, op.getType(), *targetShape, loc, rewriter);
308struct UnrollStoreNdOp :
public UnrollPattern<xegpu::StoreNdOp> {
309 using UnrollPattern<xegpu::StoreNdOp>::UnrollPattern;
310 LogicalResult matchAndRewrite(xegpu::StoreNdOp op,
313 VectorType valueTy = op.getValueType();
314 xegpu::TensorDescType tdescTy = op.getTensorDescType();
316 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
320 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
322 layout = layout.dropInstData();
325 getUnrolledTypes(valueTy, *targetShape);
328 pack(op.getValue(), convertedValTypes, *targetShape, loc, rewriter);
330 size_t valueIndex = 0;
336 getUnrolledTypes(tdescTy, *targetShape);
338 op.getTensorDesc(), convertedTdescTypes, *targetShape, loc, rewriter);
341 xegpu::StoreNdOp::create(rewriter, loc, convertedValues[valueIndex++],
342 convertedTdescs[0], offsets, op.getL1HintAttr(),
343 op.getL2HintAttr(), op.getL3HintAttr(), layout);
344 return (
Value)
nullptr;
346 unrollByTile(op.getMixedOffsets(), tdescTy, *targetShape, createStore, loc,
354struct UnrollDpasOp :
public UnrollPattern<xegpu::DpasOp> {
355 using UnrollPattern<xegpu::DpasOp>::UnrollPattern;
356 LogicalResult matchAndRewrite(xegpu::DpasOp op,
360 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
361 if (!targetShape || targetShape->size() < 3)
365 int64_t tsRank = targetShape->size();
366 auto M = (*targetShape)[tsRank - 3];
367 auto K = (*targetShape)[tsRank - 2];
368 auto N = (*targetShape)[tsRank - 1];
373 aBlockSize.push_back(M);
374 aBlockSize.push_back(K);
376 bBlockSize.push_back(K);
377 bBlockSize.push_back(N);
379 cBlockSize.push_back(M);
380 cBlockSize.push_back(N);
382 auto a = op.getLhs();
383 auto b = op.getRhs();
384 auto c = op.getAcc();
390 cVals = packOperandForDpas(c, cBlockSize, loc, rewriter);
394 if (llvm::any_of(ranges, [](
auto &v) {
return v.size() == 0; }) ||
395 llvm::all_of(ranges, [](
auto &v) {
return v.size() == 1; }))
398 VectorType resultTy = op.getResult().getType();
399 auto vecTy = VectorType::get(cBlockSize, resultTy.getElementType());
401 auto aShape = a.getType().getShape();
402 auto bShape =
b.getType().getShape();
406 int64_t batchRank = batchDims.size();
407 int64_t mIters = aShape[batchRank] / M;
408 int64_t kIters = aShape[batchRank + 1] / K;
409 int64_t nIters = bShape[batchRank + 1] / N;
413 for (
int64_t d = 0; d < batchRank; ++d)
414 batchIters *= aShape[d] / batchDims[d];
417 for (
int64_t batch = 0; batch < batchIters; ++batch) {
418 for (
int64_t i = 0; i < mIters; ++i) {
422 tmpC = cVals[batch * (mIters * nIters) + i * nIters +
j];
424 for (
int64_t k = 0; k < kIters; ++k) {
425 Value aVec = aVals[batch * (mIters * kIters) + i * kIters + k];
426 Value bVec = bVals[batch * (kIters * nIters) + k * nIters +
j];
429 operands.push_back(tmpC);
431 auto newDpasOp = xegpu::DpasOp::create(
432 rewriter, loc,
TypeRange{vecTy}, operands, op.getProperties(),
434 op->getDiscardableAttrDictionary().getValue()));
436 tmpC = newDpasOp.getResult();
438 newOps.push_back(tmpC);
442 Value castOp = unpack(newOps, resultTy, cBlockSize, loc, rewriter);
448struct UnrollDpasMxOp :
public UnrollPattern<xegpu::DpasMxOp> {
449 using UnrollPattern<xegpu::DpasMxOp>::UnrollPattern;
450 LogicalResult matchAndRewrite(xegpu::DpasMxOp op,
454 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
455 if (!targetShape || targetShape->size() < 4)
459 int64_t tsRank = targetShape->size();
460 auto M = (*targetShape)[tsRank - 4];
461 auto K = (*targetShape)[tsRank - 3];
462 auto N = (*targetShape)[tsRank - 2];
463 auto S = (*targetShape)[tsRank - 1];
467 aBlockSize.push_back(M);
468 aBlockSize.push_back(K);
470 bBlockSize.push_back(K);
471 bBlockSize.push_back(N);
473 cBlockSize.push_back(M);
474 cBlockSize.push_back(N);
476 aScaleBlockSize.push_back(M);
477 aScaleBlockSize.push_back(S);
479 bScaleBlockSize.push_back(S);
480 bScaleBlockSize.push_back(N);
484 auto c = op.getAcc();
485 auto ascale = dyn_cast<TypedValue<VectorType>>(op.getScaleA());
486 auto bscale = dyn_cast<TypedValue<VectorType>>(op.getScaleB());
492 cVals = packOperandForDpas(c, cBlockSize, loc, rewriter);
495 aScaleVals = packOperandForDpas(ascale, aScaleBlockSize, loc, rewriter);
498 bScaleVals = packOperandForDpas(bscale, bScaleBlockSize, loc, rewriter);
500 VectorType resultTy = op.getResult().getType();
501 auto vecTy = VectorType::get(cBlockSize, resultTy.getElementType());
503 auto aShape = a.getType().getShape();
504 auto bShape =
b.getType().getShape();
505 int64_t batchRank = batchDims.size();
506 int64_t mIters = aShape[batchRank] / M;
507 int64_t kIters = aShape[batchRank + 1] / K;
508 int64_t nIters = bShape[batchRank + 1] / N;
511 for (
int64_t d = 0; d < batchRank; ++d)
512 batchIters *= aShape[d] / batchDims[d];
515 xegpu::DpasMxOp newDpasMxOp;
516 for (
int64_t batch = 0; batch < batchIters; ++batch) {
517 for (
int64_t i = 0; i < mIters; ++i) {
521 tmpC = cVals[batch * (mIters * nIters) + i * nIters +
j];
523 for (
int64_t k = 0; k < kIters; ++k) {
524 Value aVec = aVals[batch * (mIters * kIters) + i * kIters + k];
525 Value bVec = bVals[batch * (kIters * nIters) + k * nIters +
j];
528 operands.push_back(tmpC);
531 aScaleVals[batch * (mIters * kIters) + i * kIters + k]);
534 bScaleVals[batch * (kIters * nIters) + k * nIters +
j]);
536 newDpasMxOp = xegpu::DpasMxOp::create(
537 rewriter, loc,
TypeRange{vecTy}, operands, op.getProperties(),
539 op->getDiscardableAttrDictionary().getValue()));
541 tmpC = newDpasMxOp.getResult();
543 newOps.push_back(newDpasMxOp);
547 Value castOp = unpack(newOps, resultTy, cBlockSize, loc, rewriter);
557struct UnrollLoadGatherOp :
public UnrollPattern<xegpu::LoadGatherOp> {
558 using UnrollPattern<xegpu::LoadGatherOp>::UnrollPattern;
559 LogicalResult matchAndRewrite(xegpu::LoadGatherOp op,
562 VectorType valueTy = llvm::dyn_cast<VectorType>(op.getType());
563 Value offsets = op.getOffsets();
564 Value mask = op.getMask();
566 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
571 int64_t chunkSize = op.getChunkSize().value_or(1);
574 VectorType maskTy = llvm::dyn_cast<VectorType>(mask.getType());
575 VectorType offsetsTy = llvm::dyn_cast<VectorType>(offsets.
getType());
576 Type elemTy = valueTy.getElementType();
577 VectorType newValueTy = VectorType::get(*targetShape, elemTy);
586 targetMaskShape.pop_back();
587 int64_t blockedChunkSize = targetShape->back();
588 int64_t numNewChunks = chunkSize / blockedChunkSize;
589 chunkSize = blockedChunkSize;
591 convertedMaskTypes = getUnrolledTypes(maskTy, targetMaskShape);
592 convertedOffsetTypes = getUnrolledTypes(offsetsTy, targetMaskShape);
595 pack(mask, convertedMaskTypes, targetMaskShape, loc, rewriter);
597 pack(offsets, convertedOffsetTypes, targetMaskShape, loc, rewriter);
599 for (
auto maskVal : convertedMasksBase)
600 convertedMasks.append(numNewChunks, maskVal);
602 for (
auto [baseOffset, offsetType] :
603 llvm::zip(convertedOffsetsBase, convertedOffsetTypes)) {
604 for (
int64_t i = 0; i < numNewChunks; ++i) {
606 i * blockedChunkSize);
608 vector::BroadcastOp::create(rewriter, loc, offsetType, inc);
610 arith::AddIOp::create(rewriter, loc, baseOffset, incVec);
611 convertedOffsets.push_back(offsetVal);
615 convertedMaskTypes = getUnrolledTypes(maskTy, targetMaskShape);
617 pack(mask, convertedMaskTypes, targetMaskShape, loc, rewriter);
619 convertedOffsetTypes = getUnrolledTypes(offsetsTy, *targetShape);
621 pack(offsets, convertedOffsetTypes, *targetShape, loc, rewriter);
624 auto layout = op.getLayoutAttr();
626 layout = layout.dropInstData();
629 for (
auto [o, m] : llvm::zip(convertedOffsets, convertedMasks)) {
630 auto newOp = xegpu::LoadGatherOp::create(
631 rewriter, loc, newValueTy, op.getSource(), o, m,
633 op.getL2HintAttr(), op.getL3HintAttr(), layout,
635 newOps.push_back(newOp);
638 Value castOp = unpack(newOps, op.getType(), *targetShape, loc, rewriter);
648struct UnrollStoreScatterOp :
public UnrollPattern<xegpu::StoreScatterOp> {
649 using UnrollPattern<xegpu::StoreScatterOp>::UnrollPattern;
650 LogicalResult matchAndRewrite(xegpu::StoreScatterOp op,
653 VectorType valueTy = llvm::dyn_cast<VectorType>(op.getValue().getType());
654 Value offsets = op.getOffsets();
655 Value mask = op.getMask();
657 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
661 int64_t chunkSize = op.getChunkSize().value_or(1);
664 VectorType maskTy = llvm::dyn_cast<VectorType>(mask.getType());
665 VectorType offsetsTy = llvm::dyn_cast<VectorType>(offsets.
getType());
673 targetMaskShape.pop_back();
674 int64_t blockedChunkSize = targetShape->back();
675 int64_t numNewChunks = chunkSize / blockedChunkSize;
676 chunkSize = blockedChunkSize;
678 convertedMaskTypes = getUnrolledTypes(maskTy, targetMaskShape);
679 convertedOffsetTypes = getUnrolledTypes(offsetsTy, targetMaskShape);
682 pack(mask, convertedMaskTypes, targetMaskShape, loc, rewriter);
684 pack(offsets, convertedOffsetTypes, targetMaskShape, loc, rewriter);
686 for (
auto maskVal : convertedMasksBase)
687 convertedMasks.append(numNewChunks, maskVal);
689 for (
auto [baseOffset, offsetType] :
690 llvm::zip(convertedOffsetsBase, convertedOffsetTypes)) {
691 for (
int64_t i = 0; i < numNewChunks; ++i) {
693 i * blockedChunkSize);
695 vector::BroadcastOp::create(rewriter, loc, offsetType, inc);
697 arith::AddIOp::create(rewriter, loc, baseOffset, incVec);
698 convertedOffsets.push_back(offsetVal);
702 convertedMaskTypes = getUnrolledTypes(maskTy, targetMaskShape);
704 pack(mask, convertedMaskTypes, targetMaskShape, loc, rewriter);
706 convertedOffsetTypes = getUnrolledTypes(offsetsTy, *targetShape);
708 pack(offsets, convertedOffsetTypes, *targetShape, loc, rewriter);
712 getUnrolledTypes(valueTy, *targetShape);
714 pack(op.getValue(), convertedValTypes, *targetShape, loc, rewriter);
716 auto layout = op.getLayoutAttr();
718 layout = layout.dropInstData();
720 for (
auto [v, o, m] :
721 llvm::zip(convertedValues, convertedOffsets, convertedMasks)) {
722 xegpu::StoreScatterOp::create(rewriter, loc, v, op.getDest(), o, m,
724 op.getL1HintAttr(), op.getL2HintAttr(),
725 op.getL3HintAttr(), layout,
734struct UnrollLoadMatrixOp :
public UnrollPattern<xegpu::LoadMatrixOp> {
735 using UnrollPattern<xegpu::LoadMatrixOp>::UnrollPattern;
736 LogicalResult matchAndRewrite(xegpu::LoadMatrixOp op,
739 VectorType valueTy = llvm::dyn_cast<VectorType>(op.getType());
740 assert(valueTy &&
"the value type must be vector type!");
742 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
743 if (!targetShape || targetShape->size() != (
size_t)valueTy.getRank())
746 Type elemTy = valueTy.getElementType();
748 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
750 VectorType newValueTy = valueTy.cloneWith(*targetShape, elemTy);
757 rewriter, loc, mixedOffsets,
759 offsetsList.push_back(adds);
764 layout = layout.dropInstData();
766 auto newOp = xegpu::LoadMatrixOp::create(
767 rewriter, op.getLoc(), newValueTy, op.getMemDesc(), offsets, layout);
768 newOps.push_back(newOp);
770 Value castOp = unpack(newOps, op.getType(), *targetShape, loc, rewriter);
776struct UnrollStoreMatrixOp :
public UnrollPattern<xegpu::StoreMatrixOp> {
777 using UnrollPattern<xegpu::StoreMatrixOp>::UnrollPattern;
778 LogicalResult matchAndRewrite(xegpu::StoreMatrixOp op,
780 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
785 VectorType valueTy = llvm::dyn_cast<VectorType>(op.getData().getType());
786 assert(valueTy &&
"the value type must be vector type!");
788 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
790 layout = layout.dropInstData();
793 getUnrolledTypes(valueTy, *targetShape);
795 pack(op.getData(), convertedValTypes, *targetShape, loc, rewriter);
802 rewriter, loc, mixedOffsets,
804 offsetsList.push_back(adds);
807 for (
auto [v, offsets] : llvm::zip_equal(convertedValues, offsetsList))
808 xegpu::StoreMatrixOp::create(rewriter, loc, v, op.getMemDesc(), offsets,
826struct UnrollConvertLayoutOp :
public UnrollPattern<xegpu::ConvertLayoutOp> {
827 using UnrollPattern<xegpu::ConvertLayoutOp>::UnrollPattern;
833 rewriteWithRegrouping(xegpu::ConvertLayoutOp op, VectorType valueTy,
836 xegpu::DistributeLayoutAttr inputLayout,
837 xegpu::DistributeLayoutAttr targetLayout,
Location loc,
845 Type elemTy = valueTy.getElementType();
846 int64_t rank = valueTy.getRank();
847 VectorType convTy = VectorType::get(convTile, elemTy);
850 Value source = op.getSource();
851 auto zeroOf = [&](VectorType ty) ->
Value {
852 return arith::ConstantOp::create(
859 for (
auto [r, v] : llvm::zip_equal(res,
b))
869 if (convTile == inTile) {
870 conv = vector::ExtractStridedSliceOp::create(
871 rewriter, loc, source, convOff, convTile, strides);
873 conv = zeroOf(convTy);
876 Value piece = vector::ExtractStridedSliceOp::create(
877 rewriter, loc, source, addOffsets(convOff, inLocal), inTile,
879 conv = vector::InsertStridedSliceOp::create(rewriter, loc, piece,
880 conv, inLocal, strides);
884 conv = xegpu::ConvertLayoutOp::create(rewriter, loc, convTy, conv,
885 inputLayout, targetLayout);
888 if (convTile == outTile) {
889 result = vector::InsertStridedSliceOp::create(rewriter, loc, conv,
890 result, convOff, strides);
894 Value piece = vector::ExtractStridedSliceOp::create(
895 rewriter, loc, conv, outLocal, outTile, strides);
896 result = vector::InsertStridedSliceOp::create(
897 rewriter, loc, piece,
result, addOffsets(convOff, outLocal),
907 LogicalResult matchAndRewrite(xegpu::ConvertLayoutOp op,
910 Type valType = op.getType();
912 xegpu::DistributeLayoutAttr inputLayout = op.getEffectiveInputLayout();
913 xegpu::DistributeLayoutAttr targetLayout = op.getTargetLayoutAttr();
914 if (!inputLayout || !targetLayout)
925 if (inTile.empty() || outTile.empty())
928 inputLayout = inputLayout.dropInstData();
929 targetLayout = targetLayout.dropInstData();
931 VectorType valueTy = llvm::dyn_cast<VectorType>(op.getType());
932 assert(valueTy &&
"the value type must be vector type!");
934 std::optional<SmallVector<int64_t>> targetShape =
getTargetShape(op);
935 if (!targetShape || targetShape->size() != (
size_t)valueTy.getRank())
939 if (!inputLayout || !targetLayout || inputLayout.isEqualTo(targetLayout)) {
945 if (succeeded(rewriteWithRegrouping(op, valueTy, *targetShape, inTile,
946 outTile, inputLayout, targetLayout, loc,
952 getUnrolledTypes(valueTy, *targetShape);
954 pack(op.getOperand(), convertedValTypes, *targetShape, loc, rewriter);
956 for (
auto [v, t] : llvm::zip(convertedValues, convertedValTypes)) {
957 auto newOp = xegpu::ConvertLayoutOp::create(rewriter, loc, t, v,
958 inputLayout, targetLayout);
959 newOps.push_back(newOp);
961 Value newSource = unpack(newOps, op.getType(), *targetShape, loc, rewriter);
982struct UnrollMultiReductionOp
983 :
public UnrollPattern<vector::MultiDimReductionOp> {
987 : UnrollPattern<vector::MultiDimReductionOp>(context,
options, benefit) {}
989 LogicalResult matchAndRewrite(vector::MultiDimReductionOp reductionOp,
991 VectorType srcTy = reductionOp.getSourceVectorType();
993 int64_t srcRank = srcTy.getRank();
995 Location loc = reductionOp.getLoc();
996 Value source = reductionOp.getSource();
998 vector::CombiningKind kind = reductionOp.getKind();
1001 auto resultType = dyn_cast<VectorType>(reductionOp.getDestType());
1005 std::optional<SmallVector<int64_t>> targetShapeOpt =
1007 if (!targetShapeOpt ||
1008 static_cast<int64_t>(targetShapeOpt->size()) != srcRank)
1014 for (
int64_t i = 0; i < srcRank; ++i) {
1015 if (srcShape[i] % targetShape[i] != 0)
1022 for (
int64_t i = 0; i < srcRank; ++i) {
1023 if (reductionMask[i])
1024 reducedDims.push_back(i);
1026 keptDims.push_back(i);
1033 numReducedTilesPerDim.push_back(srcShape[d] / targetShape[d]);
1038 keptShape.push_back(srcShape[d]);
1039 keptTileShape.push_back(targetShape[d]);
1043 Value result = arith::ConstantOp::create(rewriter, loc, resultType,
1056 for (
auto [idx, dim] : llvm::enumerate(keptDims))
1057 baseOffsets[dim] = keptOffsets[idx];
1073 for (
auto [idx, dim] : llvm::enumerate(reducedDims))
1074 offsets[dim] = reducedTileIdx[idx] * targetShape[dim];
1076 Value tile = vector::ExtractStridedSliceOp::create(
1077 rewriter, loc, source, offsets, targetShape, strides);
1078 tiles.push_back(
tile);
1082 Value reduced = tiles[0];
1083 for (
size_t i = 1; i < tiles.size(); ++i)
1089 Value accSlice = vector::ExtractStridedSliceOp::create(
1090 rewriter, loc,
acc, keptOffsets, keptTileShape, accStrides);
1092 auto newReduction = vector::MultiDimReductionOp::create(
1093 rewriter, loc, reduced, accSlice, reductionMask, kind);
1097 result = vector::InsertStridedSliceOp::create(
1098 rewriter, loc, newReduction,
result, keptOffsets, dstStrides);
1111 .
add<UnrollCreateNdOp, UnrollPrefetchNdOp, UnrollLoadNdOp,
1112 UnrollStoreNdOp, UnrollDpasOp, UnrollDpasMxOp, UnrollLoadMatrixOp,
1113 UnrollStoreMatrixOp, UnrollLoadGatherOp, UnrollStoreScatterOp,
1114 UnrollConvertLayoutOp, UnrollMultiReductionOp>(patterns.
getContext(),
static llvm::ManagedStatic< PassManagerOptions > options
static std::optional< SmallVector< int64_t > > getTargetShape(const vector::UnrollVectorOptions &options, Operation *op)
Return the target shape for unrolling for the given op.
DenseI64ArrayAttr getDenseI64ArrayAttr(ArrayRef< int64_t > values)
IntegerAttr getI64IntegerAttr(int64_t value)
StringAttr getStringAttr(const Twine &bytes)
TypedAttr getZeroAttr(Type type)
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
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.
NamedAttribute represents a combination of a name and an Attribute value.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
This class represents a single result from folding an operation.
Operation is the basic unit of execution within MLIR.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
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,...
A range-style iterator that allows for iterating over the offsets of all potential tiles of size tile...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
This class provides an abstraction over the different types of ranges over Values.
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.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
Value makeArithReduction(OpBuilder &b, Location loc, CombiningKind kind, Value v1, Value acc, arith::FastMathFlagsAttr fastmath=nullptr, Value mask=nullptr)
Returns the result value of reducing two scalar/vector values with the corresponding arith operation.
Value createVectorWithShapeFromValues(OpBuilder &builder, Location loc, ValueRange values, ArrayRef< int64_t > shape)
Create a vector of shape from a set of values using vector.insert_stride_slice.
void populateXeGPUUnrollPatterns(RewritePatternSet &patterns, const UnrollOptions &options)
Collect a set of patterns to unroll xegpu operations to a smaller shapes.
SmallVector< NamedAttribute > dropInstDataOnAttrs(ArrayRef< NamedAttribute > attrs)
Updates the NamedAttribute sequence by dropping inst-data information from any DistributeLayoutAttr f...
void dropInstDataOnInherentAttrs(Operation *op)
Drops inst-data information from DistributeLayoutAttrs stored as inherent attributes on the operation...
SmallVector< Value > extractVectorsWithShapeFromValue(OpBuilder &builder, Location loc, Value value, ArrayRef< int64_t > shape)
Extract a set of small vectors from a value with a given shape using vector.extract_stride_slice.
SmallVector< OpFoldResult > addElementwise(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > lhs, ArrayRef< OpFoldResult > rhs)
Generates element-wise addition ops of two arrays with same length.
Include the generated interface declarations.
OpFoldResult getAsIndexOpFoldResult(MLIRContext *ctx, int64_t val)
Convert int64_t to integer attributes of index type and return them as OpFoldResult.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
int64_t computeProduct(ArrayRef< int64_t > basis)
Self-explicit.
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.
SmallVector< Loops, 8 > tile(ArrayRef< scf::ForOp > forOps, ArrayRef< Value > sizes, ArrayRef< scf::ForOp > targets)
Performs tiling fo imperfectly nested loops (with interchange) by strip-mining the forOps by sizes an...
std::optional< SmallVector< int64_t > > computeShapeRatio(ArrayRef< int64_t > shape, ArrayRef< int64_t > subShape)
Return the multi-dimensional integral ratio of subShape to the trailing dimensions of shape.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Options to control the XeGPU unrolling.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.