30#include "llvm/ADT/SetVector.h"
31#include "llvm/Support/LogicalResult.h"
32#include "llvm/Support/raw_ostream.h"
37#define GEN_PASS_DEF_XEGPUSGTOLANEDISTRIBUTE
38#include "mlir/Dialect/XeGPU/Transforms/Passes.h.inc"
44#define DEBUG_TYPE "xegpu-sg-to-lane-distribute"
45#define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE "]: ")
50static Value castValueTo(ConversionPatternRewriter &rewriter,
53 if (v.getType() == expectedTy)
56 if (isa<VectorType>(v.getType()) &&
57 v.getType().getNumElements() == expectedTy.getNumElements())
58 return vector::ShapeCastOp::create(rewriter, v.getLoc(), expectedTy, v);
61 auto newOp = UnrealizedConversionCastOp::create(rewriter, v.getLoc(),
63 return newOp.getResult(0);
69static bool isValidSubgroupMultiReductionOp(vector::MultiDimReductionOp op) {
72 if (!resLayout || !resLayout.isForSubgroup())
75 if (op.getType().isIntOrFloat())
76 return op.getReductionDims().size() == 1;
77 VectorType resTy = dyn_cast<VectorType>(op.getType());
81 FailureOr<VectorType> resDistTypeOrFailure =
82 getDistVecTypeBasedOnLaneLayout(resLayout, resTy);
83 if (failed(resDistTypeOrFailure))
85 return op.getReductionDims().size() == 1;
92static bool isReductionLaneLocal(vector::MultiDimReductionOp op) {
94 assert(isValidSubgroupMultiReductionOp(op) &&
"Expecting a valid subgroup "
95 "MultiDimReductionOp");
97 VectorType resTy = dyn_cast<VectorType>(op.getType());
98 auto resDistTypeOrFailure = getDistVecTypeBasedOnLaneLayout(resLayout, resTy);
99 return resTy != resDistTypeOrFailure.value();
105 VectorType distributedType) {
106 assert(originalType.getRank() == distributedType.getRank() &&
107 "original and distributed vector types must have the same rank");
109 for (
int64_t i = 0; i < originalType.getRank(); ++i) {
110 if (distributedType.getDimSize(i) != originalType.getDimSize(i))
111 distributedDims.push_back(i);
113 return distributedDims;
118struct SgToLaneCreateNdDesc
119 :
public OpConversionPattern<xegpu::CreateNdDescOp> {
120 using OpConversionPattern<xegpu::CreateNdDescOp>::OpConversionPattern;
123 matchAndRewrite(xegpu::CreateNdDescOp op, OpAdaptor adaptor,
124 ConversionPatternRewriter &rewriter)
const override {
125 xegpu::TensorDescType resultType = op.getType();
127 if (!resultType.getLayout())
130 auto newOp = xegpu::CreateNdDescOp::create(
131 rewriter, op.getLoc(), resultType.dropLayouts(), op.getOperands(),
133 rewriter.replaceOp(op, newOp.getResult());
141struct SgToLaneLoadNd :
public OpConversionPattern<xegpu::LoadNdOp> {
142 using OpConversionPattern<xegpu::LoadNdOp>::OpConversionPattern;
145 matchAndRewrite(xegpu::LoadNdOp op, OpAdaptor adaptor,
146 ConversionPatternRewriter &rewriter)
const override {
147 xegpu::DistributeLayoutAttr layout = op.getAnchorLayout();
153 if (op.getTensorDescType().getLayout() != layout)
154 return rewriter.notifyMatchFailure(
155 op,
"conflicting layout attributes on tensor descriptor and anchor");
159 return rewriter.notifyMatchFailure(
160 op,
"xegpu::LoadNdOp require target attribute attached to "
161 "determine transpose "
163 auto supportedLaneResultTyOrFailure =
165 auto expectedLaneResultTyOrFailure =
167 if (failed(supportedLaneResultTyOrFailure))
168 return rewriter.notifyMatchFailure(
169 op,
"unable to compute the lane vector type for LoadNdOp");
170 if (failed(expectedLaneResultTyOrFailure))
171 return rewriter.notifyMatchFailure(
172 op,
"unable to compute expected lane vector type from lane layout");
173 auto newOp = xegpu::LoadNdOp::create(
174 rewriter, op.getLoc(), supportedLaneResultTyOrFailure.value(),
175 adaptor.getTensorDesc(), op.getMixedOffsets(), op.getPackedAttr(),
176 op.getTransposeAttr(), op.getL1HintAttr(), op.getL2HintAttr(),
177 op.getL3HintAttr(),
nullptr);
183 rewriter.replaceOp(op, castValueTo(rewriter, newOp.getResult(),
184 expectedLaneResultTyOrFailure.value()));
192struct SgToLaneStoreNd :
public OpConversionPattern<xegpu::StoreNdOp> {
193 using OpConversionPattern<xegpu::StoreNdOp>::OpConversionPattern;
196 matchAndRewrite(xegpu::StoreNdOp op, OpAdaptor adaptor,
197 ConversionPatternRewriter &rewriter)
const override {
198 xegpu::DistributeLayoutAttr layout = op.getAnchorLayout();
204 if (op.getTensorDescType().getLayout() != layout)
205 return rewriter.notifyMatchFailure(
206 op,
"conflicting layout attributes on tensor descriptor and anchor");
208 if (valueLayout != layout)
209 return rewriter.notifyMatchFailure(
210 op,
"conflicting layout attributes on value and anchor");
211 auto supportedLaneValueTyOrFailure =
213 if (failed(supportedLaneValueTyOrFailure))
214 return rewriter.notifyMatchFailure(
216 "unable to compute lane vector type for StoreNdOp value from tensor "
219 xegpu::StoreNdOp::create(
220 rewriter, op.getLoc(),
222 supportedLaneValueTyOrFailure.value()),
223 adaptor.getTensorDesc(), op.getMixedOffsets(), op.getL1HintAttr(),
224 op.getL2HintAttr(), op.getL3HintAttr(),
nullptr);
225 rewriter.eraseOp(op);
233struct SgToLaneDpas :
public OpConversionPattern<xegpu::DpasOp> {
234 using OpConversionPattern<xegpu::DpasOp>::OpConversionPattern;
237 matchAndRewrite(xegpu::DpasOp op, OpAdaptor adaptor,
238 ConversionPatternRewriter &rewriter)
const override {
240 auto layoutA = cast<xegpu::LayoutAttr>(op.getLayoutAAttr());
241 auto layoutB = cast<xegpu::LayoutAttr>(op.getLayoutBAttr());
242 auto layoutCd = cast<xegpu::LayoutAttr>(op.getLayoutCdAttr());
243 if (!layoutA || !layoutB || !layoutCd)
245 auto laneResultTyOrFailure =
247 auto laneATypeOrFailure =
249 auto laneBTypeOrFailure =
251 auto expectedLaneResultTyOrFailure =
253 if (failed(laneResultTyOrFailure) || failed(laneATypeOrFailure) ||
254 failed(laneBTypeOrFailure))
255 return rewriter.notifyMatchFailure(
256 op,
"failed to calculate supported lane vector types for DpasOp "
258 if (failed(expectedLaneResultTyOrFailure))
259 return rewriter.notifyMatchFailure(
260 op,
"unable to compute expected lane vector type for DpasOp from "
267 const auto *uArchInstruction =
268 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(
269 uArch->getInstruction(
271 if (uArchInstruction) {
272 auto laneAType = laneATypeOrFailure.value();
273 auto laneBType = laneBTypeOrFailure.value();
275 unsigned aPackedBitWidth =
276 laneAType.getElementTypeBitWidth() * laneAType.getNumElements();
277 unsigned bPackedBitWidth =
278 laneBType.getElementTypeBitWidth() * laneBType.getNumElements();
279 unsigned expectedABitSize = uArchInstruction->getPackedFormatBitSizeA();
280 unsigned expectedBBitSize = uArchInstruction->getPackedFormatBitSizeB();
282 if (aPackedBitWidth % expectedABitSize != 0)
283 return rewriter.notifyMatchFailure(
285 "A operand packed bit width must be a multiple of uArch packed "
286 "format requirement");
287 if (bPackedBitWidth % expectedBBitSize != 0)
288 return rewriter.notifyMatchFailure(
290 "B operand packed bit width must be a multiple of uArch packed "
291 "format requirement");
295 auto newOp = xegpu::DpasOp::create(
296 rewriter, op->getLoc(), laneResultTyOrFailure.value(),
298 laneATypeOrFailure.value()),
300 laneBTypeOrFailure.value()),
302 laneResultTyOrFailure.value()),
306 rewriter.replaceOp(op, castValueTo(rewriter, newOp.getResult(),
307 expectedLaneResultTyOrFailure.value()));
314struct SgToLaneElementWise :
public ConversionPattern {
316 : ConversionPattern(MatchAnyOpTypeTag(), 1, ctx) {}
320 ConversionPatternRewriter &rewriter)
const override {
327 return rewriter.notifyMatchFailure(
328 op,
"operation result is not a vector type");
330 xegpu::DistributeLayoutAttr layout =
332 if (!layout || !layout.isForSubgroup())
333 return rewriter.notifyMatchFailure(
334 op,
"operation result does not have subgroup distribute layout");
336 auto laneShapeOrFailure =
339 if (failed(laneShapeOrFailure))
340 return rewriter.notifyMatchFailure(
341 op,
"unable to compute lane vector type from the layout");
343 VectorType newResultType = laneShapeOrFailure.value();
345 state.addOperands(operands);
346 state.addTypes(newResultType);
349 if (!isa<xegpu::DistributeLayoutAttr>(attr.getValue()))
350 state.addAttribute(attr.getName(), attr.getValue());
352 Operation *newOp = rewriter.create(state);
354 rewriter.replaceOp(op, newOp->
getResult(0));
366struct SgToLaneArithConstant :
public OpConversionPattern<arith::ConstantOp> {
367 using OpConversionPattern<arith::ConstantOp>::OpConversionPattern;
370 matchAndRewrite(arith::ConstantOp op, OpAdaptor adaptor,
371 ConversionPatternRewriter &rewriter)
const override {
372 auto resultType = dyn_cast<VectorType>(op.getType());
377 auto denseAttr = dyn_cast<DenseElementsAttr>(op.getValue());
379 return rewriter.notifyMatchFailure(
380 op,
"only dense vector constants are supported");
382 xegpu::DistributeLayoutAttr layout =
384 if (!layout || !layout.isForSubgroup())
385 return rewriter.notifyMatchFailure(
386 op,
"operation result does not have subgroup distribute layout");
388 auto laneShapeOrFailure =
391 if (
failed(laneShapeOrFailure))
392 return rewriter.notifyMatchFailure(
393 op,
"unable to compute lane vector type from the layout");
395 VectorType newResultType = laneShapeOrFailure.value();
396 Location loc = op.getLoc();
400 if (denseAttr.isSplat()) {
401 auto scalarValue = denseAttr.getSplatValue<Attribute>();
404 arith::ConstantOp::create(rewriter, loc, newResultType, newDenseAttr);
405 rewriter.replaceOp(op, newOp.
getResult());
412 arith::ConstantOp::create(rewriter, loc, resultType, denseAttr);
414 Value laneId = gpu::LaneIdOp::create(rewriter, loc, rewriter.getIndexType(),
415 mlir::IntegerAttr());
416 auto maybeCoordsVec = layout.computeDistributedCoords(
417 rewriter, loc, laneId, resultType.getShape());
418 if (
failed(maybeCoordsVec))
419 return rewriter.notifyMatchFailure(
420 op,
"failed to compute distributed coordinates from layout");
422 SmallVector<SmallVector<Value>> coordsVec = maybeCoordsVec.value();
423 SmallVector<int64_t> laneData = layout.getEffectiveLaneDataAsInt();
424 ArrayRef<int64_t> distShape = newResultType.getShape();
425 int64_t rank = newResultType.getRank();
430 SmallVector<int64_t> blockGridShape(rank);
431 for (int64_t d = 0; d < rank; d++)
432 blockGridShape[d] = distShape[d] / laneData[d];
433 SmallVector<int64_t> blockGridStrides =
computeStrides(blockGridShape);
435 auto blockType = VectorType::get(laneData, newResultType.getElementType());
436 SmallVector<int64_t> unitTile(rank, 1);
437 SmallVector<int64_t> strides(rank, 1);
439 Value
result = arith::ConstantOp::create(
440 rewriter, loc, newResultType, rewriter.getZeroAttr(newResultType));
442 for (
auto [blockIdx, blockStart] : llvm::enumerate(coordsVec)) {
446 SmallVector<Value> blockElems;
447 for (SmallVector<int64_t> off :
448 StaticTileOffsetRange(laneData, unitTile)) {
449 SmallVector<OpFoldResult> pos(rank);
450 for (int64_t d = 0; d < rank; d++)
452 rewriter, loc, blockStart[d],
454 blockElems.push_back(vector::ExtractOp::create(
455 rewriter, loc, fullConst.getResult(), pos));
462 vector::FromElementsOp::create(rewriter, loc, blockType, blockElems);
463 SmallVector<int64_t> blockGridPos =
465 SmallVector<int64_t> offsets(rank);
466 for (int64_t d = 0; d < rank; d++)
467 offsets[d] = blockGridPos[d] * laneData[d];
468 result = vector::InsertStridedSliceOp::create(rewriter, loc, block,
469 result, offsets, strides);
472 rewriter.replaceOp(op,
result);
478struct SgToLanePrefetchNd :
public OpConversionPattern<xegpu::PrefetchNdOp> {
479 using OpConversionPattern<xegpu::PrefetchNdOp>::OpConversionPattern;
482 matchAndRewrite(xegpu::PrefetchNdOp op, OpAdaptor adaptor,
483 ConversionPatternRewriter &rewriter)
const override {
484 xegpu::DistributeLayoutAttr layout = op.getAnchorLayout();
489 xegpu::PrefetchNdOp::create(rewriter, op.getLoc(), adaptor.getTensorDesc(),
490 op.getMixedOffsets(), op.getL1HintAttr(),
491 op.getL2HintAttr(), op.getL3HintAttr(),
493 rewriter.eraseOp(op);
531struct SgToLaneLoadGather :
public OpConversionPattern<xegpu::LoadGatherOp> {
532 using OpConversionPattern<xegpu::LoadGatherOp>::OpConversionPattern;
535 matchAndRewrite(xegpu::LoadGatherOp op, OpAdaptor adaptor,
536 ConversionPatternRewriter &rewriter)
const override {
537 xegpu::DistributeLayoutAttr layout = op.getAnchorLayout();
541 VectorType origResultTy = op.getValueType();
546 int chunkSize = op.getChunkSize().value_or(1);
547 int effectiveVecRank = (chunkSize == 1) ? 1 : 2;
548 ArrayRef<int64_t> shape = origResultTy.getShape();
550 shape.take_front(origResultTy.getRank() - effectiveVecRank),
551 [](int64_t d) { return d != 1; }))
552 return rewriter.notifyMatchFailure(
553 op,
"Only unit dimensions allowed for the leading "
554 "dimensions of the load vector!");
556 auto distResultTyOrFailure =
558 if (
failed(distResultTyOrFailure))
559 return rewriter.notifyMatchFailure(
560 op,
"unable to compute expected lane vector type from lane layout");
562 VectorType distResultTy = distResultTyOrFailure.value();
563 VectorType distResultTy1D = VectorType::get({distResultTy.getNumElements()},
564 distResultTy.getElementType());
567 Value distOffsets = adaptor.getOffsets();
568 auto distOffsetsTy = cast<VectorType>(distOffsets.
getType());
569 VectorType offsetsTy1D = VectorType::get({distOffsetsTy.getNumElements()},
570 distOffsetsTy.getElementType());
571 distOffsets = castValueTo(
574 Value distMask = adaptor.getMask();
575 auto distMaskTy = cast<VectorType>(distMask.
getType());
576 VectorType maskTy1D = VectorType::get({distMaskTy.getNumElements()},
577 distMaskTy.getElementType());
581 Value distSource = adaptor.getSource();
582 auto newOp = xegpu::LoadGatherOp::create(
583 rewriter, op.getLoc(), distResultTy1D, distSource, distOffsets,
584 distMask, op.getChunkSizeAttr(), op.getL1HintAttr(), op.getL2HintAttr(),
585 op.getL3HintAttr(),
nullptr,
nullptr);
588 if (distResultTy1D != distResultTy)
591 rewriter.replaceOp(op,
result);
600struct SgToLaneVectorReduction
601 :
public OpConversionPattern<vector::ReductionOp> {
602 using OpConversionPattern<vector::ReductionOp>::OpConversionPattern;
605 matchAndRewrite(vector::ReductionOp op, OpAdaptor adaptor,
606 ConversionPatternRewriter &rewriter)
const override {
610 if (!layout || !layout.isForSubgroup())
613 VectorType srcVecType = op.getSourceVectorType();
615 if (srcVecType.getRank() != 1)
616 return rewriter.notifyMatchFailure(
617 op,
"Only rank 1 reductions can be distributed.");
619 if (layout.getRank() != srcVecType.getRank())
620 return rewriter.notifyMatchFailure(
621 op,
"Layout rank does not match vector rank.");
624 int64_t sgSize = layout.getEffectiveLaneLayoutAsInt()[0];
628 return rewriter.notifyMatchFailure(
629 op,
"xegpu::ReductionOp require target attribute attached to "
630 "determine subgroup size");
633 if (sgSize != uArch->getSubgroupSize() ||
634 srcVecType.getShape()[0] % sgSize != 0)
635 return rewriter.notifyMatchFailure(op,
636 "Invalid layout or reduction vector "
637 "dimension must match subgroup size.");
639 if (!op.getType().isIntOrFloat())
640 return rewriter.notifyMatchFailure(
641 op,
"Reduction distribution currently only supports floats and "
645 Value laneValVec = adaptor.getVector();
649 op.getLoc(), rewriter, laneValVec, op.getKind(), sgSize);
652 if (adaptor.getAcc())
654 rewriter, op.getLoc(), op.getKind(), fullReduce, adaptor.getAcc());
656 rewriter.replaceOp(op, fullReduce);
665struct SgToLaneMultiDimReduction
666 :
public OpConversionPattern<vector::MultiDimReductionOp> {
667 using OpConversionPattern<vector::MultiDimReductionOp>::OpConversionPattern;
670 matchAndRewrite(vector::MultiDimReductionOp op, OpAdaptor adaptor,
671 ConversionPatternRewriter &rewriter)
const override {
673 ArrayRef<int64_t> reductionDims = op.getReductionDims();
674 assert(reductionDims.size() == 1 &&
675 "Expecting single reduction dimension for subgroup multi "
678 VectorType sourceType = op.getSourceVectorType();
679 int64_t rank = sourceType.getRank();
681 ArrayRef<int64_t> shape = sourceType.getShape();
682 if (llvm::any_of(shape.take_front(rank - 2),
683 [](int64_t d) { return d != 1; }))
684 return rewriter.notifyMatchFailure(
685 op,
"only unit leading dimensions are supported for "
686 "multi_reduction with rank > 2");
690 if (op.getType().isIntOrFloat()) {
691 auto reductionDim = reductionDims[0];
692 VectorType origSourceType = op.getSourceVectorType();
693 int64_t reductionDimSize = origSourceType.getShape()[reductionDim];
697 op.getKind(), reductionDimSize);
699 if (adaptor.getAcc())
701 result, adaptor.getAcc());
702 }
else if (isReductionLaneLocal(op)) {
706 auto reductionDim = reductionDims[0];
710 reductionDim, op.getLoc(), rewriter);
712 auto reductionDim = reductionDims[0];
713 VectorType sourceType = op.getSourceVectorType();
714 int64_t reductionDimSize = sourceType.getShape()[reductionDim];
718 reductionDim, reductionDimSize, op.getLoc(), rewriter);
720 rewriter.replaceOp(op,
result);
729 ConversionPatternRewriter &rewriter,
Location loc,
732 Value laneId = gpu::LaneIdOp::create(rewriter, loc, rewriter.getIndexType(),
733 mlir::IntegerAttr());
735 layout.computeDistributedCoords(rewriter, loc, laneId, payloadShape);
738 assert(maybeCoords.value().size() == 1 &&
739 "Expected one set of distributed offsets");
743 return llvm::map_to_vector(ofrVec, llvm::CastTo<Value>);
747struct SgToLaneLoadMatrix :
public OpConversionPattern<xegpu::LoadMatrixOp> {
748 using OpConversionPattern<xegpu::LoadMatrixOp>::OpConversionPattern;
751 matchAndRewrite(xegpu::LoadMatrixOp op, OpAdaptor adaptor,
752 ConversionPatternRewriter &rewriter)
const override {
753 auto layout = op.getLayoutAttr();
758 VectorType sgPayloadTy = dyn_cast<VectorType>(op.getResult().getType());
760 return rewriter.notifyMatchFailure(
761 op,
"the matrix op payload must be a vector type");
763 auto loc = op.getLoc();
764 auto offsets = op.getMixedOffsets();
766 return rewriter.notifyMatchFailure(op,
"the load op must have offsets");
768 FailureOr<VectorType> distPayloadTyOrFailure =
770 if (
failed(distPayloadTyOrFailure))
771 return rewriter.notifyMatchFailure(
772 op,
"Failed to distribute matrix op payload based on layout.");
774 SmallVector<Value> offsetsAsValues =
777 SmallVector<Value> newCoords = offsetsAsValues;
778 if (!op.getSubgroupBlockIoAttr()) {
779 newCoords = computeDistributedCoordsForMatrixOp(
780 rewriter, loc, layout, sgPayloadTy.getShape(), offsetsAsValues);
781 if (newCoords.empty())
782 return rewriter.notifyMatchFailure(
783 op,
"Failed to compute distributed coordinates.");
786 SmallVector<int64_t> newConstOffsets(op.getConstOffsets().size(),
787 ShapedType::kDynamic);
789 rewriter.getDenseI64ArrayAttr(newConstOffsets);
791 auto newOp = xegpu::LoadMatrixOp::create(
792 rewriter, loc, *distPayloadTyOrFailure, adaptor.getMemDesc(),
793 ValueRange(newCoords), newConstOffsetsAttr, op.getSubgroupBlockIoAttr(),
794 xegpu::DistributeLayoutAttr{});
795 rewriter.replaceOp(op, newOp.
getResult());
801struct SgToLaneVectorTranspose
802 :
public OpConversionPattern<vector::TransposeOp> {
803 using OpConversionPattern<vector::TransposeOp>::OpConversionPattern;
806 matchAndRewrite(vector::TransposeOp op, OpAdaptor adaptor,
807 ConversionPatternRewriter &rewriter)
const override {
808 xegpu::DistributeLayoutAttr sourceLayout =
810 xegpu::DistributeLayoutAttr resultLayout =
812 if (!sourceLayout || !resultLayout)
813 return rewriter.notifyMatchFailure(
814 op,
"the source or result vector of the transpose op lacks layout "
816 ArrayRef<int64_t> perm = op.getPermutation();
818 if (!resultLayout.isTransposeOf(sourceLayout, perm,
819 xegpu::LayoutKind::Lane))
820 return rewriter.notifyMatchFailure(
821 op,
"the source or result vector layouts must be transposes of "
823 FailureOr<VectorType> distributedResultTypeOrFailure =
825 if (
failed(distributedResultTypeOrFailure))
826 return rewriter.notifyMatchFailure(
827 op,
"Failed to distribute the result vector type in "
828 "vector::Transpose op");
829 auto newOp = vector::TransposeOp::create(rewriter, op.getLoc(),
830 adaptor.getVector(), perm);
831 rewriter.replaceOp(op, castValueTo(rewriter, newOp.
getResult(),
832 distributedResultTypeOrFailure.value()));
839struct SgToLaneVectorBitcast :
public OpConversionPattern<vector::BitCastOp> {
840 using OpConversionPattern<vector::BitCastOp>::OpConversionPattern;
843 matchAndRewrite(vector::BitCastOp op, OpAdaptor adaptor,
844 ConversionPatternRewriter &rewriter)
const override {
845 xegpu::DistributeLayoutAttr resultLayout =
848 return rewriter.notifyMatchFailure(
849 op,
"result vector of the bitcast op lacks layout attribute");
850 FailureOr<VectorType> distributedResultTypeOrFailure =
852 if (
failed(distributedResultTypeOrFailure))
853 return rewriter.notifyMatchFailure(
854 op,
"Failed to distribute the result vector type in "
855 "vector::BitCast op");
856 auto newOp = vector::BitCastOp::create(
857 rewriter, op.getLoc(), distributedResultTypeOrFailure.value(),
858 adaptor.getSource());
859 rewriter.replaceOp(op, newOp.
getResult());
887template <
typename OpType,
888 typename = std::enable_if_t<llvm::is_one_of<
889 OpType, vector::CreateMaskOp, vector::ConstantMaskOp>::value>>
890struct SgToLaneCreateMask :
public OpConversionPattern<OpType> {
891 using OpConversionPattern<OpType>::OpConversionPattern;
894 matchAndRewrite(OpType op,
typename OpType::Adaptor adaptor,
895 ConversionPatternRewriter &rewriter)
const override {
896 xegpu::DistributeLayoutAttr layout =
898 if (!layout || !layout.isForSubgroup())
899 return rewriter.notifyMatchFailure(
900 op,
"operation result does not have subgroup distribute layout");
902 VectorType origType = op.getType();
903 FailureOr<VectorType> distTypeOrFailure =
905 if (
failed(distTypeOrFailure))
906 return rewriter.notifyMatchFailure(
907 op,
"unable to compute lane vector type from the layout");
909 VectorType distType = distTypeOrFailure.value();
910 Location loc = op.getLoc();
913 SmallVector<Value> origBounds;
914 if constexpr (std::is_same_v<OpType, vector::CreateMaskOp>) {
915 origBounds.append(op.getOperands().begin(), op.getOperands().end());
917 auto dimSizes = op.getMaskDimSizesAttr().asArrayRef();
918 for (
auto dimSize : dimSizes)
919 origBounds.push_back(
923 ArrayRef<int64_t> origShape = origType.getShape();
926 Value laneId = gpu::LaneIdOp::create(rewriter, loc, rewriter.getIndexType(),
927 mlir::IntegerAttr());
928 auto maybeCoordsVec =
929 layout.computeDistributedCoords(rewriter, loc, laneId, origShape);
930 if (
failed(maybeCoordsVec))
931 return rewriter.notifyMatchFailure(
932 op,
"failed to compute distributed coordinates from layout");
934 SmallVector<SmallVector<Value>> coordsVec = maybeCoordsVec.value();
935 int64_t numElements = distType.getNumElements();
936 assert(
static_cast<int64_t
>(coordsVec.size()) == numElements &&
937 "number of coordinate sets must match number of distributed "
943 SmallVector<Value> maskBits;
944 for (
auto &coords : coordsVec) {
945 Value inBounds = trueVal;
946 for (
size_t i = 0; i < coords.size(); ++i) {
947 Value cmp = arith::CmpIOp::create(
948 rewriter, loc, arith::CmpIPredicate::slt, coords[i], origBounds[i]);
949 inBounds = arith::AndIOp::create(rewriter, loc, inBounds, cmp);
951 maskBits.push_back(inBounds);
956 if (numElements == 1) {
958 vector::BroadcastOp::create(rewriter, loc, distType, maskBits[0]);
961 vector::FromElementsOp::create(rewriter, loc, distType, maskBits);
963 rewriter.replaceOp(op,
result);
969struct SgToLaneStoreMatrix :
public OpConversionPattern<xegpu::StoreMatrixOp> {
970 using OpConversionPattern<xegpu::StoreMatrixOp>::OpConversionPattern;
973 matchAndRewrite(xegpu::StoreMatrixOp op, OpAdaptor adaptor,
974 ConversionPatternRewriter &rewriter)
const override {
975 auto layout = op.getLayoutAttr();
980 VectorType sgPayloadTy = dyn_cast<VectorType>(op.getData().getType());
982 return rewriter.notifyMatchFailure(
983 op,
"the matrix op payload must be a vector type");
985 auto loc = op.getLoc();
986 auto offsets = op.getMixedOffsets();
988 return rewriter.notifyMatchFailure(op,
"the store op must have offsets");
990 FailureOr<VectorType> distPayloadTyOrFailure =
992 if (
failed(distPayloadTyOrFailure))
993 return rewriter.notifyMatchFailure(
994 op,
"Failed to distribute matrix op payload based on layout.");
996 SmallVector<Value> offsetsAsValues =
999 SmallVector<Value> newCoords = offsetsAsValues;
1000 if (!op.getSubgroupBlockIoAttr()) {
1001 newCoords = computeDistributedCoordsForMatrixOp(
1002 rewriter, loc, layout, sgPayloadTy.getShape(), offsetsAsValues);
1003 if (newCoords.empty())
1004 return rewriter.notifyMatchFailure(
1005 op,
"Failed to compute distributed coordinates.");
1008 SmallVector<int64_t> newConstOffsets(op.getConstOffsets().size(),
1009 ShapedType::kDynamic);
1011 rewriter.getDenseI64ArrayAttr(newConstOffsets);
1013 xegpu::StoreMatrixOp::create(
1016 distPayloadTyOrFailure.value()),
1017 adaptor.getMemDesc(),
ValueRange(newCoords), newConstOffsetsAttr,
1018 op.getSubgroupBlockIoAttr(), xegpu::DistributeLayoutAttr{});
1019 rewriter.eraseOp(op);
1058struct SgToLaneStoreScatter
1059 :
public OpConversionPattern<xegpu::StoreScatterOp> {
1060 using OpConversionPattern<xegpu::StoreScatterOp>::OpConversionPattern;
1063 matchAndRewrite(xegpu::StoreScatterOp op, OpAdaptor adaptor,
1064 ConversionPatternRewriter &rewriter)
const override {
1065 xegpu::DistributeLayoutAttr layout = op.getAnchorLayout();
1069 VectorType origValueTy = op.getValueType();
1074 int chunkSize = op.getChunkSize().value_or(1);
1075 int effectiveVecRank = (chunkSize == 1) ? 1 : 2;
1076 ArrayRef<int64_t> shape = origValueTy.getShape();
1077 if (llvm::any_of(shape.take_front(origValueTy.getRank() - effectiveVecRank),
1078 [](int64_t d) { return d != 1; }))
1079 return rewriter.notifyMatchFailure(
1080 op,
"Only unit dimensions allowed for the leading "
1081 "dimensions of the store vector!");
1083 auto distValueTyOrFailure =
1085 if (
failed(distValueTyOrFailure))
1086 return rewriter.notifyMatchFailure(
1087 op,
"unable to compute expected lane vector type from lane layout");
1089 VectorType distValueTy = distValueTyOrFailure.value();
1090 VectorType distValueTy1D = VectorType::get({distValueTy.getNumElements()},
1091 distValueTy.getElementType());
1093 Value distValue = adaptor.getValue();
1094 if (distValue.
getType() != distValueTy1D)
1099 Value distOffsets = adaptor.getOffsets();
1100 auto distOffsetsTy = cast<VectorType>(distOffsets.
getType());
1101 VectorType offsetsTy1D = VectorType::get({distOffsetsTy.getNumElements()},
1102 distOffsetsTy.getElementType());
1103 distOffsets = castValueTo(
1106 Value distMask = adaptor.getMask();
1107 auto distMaskTy = cast<VectorType>(distMask.
getType());
1108 VectorType maskTy1D = VectorType::get({distMaskTy.getNumElements()},
1109 distMaskTy.getElementType());
1113 Value distDest = adaptor.getDest();
1114 xegpu::StoreScatterOp::create(rewriter, op.getLoc(), distValue, distDest,
1115 distOffsets, distMask, op.getChunkSizeAttr(),
1116 op.getL1HintAttr(), op.getL2HintAttr(),
1117 op.getL3HintAttr(),
nullptr,
1119 rewriter.eraseOp(op);
1128struct SgToLaneVectorStep :
public OpConversionPattern<vector::StepOp> {
1129 using OpConversionPattern<vector::StepOp>::OpConversionPattern;
1132 matchAndRewrite(vector::StepOp op, OpAdaptor adaptor,
1133 ConversionPatternRewriter &rewriter)
const override {
1134 xegpu::DistributeLayoutAttr resultLayout =
1136 if (!resultLayout || !resultLayout.isForSubgroup())
1137 return rewriter.notifyMatchFailure(
1138 op,
"the result vector of the step op lacks subgroup layout");
1140 auto loc = op.getLoc();
1141 auto stepResultVecTy = op.getResult().getType();
1142 auto laneShapeOrFailure =
1144 if (
failed(laneShapeOrFailure))
1145 return rewriter.notifyMatchFailure(
1146 op,
"unable to compute lane vector type from the layout");
1147 VectorType newVecTy = laneShapeOrFailure.value();
1149 Value laneId = gpu::LaneIdOp::create(rewriter, loc, rewriter.getIndexType(),
1150 mlir::IntegerAttr());
1151 auto laneDataBlockCoords = resultLayout.computeDistributedCoords(
1152 rewriter, loc, laneId, stepResultVecTy.getShape());
1153 if (
failed(laneDataBlockCoords))
1154 return rewriter.notifyMatchFailure(
1155 op,
"failed to compute lane data block coordinates");
1157 auto laneDataBlockCoordsVec = laneDataBlockCoords.value();
1158 auto laneDataBlockLength = resultLayout.getEffectiveLaneDataAsInt()[0];
1159 assert(
static_cast<int64_t
>(laneDataBlockCoordsVec.size()) ==
1160 newVecTy.getNumElements() / laneDataBlockLength);
1161 SmallVector<Value> stepVals;
1169 for (
auto &laneDataBlockCoords : laneDataBlockCoordsVec) {
1170 auto laneDataBlockStartCoord = laneDataBlockCoords[0];
1171 stepVals.push_back(laneDataBlockStartCoord);
1172 for (
int i = 1; i < laneDataBlockLength; ++i) {
1174 stepVals.push_back(arith::AddIOp::create(
1175 rewriter, loc, laneDataBlockStartCoord, offset));
1178 assert(
static_cast<int64_t
>(stepVals.size()) == newVecTy.getNumElements() &&
1179 "Expecting the number of step values to match the number of "
1180 "elements in the vector");
1182 vector::FromElementsOp::create(rewriter, loc, newVecTy, stepVals);
1183 rewriter.replaceOp(op, stepOpVal);
1190struct SgToLaneVectorExtract :
public OpConversionPattern<vector::ExtractOp> {
1191 using OpConversionPattern<vector::ExtractOp>::OpConversionPattern;
1194 matchAndRewrite(vector::ExtractOp op, OpAdaptor adaptor,
1195 ConversionPatternRewriter &rewriter)
const override {
1197 auto resultType = dyn_cast<VectorType>(op.getType());
1199 return rewriter.notifyMatchFailure(op,
"scalar extract not supported");
1201 xegpu::DistributeLayoutAttr layout =
1203 if (!layout || !layout.isForSubgroup())
1208 auto laneLayout = layout.getEffectiveLaneLayoutAsInt();
1209 if (llvm::any_of(ArrayRef<int64_t>(laneLayout).drop_back(1),
1210 [](int64_t v) {
return v != 1; }))
1211 return rewriter.notifyMatchFailure(
1212 op,
"only innermost dimension distribution is supported for "
1215 auto newOp = vector::ExtractOp::create(
1216 rewriter, op.getLoc(), adaptor.getSource(), op.getMixedPosition());
1217 rewriter.replaceOp(op, newOp.
getResult());
1223struct SgToLaneVectorShapeCast
1224 :
public OpConversionPattern<vector::ShapeCastOp> {
1225 using OpConversionPattern<vector::ShapeCastOp>::OpConversionPattern;
1228 matchAndRewrite(vector::ShapeCastOp op, OpAdaptor adaptor,
1229 ConversionPatternRewriter &rewriter)
const override {
1230 xegpu::DistributeLayoutAttr resultLayout =
1232 if (!resultLayout || !resultLayout.isForSubgroup())
1233 return rewriter.notifyMatchFailure(
1234 op,
"the result vector of the shape_cast op lacks subgroup layout");
1237 resultLayout, op.getResultVectorType());
1238 if (
failed(resultDistTypeOrFailure))
1239 return rewriter.notifyMatchFailure(
1240 op,
"failed to get distributed vector type for result");
1242 Value source = adaptor.getSource();
1243 auto newShapeCast = vector::ShapeCastOp::create(
1244 rewriter, op.getLoc(), resultDistTypeOrFailure.value(), source);
1245 rewriter.replaceOp(op, newShapeCast);
1253struct SgToLaneVectorExtractStridedSlice
1254 :
public OpConversionPattern<vector::ExtractStridedSliceOp> {
1255 using OpConversionPattern<vector::ExtractStridedSliceOp>::OpConversionPattern;
1258 matchAndRewrite(vector::ExtractStridedSliceOp op, OpAdaptor adaptor,
1259 ConversionPatternRewriter &rewriter)
const override {
1260 xegpu::DistributeLayoutAttr resultLayout =
1262 if (!resultLayout || !resultLayout.isForSubgroup())
1265 VectorType resultType = op.getType();
1266 auto distResultTyOrFailure =
1268 if (
failed(distResultTyOrFailure))
1269 return rewriter.notifyMatchFailure(
1270 op,
"unable to compute distributed vector type from lane layout");
1271 VectorType distResultTy = *distResultTyOrFailure;
1273 SmallVector<int64_t> distributedDims =
1274 getDistributedDims(resultType, distResultTy);
1277 int64_t sourceRank = op.getSourceVectorType().getRank();
1278 SmallVector<Attribute> updatedSizes =
1279 llvm::map_to_vector(op.getSizes(), [](Attribute attr) { return attr; });
1280 SmallVector<Attribute> updatedOffsets = llvm::map_to_vector(
1281 op.getOffsets(), [](Attribute attr) { return attr; });
1282 SmallVector<Attribute> updatedStrides = llvm::map_to_vector(
1283 op.getStrides(), [](Attribute attr) { return attr; });
1284 for (int64_t i = op.getSizes().size(); i < sourceRank; ++i) {
1285 updatedSizes.push_back(
1286 rewriter.getI64IntegerAttr(op.getSourceVectorType().getDimSize(i)));
1287 updatedOffsets.push_back(rewriter.getI64IntegerAttr(0));
1288 updatedStrides.push_back(rewriter.getI64IntegerAttr(1));
1293 if (!distributedDims.empty()) {
1294 if (distributedDims.size() != 1)
1295 return rewriter.notifyMatchFailure(
1296 op,
"only single dimension distribution is supported");
1297 int64_t distDim = distributedDims[0];
1301 return rewriter.notifyMatchFailure(
1302 op,
"target attribute required to determine subgroup size");
1303 int subgroupSize = uArch->getSubgroupSize();
1305 if (!sourceLayout || sourceLayout.getEffectiveLaneLayoutAsInt().empty())
1306 return rewriter.notifyMatchFailure(
1307 op,
"source of extract_strided_slice lacks distribution layout");
1308 int sourceDistrDimSize = op.getSourceVectorType().getShape()[distDim];
1309 auto laneLayout = sourceLayout.getEffectiveLaneLayoutAsInt();
1312 if (laneLayout[distDim] < subgroupSize &&
1313 subgroupSize % laneLayout[distDim] == 0)
1314 subgroupSize = laneLayout[distDim];
1315 if (sourceDistrDimSize % subgroupSize != 0)
1316 return rewriter.notifyMatchFailure(
1317 op,
"source size along distributed dim is not a multiple of "
1319 auto sourceLaneData = sourceLayout.getEffectiveLaneDataAsInt();
1322 if (distDim <
static_cast<int64_t
>(sourceLaneData.size()) &&
1323 sourceLaneData[distDim] != 1)
1324 return rewriter.notifyMatchFailure(
1325 op,
"expecting unit lane data along the distributed dimension");
1326 int64_t distrDimOffset =
1327 cast<IntegerAttr>(updatedOffsets[distDim]).getInt();
1328 if (distrDimOffset % subgroupSize != 0)
1329 return rewriter.notifyMatchFailure(
1330 op,
"offset along distributed dim is not a multiple of "
1333 updatedSizes[distDim] =
1334 rewriter.getI64IntegerAttr(distResultTy.getDimSize(distDim));
1335 updatedOffsets[distDim] =
1336 rewriter.getI64IntegerAttr(distrDimOffset / subgroupSize);
1339 auto newOp = vector::ExtractStridedSliceOp::create(
1340 rewriter, op.getLoc(), distResultTy, adaptor.getSource(),
1341 ArrayAttr::get(rewriter.getContext(), updatedOffsets),
1342 ArrayAttr::get(rewriter.getContext(), updatedSizes),
1343 ArrayAttr::get(rewriter.getContext(), updatedStrides));
1344 rewriter.replaceOp(op, newOp.
getResult());
1406struct SgToLaneBroadcast :
public OpConversionPattern<vector::BroadcastOp> {
1407 using OpConversionPattern<vector::BroadcastOp>::OpConversionPattern;
1410 matchAndRewrite(vector::BroadcastOp op, OpAdaptor adaptor,
1411 ConversionPatternRewriter &rewriter)
const override {
1412 xegpu::DistributeLayoutAttr resultLayout =
1414 if (!resultLayout || !resultLayout.isForSubgroup())
1415 return rewriter.notifyMatchFailure(
1416 op,
"result does not have subgroup distribute layout");
1418 VectorType destType = op.getResultVectorType();
1419 VectorType sourceType = dyn_cast<VectorType>(op.getSourceType());
1421 xegpu::DistributeLayoutAttr sourceLayout =
1425 int64_t rankDiff = destType.getRank() - sourceType.getRank();
1428 if (!sourceLayout || !sourceLayout.isSliceOf(resultLayout))
1430 "broadcast source layout must be a slice of result layout");
1431 }
else if (rankDiff == 0) {
1433 auto broadcastUnitDimsSet = op.computeBroadcastedUnitDims();
1434 SmallVector<int64_t> broadcastUnitDims(broadcastUnitDimsSet.begin(),
1435 broadcastUnitDimsSet.end());
1436 assert(sourceLayout.isEqualTo(
1437 sourceLayout.setUnitDimData(broadcastUnitDims)) &&
1438 "The sg_data for unit dimensions should be set as 1");
1439 sourceLayout = sourceLayout.setUnitDimLayout(broadcastUnitDims);
1444 return rewriter.notifyMatchFailure(
1445 op,
"broadcast from scalar must not have a layout attribute");
1450 if (
failed(destDistType))
1451 return rewriter.notifyMatchFailure(
1452 op,
"failed to distribute the result vector type");
1454 Value source = adaptor.getSource();
1456 if (source.
getType() == destDistType.value()) {
1457 rewriter.replaceOp(op, source);
1461 auto newOp = vector::BroadcastOp::create(rewriter, op.getLoc(),
1462 destDistType.value(), source);
1463 rewriter.replaceOp(op, newOp);
1471struct SgToLaneVectorInsertStridedSlice
1472 :
public OpConversionPattern<vector::InsertStridedSliceOp> {
1473 using OpConversionPattern<vector::InsertStridedSliceOp>::OpConversionPattern;
1476 matchAndRewrite(vector::InsertStridedSliceOp op, OpAdaptor adaptor,
1477 ConversionPatternRewriter &rewriter)
const override {
1478 xegpu::DistributeLayoutAttr resultLayout =
1480 if (!resultLayout || !resultLayout.isForSubgroup())
1483 VectorType destType = op.getDestVectorType();
1484 auto distDestTyOrFailure =
1486 if (
failed(distDestTyOrFailure))
1487 return rewriter.notifyMatchFailure(
1488 op,
"unable to compute distributed vector type from lane layout");
1489 VectorType distDestTy = *distDestTyOrFailure;
1491 SmallVector<int64_t> destDistributedDims =
1492 getDistributedDims(destType, distDestTy);
1494 SmallVector<Attribute> updatedOffsets = llvm::map_to_vector(
1495 op.getOffsets(), [](Attribute attr) { return attr; });
1497 if (!destDistributedDims.empty()) {
1498 if (destDistributedDims.size() != 1)
1499 return rewriter.notifyMatchFailure(
1500 op,
"only single dimension distribution is supported");
1501 int64_t destDistDim = destDistributedDims[0];
1506 return rewriter.notifyMatchFailure(
1507 op,
"target attribute required to determine subgroup size");
1508 int subgroupSize = uArch->getSubgroupSize();
1510 VectorType srcType = op.getSourceVectorType();
1512 int64_t sourceDistDim =
1513 destDistDim - (destType.getRank() - srcType.getRank());
1514 if (sourceDistDim < 0)
1515 return rewriter.notifyMatchFailure(
1516 op,
"distributed dimension must be in the last k dims of dest");
1520 if (!destLayout || !sourceLayout ||
1521 destLayout.getEffectiveLaneLayoutAsInt().empty() ||
1522 sourceLayout.getEffectiveLaneLayoutAsInt().empty())
1523 return rewriter.notifyMatchFailure(
1524 op,
"source or dest of insert_strided_slice lacks distribution "
1527 auto destLaneData = destLayout.getEffectiveLaneDataAsInt();
1528 auto sourceLaneData = sourceLayout.getEffectiveLaneDataAsInt();
1531 if ((destDistDim <
static_cast<int64_t
>(destLaneData.size()) &&
1532 destLaneData[destDistDim] != 1) ||
1533 (sourceDistDim <
static_cast<int64_t
>(sourceLaneData.size()) &&
1534 sourceLaneData[sourceDistDim] != 1))
1535 return rewriter.notifyMatchFailure(
1536 op,
"expecting unit lane data along the distributed dimension");
1538 int64_t srcDistrDimSize = srcType.getDimSize(sourceDistDim);
1539 if (srcDistrDimSize % subgroupSize != 0)
1540 return rewriter.notifyMatchFailure(
1541 op,
"source distributed dim size is not a multiple of "
1544 int64_t destDistrDimOffset =
1545 cast<IntegerAttr>(op.getOffsets()[destDistDim]).getInt();
1546 if (destDistrDimOffset % subgroupSize != 0)
1547 return rewriter.notifyMatchFailure(
1548 op,
"offset along distributed dim is not a multiple of "
1551 updatedOffsets[destDistDim] =
1552 rewriter.getI64IntegerAttr(destDistrDimOffset / subgroupSize);
1555 auto newOp = vector::InsertStridedSliceOp::create(
1556 rewriter, op.getLoc(), distDestTy, adaptor.getValueToStore(),
1558 ArrayAttr::get(rewriter.getContext(), updatedOffsets), op.getStrides());
1559 rewriter.replaceOp(op, newOp.
getResult());
1566struct SgToLaneVectorInsert :
public OpConversionPattern<vector::InsertOp> {
1567 using OpConversionPattern<vector::InsertOp>::OpConversionPattern;
1570 matchAndRewrite(vector::InsertOp op, OpAdaptor adaptor,
1571 ConversionPatternRewriter &rewriter)
const override {
1573 auto valueType = dyn_cast<VectorType>(op.getValueToStoreType());
1575 return rewriter.notifyMatchFailure(op,
"scalar insert not supported");
1577 xegpu::DistributeLayoutAttr layout =
1579 if (!layout || !layout.isForSubgroup())
1584 auto laneLayout = layout.getEffectiveLaneLayoutAsInt();
1585 if (llvm::any_of(ArrayRef<int64_t>(laneLayout).drop_back(1),
1586 [](int64_t v) {
return v != 1; }))
1587 return rewriter.notifyMatchFailure(
1588 op,
"only innermost dimension distribution is supported for "
1591 auto newOp = vector::InsertOp::create(
1592 rewriter, op.getLoc(), adaptor.getValueToStore(), adaptor.getDest(),
1593 op.getMixedPosition());
1594 rewriter.replaceOp(op, newOp.
getResult());
1612static FailureOr<Value>
1613shuffleDataAsLaneLayoutChange(ConversionPatternRewriter &rewriter,
Location loc,
1616 VectorType srcTy = dyn_cast<VectorType>(src.
getType());
1617 if (!srcTy || srcTy.getRank() != 2)
1620 if (targetLaneNum <= 0 || currentLaneNum != targetLaneNum * 2)
1624 srcTy.getNumElements() * srcTy.getElementTypeBitWidth();
1625 if (vectorBitWidth % 32 != 0)
1637 Type shuffleElemTy = rewriter.getI32Type();
1638 int64_t numShuffles = vectorBitWidth / 32;
1639 VectorType shuffleBundleTy = VectorType::get({numShuffles}, shuffleElemTy);
1641 Value temp = arith::ConstantOp::create(
1644 IntegerAttr::get(shuffleElemTy, 0)));
1645 VectorType flatSrcTy =
1646 VectorType::get({srcTy.getNumElements()}, srcTy.getElementType());
1647 Value flatSrc = vector::ShapeCastOp::create(rewriter, loc, flatSrcTy, src);
1648 Value shuffleBundle =
1649 vector::BitCastOp::create(rewriter, loc, shuffleBundleTy, flatSrc);
1650 for (
int64_t i = 0; i < numShuffles; i++) {
1652 vector::ExtractOp::create(rewriter, loc, shuffleBundle, i);
1653 shuffleElem = gpu::ShuffleOp::create(rewriter, loc, shuffleElem, 0,
1654 targetLaneNum, gpu::ShuffleMode::UP)
1656 temp = vector::InsertOp::create(rewriter, loc, shuffleElem, temp, i);
1658 temp = vector::BitCastOp::create(rewriter, loc, flatSrcTy, temp);
1659 temp = vector::ShapeCastOp::create(rewriter, loc, srcTy, temp);
1664 Value res = vector::ShuffleOp::create(rewriter, loc, src, temp,
indices);
1669struct SgToLaneConvertLayout
1670 :
public OpConversionPattern<xegpu::ConvertLayoutOp> {
1671 using OpConversionPattern<xegpu::ConvertLayoutOp>::OpConversionPattern;
1674 matchAndRewrite(xegpu::ConvertLayoutOp op, OpAdaptor adaptor,
1675 ConversionPatternRewriter &rewriter)
const override {
1676 auto inputLayout = op.getInputLayoutAttr();
1677 auto targetLayout = op.getTargetLayoutAttr();
1678 Type valType = op.getResult().
getType();
1681 rewriter.replaceOp(op, op.getSource());
1685 auto resShape = cast<VectorType>(valType).getShape();
1686 SmallVector<int64_t> resShapeVec(resShape.begin(), resShape.end());
1690 if (inputLayout.isCompatibleWith(targetLayout, resShapeVec,
1691 xegpu::LayoutKind::Lane)) {
1692 rewriter.replaceOp(op, adaptor.getSource());
1703 if (inputLayout.getEffectiveOrderAsInt() ==
1704 targetLayout.getEffectiveOrderAsInt() &&
1705 inputLayout.getRank() == 2 && targetLayout.getRank() == 2) {
1706 auto laneLayout = inputLayout.getEffectiveLaneLayoutAsInt();
1707 auto targetLaneLayout = targetLayout.getEffectiveLaneLayoutAsInt();
1708 auto laneData = inputLayout.getEffectiveLaneDataAsInt();
1709 auto targetLaneData = targetLayout.getEffectiveLaneDataAsInt();
1710 if (laneLayout.size() == 2 && targetLaneLayout.size() == 2 &&
1711 laneData == targetLaneData && laneLayout[1] == 1 &&
1712 targetLaneLayout[1] == 1 && laneLayout[0] > 1 &&
1713 laneLayout[0] != targetLaneLayout[0]) {
1714 FailureOr<Value> res = shuffleDataAsLaneLayoutChange(
1715 rewriter, op.getLoc(), adaptor.getSource(), laneLayout[0],
1716 targetLaneLayout[0]);
1717 if (succeeded(res)) {
1718 rewriter.replaceOp(op, *res);
1724 return rewriter.notifyMatchFailure(
1725 op,
"lowering incompatible convert_layout not yet supported");
1730struct SgToLaneVectorInterleave
1731 :
public OpConversionPattern<vector::InterleaveOp> {
1732 using OpConversionPattern<vector::InterleaveOp>::OpConversionPattern;
1735 matchAndRewrite(vector::InterleaveOp op, OpAdaptor adaptor,
1736 ConversionPatternRewriter &rewriter)
const override {
1738 auto newOp = vector::InterleaveOp::create(
1739 rewriter, op.getLoc(), adaptor.getLhs(), adaptor.getRhs());
1740 rewriter.replaceOp(op, newOp.
getResult());
1746struct SgToLaneVectorDeinterleave
1747 :
public OpConversionPattern<vector::DeinterleaveOp> {
1748 using OpConversionPattern<vector::DeinterleaveOp>::OpConversionPattern;
1751 matchAndRewrite(vector::DeinterleaveOp op, OpAdaptor adaptor,
1752 ConversionPatternRewriter &rewriter)
const override {
1754 auto newOp = vector::DeinterleaveOp::create(rewriter, op.getLoc(),
1755 adaptor.getSource());
1761struct SgToLaneDpasMx :
public OpConversionPattern<xegpu::DpasMxOp> {
1762 using OpConversionPattern<xegpu::DpasMxOp>::OpConversionPattern;
1765 matchAndRewrite(xegpu::DpasMxOp op, OpAdaptor adaptor,
1766 ConversionPatternRewriter &rewriter)
const override {
1771 if (!uArch->isSupportedInstruction(
1772 xegpu::uArch::InstructionKind::SubgroupScaledMatrixMultiplyAcc))
1773 return rewriter.notifyMatchFailure(
1774 op,
"target uArch does not support scaled subgroup mma");
1776 auto layoutA = cast<xegpu::LayoutAttr>(op.getLayoutAAttr());
1777 auto layoutB = cast<xegpu::LayoutAttr>(op.getLayoutBAttr());
1778 auto layoutCd = cast<xegpu::LayoutAttr>(op.getLayoutCdAttr());
1779 if (!layoutA || !layoutB || !layoutCd)
1780 return rewriter.notifyMatchFailure(
1781 op,
"missing required layout attributes for DpasMxOp distribution");
1784 auto expected1DTypeResult =
1786 auto expected1DTypeA =
1788 auto expected1DTypeB =
1791 VectorType expected1DTypeScaleA, expected1DTypeScaleB;
1792 if (op.getScaleA()) {
1793 auto layoutScaleA = cast<xegpu::LayoutAttr>(op.getLayoutAScaleAttr());
1795 cast<VectorType>(op.getScaleA().getType()), layoutScaleA);
1796 if (
failed(expected1DTypeScaleAOrFailure))
1797 return rewriter.notifyMatchFailure(
1798 op,
"failed to calculate expected 1D vector type for scale A");
1799 expected1DTypeScaleA = expected1DTypeScaleAOrFailure.value();
1801 if (op.getScaleB()) {
1802 auto layoutScaleB = cast<xegpu::LayoutAttr>(op.getLayoutBScaleAttr());
1804 cast<VectorType>(op.getScaleB().getType()), layoutScaleB);
1805 if (
failed(expected1DTypeScaleBOrFailure))
1806 return rewriter.notifyMatchFailure(
1807 op,
"failed to calculate expected 1D vector type for scale B");
1808 expected1DTypeScaleB = expected1DTypeScaleBOrFailure.value();
1811 auto expectedNDTypeResult =
1813 if (
failed(expected1DTypeResult) ||
failed(expected1DTypeA) ||
1815 return rewriter.notifyMatchFailure(
1817 "failed to calculate supported workitem 1D vector types for DpasOp "
1819 if (
failed(expectedNDTypeResult))
1820 return rewriter.notifyMatchFailure(
1821 op,
"unable to compute expected workitem vector type for DpasOp from "
1825 const auto *uArchInstruction = dyn_cast<
1827 xegpu::uArch::InstructionKind::SubgroupScaledMatrixMultiplyAcc));
1828 assert(uArchInstruction);
1829 auto wiAType = expected1DTypeA.value();
1830 auto wiBType = expected1DTypeB.value();
1832 unsigned aPackedBitWidth =
1833 wiAType.getElementTypeBitWidth() * wiAType.getNumElements();
1834 unsigned bPackedBitWidth =
1835 wiBType.getElementTypeBitWidth() * wiBType.getNumElements();
1836 if (aPackedBitWidth % uArchInstruction->getPackedFormatBitSizeA())
1837 return rewriter.notifyMatchFailure(
1838 op,
"A operand packed bit width must be a multiple of uArch packed "
1839 "format requirement");
1840 if (bPackedBitWidth % uArchInstruction->getPackedFormatBitSizeB())
1841 return rewriter.notifyMatchFailure(
1842 op,
"B operand packed bit width must be a multiple of uArch packed "
1843 "format requirement");
1845 auto newOp = xegpu::DpasMxOp::create(
1846 rewriter, op->getLoc(), expected1DTypeResult.value(),
1848 expected1DTypeA.value()),
1850 expected1DTypeB.value()),
1852 ? castValueTo(rewriter,
1854 expected1DTypeResult.value())
1858 ? castValueTo(rewriter,
1860 expected1DTypeScaleA)
1863 ? castValueTo(rewriter,
1865 expected1DTypeScaleB)
1871 rewriter.replaceOp(op, castValueTo(rewriter, newOp.
getResult(),
1872 expectedNDTypeResult.value()));
1877struct XeGPUSgToLaneDistributePass
1879 XeGPUSgToLaneDistributePass> {
1880 void runOnOperation()
override;
1885void XeGPUSgToLaneDistributePass::runOnOperation() {
1888 Operation *root = getOperation();
1890 signalPassFailure();
1895 llvm::SmallSetVector<UnrealizedConversionCastOp, 8> existingCasts;
1897 [&](UnrealizedConversionCastOp castOp) { existingCasts.insert(castOp); });
1903 TypeConverter typeConverter;
1907 auto materializeCast = [](OpBuilder &builder, Type type,
ValueRange inputs,
1908 Location loc) -> Value {
1909 return UnrealizedConversionCastOp::create(builder, loc, type, inputs)
1912 typeConverter.addSourceMaterialization(materializeCast);
1913 typeConverter.addTargetMaterialization(materializeCast);
1918 typeConverter, patterns,
target, root);
1919 target.addLegalOp<UnrealizedConversionCastOp>();
1920 (void)applyPartialConversion(root,
target, std::move(patterns));
1931 typeConverter.addConversion([](
Type type) ->
Type {
return type; });
1933 typeConverter.addConversion([](TensorDescType type) ->
Type {
1934 if (type.getLayoutAttr()) {
1935 return type.dropLayouts();
1943 auto getSubShapeAndCount = [](VectorType vecTy,
1944 xegpu::DistributeLayoutAttr layout)
1947 if (failed(distTyOrFailure))
1954 std::move(loopArgTypes));
1962 target.addDynamicallyLegalOp<xegpu::CreateNdDescOp>(
1963 [&](xegpu::CreateNdDescOp op) {
return !op.getType().getLayoutAttr(); });
1965 target.addDynamicallyLegalDialect<xegpu::XeGPUDialect>([](
Operation *op) {
1966 if (isa<xegpu::ConvertLayoutOp>(op))
1968 auto anchorOp = dyn_cast<AnchorLayoutInterface>(op);
1971 return !anchorOp.getAnchorLayout();
1974 target.addDynamicallyLegalOp<arith::ConstantOp>(
1975 [=](arith::ConstantOp op) ->
bool {
1977 if (!isa<VectorType>(op.getResult().getType()))
1983 target.addDynamicallyLegalDialect<math::MathDialect, arith::ArithDialect>(
1984 [=](
Operation *op) -> std::optional<bool> {
1989 if (op->getNumResults() != 1)
1992 VectorType resultType =
1993 dyn_cast<VectorType>(op->getResult(0).getType());
1998 for (
Value operand : op->getOperands()) {
1999 VectorType operandType = dyn_cast<VectorType>(operand.getType());
2000 if (!operandType || operandType.getShape() != resultType.getShape()) {
2008 target.addDynamicallyLegalOp<vector::ReductionOp>(
2009 [=](vector::ReductionOp op) ->
bool {
2014 target.addDynamicallyLegalOp<vector::MultiDimReductionOp>(
2015 [=](vector::MultiDimReductionOp op) ->
bool {
2016 return !isValidSubgroupMultiReductionOp(op);
2018 target.addDynamicallyLegalOp<vector::CreateMaskOp, vector::ConstantMaskOp,
2019 vector::TransposeOp, vector::BitCastOp,
2020 vector::ShapeCastOp, vector::StepOp,
2021 vector::BroadcastOp>([=](
Operation *op) ->
bool {
2024 target.addDynamicallyLegalOp<vector::ExtractOp>(
2025 [=](vector::ExtractOp op) ->
bool {
2026 if (!isa<VectorType>(op.getType()))
2030 target.addDynamicallyLegalOp<vector::InsertOp>(
2031 [=](vector::InsertOp op) ->
bool {
2034 target.addDynamicallyLegalOp<vector::ExtractStridedSliceOp>(
2035 [=](vector::ExtractStridedSliceOp op) ->
bool {
2038 target.addDynamicallyLegalOp<vector::InsertStridedSliceOp>(
2039 [=](vector::InsertStridedSliceOp op) ->
bool {
2042 target.addDynamicallyLegalOp<vector::InterleaveOp, vector::DeinterleaveOp>(
2046 target.markUnknownOpDynamicallyLegal([](
Operation *op) {
return true; });
2048 SgToLaneCreateNdDesc, SgToLaneLoadNd, SgToLaneStoreNd, SgToLaneDpas,
2049 SgToLaneElementWise, SgToLaneArithConstant, SgToLanePrefetchNd,
2050 SgToLaneLoadGather, SgToLaneStoreScatter, SgToLaneVectorReduction,
2051 SgToLaneMultiDimReduction, SgToLaneVectorExtract, SgToLaneVectorInsert,
2052 SgToLaneVectorExtractStridedSlice, SgToLaneVectorInsertStridedSlice,
2053 SgToLaneLoadMatrix, SgToLaneStoreMatrix, SgToLaneConvertLayout,
2054 SgToLaneVectorTranspose, SgToLaneVectorBitcast, SgToLaneVectorStep,
2055 SgToLaneVectorShapeCast, SgToLaneBroadcast,
2056 SgToLaneCreateMask<vector::CreateMaskOp>,
2057 SgToLaneCreateMask<vector::ConstantMaskOp>, SgToLaneVectorDeinterleave,
2058 SgToLaneVectorInterleave, SgToLaneDpasMx>(typeConverter,
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.
Operation is the basic unit of execution within MLIR.
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
OperationName getName()
The name of an operation is the key identifier for it.
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),...
result_range getResults()
unsigned getNumResults()
Return the number of results held by this operation.
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.
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)
static ConstantIntOp create(OpBuilder &builder, Location location, int64_t value, unsigned width)
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int64_t > content)
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
void populateSCFStructuralTypeConversionsAndLegality(const TypeConverter &typeConverter, RewritePatternSet &patterns, ConversionTarget &target, PatternBenefit benefit=1)
Populates patterns for SCF structural type conversions and sets up the provided ConversionTarget with...
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.
SmallVector< Value > getAsValues(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > foldResults)
Convert foldResults into Values.
@ SubgroupMatrixMultiplyAcc
@ SubgroupScaledMatrixMultiplyAcc
const uArch * getUArch(llvm::StringRef archName)
void populateXeGPUSgToLaneDistributeTypeConversionAndLegality(TypeConverter &typeConverter, RewritePatternSet &patterns, ConversionTarget &target, Operation *topLevelOp)
Defines type conversions and legality for XeGPU subgroup to lane distribution and appends the require...
bool requirePacked(const DistributeLayoutAttr layout)
Helper function to check if the layout is packed.
void removeTemporaryLayoutAttrs(Operation *op)
Removes the temporary layout attributes for each OpOperand and OpResult of the given operation.
Value subgroupReduction(Location loc, OpBuilder &builder, Value input, vector::CombiningKind kind, uint32_t size)
Given an input value representing per-lane data, this function returns the result after performing a ...
bool recoverTemporaryLayouts(Operation *rootOp)
Attach layout attributes to all vector-type operands of operations within the given operation's neste...
FailureOr< VectorType > getDistVecTypeBasedOnLaneLayout(DistributeLayoutAttr layout, VectorType originalType)
Helper function to get distributed vector type for a source vector type according to the lane_layout.
Value lowerToVectorReductions(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, Location loc, PatternRewriter &rewriter)
Given a src and an acc argumments from a vector::MultiDimReductionOp, lower to a set of vector::Reduc...
bool requireTranspose(const DistributeLayoutAttr layout, const uArch::uArch *uArch)
Helper function to check if the layout requires a transpose effect.
DistributeLayoutAttr getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value.
DenseMap< Value, SmallVector< Type > > precomputeLoopBlockArgTypes(Operation *topLevelOp, SubShapeAndCountFn getSubShapeAndCount)
Pre-computes distributed VectorType mappings for every value carried through an SCF loop under topLev...
std::optional< std::string > getChipStr(Operation *op)
Retrieves the chip string from the XeVM target attribute of the parent GPU module operation.
void addVectorTypeConversion(TypeConverter &converter, SubShapeAndCountFn getSubShapeAndCount, DenseMap< Value, SmallVector< Type > > loopArgTypes)
Adds a context-aware VectorType conversion to converter (1:1 shape-changing or 1:N,...
DistributeLayoutAttr getTemporaryLayout(const T &operandOrResult)
get and set distribute layout attribute for non-anchor operations (and offsets/masks of load/store op...
void populateXeGPUSgToLaneDistributeTypeConversions(TypeConverter &typeConverter, Operation *topLevelOp)
Define only the type conversions needed for XeGPU subgroup to lane distribution.
Value lowerCrossLaneReductionToShuffles(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, int64_t reductionSize, Location loc, PatternRewriter &rewriter)
Lowers cross-lane reductions to shuffle operations on a 2D vector.
void cleanupUnrealizedConversionCasts(Operation *root, const llvm::SmallSetVector< UnrealizedConversionCastOp, 8 > &existingCasts)
Cleans up UnrealizedConversionCastOps inserted during SCF structural type conversion and/or XeGPU unr...
SmallVector< OpFoldResult > addWithRightAligned(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > lhs, ArrayRef< OpFoldResult > rhs)
Generates element-wise addition ops of two arrays with automatic alignment.
FailureOr< VectorType > getDistributedVectorType(xegpu::TensorDescType tdescTy)
If tensor descriptor has a layout attribute it is used in SIMT mode.
Include the generated interface declarations.
detail::DenseArrayAttrImpl< int64_t > DenseI64ArrayAttr
SmallVector< int64_t > computeStrides(ArrayRef< int64_t > sizes)
SmallVector< int64_t > delinearize(int64_t linearIndex, ArrayRef< int64_t > strides)
Given the strides together with a linear index in the dimension space, return the vector-space offset...
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.
OpFoldResult getAsOpFoldResult(Value val)
Given a value, try to extract a constant Attribute.
This represents an operation in an abstracted form, suitable for use with the builder APIs.