25#include "llvm/ADT/SetVector.h"
30#define GEN_PASS_DEF_XEGPUWGTOSGDISTRIBUTE
31#include "mlir/Dialect/XeGPU/Transforms/Passes.h.inc"
40static xegpu::RangeAttr getRangeSpecAttr(
Operation *op) {
43 if (
auto attr = llvm::dyn_cast_if_present<xegpu::RangeAttr>(
44 parent->
getAttr(
"sg_id_range")))
51static std::pair<SmallVector<int64_t>,
int>
53 xegpu::DistributeLayoutAttr layout) {
56 auto distributedShape = layout.computeDistributedShape(
58 if (
failed(distributedShape))
59 return std::make_pair(sgShape, count);
60 auto sgData = layout.getEffectiveSgDataAsInt();
62 return std::make_pair(sgData, count);
69template <
typename OpType,
70 typename = std::enable_if_t<llvm::is_one_of<
71 OpType, xegpu::LoadNdOp, xegpu::StoreNdOp, xegpu::PrefetchNdOp,
72 xegpu::LoadMatrixOp, xegpu::StoreMatrixOp>::value>>
74genOffsetsList(ConversionPatternRewriter &rewriter, OpType op,
79 if (origOffsets.empty())
83 xegpu::DistributeLayoutAttr layout;
84 if constexpr (std::is_same_v<OpType, xegpu::LoadMatrixOp> ||
85 std::is_same_v<OpType, xegpu::StoreMatrixOp>) {
86 layout = op.getLayoutAttr();
88 layout = op.getDescLayoutAttr();
92 if (!layout || !layout.isForWorkgroup())
96 gpu::SubgroupIdOp::create(rewriter, loc,
nullptr);
99 xegpu::RangeAttr sgIdRange = getRangeSpecAttr(op);
101 int64_t startOfRange = sgIdRange.getStart().getInt();
102 int64_t endOfRange = sgIdRange.getEnd().getInt();
104 if (layout.getNumSubgroups() != endOfRange - startOfRange)
105 return rewriter.notifyMatchFailure(
106 op,
"sg_layout size must match the sg_id_range");
108 if (startOfRange > 0) {
109 Value startOfRangeVal =
111 sgId = index::SubOp::create(rewriter, loc, sgId, startOfRangeVal);
118 auto maybeDescOffsets =
119 layout.computeDistributedCoords(rewriter, loc, sgId, wgShape);
120 if (
failed(maybeDescOffsets))
125 for (
const auto &sgOffsets : *maybeDescOffsets) {
128 offsetsList.push_back(std::move(newOffsets));
182struct WgToSgCreateNdOp :
public OpConversionPattern<xegpu::CreateNdDescOp> {
183 using OpConversionPattern<xegpu::CreateNdDescOp>::OpConversionPattern;
186 matchAndRewrite(xegpu::CreateNdDescOp op, OneToNOpAdaptor adaptor,
187 ConversionPatternRewriter &rewriter)
const override {
189 Location loc = op.getLoc();
191 xegpu::TensorDescType tdescTy = op.getType();
192 auto layout = dyn_cast<xegpu::LayoutAttr>(tdescTy.getLayout());
193 if (!layout || !layout.isForWorkgroup())
196 Type elemTy = tdescTy.getElementType();
197 ArrayRef<int64_t> wgShape = tdescTy.getShape();
199 SmallVector<int64_t> sgShape;
201 std::tie(sgShape, count) = getSgShapeAndCount(wgShape, layout);
202 xegpu::TensorDescType newTdescTy =
203 xegpu::TensorDescType::get(ctx, sgShape, elemTy, tdescTy.getEncoding(),
204 layout.dropSgLayoutAndData());
206 SmallVector<Value> newCreateNdOps(count);
207 std::generate(newCreateNdOps.begin(), newCreateNdOps.end(), [&]() {
208 return xegpu::CreateNdDescOp::create(rewriter, loc, newTdescTy,
209 op.getSource(), op.getMixedSizes(),
210 op.getMixedStrides());
213 rewriter.replaceOpWithMultiple(op, {newCreateNdOps});
219struct WgToSgLoadNdOp :
public OpConversionPattern<xegpu::LoadNdOp> {
220 using OpConversionPattern<xegpu::LoadNdOp>::OpConversionPattern;
222 matchAndRewrite(xegpu::LoadNdOp op, OneToNOpAdaptor adaptor,
223 ConversionPatternRewriter &rewriter)
const override {
225 SmallVector<SmallVector<OpFoldResult>> offsetsList;
226 if (
failed(genOffsetsList(rewriter, op, offsetsList)))
229 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
231 layout = layout.dropSgLayoutAndData();
232 SmallVector<Value> newOps;
233 for (
auto [tdesc, offsets] :
234 llvm::zip(adaptor.getTensorDesc(), offsetsList)) {
235 auto tdescTy = dyn_cast<xegpu::TensorDescType>(tdesc.getType());
236 VectorType newResTy =
237 VectorType::get(tdescTy.getShape(), tdescTy.getElementType());
238 auto newOp = xegpu::LoadNdOp::create(
239 rewriter, op.getLoc(), newResTy, tdesc, offsets,
240 nullptr,
nullptr, op.getL1HintAttr(),
241 op.getL2HintAttr(), op.getL3HintAttr(), layout);
242 newOps.push_back(newOp);
244 rewriter.replaceOpWithMultiple(op, {newOps});
251struct WgToSgStoreNdOp :
public OpConversionPattern<xegpu::StoreNdOp> {
252 using OpConversionPattern<xegpu::StoreNdOp>::OpConversionPattern;
254 matchAndRewrite(xegpu::StoreNdOp op, OneToNOpAdaptor adaptor,
255 ConversionPatternRewriter &rewriter)
const override {
256 SmallVector<SmallVector<OpFoldResult>> offsetsList;
257 if (
failed(genOffsetsList(rewriter, op, offsetsList)))
260 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
262 layout = layout.dropSgLayoutAndData();
263 for (
auto [v, tdesc, offsets] :
264 llvm::zip(adaptor.getValue(), adaptor.getTensorDesc(), offsetsList)) {
265 xegpu::StoreNdOp::create(rewriter, op.getLoc(), v, tdesc, offsets,
266 op.getL1HintAttr(), op.getL2HintAttr(),
267 op.getL3HintAttr(), layout);
269 rewriter.eraseOp(op);
276struct WgToSgPrefetchNdOp :
public OpConversionPattern<xegpu::PrefetchNdOp> {
277 using OpConversionPattern<xegpu::PrefetchNdOp>::OpConversionPattern;
279 matchAndRewrite(xegpu::PrefetchNdOp op, OneToNOpAdaptor adaptor,
280 ConversionPatternRewriter &rewriter)
const override {
281 SmallVector<SmallVector<OpFoldResult>> offsetsList;
282 if (
failed(genOffsetsList(rewriter, op, offsetsList)))
285 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
287 layout = layout.dropSgLayoutAndData();
288 for (
auto [tdesc, offsets] :
289 llvm::zip(adaptor.getTensorDesc(), offsetsList)) {
290 xegpu::PrefetchNdOp::create(rewriter, op.getLoc(), tdesc, offsets,
291 op.getL1HintAttr(), op.getL2HintAttr(),
292 op.getL3HintAttr(), layout);
294 rewriter.eraseOp(op);
301struct WgToSgDpasOp :
public OpConversionPattern<xegpu::DpasOp> {
302 using OpConversionPattern<xegpu::DpasOp>::OpConversionPattern;
304 matchAndRewrite(xegpu::DpasOp op, OneToNOpAdaptor adaptor,
305 ConversionPatternRewriter &rewriter)
const override {
306 Location loc = op.getLoc();
307 VectorType resultTy = op.getResult().getType();
308 if (resultTy.getRank() < 2)
311 auto layoutCd = op.getLayoutCdAttr();
312 auto layoutA = op.getLayoutAAttr();
313 auto layoutB = op.getLayoutBAttr();
314 if (!layoutCd || !layoutA || !layoutB)
317 SmallVector<Value> newDpasOps;
318 for (
auto aVec : adaptor.getLhs()) {
319 for (
auto bVec : adaptor.getRhs()) {
321 llvm::SmallVector<Value> operands({aVec, bVec});
324 tmpC = adaptor.getAcc()[i++];
325 operands.push_back(tmpC);
328 ArrayRef<int64_t> aVecShape =
329 cast<VectorType>(aVec.getType()).getShape();
330 ArrayRef<int64_t> bVecShape =
331 cast<VectorType>(bVec.getType()).getShape();
334 SmallVector<int64_t> resShape(aVecShape.drop_back(2));
335 resShape.push_back(aVecShape[aVecShape.size() - 2]);
336 resShape.push_back(bVecShape[bVecShape.size() - 1]);
337 VectorType resTy = VectorType::get(resShape, resultTy.getElementType());
338 auto newDpasOp = xegpu::DpasOp::create(rewriter, loc, resTy, operands);
339 newDpasOp.setLayoutCdAttr(layoutCd.dropSgLayoutAndData());
340 newDpasOp.setLayoutAAttr(layoutA.dropSgLayoutAndData());
341 newDpasOp.setLayoutBAttr(layoutB.dropSgLayoutAndData());
343 newDpasOps.push_back(newDpasOp);
346 rewriter.replaceOpWithMultiple(op, {newDpasOps});
352struct WgToSgDpasMxOp :
public OpConversionPattern<xegpu::DpasMxOp> {
353 using OpConversionPattern<xegpu::DpasMxOp>::OpConversionPattern;
355 matchAndRewrite(xegpu::DpasMxOp op, OneToNOpAdaptor adaptor,
356 ConversionPatternRewriter &rewriter)
const override {
358 Location loc = op.getLoc();
359 VectorType resultTy = op.getResult().getType();
361 if (resultTy.getRank() < 2)
364 auto layoutCd = op.getLayoutCdAttr();
365 auto layoutA = op.getLayoutAAttr();
366 auto layoutB = op.getLayoutBAttr();
367 auto layoutAScale = op.getLayoutAScaleAttr();
368 auto layoutBScale = op.getLayoutBScaleAttr();
370 if (!layoutCd || !layoutA || !layoutB || !layoutAScale || !layoutBScale)
374 SmallVector<Value> newDpasMxOps;
375 for (
auto [index_a, aVec] : llvm::enumerate(adaptor.getA())) {
376 for (
auto [index_b, bVec] : llvm::enumerate(adaptor.getB())) {
377 Value accVal = (op.getAcc()) ? adaptor.getAcc()[index_c++] : Value();
379 (op.getScaleA()) ? adaptor.getScaleA()[index_a] : Value();
381 (op.getScaleB()) ? adaptor.getScaleB()[index_b] : Value();
383 ArrayRef<int64_t> aVecShape =
384 cast<VectorType>(aVec.getType()).getShape();
385 ArrayRef<int64_t> bVecShape =
386 cast<VectorType>(bVec.getType()).getShape();
388 SmallVector<int64_t> resShape(aVecShape.drop_back(2));
389 resShape.push_back(aVecShape[aVecShape.size() - 2]);
390 resShape.push_back(bVecShape[bVecShape.size() - 1]);
391 VectorType resTy = VectorType::get(resShape, resultTy.getElementType());
392 auto newDpasMxOp = xegpu::DpasMxOp::create(
393 rewriter, loc, resTy, aVec, bVec, accVal, scaleAVal, scaleBVal,
394 layoutA.dropSgLayoutAndData(), layoutB.dropSgLayoutAndData(),
395 layoutCd.dropSgLayoutAndData(), layoutAScale.dropSgLayoutAndData(),
396 layoutBScale.dropSgLayoutAndData());
398 newDpasMxOps.push_back(newDpasMxOp);
401 rewriter.replaceOpWithMultiple(op, {newDpasMxOps});
407struct WgToSgVectorBroadcastOp
408 :
public OpConversionPattern<vector::BroadcastOp> {
409 using OpConversionPattern<vector::BroadcastOp>::OpConversionPattern;
412 matchAndRewrite(vector::BroadcastOp op, OneToNOpAdaptor adaptor,
413 ConversionPatternRewriter &rewriter)
const override {
415 VectorType resultType = op.getResult().getType();
416 ArrayRef<int64_t> wgShape = resultType.getShape();
418 xegpu::DistributeLayoutAttr layout =
420 if (!layout || !layout.isForWorkgroup())
423 SmallVector<int64_t> sgShape;
425 std::tie(sgShape, count) = getSgShapeAndCount(wgShape, layout);
426 VectorType newResultType =
427 VectorType::get(sgShape, resultType.getElementType());
429 SmallVector<Value> newBroadcastOps;
430 auto distSource = adaptor.getOperands().front();
431 int numDistributions = count / distSource.size();
432 for (
int i = 0; i < numDistributions; ++i) {
433 for (
auto operand : distSource) {
434 auto newBroadcast = vector::BroadcastOp::create(rewriter, op.getLoc(),
435 newResultType, operand);
437 newBroadcastOps.push_back(newBroadcast.getResult());
440 rewriter.replaceOpWithMultiple(op, {newBroadcastOps});
446struct WgToSgElementwiseOp :
public ConversionPattern {
448 : ConversionPattern(MatchAnyOpTypeTag(), 1, ctx) {}
452 ConversionPatternRewriter &rewriter)
const override {
458 assert(resultType &&
"Expected result to be a VectorType");
462 xegpu::DistributeLayoutAttr layout =
464 if (!layout || !layout.isForWorkgroup())
469 size_t numVariants = operands.empty() ? 0 : operands.front().size();
471 if (llvm::any_of(operands, [&](
const ValueRange &operandVec) {
472 return operandVec.size() != numVariants;
477 VectorType newResultType =
478 VectorType::get(sgShape, resultType.getElementType());
480 for (
size_t i = 0; i < numVariants; ++i) {
482 for (
auto &operandVec : operands)
483 opOperands.push_back(operandVec[i]);
486 state.addOperands(opOperands);
487 state.addTypes(newResultType);
488 state.addAttributes(op->
getAttrs());
489 Operation *newOp = rewriter.create(state);
491 newResults.push_back(newOp->
getResult(0));
494 rewriter.replaceOpWithMultiple(op, {newResults});
525struct WgToSgConvertLayoutOp
526 :
public OpConversionPattern<xegpu::ConvertLayoutOp> {
527 using OpConversionPattern<xegpu::ConvertLayoutOp>::OpConversionPattern;
531 ConversionPatternRewriter &rewriter)
const override {
533 auto inputLayout = op.getInputLayout();
534 auto targetLayout = op.getTargetLayout();
536 if (!inputLayout || !targetLayout || !inputLayout.isForWorkgroup() ||
537 !targetLayout.isForWorkgroup())
538 return rewriter.notifyMatchFailure(
539 op,
"Input and target layouts must have subgroup layout");
541 Type resultType = op.getResult().getType();
543 rewriter.replaceOp(op, op.getSource());
544 assert(!inputLayout.dropSgLayoutAndData() &&
545 !targetLayout.dropSgLayoutAndData() &&
546 "unexpected layout attributes for scalar type");
552 inputLayout.getEffectiveSgLayoutAsInt();
555 targetLayout.getEffectiveSgLayoutAsInt();
560 if (inputLayout.isCompatibleWith(targetLayout, wgShapeVec,
562 inputLayout = inputLayout.dropSgLayoutAndData();
563 targetLayout = targetLayout.dropSgLayoutAndData();
566 if (inputLayout && targetLayout) {
567 for (
auto [i, src] : llvm::enumerate(adaptor.getSource())) {
568 auto newOp = xegpu::ConvertLayoutOp::create(
569 rewriter, loc, src.getType(), src, inputLayout, targetLayout);
573 rewriter.replaceOpWithMultiple(op, {newOps});
578 Type elemTy = cast<VectorType>(op.getSource().getType()).getElementType();
584 auto bytesPerElement = bitWidth / 8;
588 auto slmTy = MemRefType::get({slmSize}, rewriter.getI8Type(), {}, 3);
589 auto slm = memref::AllocaOp::create(rewriter, loc, slmTy);
591 auto memDescType = xegpu::MemDescType::get(rewriter.getContext(), slmShape,
594 xegpu::CreateMemDescOp::create(rewriter, loc, memDescType, slm);
596 auto sgId = gpu::SubgroupIdOp::create(rewriter, loc,
597 rewriter.getIndexType(),
nullptr);
600 auto storeCoords = inputLayout.computeDistributedCoords(
601 rewriter, loc, sgId.getResult(), wgShape);
602 if (failed(storeCoords))
606 for (
auto [src, coords] : llvm::zip(adaptor.getSource(), *storeCoords)) {
608 for (
Value coord : coords) {
609 storeMatrixOffsets.push_back(coord);
611 xegpu::StoreMatrixOp::create(rewriter, loc, src, memDesc.getResult(),
612 storeMatrixOffsets,
nullptr );
615 gpu::BarrierOp::create(rewriter, loc);
618 auto loadCoords = targetLayout.computeDistributedCoords(
619 rewriter, loc, sgId.getResult(), wgShape);
620 if (failed(loadCoords))
623 VectorType loadType = VectorType::get(targetSgData, elemTy);
627 for (
auto coords : *loadCoords) {
629 for (
Value coord : coords) {
630 loadMatrixOffsets.push_back(coord);
632 auto loadOp = xegpu::LoadMatrixOp::create(
633 rewriter, loc, loadType, memDesc.getResult(), loadMatrixOffsets,
634 targetLayout.dropSgLayoutAndData());
636 finalResults.push_back(loadOp.getResult());
639 rewriter.replaceOpWithMultiple(op, {finalResults});
645struct WgToSgArithConstantOp :
public OpConversionPattern<arith::ConstantOp> {
646 using OpConversionPattern<arith::ConstantOp>::OpConversionPattern;
650 ConversionPatternRewriter &rewriter)
const override {
651 auto vecAttr = dyn_cast<DenseElementsAttr>(op.getValue());
652 auto vecType = dyn_cast<VectorType>(op.getType());
653 if (!vecAttr || !vecType)
656 xegpu::DistributeLayoutAttr layout =
658 if (!layout || !layout.isForWorkgroup())
664 std::tie(sgShape, count) = getSgShapeAndCount(wgShape, layout);
666 auto newType = VectorType::get(sgShape, vecType.getElementType());
668 auto eltType = vecType.getElementType();
670 if (vecAttr.isSplat()) {
675 for (
int i = 0; i < count; ++i) {
676 auto cstOp = arith::ConstantOp::create(rewriter, loc, newType, sgAttr);
677 newConstOps.push_back(cstOp);
679 rewriter.replaceOpWithMultiple(op, {newConstOps});
681 }
else if (sgShape == wgShape) {
684 arith::ConstantOp::create(rewriter, op.getLoc(), vecType, vecAttr);
685 rewriter.replaceOp(op, newConstOp);
691 if (!eltType.isIndex())
692 return rewriter.notifyMatchFailure(
693 op,
"Unsupported element type for non-splat constant op.");
695 if (wgShape.size() > 2)
696 return rewriter.notifyMatchFailure(
697 op,
"Only 1D & 2D vector constant supported");
699 SmallVector<Attribute> values(vecAttr.getValues<Attribute>());
700 int64_t rowStride = 0, colStride = 0;
701 int64_t rows = wgShape.size() == 1 ? 1 : wgShape[0];
702 int64_t cols = wgShape.size() == 1 ? wgShape[0] : wgShape[1];
706 colStride = cast<IntegerAttr>(values[1]).getInt() -
707 cast<IntegerAttr>(values[0]).getInt();
710 rowStride = cast<IntegerAttr>(values[cols]).getInt() -
711 cast<IntegerAttr>(values[0]).getInt();
714 for (int64_t r = 0; r < rows; ++r) {
715 for (int64_t c = 0; c < cols; ++c) {
716 int64_t idx = r * cols + c;
718 if (c > 0 && cols > 1) {
719 int64_t prevIdx = r * cols + (c - 1);
720 int64_t diff = cast<IntegerAttr>(values[idx]).getInt() -
721 cast<IntegerAttr>(values[prevIdx]).getInt();
722 if (diff != colStride)
723 return rewriter.notifyMatchFailure(
724 op,
"Non-constant column stride in constant op.");
727 if (r > 0 && rows > 1) {
728 int64_t prevIdx = (r - 1) * cols + c;
729 int64_t diff = cast<IntegerAttr>(values[idx]).getInt() -
730 cast<IntegerAttr>(values[prevIdx]).getInt();
731 if (diff != rowStride)
732 return rewriter.notifyMatchFailure(
733 op,
"Non-constant row stride in constant op.");
741 SmallVector<Attribute> baseTileValues;
742 int baseTileCols = sgShape[sgShape.size() - 1];
743 int64_t baseTileRows = sgShape.size() == 1 ? 1 : sgShape[0];
744 for (int64_t r = 0; r < baseTileRows; ++r) {
745 for (int64_t c = 0; c < baseTileCols; ++c) {
746 baseTileValues.push_back(values[r * cols + c]);
752 auto baseConstVec = arith::ConstantOp::create(rewriter, loc, tileAttr);
756 gpu::SubgroupIdOp::create(rewriter, loc,
nullptr);
758 layout.computeDistributedCoords(rewriter, loc, sgId, wgShape);
762 SmallVector<Value, 2> strideConsts;
763 strideConsts.push_back(
767 strideConsts.begin(),
770 SmallVector<Value> newConstOps;
771 for (
auto offsets : *sgOffsets) {
774 for (
size_t i = 0; i < strideConsts.size(); ++i) {
776 arith::MulIOp::create(rewriter, loc, rewriter.getIndexType(),
777 offsets[i], strideConsts[i]);
778 mulOffset = arith::AddIOp::create(
779 rewriter, loc, rewriter.getIndexType(), mulOffset,
mul);
782 auto bcastOffset = vector::BroadcastOp::create(
783 rewriter, loc, baseConstVec.getType(), mulOffset);
785 arith::AddIOp::create(rewriter, loc, baseConstVec, bcastOffset);
786 newConstOps.push_back(finalConst);
788 rewriter.replaceOpWithMultiple(op, {newConstOps});
796struct WgToSgLoadGatherOp :
public OpConversionPattern<xegpu::LoadGatherOp> {
797 using OpConversionPattern<xegpu::LoadGatherOp>::OpConversionPattern;
799 matchAndRewrite(xegpu::LoadGatherOp op, OneToNOpAdaptor adaptor,
800 ConversionPatternRewriter &rewriter)
const override {
802 Location loc = op.getLoc();
803 VectorType resultType = dyn_cast<VectorType>(op.getResult().getType());
806 ArrayRef<int64_t> wgShape = resultType.getShape();
808 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
810 if (!layout || !layout.isForWorkgroup())
813 SmallVector<int64_t> sgShape = getSgShapeAndCount(wgShape, layout).first;
816 auto offsetsVecType =
817 dyn_cast<VectorType>(adaptor.getOffsets().front().getType());
819 dyn_cast<VectorType>(adaptor.getMask().front().getType());
820 if (!offsetsVecType || !maskVecType ||
821 offsetsVecType.getShape() != maskVecType.getShape()) {
822 return rewriter.notifyMatchFailure(op,
823 "offsets have not been distributed");
826 SmallVector<Value> newLoadOps;
828 rewriter.getI64IntegerAttr(op.getChunkSize().value_or(1));
829 VectorType newTy = VectorType::get(sgShape, resultType.getElementType());
830 for (
auto [offsets, mask] :
831 llvm::zip(adaptor.getOffsets(), adaptor.getMask())) {
832 auto newLayout = layout.dropSgLayoutAndData();
833 auto newLoadOp = xegpu::LoadGatherOp::create(
834 rewriter, loc, newTy, op.getSource(), offsets, mask, chunkSizeAttr,
835 op.getL1HintAttr(), op.getL2HintAttr(), op.getL3HintAttr(), newLayout,
837 newLoadOps.push_back(newLoadOp);
839 rewriter.replaceOpWithMultiple(op, {newLoadOps});
846struct WgToSgStoreScatterOp
847 :
public OpConversionPattern<xegpu::StoreScatterOp> {
848 using OpConversionPattern<xegpu::StoreScatterOp>::OpConversionPattern;
850 matchAndRewrite(xegpu::StoreScatterOp op, OneToNOpAdaptor adaptor,
851 ConversionPatternRewriter &rewriter)
const override {
853 Location loc = op.getLoc();
854 VectorType valueType = dyn_cast<VectorType>(op.getValue().getType());
858 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
860 if (!layout || !layout.isForWorkgroup())
864 auto offsetsVecType =
865 dyn_cast<VectorType>(adaptor.getOffsets().front().getType());
867 dyn_cast<VectorType>(adaptor.getMask().front().getType());
868 if (!offsetsVecType || !maskVecType ||
869 offsetsVecType.getShape() != maskVecType.getShape()) {
870 return rewriter.notifyMatchFailure(op,
871 "offsets have not been distributed");
874 auto chunkSizeOpt = op.getChunkSize();
875 int64_t chunkSize = chunkSizeOpt ?
static_cast<int64_t
>(*chunkSizeOpt) : 1;
876 auto chunkSizeAttr = rewriter.getI64IntegerAttr(chunkSize);
877 for (
auto [val, offs, mask] : llvm::zip(
878 adaptor.getValue(), adaptor.getOffsets(), adaptor.getMask())) {
879 xegpu::StoreScatterOp::create(rewriter, loc, val, op.getDest(), offs,
880 mask, chunkSizeAttr, op.getL1HintAttr(),
881 op.getL2HintAttr(), op.getL3HintAttr(),
882 layout.dropSgLayoutAndData(),
885 rewriter.eraseOp(op);
890struct WgToSgLoadMatrixOp :
public OpConversionPattern<xegpu::LoadMatrixOp> {
891 using OpConversionPattern<xegpu::LoadMatrixOp>::OpConversionPattern;
893 matchAndRewrite(xegpu::LoadMatrixOp op, OneToNOpAdaptor adaptor,
894 ConversionPatternRewriter &rewriter)
const override {
896 SmallVector<SmallVector<OpFoldResult>> offsetsList;
897 if (
failed(genOffsetsList(rewriter, op, offsetsList)))
900 ArrayRef<int64_t> wgShape = op.getDataShape();
901 VectorType valueTy = llvm::dyn_cast<VectorType>(op.getRes().getType());
902 assert(valueTy &&
"the value type must be vector type!");
903 Type elemTy = valueTy.getElementType();
905 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
906 SmallVector<int64_t> sgShape = getSgShapeAndCount(wgShape, layout).first;
907 VectorType newResTy = VectorType::get(sgShape, elemTy);
908 SmallVector<Value> newOps;
909 for (
auto offsets : offsetsList) {
910 auto newOp = xegpu::LoadMatrixOp::create(rewriter, op.getLoc(), newResTy,
911 op.getMemDesc(), offsets,
912 layout.dropSgLayoutAndData());
913 newOps.push_back(newOp);
915 rewriter.replaceOpWithMultiple(op, {newOps});
921struct WgToSgStoreMatrixOp :
public OpConversionPattern<xegpu::StoreMatrixOp> {
922 using OpConversionPattern<xegpu::StoreMatrixOp>::OpConversionPattern;
924 matchAndRewrite(xegpu::StoreMatrixOp op, OneToNOpAdaptor adaptor,
925 ConversionPatternRewriter &rewriter)
const override {
927 SmallVector<SmallVector<OpFoldResult>> offsetsList;
928 if (
failed(genOffsetsList(rewriter, op, offsetsList)))
931 xegpu::DistributeLayoutAttr layout = op.getLayoutAttr();
932 for (
auto [v, offsets] : llvm::zip(adaptor.getData(), offsetsList))
933 xegpu::StoreMatrixOp::create(rewriter, op.getLoc(), v, op.getMemDesc(),
934 offsets, layout.dropSgLayoutAndData());
935 rewriter.eraseOp(op);
941struct WgToSgVectorStepOp :
public OpConversionPattern<vector::StepOp> {
942 using OpConversionPattern<vector::StepOp>::OpConversionPattern;
944 matchAndRewrite(vector::StepOp op, OneToNOpAdaptor adaptor,
945 ConversionPatternRewriter &rewriter)
const override {
946 xegpu::DistributeLayoutAttr layout =
948 if (!layout || !layout.isForWorkgroup())
951 Location loc = op.getLoc();
952 VectorType type = op.getResult().getType();
953 auto wgShape = type.getShape();
954 std::optional<SmallVector<int64_t>> sgShape =
955 getSgShapeAndCount(wgShape, layout).first;
960 gpu::SubgroupIdOp::create(rewriter, loc,
nullptr);
962 layout.computeDistributedCoords(rewriter, loc, sgId, wgShape);
966 VectorType newTy = type.cloneWith(*sgShape, type.getElementType());
967 auto steps = vector::StepOp::create(rewriter, loc, newTy);
968 SmallVector<Value> newOps;
969 for (
auto offsets : *sgOffsets) {
972 vector::BroadcastOp::create(rewriter, loc, newTy, offsets[0]);
974 arith::AddIOp::create(rewriter, loc, steps, bcastOffset);
975 newOps.push_back(finalSteps);
978 rewriter.replaceOpWithMultiple(op, {newOps});
984struct WgToSgVectorShapeCastOp
985 :
public OpConversionPattern<vector::ShapeCastOp> {
986 using OpConversionPattern<vector::ShapeCastOp>::OpConversionPattern;
989 matchAndRewrite(vector::ShapeCastOp op, OneToNOpAdaptor adaptor,
990 ConversionPatternRewriter &rewriter)
const override {
992 VectorType resultType = dyn_cast<VectorType>(op.getResult().getType());
996 ArrayRef<int64_t> wgShape = resultType.getShape();
997 xegpu::DistributeLayoutAttr layout =
999 if (!layout || !layout.isForWorkgroup())
1004 auto srcType = dyn_cast<VectorType>(op.getSource().getType());
1008 ArrayRef<int64_t> srcShape = srcType.getShape();
1010 xegpu::DistributeLayoutAttr layoutToDistribute = layout;
1011 SmallVector<int64_t> expandedUnitDims;
1013 xegpu::DistributeLayoutAttr sourceLayout =
1016 if (!sourceLayout.isSliceOf(layout))
1017 return rewriter.notifyMatchFailure(
1018 op,
"The ShapeCast op only expands dimensions, the input layout "
1019 "must be a slice of the result layout.");
1021 assert(layoutToDistribute.isEqualTo(
1022 layoutToDistribute.setUnitDimData(expandedUnitDims)) &&
1023 "The sg_data for unit dimensions should be set as 1");
1026 SmallVector<int64_t> sgShape =
1027 getSgShapeAndCount(wgShape, layoutToDistribute).first;
1028 VectorType newResultType =
1029 VectorType::get(sgShape, resultType.getElementType());
1031 SmallVector<Value> newShapeCastOps;
1032 for (
auto src : adaptor.getSource()) {
1033 auto newShapeCast = vector::ShapeCastOp::create(rewriter, op.getLoc(),
1034 newResultType, src);
1035 newShapeCastOps.push_back(newShapeCast.getResult());
1038 rewriter.replaceOpWithMultiple(op, {newShapeCastOps});
1075struct WgToSgMultiDimReductionOp
1076 :
public OpConversionPattern<vector::MultiDimReductionOp> {
1077 using OpConversionPattern<vector::MultiDimReductionOp>::OpConversionPattern;
1080 matchAndRewrite(vector::MultiDimReductionOp op, OneToNOpAdaptor adaptor,
1081 ConversionPatternRewriter &rewriter)
const override {
1082 Location loc = op.getLoc();
1084 VectorType srcType = op.getSourceVectorType();
1085 Type resultTy = op.getResult().getType();
1086 VectorType dstVecType = dyn_cast<VectorType>(resultTy);
1087 bool isScalarResult = !dstVecType;
1089 auto originalSrcShape = srcType.getShape();
1090 Type elemTy = srcType.getElementType();
1092 xegpu::DistributeLayoutAttr layout =
1094 if (!layout || !layout.isForWorkgroup())
1097 auto reductionDims = llvm::to_vector(op.getReductionDims());
1100 SmallVector<int64_t> sgLayout;
1101 SmallVector<int64_t> sgData;
1102 xegpu::DistributeLayoutAttr parentLayout;
1103 if (
auto sliceAttr = dyn_cast<xegpu::SliceAttr>(layout)) {
1104 parentLayout = sliceAttr.getParent();
1105 sgLayout = parentLayout.getEffectiveSgLayoutAsInt();
1106 sgData = parentLayout.getEffectiveSgDataAsInt();
1108 return rewriter.notifyMatchFailure(
1109 op,
"Reduction should have SliceAttr layout");
1112 SmallVector<Value> localReductions;
1113 auto sgSrcs = adaptor.getSource();
1114 auto sgSrcType = dyn_cast<VectorType>(sgSrcs.front().getType());
1115 SmallVector<int64_t> sgSrcShape(sgSrcType.getShape().begin(),
1116 sgSrcType.getShape().end());
1123 auto originalDstShape = dstVecType.getShape();
1124 SmallVector<int64_t> sgDstShape =
1125 getSgShapeAndCount(originalDstShape, layout).first;
1126 sgDstType = VectorType::get(sgDstShape, elemTy);
1131 for (
auto sgSrc : sgSrcs) {
1134 rewriter, loc, sgDstType, op.getKind());
1136 auto localReduce = vector::MultiDimReductionOp::create(
1137 rewriter, loc, sgDstType, op.getKind(), sgSrc, neutralLocalAcc,
1139 localReductions.push_back(localReduce.getResult());
1143 SmallVector<int64_t> crossSgReductionDims;
1144 for (int64_t reductionDim : reductionDims) {
1145 bool needsCrossSubgroupReduction =
1146 (sgLayout[reductionDim] > 1) &&
1147 (sgData[reductionDim] < originalSrcShape[reductionDim]);
1149 if (needsCrossSubgroupReduction) {
1150 crossSgReductionDims.push_back(reductionDim);
1155 if (crossSgReductionDims.empty()) {
1156 SmallVector<Value> results;
1157 for (
auto localResult : localReductions) {
1159 rewriter, loc, op.getKind(), localResult, adaptor.getAcc()[0]);
1160 results.push_back(finalResult);
1162 rewriter.replaceOpWithMultiple(op, {results});
1167 auto slmStoreDataShape = sgSrcShape;
1168 for (int64_t dim : reductionDims)
1169 slmStoreDataShape[dim] = 1;
1170 VectorType slmStoreDataType = VectorType::get(slmStoreDataShape, elemTy);
1171 SmallVector<Value> slmStoreData;
1172 for (
auto localResult : localReductions) {
1173 if (isScalarResult) {
1175 slmStoreData.push_back(vector::BroadcastOp::create(
1176 rewriter, loc, slmStoreDataType, localResult));
1178 slmStoreData.push_back(vector::ShapeCastOp::create(
1179 rewriter, loc, slmStoreDataType, localResult));
1183 SmallVector<int64_t> slmShape(originalSrcShape.begin(),
1184 originalSrcShape.end());
1185 SmallVector<int> slmSgData(sgData.begin(), sgData.end());
1186 SmallVector<int> slmSgLayout(sgLayout.begin(), sgLayout.end());
1187 for (
int dim : reductionDims) {
1188 slmShape[dim] = sgLayout[dim];
1191 xegpu::LayoutAttr slmStoreLayout =
1192 xegpu::LayoutAttr::get(rewriter.getContext(), slmSgLayout, slmSgData);
1196 auto bytesPerElement = bitWidth / 8;
1198 auto slmTy = MemRefType::get({slmSize}, rewriter.getI8Type(), {}, 3);
1199 auto slm = memref::AllocaOp::create(rewriter, loc, slmTy);
1201 auto memDescType = xegpu::MemDescType::get(rewriter.getContext(), slmShape,
1204 xegpu::CreateMemDescOp::create(rewriter, loc, memDescType, slm);
1207 auto sgId = gpu::SubgroupIdOp::create(rewriter, loc,
1208 rewriter.getIndexType(),
nullptr);
1210 auto slmStoreCoords =
1211 slmStoreLayout.computeDistributedCoords(rewriter, loc, sgId, slmShape);
1212 if (
failed(slmStoreCoords))
1214 for (
auto [data, coord] : llvm::zip(slmStoreData, *slmStoreCoords)) {
1215 SmallVector<OpFoldResult> coordOfr(coord.begin(), coord.end());
1216 xegpu::StoreMatrixOp::create(rewriter, loc, data, memDesc.getResult(),
1221 gpu::BarrierOp::create(rewriter, loc);
1224 SmallVector<int64_t> slmLoadDataShape(sgSrcShape.begin(), sgSrcShape.end());
1225 for (int64_t dim : reductionDims) {
1226 slmLoadDataShape[dim] = slmShape[dim];
1227 slmSgData[dim] = slmShape[dim];
1229 xegpu::LayoutAttr slmLoadLayout =
1230 xegpu::LayoutAttr::get(rewriter.getContext(), slmSgLayout, slmSgData);
1231 auto slmLoadCoords =
1232 slmLoadLayout.computeDistributedCoords(rewriter, loc, sgId, slmShape);
1233 if (
failed(slmLoadCoords))
1236 VectorType slmLoadType = VectorType::get(slmLoadDataShape, elemTy);
1237 SmallVector<Value> slmLoadData;
1238 for (
auto coord : *slmLoadCoords) {
1239 SmallVector<OpFoldResult> coordOfr(coord.begin(), coord.end());
1240 slmLoadData.push_back(xegpu::LoadMatrixOp::create(
1241 rewriter, loc, slmLoadType, memDesc.getResult(), coordOfr,
1248 rewriter, loc, sgDstType, op.getKind());
1250 SmallVector<Value> finalResults;
1251 for (
size_t i = 0; i < slmLoadData.size(); ++i) {
1252 auto loaded = slmLoadData[i];
1253 auto finalReduce = vector::MultiDimReductionOp::create(
1254 rewriter, loc, sgDstType, op.getKind(), loaded, neutralFinalAcc,
1257 rewriter, loc, op.getKind(), finalReduce.getResult(),
1258 adaptor.getAcc()[i]));
1260 rewriter.replaceOpWithMultiple(op, {finalResults});
1266struct WgToSgVectorTransposeOp
1267 :
public OpConversionPattern<vector::TransposeOp> {
1268 using OpConversionPattern<vector::TransposeOp>::OpConversionPattern;
1271 matchAndRewrite(vector::TransposeOp op, OneToNOpAdaptor adaptor,
1272 ConversionPatternRewriter &rewriter)
const override {
1273 VectorType resultType = op.getResultVectorType();
1275 ArrayRef<int64_t> wgShape = resultType.getShape();
1276 xegpu::DistributeLayoutAttr layout =
1278 if (!layout || !layout.isForWorkgroup())
1280 xegpu::DistributeLayoutAttr sourceLayout =
1282 if (!sourceLayout || !sourceLayout.isForWorkgroup())
1285 SmallVector<int64_t> sourceSgLayout =
1286 sourceLayout.getEffectiveSgLayoutAsInt();
1287 SmallVector<int64_t> resultSgLayout = layout.getEffectiveSgLayoutAsInt();
1289 ArrayRef<int64_t> permutation = op.getPermutation();
1290 size_t permutationSize = permutation.size();
1291 if (sourceSgLayout.size() != permutationSize ||
1292 resultSgLayout.size() != permutationSize) {
1293 return rewriter.notifyMatchFailure(
1294 op,
"Layouts and permutation must have the same rank");
1299 if (!layout.isTransposeOf(sourceLayout, permutation,
1300 xegpu::LayoutKind::Subgroup))
1301 return rewriter.notifyMatchFailure(
1302 op,
"Result layout is not a valid transpose of source layout "
1303 "according to permutation");
1305 SmallVector<int64_t> sgShape = getSgShapeAndCount(wgShape, layout).first;
1306 VectorType newResultType =
1307 VectorType::get(sgShape, resultType.getElementType());
1309 SmallVector<Value> newTransposeOps;
1310 for (
auto src : adaptor.getVector()) {
1311 auto newTranspose = vector::TransposeOp::create(
1312 rewriter, op.getLoc(), newResultType, src, permutation);
1313 newTransposeOps.push_back(newTranspose.getResult());
1315 rewriter.replaceOpWithMultiple(op, {newTransposeOps});
1321template <
typename MaskOpType>
1322struct WgToSgVectorMaskOp :
public OpConversionPattern<MaskOpType> {
1323 using OpConversionPattern<MaskOpType>::OpConversionPattern;
1325 LogicalResult matchAndRewrite(
1327 typename OpConversionPattern<MaskOpType>::OneToNOpAdaptor adaptor,
1328 ConversionPatternRewriter &rewriter)
const override {
1329 xegpu::DistributeLayoutAttr layout =
1331 if (!layout || !layout.isForWorkgroup())
1334 Location loc = op.getLoc();
1335 VectorType type = op.getResult().getType();
1336 auto wgShape = type.getShape();
1338 SmallVector<Value> wgMaskDimSizes;
1339 if constexpr (std::is_same_v<MaskOpType, vector::ConstantMaskOp>) {
1340 for (int64_t maskSize : op.getMaskDimSizes()) {
1341 wgMaskDimSizes.push_back(
1344 }
else if constexpr (std::is_same_v<MaskOpType, vector::CreateMaskOp>) {
1345 wgMaskDimSizes = llvm::to_vector(op.getOperands());
1349 gpu::SubgroupIdOp::create(rewriter, loc,
nullptr);
1351 layout.computeDistributedCoords(rewriter, loc, sgId, wgShape);
1355 SmallVector<int64_t> sgShape = getSgShapeAndCount(wgShape, layout).first;
1356 VectorType resultType = VectorType::get(sgShape, type.getElementType());
1360 SmallVector<Value> newCreateMaskOps;
1361 for (
auto offsetSet : *sgOffsets) {
1362 SmallVector<Value> maskOperands;
1364 for (
auto [i, wgMaskDimSize] : llvm::enumerate(wgMaskDimSizes)) {
1367 Value offset = offsetSet[i];
1368 Value adjustedMaskSize =
1369 arith::SubIOp::create(rewriter, loc, wgMaskDimSize, offset);
1372 arith::MaxSIOp::create(rewriter, loc, adjustedMaskSize, zero);
1374 arith::MinSIOp::create(rewriter, loc, nonNegative, dimSizeVal);
1375 maskOperands.push_back(sgMaskSize);
1378 auto newCreateMaskOp =
1379 vector::CreateMaskOp::create(rewriter, loc, resultType, maskOperands);
1380 newCreateMaskOps.push_back(newCreateMaskOp.getResult());
1383 rewriter.replaceOpWithMultiple(op, {newCreateMaskOps});
1388using WgToSgVectorConstantMaskOp = WgToSgVectorMaskOp<vector::ConstantMaskOp>;
1389using WgToSgVectorCreateMaskOp = WgToSgVectorMaskOp<vector::CreateMaskOp>;
1392struct WgToSgVectorBitCastOp :
public OpConversionPattern<vector::BitCastOp> {
1393 using OpConversionPattern<vector::BitCastOp>::OpConversionPattern;
1396 matchAndRewrite(vector::BitCastOp op, OneToNOpAdaptor adaptor,
1397 ConversionPatternRewriter &rewriter)
const override {
1398 VectorType resultType = op.getResultVectorType();
1400 ArrayRef<int64_t> wgShape = resultType.getShape();
1401 xegpu::DistributeLayoutAttr layout =
1403 if (!layout || !layout.isForWorkgroup())
1406 SmallVector<int64_t> sgShape = getSgShapeAndCount(wgShape, layout).first;
1407 VectorType newResultType =
1408 VectorType::get(sgShape, resultType.getElementType());
1410 SmallVector<Value> newBitCastOps;
1411 for (
auto src : adaptor.getSource()) {
1413 vector::BitCastOp::create(rewriter, op.getLoc(), newResultType, src);
1414 newBitCastOps.push_back(newBitCast.getResult());
1417 rewriter.replaceOpWithMultiple(op, {newBitCastOps});
1423struct WgToSgVectorInterleaveOp
1424 :
public OpConversionPattern<vector::InterleaveOp> {
1425 using OpConversionPattern<vector::InterleaveOp>::OpConversionPattern;
1428 matchAndRewrite(vector::InterleaveOp op, OneToNOpAdaptor adaptor,
1429 ConversionPatternRewriter &rewriter)
const override {
1430 VectorType resultType = op.getResultVectorType();
1432 ArrayRef<int64_t> wgShape = resultType.getShape();
1433 xegpu::DistributeLayoutAttr layout =
1435 if (!layout || !layout.isForWorkgroup())
1438 SmallVector<int64_t> sgShape = getSgShapeAndCount(wgShape, layout).first;
1439 VectorType newResultType =
1440 VectorType::get(sgShape, resultType.getElementType());
1442 SmallVector<Value> newInterleaveOps;
1445 for (
auto [
lhs,
rhs] : llvm::zip(adaptor.getLhs(), adaptor.getRhs())) {
1446 auto newInterleave = vector::InterleaveOp::create(
1447 rewriter, op.getLoc(), newResultType,
lhs,
rhs);
1448 newInterleaveOps.push_back(newInterleave.getResult());
1451 rewriter.replaceOpWithMultiple(op, {newInterleaveOps});
1457struct WgToSgVectorDeinterleaveOp
1458 :
public OpConversionPattern<vector::DeinterleaveOp> {
1459 using OpConversionPattern<vector::DeinterleaveOp>::OpConversionPattern;
1462 matchAndRewrite(vector::DeinterleaveOp op, OneToNOpAdaptor adaptor,
1463 ConversionPatternRewriter &rewriter)
const override {
1464 SmallVector<Value> newRes1Ops;
1465 SmallVector<Value> newRes2Ops;
1467 for (
auto src : adaptor.getSource()) {
1468 auto newDeinterleave =
1469 vector::DeinterleaveOp::create(rewriter, op.getLoc(), src);
1470 newRes1Ops.push_back(newDeinterleave.getRes1());
1471 newRes2Ops.push_back(newDeinterleave.getRes2());
1474 SmallVector<SmallVector<Value>> results = {newRes1Ops, newRes2Ops};
1475 rewriter.replaceOpWithMultiple(op, results);
1487 converter.addConversion([](
Type type) ->
Type {
return type; });
1490 converter.addConversion(
1491 [](xegpu::TensorDescType type,
1493 xegpu::DistributeLayoutAttr layout = type.getLayoutAttr();
1494 if (!layout || !layout.isForWorkgroup())
1495 return std::nullopt;
1497 Type elemTy = type.getElementType();
1502 std::tie(subShape, count) = getSgShapeAndCount(
shape, layout);
1504 layout = layout.dropSgLayoutAndData();
1506 auto newTy = xegpu::TensorDescType::get(
1507 type.
getContext(), subShape, elemTy, type.getEncoding(), layout);
1508 result.append(count, newTy);
1514 auto getSubShapeAndCount = [](VectorType vecTy,
1515 xegpu::DistributeLayoutAttr layout)
1517 if (!layout.isForWorkgroup())
1519 return getSgShapeAndCount(vecTy.getShape(), layout);
1524 std::move(loopArgTypes));
1528 patterns.
add<WgToSgCreateNdOp, WgToSgLoadNdOp, WgToSgStoreNdOp, WgToSgDpasOp,
1529 WgToSgDpasMxOp, WgToSgPrefetchNdOp, WgToSgElementwiseOp,
1530 WgToSgVectorBroadcastOp, WgToSgConvertLayoutOp,
1531 WgToSgArithConstantOp, WgToSgLoadGatherOp, WgToSgStoreScatterOp,
1532 WgToSgLoadMatrixOp, WgToSgStoreMatrixOp, WgToSgVectorStepOp,
1533 WgToSgVectorShapeCastOp, WgToSgMultiDimReductionOp,
1534 WgToSgVectorTransposeOp, WgToSgVectorConstantMaskOp,
1535 WgToSgVectorCreateMaskOp, WgToSgVectorBitCastOp,
1536 WgToSgVectorInterleaveOp, WgToSgVectorDeinterleaveOp>(
1543struct XeGPUWgToSgDistributePass
1545 void runOnOperation()
override;
1549void XeGPUWgToSgDistributePass::runOnOperation() {
1551 Operation *op = getOperation();
1553 signalPassFailure();
1558 llvm::SmallSetVector<UnrealizedConversionCastOp, 8> existingCasts;
1559 getOperation()->walk(
1560 [&](UnrealizedConversionCastOp castOp) { existingCasts.insert(castOp); });
1567 RewritePatternSet patterns(ctx);
1568 ConversionTarget
target(*ctx);
1569 TypeConverter converter;
1572 auto materializeCast = [](OpBuilder &builder, Type type,
ValueRange inputs,
1573 Location loc) -> Value {
1574 return UnrealizedConversionCastOp::create(builder, loc, type, inputs)
1577 converter.addSourceMaterialization(materializeCast);
1578 converter.addTargetMaterialization(materializeCast);
1582 auto getTensorDescType = [](Operation *op) -> xegpu::TensorDescType {
1583 if (
auto createOp = dyn_cast<xegpu::CreateNdDescOp>(op))
1584 return createOp.getType();
1585 if (
auto loadOp = dyn_cast<xegpu::LoadNdOp>(op))
1586 return loadOp.getTensorDescType();
1587 if (
auto storeOp = dyn_cast<xegpu::StoreNdOp>(op))
1588 return storeOp.getTensorDescType();
1589 if (
auto prefetchOp = dyn_cast<xegpu::PrefetchNdOp>(op))
1590 return prefetchOp.getTensorDescType();
1591 return xegpu::TensorDescType();
1594 auto isLegal = [&](xegpu::DistributeLayoutAttr layout) ->
bool {
1595 return !layout || !layout.isForWorkgroup();
1598 target.addDynamicallyLegalOp<xegpu::CreateNdDescOp, xegpu::LoadNdOp,
1599 xegpu::StoreNdOp, xegpu::PrefetchNdOp>(
1600 [=](Operation *op) ->
bool {
1601 auto tdescTy = getTensorDescType(op);
1603 dyn_cast_if_present<xegpu::LayoutAttr>(tdescTy.getLayout());
1604 return isLegal(layout);
1607 target.addDynamicallyLegalOp<xegpu::DpasOp>([=](xegpu::DpasOp op) ->
bool {
1608 auto layout = op.getLayoutCdAttr();
1609 return isLegal(layout);
1612 target.addDynamicallyLegalOp<xegpu::DpasMxOp>(
1613 [=](xegpu::DpasMxOp op) ->
bool {
1614 auto layout = op.getLayoutCdAttr();
1615 return isLegal(layout);
1618 target.addDynamicallyLegalOp<xegpu::LoadMatrixOp>(
1619 [=](xegpu::LoadMatrixOp op) ->
bool {
1620 return isLegal(op.getLayoutAttr());
1623 target.addDynamicallyLegalOp<xegpu::StoreMatrixOp>(
1624 [=](xegpu::StoreMatrixOp op) ->
bool {
1625 return isLegal(op.getLayoutAttr());
1628 target.addDynamicallyLegalOp<arith::ConstantOp>(
1629 [=](arith::ConstantOp op) ->
bool {
1630 auto vecType = dyn_cast<VectorType>(op.getType());
1636 return isLegal(layout);
1639 target.addDynamicallyLegalOp<
1640 vector::ShapeCastOp, vector::StepOp, vector::TransposeOp,
1641 vector::BroadcastOp, vector::MultiDimReductionOp, vector::ConstantMaskOp,
1642 vector::CreateMaskOp, vector::BitCastOp, vector::InterleaveOp,
1643 vector::DeinterleaveOp>([=](Operation *op) ->
bool {
1647 return isLegal(layout);
1650 target.addDynamicallyLegalOp<xegpu::LoadGatherOp>(
1651 [=](xegpu::LoadGatherOp op) ->
bool {
1652 auto layout = op.getLayoutAttr();
1653 return isLegal(layout);
1656 target.addDynamicallyLegalOp<xegpu::StoreScatterOp>(
1657 [=](xegpu::StoreScatterOp op) ->
bool {
1658 auto layout = op.getLayoutAttr();
1659 return isLegal(layout);
1662 target.addDynamicallyLegalOp<xegpu::ConvertLayoutOp>(
1663 [=](xegpu::ConvertLayoutOp op) ->
bool {
1664 return isLegal(op.getInputLayout()) && isLegal(op.getTargetLayout());
1667 target.addDynamicallyLegalDialect<math::MathDialect, arith::ArithDialect>(
1668 [=](Operation *op) -> std::optional<bool> {
1673 VectorType resultType =
1681 VectorType operandType = dyn_cast<VectorType>(operand.getType());
1682 if (!operandType || operandType.getShape() != resultType.getShape()) {
1687 xegpu::DistributeLayoutAttr layout =
1689 return isLegal(layout);
1692 target.addLegalOp<UnrealizedConversionCastOp>();
1694 target.markUnknownOpDynamicallyLegal([](Operation *) {
return true; });
1700 applyPartialConversion(getOperation(),
target, std::move(patterns))))
1701 return signalPassFailure();
Attributes are known-constant values of operations.
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 * getContext() const
Return the context this location is uniqued in.
MLIRContext is the top-level object for a collection of MLIR operations.
Operation is the basic unit of execution within MLIR.
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
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.
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
OperationName getName()
The name of an operation is the key identifier for it.
operand_range getOperands()
Returns an iterator on the underlying Value's.
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...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
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)
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.
void removeTemporaryLayoutAttrs(Operation *op)
Removes the temporary layout attributes for each OpOperand and OpResult of the given operation.
void populateXeGPUWgToSgDistributeTypeConversions(TypeConverter &converter, Operation *topLevelOp)
Define the type conversions needed for XeGPU workgroup to subgroup distribution.
Value createReductionNeutralValue(OpBuilder &builder, Location loc, Type type, vector::CombiningKind kind)
Creates a constant filled with the neutral (identity) value for the given reduction kind.
bool matchUnitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< int64_t > &expandedUnitDims)
bool recoverTemporaryLayouts(Operation *rootOp)
Attach layout attributes to all vector-type operands of operations within the given operation's neste...
DenseMap< Value, SmallVector< Type > > precomputeLoopBlockArgTypes(Operation *topLevelOp, SubShapeAndCountFn getSubShapeAndCount)
Pre-computes distributed VectorType mappings for every value carried through an SCF loop under topLev...
void populateXeGPUWgToSgDistributePatterns(RewritePatternSet &patterns)
Appends patterns for XeGPU workgroup to subgroup distribution into patterns.
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 removeLayoutAttrs(Operation *op)
Removes the DistributeLayoutAttr for each OpOperand and OpResult of the given operation if they exist...
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.
Include the generated interface declarations.
int64_t computeProduct(ArrayRef< int64_t > basis)
Self-explicit.
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.