32#include "llvm/ADT/ArrayRef.h"
33#include "llvm/ADT/DenseMap.h"
34#include "llvm/ADT/STLExtras.h"
35#include "llvm/ADT/SmallSet.h"
36#include "llvm/ADT/SmallVector.h"
37#include "llvm/ADT/TypeSwitch.h"
38#include "llvm/Support/Casting.h"
39#include "llvm/Support/Debug.h"
40#include "llvm/Support/LogicalResult.h"
41#include "llvm/Support/raw_ostream.h"
46#define GEN_PASS_DEF_XEGPUPROPAGATELAYOUT
47#include "mlir/Dialect/XeGPU/Transforms/Passes.h.inc"
51#define DEBUG_TYPE "xegpu-propagate-layout"
52#define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE "]: ")
96 xegpu::DistributeLayoutAttr storage =
nullptr;
99 int64_t programOrder = std::numeric_limits<int64_t>::max();
102 LayoutInfo() =
default;
103 LayoutInfo(
const xegpu::DistributeLayoutAttr &layout,
int64_t programOrder)
104 : storage(layout), programOrder(programOrder) {}
110 bool operator==(
const LayoutInfo &other)
const {
111 if (isAssigned() != other.isAssigned())
115 return storage.isEqualTo(other.storage);
118 static LayoutInfo meet(
const LayoutInfo &
lhs,
const LayoutInfo &
rhs);
120 static LayoutInfo
join(
const LayoutInfo &
lhs,
const LayoutInfo &
rhs);
124 bool isAssigned()
const {
return storage !=
nullptr; }
138 bool isSliceLayout()
const {
141 return isa<xegpu::SliceAttr>(storage);
147 return storage.getRank();
151 void set(
const xegpu::DistributeLayoutAttr &layout) { storage = layout; }
158 os <<
"Not assigned.";
162LayoutInfo LayoutInfo::meet(
const LayoutInfo &
lhs,
const LayoutInfo &
rhs) {
163 if (!
lhs.isAssigned())
165 if (!
rhs.isAssigned())
170 if (
rhs.programOrder <
lhs.programOrder)
176LayoutInfo LayoutInfo::join(
const LayoutInfo &
lhs,
const LayoutInfo &
rhs) {
177 llvm_unreachable(
"Join should not be triggered by layout propagation.");
185struct LayoutInfoLattice :
public Lattice<LayoutInfo> {
187 using Lattice::Lattice;
199class LayoutInfoPropagation
217 LayoutInfo makeLayoutInfo(const
xegpu::DistributeLayoutAttr &layout) {
218 return LayoutInfo(layout, currentProgramOrder);
224 void visitDpasMxOp(xegpu::DpasMxOp dpasMx,
228 void visitStoreNdOp(xegpu::StoreNdOp store,
232 void visitStoreScatterOp(xegpu::StoreScatterOp storeScatter,
236 void visitLoadNdOp(xegpu::LoadNdOp
load,
240 void visitLoadGatherOp(xegpu::LoadGatherOp
load,
244 void visitTransposeOp(vector::TransposeOp transpose,
248 void visitVectorBitcastOp(vector::BitCastOp bitcast,
252 void visitVectorInterleaveOp(vector::InterleaveOp interleave,
256 void visitVectorDeinterleaveOp(vector::DeinterleaveOp deinterleave,
260 void visitPrefetchNdOp(xegpu::PrefetchNdOp prefetch,
264 void visitVectorMultiReductionOp(vector::MultiDimReductionOp reduction,
268 void visitVectorReductionOp(vector::ReductionOp reduction,
272 void visitVectorBroadCastOp(vector::BroadcastOp
broadcast,
275 void visitShapeCastOp(vector::ShapeCastOp shapeCast,
279 visitInsertStridedSliceOp(vector::InsertStridedSliceOp insertStridedSlice,
283 void visitLoadMatrixOp(xegpu::LoadMatrixOp
load,
287 void visitStoreMatrixOp(xegpu::StoreMatrixOp store,
291 void visitLoadGatherOp(xegpu::LoadMatrixOp
load,
295 void visitStoreScatterOp(xegpu::StoreMatrixOp store,
299 void visitConvertLayoutOp(xegpu::ConvertLayoutOp convertLayout,
303 bool hasParamsOfLayoutKind(xegpu::DistributeLayoutAttr anchorLayout);
310 layoutKind(layoutKind), indexBitWidth(indexBitWidth) {}
317 void visitBranchOperand(
OpOperand &operand)
override {};
319 void visitCallOperand(
OpOperand &operand)
override {};
322 visitNonControlFlowArguments(RegionSuccessor &successor,
323 ArrayRef<BlockArgument> arguments)
override {};
325 void visitExternalCall(CallOpInterface call,
326 ArrayRef<LayoutInfoLattice *> operands,
327 ArrayRef<const LayoutInfoLattice *> results)
override {
330 void setToExitState(LayoutInfoLattice *lattice)
override {
331 (void)lattice->meet(LayoutInfo());
336int64_t LayoutInfoPropagation::getProgramOrder(Operation *op) {
337 auto it = programOrder.find(op);
338 if (it != programOrder.end())
344 Operation *root = op;
348 root->
walk<WalkOrder::PreOrder>(
349 [&](Operation *o) { programOrder[o] = counter++; });
350 return programOrder.lookup(op);
353LogicalResult LayoutInfoPropagation::visitOperation(
354 Operation *op, ArrayRef<LayoutInfoLattice *> operands,
355 ArrayRef<const LayoutInfoLattice *> results) {
358 currentProgramOrder = getProgramOrder(op);
361 [&](xegpu::DpasOp dpasOp) { visitDpasOp(dpasOp, operands, results); })
362 .Case([&](xegpu::DpasMxOp dpasMxOp) {
363 visitDpasMxOp(dpasMxOp, operands, results);
365 .Case([&](xegpu::StoreNdOp storeNdOp) {
366 visitStoreNdOp(storeNdOp, operands, results);
368 .Case([&](xegpu::StoreScatterOp storeScatterOp) {
369 visitStoreScatterOp(storeScatterOp, operands, results);
371 .Case([&](xegpu::LoadNdOp loadNdOp) {
372 visitLoadNdOp(loadNdOp, operands, results);
374 .Case([&](xegpu::LoadGatherOp loadGatherOp) {
375 visitLoadGatherOp(loadGatherOp, operands, results);
377 .Case([&](xegpu::PrefetchNdOp prefetchNdOp) {
378 visitPrefetchNdOp(prefetchNdOp, operands, results);
380 .Case([&](vector::TransposeOp transposeOp) {
381 visitTransposeOp(transposeOp, operands, results);
383 .Case([&](vector::BitCastOp bitcastOp) {
384 visitVectorBitcastOp(bitcastOp, operands, results);
386 .Case([&](vector::InterleaveOp interleaveOp) {
387 visitVectorInterleaveOp(interleaveOp, operands, results);
389 .Case([&](vector::DeinterleaveOp deinterleaveOp) {
390 visitVectorDeinterleaveOp(deinterleaveOp, operands, results);
392 .Case([&](vector::MultiDimReductionOp reductionOp) {
393 visitVectorMultiReductionOp(reductionOp, operands, results);
395 .Case([&](vector::ReductionOp reductionOp) {
396 visitVectorReductionOp(reductionOp, operands, results);
398 .Case([&](vector::BroadcastOp broadcastOp) {
399 visitVectorBroadCastOp(broadcastOp, operands, results);
401 .Case([&](vector::ShapeCastOp shapeCastOp) {
402 visitShapeCastOp(shapeCastOp, operands, results);
404 .Case([&](vector::InsertStridedSliceOp insertStridedSliceOp) {
405 visitInsertStridedSliceOp(insertStridedSliceOp, operands, results);
407 .Case([&](xegpu::LoadMatrixOp loadMatrixOp) {
408 visitLoadMatrixOp(loadMatrixOp, operands, results);
410 .Case([&](xegpu::StoreMatrixOp storeMatrixOp) {
411 visitStoreMatrixOp(storeMatrixOp, operands, results);
413 .Case([&](xegpu::ConvertLayoutOp convertLayoutOp) {
414 visitConvertLayoutOp(convertLayoutOp, operands, results);
417 .Default([&](Operation *op) {
418 for (
const LayoutInfoLattice *resultInfo : results) {
419 if (!resultInfo->getValue().isAssigned())
421 for (
auto [operandInfo, operand] :
425 if (!isa<xegpu::TensorDescType, VectorType>(
426 operand.get().getType()))
429 meet(operandInfo, *resultInfo);
437bool LayoutInfoPropagation::hasParamsOfLayoutKind(
438 xegpu::DistributeLayoutAttr anchorLayout) {
439 if (anchorLayout ==
nullptr) {
442 if (layoutKind == xegpu::LayoutKind::InstData) {
443 return !(anchorLayout.getEffectiveInstDataAsInt().empty());
445 if (layoutKind == xegpu::LayoutKind::Lane) {
446 return !(anchorLayout.getEffectiveLaneLayoutAsInt().empty() ||
447 anchorLayout.getEffectiveLaneDataAsInt().empty());
449 if (layoutKind == xegpu::LayoutKind::Subgroup) {
450 return !(anchorLayout.getEffectiveSgLayoutAsInt().empty() ||
451 anchorLayout.getEffectiveSgDataAsInt().empty());
458 xegpu::DistributeLayoutAttr consumerLayout =
nullptr) {
460 if (consumerLayout) {
461 auto sgLayout = consumerLayout.getEffectiveSgLayoutAsInt();
462 if (!sgLayout.empty())
463 return llvm::product_of(sgLayout);
469 auto knownBlockSize = gpuFunc.getKnownBlockSize();
470 if (!knownBlockSize.has_value())
472 const int flatBlockSize = llvm::product_of(knownBlockSize.value());
473 return flatBlockSize / sgSize;
476void LayoutInfoPropagation::visitPrefetchNdOp(
477 xegpu::PrefetchNdOp prefetch, ArrayRef<LayoutInfoLattice *> operands,
478 ArrayRef<const LayoutInfoLattice *> results) {
480 LayoutInfo prefetchLayout;
484 xegpu::DistributeLayoutAttr anchorLayout = prefetch.getLayoutAttr();
485 if (hasParamsOfLayoutKind(anchorLayout)) {
486 prefetchLayout = makeLayoutInfo(anchorLayout);
487 if (layoutKind == xegpu::LayoutKind::InstData) {
488 const auto *uArchInstruction =
489 dyn_cast<xegpu::uArch::Subgroup2DBlockPrefetchInstruction>(
490 uArch->getInstruction(
491 xegpu::uArch::InstructionKind::Subgroup2DBlockPrefetch));
492 if (!uArchInstruction)
495 anchorLayout, prefetch.getTensorDescType().getElementType(),
496 uArchInstruction, uArch->getSubgroupSize());
498 prefetch.emitWarning(
499 "Failed to identify lane layouts for the specified inst_data.");
502 prefetch.setLayoutAttr(*completed);
503 prefetchLayout = makeLayoutInfo(*completed);
506 auto tdescTy = prefetch.getTensorDescType();
507 auto numSgOrErr =
getNumSg(prefetch, uArch->getSubgroupSize());
508 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
509 prefetch.emitWarning(
510 "Unable to determine the number of subgroups for the operation.");
515 layoutKind, tdescTy, numSgOrErr.value_or(0), uArch);
517 prefetch.emitWarning(
518 "Failed to determine required layout for prefetch_nd.");
521 prefetchLayout = makeLayoutInfo(layoutAttr);
522 prefetch.setLayoutAttr(layoutAttr);
525 propagateIfChanged(operands[0], operands[0]->meet(prefetchLayout));
528void LayoutInfoPropagation::visitVectorMultiReductionOp(
529 vector::MultiDimReductionOp reduction,
530 ArrayRef<LayoutInfoLattice *> operands,
531 ArrayRef<const LayoutInfoLattice *> results) {
532 Type resultTy = reduction.getDestType();
534 LayoutInfo resLayoutInfo = results[0]->getValue();
536 xegpu::DistributeLayoutAttr consumerLayoutAttr;
538 if (!resLayoutInfo.isAssigned())
541 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
544 VectorType sourceTy = reduction.getSourceVectorType();
545 SmallVector<int64_t> reductionDims(reduction.getReductionDims());
553 getNumSg(reduction, uArch->getSubgroupSize(), consumerLayoutAttr);
554 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
555 reduction.emitWarning(
556 "Unable to determine the number of subgroups for the operation.");
566 layoutKind, sourceTy, consumerLayoutAttr, reductionDims,
567 numSgOrErr.value_or(0), uArch);
573 requiredResLayoutAttr, reductionDims);
575 propagateIfChanged(operands[0],
576 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
578 propagateIfChanged(operands[1],
579 operands[1]->meet(makeLayoutInfo(requiredResLayoutAttr)));
582void LayoutInfoPropagation::visitVectorReductionOp(
583 vector::ReductionOp reduction, ArrayRef<LayoutInfoLattice *> operands,
584 ArrayRef<const LayoutInfoLattice *> results) {
586 VectorType sourceTy = reduction.getSourceVectorType();
592 auto requiredResLayoutAttr =
597 propagateIfChanged(operands[0],
598 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
599 if (reduction.getAcc())
601 operands[1], operands[1]->meet(makeLayoutInfo(requiredResLayoutAttr)));
604void LayoutInfoPropagation::visitVectorBroadCastOp(
605 vector::BroadcastOp
broadcast, ArrayRef<LayoutInfoLattice *> operands,
606 ArrayRef<const LayoutInfoLattice *> results) {
608 LayoutInfo resLayoutInfo = results[0]->getValue();
609 if (!resLayoutInfo.isAssigned())
613 VectorType resultTy =
broadcast.getResultVectorType();
614 VectorType sourceTy = dyn_cast<VectorType>(
broadcast.getSourceType());
619 auto srcShape = sourceTy.getShape();
620 auto resShape = resultTy.getShape();
622 auto resultLayoutAttr =
623 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
625 xegpu::DistributeLayoutAttr srcLayoutAttr =
628 propagateIfChanged(operands[0],
629 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
632void LayoutInfoPropagation::visitShapeCastOp(
633 vector::ShapeCastOp shapeCast, ArrayRef<LayoutInfoLattice *> operands,
634 ArrayRef<const LayoutInfoLattice *> results) {
636 LayoutInfo resLayoutInfo = results[0]->getValue();
637 if (!resLayoutInfo.isAssigned())
639 ArrayRef<int64_t> resShape = shapeCast.getResultVectorType().getShape();
640 ArrayRef<int64_t> srcShape = shapeCast.getSourceVectorType().getShape();
641 auto resultLayoutAttr =
642 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
644 xegpu::DistributeLayoutAttr srcLayoutAttr =
648 if (!srcLayoutAttr) {
649 shapeCast.emitWarning(
"Failed to infer source layout for shape_cast; "
650 "unsupported shape-cast pattern.");
654 propagateIfChanged(operands[0],
655 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
659void LayoutInfoPropagation::visitDpasOp(
660 xegpu::DpasOp dpas, ArrayRef<LayoutInfoLattice *> operands,
661 ArrayRef<const LayoutInfoLattice *> results) {
662 LayoutInfo dpasALayout;
663 LayoutInfo dpasBLayout;
664 LayoutInfo dpasCDLayout;
669 VectorType aTy = dpas.getLhsType();
670 VectorType bTy = dpas.getRhsType();
671 VectorType cdTy = dpas.getResultType();
673 xegpu::DistributeLayoutAttr anchorLayoutCD = dpas.getLayoutCdAttr();
674 if (hasParamsOfLayoutKind(anchorLayoutCD)) {
675 xegpu::DistributeLayoutAttr anchorLayoutA = dpas.getLayoutAAttr();
676 xegpu::DistributeLayoutAttr anchorLayoutB = dpas.getLayoutBAttr();
677 assert(hasParamsOfLayoutKind(anchorLayoutA) &&
678 "Expected anchor layout for DPAS A operand.");
679 assert(hasParamsOfLayoutKind(anchorLayoutB) &&
680 "Expected anchor layout for DPAS B operand.");
681 dpasALayout = makeLayoutInfo(anchorLayoutA);
682 dpasBLayout = makeLayoutInfo(anchorLayoutB);
683 dpasCDLayout = makeLayoutInfo(anchorLayoutCD);
684 if (layoutKind == xegpu::LayoutKind::InstData) {
686 anchorLayoutA, anchorLayoutB, anchorLayoutCD, aTy, bTy, cdTy, uArch);
689 "Failed to identify lane layouts for the specified inst_data.");
692 auto [completedA, completedB, completedCD] = *completed;
693 dpas.setLayoutAAttr(completedA);
694 dpas.setLayoutBAttr(completedB);
695 dpas.setLayoutCdAttr(completedCD);
696 dpasALayout = makeLayoutInfo(completedA);
697 dpasBLayout = makeLayoutInfo(completedB);
698 dpasCDLayout = makeLayoutInfo(completedCD);
702 xegpu::DistributeLayoutAttr consumerLayoutAttr =
nullptr;
703 xegpu::DistributeLayoutAttr requiredCDLayoutAttr, requiredALayout,
706 LayoutInfo consumerLayout = results[0]->getValue();
707 if (!consumerLayout.isAssigned())
710 dyn_cast<xegpu::DistributeLayoutAttr>(consumerLayout.get());
713 getNumSg(dpas, uArch->getSubgroupSize(), consumerLayoutAttr);
714 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
716 "Unable to determine the number of subgroups for the operation.");
722 numSgOrErr.value_or(0), uArch);
723 if (!layouts.has_value()) {
725 "Failed to determine required layouts for DPAS operands.");
729 std::tie(requiredALayout, requiredBLayout, requiredCDLayoutAttr) = *layouts;
731 dpas.setLayoutAAttr(requiredALayout);
732 dpas.setLayoutBAttr(requiredBLayout);
733 dpas.setLayoutCdAttr(requiredCDLayoutAttr);
734 dpasALayout = makeLayoutInfo(requiredALayout);
735 dpasBLayout = makeLayoutInfo(requiredBLayout);
736 dpasCDLayout = makeLayoutInfo(requiredCDLayoutAttr);
738 propagateIfChanged(operands[0], operands[0]->meet(dpasALayout));
739 propagateIfChanged(operands[1], operands[1]->meet(dpasBLayout));
740 if (operands.size() > 2)
741 propagateIfChanged(operands[2], operands[2]->meet(dpasCDLayout));
747void LayoutInfoPropagation::visitDpasMxOp(
748 xegpu::DpasMxOp dpasMx, ArrayRef<LayoutInfoLattice *> operands,
749 ArrayRef<const LayoutInfoLattice *> results) {
752 LayoutInfo dpasMxALayout, dpasMxBLayout, dpasMxCDLayout;
753 LayoutInfo dpasMxAScaleLayout, dpasMxBScaleLayout;
756 xegpu::DistributeLayoutAttr anchorLayoutA = dpasMx.getLayoutAAttr();
757 xegpu::DistributeLayoutAttr anchorLayoutB = dpasMx.getLayoutBAttr();
758 xegpu::DistributeLayoutAttr anchorLayoutCD = dpasMx.getLayoutCdAttr();
764 VectorType aTy = dpasMx.getAType();
765 VectorType bTy = dpasMx.getBType();
766 VectorType cdTy = dpasMx.getResultType();
771 Value scaleA = dpasMx.getScaleA();
772 Value scaleB = dpasMx.getScaleB();
774 aScaleTy = dyn_cast<VectorType>(scaleA.
getType());
776 bScaleTy = dyn_cast<VectorType>(scaleB.
getType());
779 if (anchorLayoutA && anchorLayoutB && anchorLayoutCD &&
780 hasParamsOfLayoutKind(anchorLayoutA) &&
781 hasParamsOfLayoutKind(anchorLayoutB) &&
782 hasParamsOfLayoutKind(anchorLayoutCD)) {
783 dpasMxALayout = makeLayoutInfo(anchorLayoutA);
784 dpasMxBLayout = makeLayoutInfo(anchorLayoutB);
785 dpasMxCDLayout = makeLayoutInfo(anchorLayoutCD);
788 xegpu::DistributeLayoutAttr anchorLayoutAScale =
789 dpasMx.getLayoutAScaleAttr();
790 xegpu::DistributeLayoutAttr anchorLayoutBScale =
791 dpasMx.getLayoutBScaleAttr();
792 if (anchorLayoutAScale)
793 dpasMxAScaleLayout = makeLayoutInfo(anchorLayoutAScale);
794 if (anchorLayoutBScale)
795 dpasMxBScaleLayout = makeLayoutInfo(anchorLayoutBScale);
797 if (layoutKind == xegpu::LayoutKind::InstData) {
799 anchorLayoutA, anchorLayoutB, anchorLayoutCD, aTy, bTy, cdTy,
800 aScaleTy, bScaleTy, uArch);
803 "Failed to identify lane layouts for the specified inst_data.");
806 auto [completedA, completedB, completedCD, completedAScale,
807 completedBScale] = *completed;
808 dpasMx.setLayoutAAttr(completedA);
809 dpasMx.setLayoutBAttr(completedB);
810 dpasMx.setLayoutCdAttr(completedCD);
811 dpasMxALayout = makeLayoutInfo(completedA);
812 dpasMxBLayout = makeLayoutInfo(completedB);
813 dpasMxCDLayout = makeLayoutInfo(completedCD);
814 if (completedAScale) {
815 dpasMx.setLayoutAScaleAttr(completedAScale);
816 dpasMxAScaleLayout = makeLayoutInfo(completedAScale);
818 if (completedBScale) {
819 dpasMx.setLayoutBScaleAttr(completedBScale);
820 dpasMxBScaleLayout = makeLayoutInfo(completedBScale);
824 xegpu::DistributeLayoutAttr consumerLayoutAttr =
nullptr;
825 xegpu::DistributeLayoutAttr requiredCDLayoutAttr, requiredALayout,
826 requiredBLayout, requiredAScaleLayout, requiredBScaleLayout;
828 LayoutInfo consumerLayout = results[0]->getValue();
829 if (!consumerLayout.isAssigned())
832 dyn_cast<xegpu::DistributeLayoutAttr>(consumerLayout.get());
835 getNumSg(dpasMx, uArch->getSubgroupSize(), consumerLayoutAttr);
836 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
838 "Unable to determine the number of subgroups for the operation.");
843 layoutKind, aTy, bTy, cdTy, aScaleTy, bScaleTy, consumerLayoutAttr,
844 numSgOrErr.value_or(0), uArch);
845 if (!layouts.has_value()) {
847 "Failed to determine required layouts for DPAS_MX operands.");
851 std::tie(requiredALayout, requiredBLayout, requiredCDLayoutAttr,
852 requiredAScaleLayout, requiredBScaleLayout) = *layouts;
854 dpasMx.setLayoutAAttr(requiredALayout);
855 dpasMx.setLayoutBAttr(requiredBLayout);
856 dpasMx.setLayoutCdAttr(requiredCDLayoutAttr);
857 if (requiredAScaleLayout)
858 dpasMx.setLayoutAScaleAttr(requiredAScaleLayout);
859 if (requiredBScaleLayout)
860 dpasMx.setLayoutBScaleAttr(requiredBScaleLayout);
862 dpasMxALayout = makeLayoutInfo(requiredALayout);
863 dpasMxBLayout = makeLayoutInfo(requiredBLayout);
864 dpasMxCDLayout = makeLayoutInfo(requiredCDLayoutAttr);
865 if (requiredAScaleLayout)
866 dpasMxAScaleLayout = makeLayoutInfo(requiredAScaleLayout);
867 if (requiredBScaleLayout)
868 dpasMxBScaleLayout = makeLayoutInfo(requiredBScaleLayout);
875 propagateIfChanged(operands[0], operands[0]->meet(dpasMxALayout));
876 propagateIfChanged(operands[1], operands[1]->meet(dpasMxBLayout));
878 if (dpasMx.getAcc()) {
879 propagateIfChanged(operands[idx], operands[idx]->meet(dpasMxCDLayout));
882 if (dpasMx.getScaleA()) {
883 if (dpasMxAScaleLayout.isAssigned())
884 propagateIfChanged(operands[idx],
885 operands[idx]->meet(dpasMxAScaleLayout));
888 if (dpasMx.getScaleB()) {
889 if (dpasMxBScaleLayout.isAssigned())
890 propagateIfChanged(operands[idx],
891 operands[idx]->meet(dpasMxBScaleLayout));
897void LayoutInfoPropagation::visitStoreNdOp(
898 xegpu::StoreNdOp store, ArrayRef<LayoutInfoLattice *> operands,
899 ArrayRef<const LayoutInfoLattice *> results) {
900 LayoutInfo storeLayout;
904 xegpu::DistributeLayoutAttr anchorLayout = store.getLayoutAttr();
905 if (hasParamsOfLayoutKind(anchorLayout)) {
906 storeLayout = makeLayoutInfo(anchorLayout);
907 if (layoutKind == xegpu::LayoutKind::InstData) {
909 const auto *uArchInstruction =
910 dyn_cast<xegpu::uArch::Subgroup2DBlockStoreInstruction>(
911 uArch->getInstruction(
912 xegpu::uArch::InstructionKind::Subgroup2DBlockStore));
913 if (!uArchInstruction)
916 anchorLayout, store.getValueType().getElementType(), uArchInstruction,
917 uArch->getSubgroupSize());
920 "Failed to identify lane layouts for the specified inst_data.");
923 store.setLayoutAttr(*completed);
924 storeLayout = makeLayoutInfo(*completed);
927 auto numSgOrErr =
getNumSg(store, uArch->getSubgroupSize());
928 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
930 "Unable to determine the number of subgroups for the operation.");
935 layoutKind, store.getValueType(), numSgOrErr.value_or(0), uArch);
937 store.emitWarning(
"Failed to determine required layout for store_nd.");
940 storeLayout = makeLayoutInfo(layoutAttr);
941 store.setLayoutAttr(layoutAttr);
945 for (LayoutInfoLattice *operand : operands)
946 propagateIfChanged(operand, operand->meet(storeLayout));
951void LayoutInfoPropagation::visitLoadNdOp(
952 xegpu::LoadNdOp
load, ArrayRef<LayoutInfoLattice *> operands,
953 ArrayRef<const LayoutInfoLattice *> results) {
954 LayoutInfo loadLayout;
959 LayoutInfo valueLayout = results[0]->getValue();
960 if (!valueLayout.isAssigned())
962 auto consumerLayoutAttr =
963 dyn_cast<xegpu::DistributeLayoutAttr>(valueLayout.get());
964 xegpu::DistributeLayoutAttr anchorLayout =
load.getLayoutAttr();
965 if (hasParamsOfLayoutKind(anchorLayout)) {
966 loadLayout = makeLayoutInfo(anchorLayout);
967 if (layoutKind == xegpu::LayoutKind::InstData &&
968 !consumerLayoutAttr.getEffectiveLaneLayoutAsInt().empty()) {
969 const auto *uArchInstruction =
970 dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
971 uArch->getInstruction(
972 xegpu::uArch::InstructionKind::Subgroup2DBlockLoad));
973 if (!uArchInstruction)
976 anchorLayout, consumerLayoutAttr,
load.getType().getElementType(),
977 uArchInstruction, uArch->getSubgroupSize());
980 "Failed to identify lane layouts for the specified inst_data.");
983 load.setLayoutAttr(*completed);
984 loadLayout = makeLayoutInfo(*completed);
988 getNumSg(
load, uArch->getSubgroupSize(), consumerLayoutAttr);
989 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
991 "Unable to determine the number of subgroups for the operation.");
995 layoutKind,
load.getType(), consumerLayoutAttr, numSgOrErr.value_or(0),
998 load.emitWarning(
"Failed to determine required layout for load_nd.");
1001 loadLayout = makeLayoutInfo(layoutAttr);
1002 load.setLayoutAttr(layoutAttr);
1005 propagateIfChanged(operands[0], operands[0]->meet(loadLayout));
1010void LayoutInfoPropagation::visitConvertLayoutOp(
1011 xegpu::ConvertLayoutOp convert, ArrayRef<LayoutInfoLattice *> operands,
1012 ArrayRef<const LayoutInfoLattice *> results) {
1014 LayoutInfo resultLayout = results[0]->getValue();
1017 auto targetLayoutAttr =
1018 dyn_cast<xegpu::LayoutAttr>(convert.getTargetLayoutAttr());
1020 auto inputLayoutAttr =
1021 dyn_cast_if_present<xegpu::LayoutAttr>(convert.getInputLayoutAttr());
1027 auto resultLayoutAttr = resultLayout.isAssigned()
1028 ? dyn_cast<xegpu::LayoutAttr>(resultLayout.get())
1030 if (resultLayoutAttr && targetLayoutAttr) {
1031 if (layoutKind == xegpu::LayoutKind::InstData &&
1032 !targetLayoutAttr.getLaneLayout()) {
1033 targetLayoutAttr = xegpu::LayoutAttr::get(
1034 convert.getContext(), targetLayoutAttr.getSgLayout(),
1035 targetLayoutAttr.getSgData(), targetLayoutAttr.getInstData(),
1036 resultLayoutAttr.getLaneLayout(), resultLayoutAttr.getLaneData(),
1037 resultLayoutAttr.getOrder());
1038 convert.setTargetLayoutAttr(targetLayoutAttr);
1045 if (inputLayoutAttr && targetLayoutAttr) {
1046 if (layoutKind == xegpu::LayoutKind::InstData &&
1047 !inputLayoutAttr.getLaneLayout()) {
1048 auto merged = xegpu::LayoutAttr::get(
1049 convert.getContext(), inputLayoutAttr.getSgLayout(),
1050 inputLayoutAttr.getSgData(), inputLayoutAttr.getInstData(),
1051 targetLayoutAttr.getLaneLayout(), targetLayoutAttr.getLaneData(),
1052 targetLayoutAttr.getOrder());
1053 convert.setInputLayoutAttr(merged);
1057 xegpu::DistributeLayoutAttr anchorLayout = convert.getEffectiveInputLayout();
1058 LayoutInfo convertLayout = makeLayoutInfo(anchorLayout);
1060 propagateIfChanged(operands[0], operands[0]->meet(convertLayout));
1065void LayoutInfoPropagation::visitTransposeOp(
1066 vector::TransposeOp transpose, ArrayRef<LayoutInfoLattice *> operands,
1067 ArrayRef<const LayoutInfoLattice *> results) {
1069 LayoutInfo resultLayout = results[0]->getValue();
1070 if (!resultLayout.isAssigned())
1073 auto consumerLayoutAttr =
1074 dyn_cast<xegpu::DistributeLayoutAttr>(resultLayout.get());
1076 consumerLayoutAttr, transpose.getPermutation());
1079 propagateIfChanged(operands[0],
1080 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1085void LayoutInfoPropagation::visitVectorBitcastOp(
1086 vector::BitCastOp bitcast, ArrayRef<LayoutInfoLattice *> operands,
1087 ArrayRef<const LayoutInfoLattice *> results) {
1089 LayoutInfo resLayoutInfo = results[0]->getValue();
1090 if (!resLayoutInfo.isAssigned())
1093 auto srcVecType = bitcast.getSourceVectorType();
1094 auto resVecType = bitcast.getResultVectorType();
1096 auto consumerLayoutAttr =
1097 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1103 layoutKind, srcVecType, resVecType, consumerLayoutAttr, uArch);
1107 int inElemTyBitWidth = srcVecType.getElementType().getIntOrFloatBitWidth();
1108 int outElemTyBitWidth = resVecType.getElementType().getIntOrFloatBitWidth();
1112 requiredResLayoutAttr, outElemTyBitWidth, inElemTyBitWidth);
1114 propagateIfChanged(operands[0],
1115 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1121void LayoutInfoPropagation::visitVectorInterleaveOp(
1122 vector::InterleaveOp interleave, ArrayRef<LayoutInfoLattice *> operands,
1123 ArrayRef<const LayoutInfoLattice *> results) {
1125 LayoutInfo resLayoutInfo = results[0]->getValue();
1126 if (!resLayoutInfo.isAssigned())
1129 auto srcVecType = interleave.getSourceVectorType();
1130 auto resVecType = interleave.getResultVectorType();
1132 auto consumerLayoutAttr =
1133 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1141 layoutKind, srcVecType, resVecType, consumerLayoutAttr, uArch);
1146 auto srcLayoutAttr =
1150 propagateIfChanged(operands[0],
1151 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1152 propagateIfChanged(operands[1],
1153 operands[1]->meet(makeLayoutInfo(srcLayoutAttr)));
1159void LayoutInfoPropagation::visitVectorDeinterleaveOp(
1160 vector::DeinterleaveOp deinterleave, ArrayRef<LayoutInfoLattice *> operands,
1161 ArrayRef<const LayoutInfoLattice *> results) {
1164 LayoutInfo resLayoutInfo = results[0]->getValue();
1165 if (!resLayoutInfo.isAssigned())
1168 auto consumerLayoutAttr =
1169 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1175 propagateIfChanged(operands[0],
1176 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1179void LayoutInfoPropagation::visitInsertStridedSliceOp(
1180 vector::InsertStridedSliceOp insertStridedSlice,
1181 ArrayRef<LayoutInfoLattice *> operands,
1182 ArrayRef<const LayoutInfoLattice *> results) {
1184 LayoutInfo resLayoutInfo = results[0]->getValue();
1185 if (!resLayoutInfo.isAssigned())
1188 auto srcVecType = insertStridedSlice.getSourceVectorType();
1189 auto resVecType = insertStridedSlice.getDestVectorType();
1191 auto consumerLayoutAttr =
1192 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1199 layoutKind, srcVecType, resVecType, consumerLayoutAttr, uArch);
1201 requiredResLayoutAttr);
1204 requiredResLayoutAttr, resVecType.getShape(), srcVecType.getShape());
1205 propagateIfChanged(operands[0],
1206 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1207 propagateIfChanged(operands[1],
1208 operands[1]->meet(makeLayoutInfo(requiredResLayoutAttr)));
1213void LayoutInfoPropagation::visitLoadGatherOp(
1214 xegpu::LoadGatherOp
load, ArrayRef<LayoutInfoLattice *> operands,
1215 ArrayRef<const LayoutInfoLattice *> results) {
1216 xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
1217 xegpu::DistributeLayoutAttr anchorLayoutAttr =
load.getLayoutAttr();
1221 VectorType resVecTy =
load.getValueType();
1222 int chunkSize =
load.getChunkSize().value_or(1);
1224 LayoutInfo resLayoutInfo = results[0]->getValue();
1225 if (!resLayoutInfo.isAssigned())
1227 auto consumerLayoutAttr =
1228 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1230 if (hasParamsOfLayoutKind(anchorLayoutAttr)) {
1231 requiredAnchorLayoutAttr = anchorLayoutAttr;
1232 if (layoutKind == xegpu::LayoutKind::InstData &&
1233 !consumerLayoutAttr.getEffectiveLaneLayoutAsInt().empty()) {
1234 const auto uArchInstruction =
1235 dyn_cast<xegpu::uArch::LoadGatherInstruction>(
1236 uArch->getInstruction(xegpu::uArch::InstructionKind::LoadGather));
1237 if (!uArchInstruction)
1240 anchorLayoutAttr, consumerLayoutAttr, resVecTy.getElementType(),
1241 uArchInstruction, uArch->getSubgroupSize());
1244 "Failed to identify lane layouts for the specified inst_data.");
1247 requiredAnchorLayoutAttr = *completed;
1248 load.setLayoutAttr(requiredAnchorLayoutAttr);
1252 load.emitWarning(
"Not propagating, non-vector payload supplied.");
1256 layoutKind, resVecTy, chunkSize, consumerLayoutAttr, uArch);
1257 load.setLayoutAttr(requiredAnchorLayoutAttr);
1260 assert((chunkSize <= 1) || (layoutKind != xegpu::LayoutKind::Subgroup));
1262 requiredAnchorLayoutAttr, chunkSize);
1263 LayoutInfo maskLayoutInfo = makeLayoutInfo(maskLayoutAttr);
1264 auto loadLayoutInfo = makeLayoutInfo(requiredAnchorLayoutAttr);
1267 if (isa<xegpu::TensorDescType>(
load.getSourceType()))
1268 propagateIfChanged(operands[0], operands[0]->meet(loadLayoutInfo));
1270 propagateIfChanged(operands[1], operands[1]->meet(maskLayoutInfo));
1271 propagateIfChanged(operands[2], operands[2]->meet(maskLayoutInfo));
1276void LayoutInfoPropagation::visitStoreScatterOp(
1277 xegpu::StoreScatterOp storeScatter, ArrayRef<LayoutInfoLattice *> operands,
1278 ArrayRef<const LayoutInfoLattice *> results) {
1280 xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
1281 xegpu::DistributeLayoutAttr anchorLayoutAttr = storeScatter.getLayoutAttr();
1286 VectorType srcVecTy = storeScatter.getValueType();
1287 int chunkSize = storeScatter.getChunkSize().value_or(1);
1289 if (hasParamsOfLayoutKind(anchorLayoutAttr)) {
1290 requiredAnchorLayoutAttr = anchorLayoutAttr;
1291 if (layoutKind == xegpu::LayoutKind::InstData) {
1292 const auto uArchInstruction =
1293 dyn_cast<xegpu::uArch::StoreScatterInstruction>(uArch->getInstruction(
1294 xegpu::uArch::InstructionKind::StoreScatter));
1295 if (!uArchInstruction)
1298 anchorLayoutAttr, srcVecTy.getElementType(), uArchInstruction,
1299 uArch->getSubgroupSize());
1301 storeScatter.emitWarning(
1302 "Failed to identify lane layouts for the specified inst_data.");
1305 requiredAnchorLayoutAttr = *completed;
1306 storeScatter.setLayoutAttr(requiredAnchorLayoutAttr);
1310 storeScatter.emitWarning(
"Not propagating, non-vector payload supplied.");
1313 auto numSgOrErr =
getNumSg(storeScatter, uArch->getSubgroupSize());
1314 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
1315 storeScatter.emitWarning(
1316 "Unable to determine the number of subgroups for the operation.");
1320 layoutKind, srcVecTy, chunkSize, numSgOrErr.value_or(0), uArch);
1321 if (!requiredAnchorLayoutAttr) {
1322 storeScatter.emitWarning(
1323 "Failed to determine required layout for store scatter.");
1326 storeScatter.setLayoutAttr(requiredAnchorLayoutAttr);
1329 LayoutInfo srcLayoutInfo = makeLayoutInfo(requiredAnchorLayoutAttr);
1330 assert((chunkSize <= 1) || (layoutKind != xegpu::LayoutKind::Subgroup));
1332 requiredAnchorLayoutAttr, chunkSize);
1333 LayoutInfo maskLayoutInfo = makeLayoutInfo(maskLayoutAttr);
1336 propagateIfChanged(operands[0], operands[0]->meet(srcLayoutInfo));
1338 if (isa<xegpu::TensorDescType>(storeScatter.getDestType()))
1339 propagateIfChanged(operands[1], operands[1]->meet(srcLayoutInfo));
1341 propagateIfChanged(operands[2], operands[2]->meet(maskLayoutInfo));
1342 propagateIfChanged(operands[3], operands[3]->meet(maskLayoutInfo));
1345void LayoutInfoPropagation::visitLoadMatrixOp(
1346 xegpu::LoadMatrixOp loadMatrixOp, ArrayRef<LayoutInfoLattice *> operands,
1347 ArrayRef<const LayoutInfoLattice *> results) {
1349 LayoutInfo resLayoutInfo = results[0]->getValue();
1350 if (!resLayoutInfo.isAssigned())
1353 auto consumerLayoutAttr =
1354 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1356 xegpu::DistributeLayoutAttr anchorLayout = loadMatrixOp.getLayoutAttr();
1360 if (!hasParamsOfLayoutKind(anchorLayout)) {
1361 VectorType resVecTy =
1362 llvm::cast<VectorType>(loadMatrixOp.getRes().getType());
1370 layoutKind, resVecTy, chunkSize, consumerLayoutAttr, uArch);
1371 loadMatrixOp.setLayoutAttr(requiredAnchorLayoutAttr);
1375void LayoutInfoPropagation::visitStoreMatrixOp(
1376 xegpu::StoreMatrixOp storeMatrix, ArrayRef<LayoutInfoLattice *> operands,
1377 ArrayRef<const LayoutInfoLattice *> results) {
1378 xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
1379 xegpu::DistributeLayoutAttr anchorLayoutAttr = storeMatrix.getLayoutAttr();
1381 VectorType srcVecTy = llvm::cast<VectorType>(storeMatrix.getData().getType());
1386 if (hasParamsOfLayoutKind(anchorLayoutAttr)) {
1387 requiredAnchorLayoutAttr = anchorLayoutAttr;
1388 if (layoutKind == xegpu::LayoutKind::InstData) {
1389 const auto uArchInstruction =
1390 dyn_cast<xegpu::uArch::StoreScatterInstruction>(uArch->getInstruction(
1391 xegpu::uArch::InstructionKind::StoreScatter));
1392 if (!uArchInstruction)
1395 anchorLayoutAttr, srcVecTy.getElementType(), uArchInstruction,
1396 uArch->getSubgroupSize());
1398 storeMatrix.emitWarning(
1399 "Failed to identify lane layouts for the specified inst_data.");
1402 requiredAnchorLayoutAttr = *completed;
1403 storeMatrix.setLayoutAttr(requiredAnchorLayoutAttr);
1408 auto numSgOrErr =
getNumSg(storeMatrix, uArch->getSubgroupSize());
1409 if (layoutKind == xegpu::LayoutKind::Subgroup &&
failed(numSgOrErr)) {
1410 storeMatrix.emitWarning(
1411 "Unable to determine the number of subgroups for the operation.");
1415 layoutKind, srcVecTy, chunkSize, numSgOrErr.value_or(0), uArch);
1416 if (!requiredAnchorLayoutAttr) {
1417 storeMatrix.emitWarning(
1418 "Failed to determine required layout for store matrix.");
1421 storeMatrix.setLayoutAttr(requiredAnchorLayoutAttr);
1423 layout = makeLayoutInfo(requiredAnchorLayoutAttr);
1424 propagateIfChanged(operands[0], operands[0]->meet(layout));
1433class RunLayoutInfoPropagation {
1438 unsigned indexBitWidth)
1440 SymbolTableCollection symbolTable;
1442 solver.
load<LayoutInfoPropagation>(symbolTable, layoutKind, indexBitWidth);
1446 LayoutInfo getLayoutInfo(Value val);
1448 void printAnalysisResult(llvm::raw_ostream &os);
1451 DataFlowSolver solver;
1456LayoutInfo RunLayoutInfoPropagation::getLayoutInfo(Value val) {
1457 auto *state = solver.
lookupState<LayoutInfoLattice>(val);
1460 return state->getValue();
1464void RunLayoutInfoPropagation::printAnalysisResult(llvm::raw_ostream &os) {
1465 auto printFunctionResult = [&](FunctionOpInterface funcOp) {
1466 os <<
"function: " << funcOp.getName() <<
":\n";
1468 for (BlockArgument arg : funcOp.getArguments()) {
1469 LayoutInfo layout = getLayoutInfo(arg);
1470 os <<
"argument: " << arg <<
"\n";
1476 funcOp.walk([&](Operation *op) {
1482 if (isa<BranchOpInterface>(op) || isa<RegionBranchOpInterface>(op))
1488 for (
auto [i, r] : llvm::enumerate(op->
getResults())) {
1489 LayoutInfo layout = getLayoutInfo(r);
1490 os <<
"layout for result #" << i <<
": ";
1497 SmallVector<FunctionOpInterface> funcOps;
1498 if (
auto modOp = dyn_cast<ModuleOp>(
target)) {
1499 for (
auto funcOp : modOp.getOps<FunctionOpInterface>())
1500 funcOps.push_back(funcOp);
1503 for (
auto gpuModOp : modOp.getOps<gpu::GPUModuleOp>()) {
1504 for (
auto gpuFuncOp : gpuModOp.getOps<FunctionOpInterface>())
1505 funcOps.push_back(gpuFuncOp);
1509 for (FunctionOpInterface funcOp : funcOps)
1510 printFunctionResult(funcOp);
1522static xegpu::CreateNdDescOp getDefiningCreateNdDescOp(Value tdescValue) {
1524 auto definingOp = tdescValue.
getDefiningOp<xegpu::CreateNdDescOp>();
1529 if (
auto arg = dyn_cast<BlockArgument>(tdescValue)) {
1530 auto *parentOp = arg.getOwner()->getParentOp();
1531 if (
auto loop = dyn_cast<LoopLikeOpInterface>(parentOp)) {
1532 OpOperand *tiedInit = loop.getTiedLoopInit(arg);
1534 return getDefiningCreateNdDescOp(tiedInit->
get());
1541struct ResolveLayoutConflicts {
1542 ResolveLayoutConflicts(Operation *parentOp)
1543 : parentOp(parentOp), builder(parentOp->
getContext()) {}
1544 LogicalResult run();
1547 Operation *parentOp;
1549 LogicalResult resolveTensorDescConsumer(OpOperand &operand);
1550 LogicalResult resolveVectorConsumer(OpOperand &operand);
1551 LogicalResult assignResultLayout(OpResult &
result);
1556LogicalResult ResolveLayoutConflicts::run() {
1559 auto r = parentOp->
walk([&](Operation *op) -> WalkResult {
1564 if (
result.getType().isIntOrFloat() &&
1565 (isa<vector::MultiDimReductionOp>(op) ||
1566 isa<vector::ReductionOp>(op))) {
1567 auto res = assignResultLayout(
result);
1569 DBGS() <<
"Failed to assign layout for scalar consumer of reduction "
1577 if (isa<VectorType>(
result.getType()) &&
result.use_empty() &&
1578 isa<RegionBranchOpInterface>(op)) {
1579 auto res = assignResultLayout(
result);
1581 DBGS() <<
"Failed to assign layout for vector consumer of region op "
1589 Type operandType = operand.get().getType();
1590 if (isa<xegpu::AnchorLayoutInterface>(op) &&
1591 isa<xegpu::TensorDescType>(operandType)) {
1592 auto res = resolveTensorDescConsumer(operand);
1594 DBGS() <<
"Failed to resolve tensor descriptor consumer: " << *op
1600 if (isa<VectorType>(operandType)) {
1601 auto res = resolveVectorConsumer(operand);
1603 DBGS() <<
"Failed to resolve vector consumer: " << *op <<
"\n";
1612 DBGS() <<
"IR after resolving layout conflicts:\n";
1616 return r.wasInterrupted() ? failure() :
success();
1619LogicalResult ResolveLayoutConflicts::assignResultLayout(OpResult &
result) {
1620 Operation *producerOp =
result.getDefiningOp();
1624 auto convertOp = xegpu::ConvertLayoutOp::create(
1627 result.replaceAllUsesExcept(convertOp.getResult(), convertOp);
1632ResolveLayoutConflicts::resolveVectorConsumer(OpOperand &operand) {
1633 Value vectorValue = operand.
get();
1634 Operation *consumerOp = operand.
getOwner();
1637 if (!producerLayout) {
1638 if (
auto vectorTy = dyn_cast<VectorType>(vectorValue.
getType());
1639 vectorTy && vectorTy.getRank() > 1)
1640 consumerOp->
emitWarning(
"Expected layout for non-1D vectors.");
1648 if (isa<RegionBranchOpInterface, RegionBranchTerminatorOpInterface>(
1653 if (!consumerLayout)
1655 "No consumer layout found for vector operand.");
1658 if (consumerLayout.isEqualTo(producerLayout))
1664 if (
auto consumerConvert = dyn_cast<xegpu::ConvertLayoutOp>(consumerOp)) {
1665 consumerConvert.setInputLayoutAttr(producerLayout);
1671 if (
auto producerConvert =
1673 producerConvert && vectorValue.
hasOneUse()) {
1676 producerConvert.setInputLayoutAttr(
1677 producerConvert.getEffectiveInputLayout());
1678 producerConvert.setTargetLayoutAttr(consumerLayout);
1690 isa<OpResult>(vectorValue) &&
1693 Operation *
clone = builder.
clone(*producerOp);
1698 operand.
set(cloneResult);
1704 auto convertOp = xegpu::ConvertLayoutOp::create(
1705 builder, consumerOp->
getLoc(), vectorValue.
getType(), vectorValue,
1706 producerLayout, consumerLayout);
1709 operand.
set(convertOp.getResult());
1714ResolveLayoutConflicts::resolveTensorDescConsumer(OpOperand &operand) {
1715 Operation *consumerOp = operand.
getOwner();
1716 Value tdescValue = operand.
get();
1717 auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(consumerOp);
1718 auto currTDescType = dyn_cast<xegpu::TensorDescType>(tdescValue.
getType());
1719 assert(anchorOp && currTDescType &&
1720 "Expected anchor layout op and tensor descriptor consumer.");
1721 Attribute currLayout = currTDescType.getLayout();
1722 Attribute expectedLayout = anchorOp.getAnchorLayout();
1725 if (expectedLayout && currLayout && expectedLayout != currLayout) {
1727 auto conflictingCreateNdOp = getDefiningCreateNdDescOp(tdescValue);
1728 if (!conflictingCreateNdOp) {
1729 DBGS() <<
"Unable to find defining CreateNdDescOp for tensor descriptor: "
1730 << tdescValue <<
"\n";
1735 auto newTensorDescType = xegpu::TensorDescType::get(
1736 conflictingCreateNdOp.getContext(), currTDescType.getShape(),
1737 currTDescType.getElementType(), currTDescType.getEncoding(),
1739 xegpu::CreateNdDescOp newOp = xegpu::CreateNdDescOp::create(
1740 builder, consumerOp->
getLoc(), newTensorDescType,
1741 conflictingCreateNdOp->getOperands(),
1742 conflictingCreateNdOp->getAttrs());
1765 if (mlir::isa<mlir::RegionBranchOpInterface>(op))
1772 if (!isa<VectorType, xegpu::TensorDescType>(resultType))
1775 xegpu::DistributeLayoutAttr layout = getLayoutOfValue(
result);
1780 bool anyAssigned =
false;
1783 srcLayouts.push_back(srclayout);
1784 anyAssigned |= (srclayout !=
nullptr);
1791 if (!layout &&
result.getNumUses() > 0) {
1792 op->
emitWarning(
"op has users but no layout assigned for its result");
1796 if (
auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(resultType)) {
1797 auto typeWithLayout = xegpu::TensorDescType::get(
1798 tensorDescTy.getContext(), tensorDescTy.getShape(),
1799 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
1800 result.setType(typeWithLayout);
1812 mlir::FunctionOpInterface funcOp,
1818 if (!isa<FunctionType>(funcOp.getFunctionType()))
1823 Type argType = arg.getType();
1824 newArgTypes.push_back(argType);
1825 if (!isa<VectorType, xegpu::TensorDescType>(argType))
1827 xegpu::DistributeLayoutAttr layout = getLayoutOfValue(arg);
1829 LLVM_DEBUG(
DBGS() <<
"Expecting layout for function argument: " << arg
1830 <<
" but got none.\n");
1833 if (
auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(argType)) {
1834 auto newTdescTy = xegpu::TensorDescType::get(
1835 tensorDescTy.getContext(), tensorDescTy.getShape(),
1836 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
1837 arg.setType(newTdescTy);
1838 newArgTypes.back() = newTdescTy;
1843 funcOp.setType(FunctionType::get(funcOp.getContext(), newArgTypes,
1844 funcOp.getResultTypes()));
1849struct XeGPUPropagateLayoutPass final
1850 :
public xegpu::impl::XeGPUPropagateLayoutBase<XeGPUPropagateLayoutPass> {
1851 XeGPUPropagateLayoutPass() =
default;
1852 XeGPUPropagateLayoutPass(
const XeGPUPropagateLayoutPass &other) =
default;
1853 XeGPUPropagateLayoutPass(xegpu::XeGPUPropagateLayoutOptions
options)
1854 : XeGPUPropagateLayoutBase(std::move(
options)) {}
1855 void runOnOperation()
override;
1862 unsigned indexBitWidth,
bool printOnly) {
1863 RunLayoutInfoPropagation analysis(
target, layoutKind, indexBitWidth);
1866 auto &os = llvm::outs();
1867 analysis.printAnalysisResult(os);
1871 auto getLayoutFromPropagation =
1872 [&](
Value val) -> xegpu::DistributeLayoutAttr {
1873 LayoutInfo layout = analysis.getLayoutInfo(val);
1874 if (
auto opResult = dyn_cast<OpResult>(val)) {
1875 Operation *defOp = opResult.getDefiningOp();
1876 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(defOp)) {
1877 auto anchorLayout = anchorOp.getAnchorLayout();
1878 if (anchorLayout !=
nullptr)
1879 return anchorLayout;
1881 xegpu::DistributeLayoutAttr requiredResLayoutAttr =
1883 if (requiredResLayoutAttr !=
nullptr)
1884 return requiredResLayoutAttr;
1886 if (!layout.isAssigned())
1888 xegpu::DistributeLayoutAttr layoutAttr =
1889 cast<xegpu::DistributeLayoutAttr>(layout.get());
1890 if (layout.isSliceLayout())
1891 return cast<xegpu::SliceAttr>(layoutAttr);
1893 return cast<xegpu::LayoutAttr>(layoutAttr);
1901 .Case([&](mlir::RegionBranchTerminatorOpInterface branchTermOp) {
1903 branchTermOp, getLayoutFromPropagation);
1905 .Case([&](mlir::RegionBranchOpInterface branchOp) {
1907 getLayoutFromPropagation);
1909 .Case([&](mlir::FunctionOpInterface funcOp) {
1911 getLayoutFromPropagation);
1917 op.
emitError(
"Failed to update operation with the layout.");
1923 if (walkResult.wasInterrupted())
1930 ResolveLayoutConflicts resolver(
target);
1931 return resolver.run();
1934void XeGPUPropagateLayoutPass::runOnOperation() {
1939 if (this->layoutKind ==
"lane") {
1941 }
else if (this->layoutKind ==
"inst") {
1943 }
else if (this->layoutKind ==
"subgroup") {
1944 layoutKind = xegpu::LayoutKind::Subgroup;
1946 getOperation()->emitError(
"Unsupported layout kind option: " +
1948 signalPassFailure();
1953 this->indexBitWidth, this->printOnly))) {
1954 signalPassFailure();
1959 signalPassFailure();
std::string join(const Ts &...args)
Helper function to concatenate arguments into a std::string.
static llvm::ManagedStatic< PassManagerOptions > options
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
#define MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(CLASS_NAME)
function_ref< xegpu::DistributeLayoutAttr(Value)> GetLayoutFnTy
static LogicalResult updateOpWithForwardFill(mlir::OpBuilder &builder, mlir::Operation *op, GetLayoutFnTy getLayoutOfValue)
Update an operation with the layout of its results.
FailureOr< int64_t > getNumSg(Operation *op, const int sgSize, xegpu::DistributeLayoutAttr consumerLayout=nullptr)
static LogicalResult updateFunctionOpInterface(mlir::OpBuilder &builder, mlir::FunctionOpInterface funcOp, GetLayoutFnTy getLayoutOfValue)
Update the function arguments and results with the layouts.
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
OpListType & getOperations()
The general data-flow analysis solver.
LogicalResult initializeAndRun(Operation *top, llvm::function_ref< bool(DataFlowAnalysis &)> analysisFilter=nullptr)
Initialize analyses starting from the provided top-level operation and run the analysis until fixpoin...
const StateT * lookupState(AnchorT anchor) const
Lookup an analysis state for the given lattice anchor.
AnalysisT * load(Args &&...args)
Load an analysis into the solver. Return the analysis instance.
IRValueT get() const
Return the current value being used by this operand.
void set(IRValueT newValue)
Set the current value being used by this operand.
This class helps build Operations.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointAfterValue(Value val)
Sets the insertion point to the node after the specified value.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents an operand of an operation.
This is a value defined by a result of an operation.
Operation is the basic unit of execution within MLIR.
void replaceUsesOfWith(Value from, Value to)
Replace any uses of 'from' with 'to' within this operation.
InFlightDiagnostic emitWarning(const Twine &message={})
Emit a warning about this operation, reporting up to any diagnostic handlers that may be listening.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
MutableArrayRef< OpOperand > getOpOperands()
unsigned getNumOperands()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
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.
void print(raw_ostream &os, const OpPrintingFlags &flags={})
operand_range getOperands()
Returns an iterator on the underlying Value's.
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.
This class represents a collection of SymbolTables.
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 represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
bool hasOneUse() const
Returns true if this value has exactly one use.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
static WalkResult interrupt()
This class represents a lattice holding a specific value of type ValueT.
A sparse (backward) data-flow analysis for propagating SSA value lattices backwards across the IR by ...
SparseBackwardDataFlowAnalysis(DataFlowSolver &solver, SymbolTableCollection &symbolTable)
Operation * getOwner() const
Return the owner of this operand.
::mlir::Pass::Option< unsigned > indexBitWidth
::mlir::Pass::Option< std::string > layoutKind
void loadBaselineAnalyses(DataFlowSolver &solver)
Populates a DataFlowSolver with analyses that are required to ensure user-defined analyses are run pr...
const uArch * getUArch(llvm::StringRef archName)
DistributeLayoutAttr inferShapeCastSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for a shape cast operation given the result layout attribute,...
DistributeLayoutAttr setupLoadNdAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, DistributeLayoutAttr consumerLayout, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a load_nd operation.
DistributeLayoutAttr inferResultLayoutFromSourceForNonAnchorOp(Operation *op, ArrayRef< DistributeLayoutAttr > operandLayouts)
Infers the result layout attribute for a non-anchor operation from the layouts of its source operands...
DistributeLayoutAttr setupLoadMatrixAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the anchor layout for load matrix operation.
DistributeLayoutAttr setupInterleaveResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the result layout for an interleave operation to ensure the source layout can be safely deriv...
DistributeLayoutAttr inferTransposeSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > permutation)
Infers the source layout attribute for a transpose operation given the result layout attribute and pe...
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > completeDpasMxLaneLayoutFromInstData(DistributeLayoutAttr aLayout, DistributeLayoutAttr bLayout, DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy, VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy, const uArch::uArch *uArch)
Like completeDpasLaneLayoutFromInstData, but for dpas_mx: additionally re-derives the A_scale / B_sca...
DistributeLayoutAttr inferInsertStridedSliceSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for an insert strided slice operation given the result layout attr...
DistributeLayoutAttr setupStoreMatrixAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a store matrix operation.
void removeTemporaryLayoutAttrs(Operation *op)
Removes the temporary layout attributes for each OpOperand and OpResult of the given operation.
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > completeDpasLaneLayoutFromInstData(DistributeLayoutAttr aLayout, DistributeLayoutAttr bLayout, DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy, VectorType cdTy, const uArch::uArch *uArch)
Completes user-provided DPAS A/B/C-D anchors that carry only inst_data by filling in lane_layout / la...
void setTemporaryLayout(const T &operandOrResult, const DistributeLayoutAttr layout)
LayoutKind
Specifies the level of a layout hierarchy for comparison or propagation.
void setDistributeLayoutAttr(const OpResult &Result, const DistributeLayoutAttr layout)
[to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult user should use setAnchorLayout...
DistributeLayoutAttr inferInterleaveSourceLayout(DistributeLayoutAttr resLayout)
Infers the source layout attribute for an interleave operation given the result layout attribute.
DistributeLayoutAttr inferBroadcastSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for a broadcast operation given the result layout attribute,...
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > setupDpasMxLayout(LayoutKind layoutKind, VectorType aTy, VectorType bTy, VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy, DistributeLayoutAttr consumerLayout, int numSg, const uArch::uArch *uArch)
Sets up the anchor layouts for dpas_mx operands (A, B, C/D, A_scale, and B_scale).
SliceAttr setupMultiReductionResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, DistributeLayoutAttr consumerLayout, SmallVector< int64_t > reductionDims, int numSg, const uArch::uArch *uArch)
Note on the consumerLayout argument used by the consumer-driven setup* / complete* helpers below:
DistributeLayoutAttr setupLoadGatherAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the anchor layout for a load gather operation.
std::optional< DistributeLayoutAttr > completeScatterLoadLaneLayoutFromInstData(DistributeLayoutAttr userSpecifiedLayout, DistributeLayoutAttr consumerLayout, Type elemTy, const xegpu::uArch::LoadGatherInstruction *uArchInstruction, const int subgroupSize)
If the consumer layout has only inst_data (no lane_layout/lane_data), completes it by running the cor...
DistributeLayoutAttr setupStoreScatterAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a store scatter operation.
DistributeLayoutAttr setupBitCastResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Setup the result layout attribute for a bitcast operation based on element type bitwidths.
void removeLayoutAttr(const T &operandOrResult)
Removes the LayoutAttr for a given OpOperand or OpResult if it exists.
DistributeLayoutAttr inferMaskOffsetLayoutForScatterIO(DistributeLayoutAttr payloadLayout, int chunkSize)
Infers the layout attribute for mask and offset operand for Chunked load and store,...
DistributeLayoutAttr getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value.
DistributeLayoutAttr setupPrefetchNdAnchorLayout(LayoutKind layoutKind, TensorDescType tdescTy, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a prefetch_nd operation.
LogicalResult propagateYieldOperandsToRegionResults(RegionBranchTerminatorOpInterface terminator, GetLayoutFnTy getLayoutOfValue)
Propagate layouts from a region branch terminator's forwarded operands to the matching region results...
LogicalResult resolveLayoutConflicts(Operation *target)
DistributeLayoutAttr inferBitCastSourceLayout(DistributeLayoutAttr resLayout, int resElemTyBitWidth, int srcElemTyBitWidth)
Infers the source layout attribute for a bitcast operation given the result layout attribute,...
DistributeLayoutAttr setupInsertStridedSliceResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the result layout for an insert strided slice operation.
std::optional< std::string > getChipStr(Operation *op)
Retrieves the chip string from the XeVM target attribute of the parent GPU module operation.
DistributeLayoutAttr inferReductionSourceLayout(DistributeLayoutAttr resLayout)
Infers the source layout attribute for a reduction operation given the result layout attribute and re...
std::optional< DistributeLayoutAttr > completeScatterStoreLaneLayoutFromInstData(DistributeLayoutAttr specifiedLayout, Type elemTy, const xegpu::uArch::StoreScatterInstruction *uArchInstruction, const int subgroupSize)
Like completeScatterLoadLaneLayoutFromInstData, but for scatter stores (store_scatter / store_matrix)...
DistributeLayoutAttr getTemporaryLayout(const T &operandOrResult)
get and set distribute layout attribute for non-anchor operations (and offsets/masks of load/store op...
std::optional< DistributeLayoutAttr > completeBlockStoreLaneLayoutFromInstData(DistributeLayoutAttr specifiedLayout, Type elemTy, const xegpu::uArch::BlockIOInstructionInterface *uArchInstruction, const int subgroupSize)
Completes a user-provided 2D-block store_nd / prefetch_nd anchor that has only inst_data.
DistributeLayoutAttr inferDeinterleaveSourceLayout(DistributeLayoutAttr resLayout)
Infers the source layout attribute for a deinterleave operation given the result layout attribute.
DistributeLayoutAttr getConsumerLayoutAt(OpOperand &operand)
Gets the expected layout for a given consumer operand.
DistributeLayoutAttr inferMultiReductionSourceLayout(DistributeLayoutAttr resLayout, SmallVector< int64_t > reduceDims)
Infers the source layout attribute for a reduction operation given the result layout attribute and re...
bool isTriviallyRematerializable(Operation *op)
Returns true if op is safe and cheap to clone: it has no side effects, no regions,...
LogicalResult propagateLayouts(OpBuilder &builder, Operation *target, LayoutKind layoutKind, unsigned indexBitWidth, bool printOnly=false)
DistributeLayoutAttr setupStoreNdAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a store_nd operation.
std::optional< DistributeLayoutAttr > completeBlockLoadLaneLayoutFromInstData(DistributeLayoutAttr specifiedLayout, DistributeLayoutAttr consumerLayout, Type elemTy, const xegpu::uArch::BlockIOInstructionInterface *uArchInstruction, const int subgroupSize)
Like completeBlockStoreLaneLayoutFromInstData, but for load_nd.
LogicalResult propagateRegionArgsToInits(RegionBranchOpInterface regionOp, GetLayoutFnTy getLayoutOfValue)
Propagate layouts from a region branch op's region entry block arguments back to its init operands.
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > setupDpasLayout(LayoutKind layoutKind, VectorType aTy, VectorType bTy, VectorType cdTy, DistributeLayoutAttr consumerLayout, int numSg, const uArch::uArch *uArch)
Sets up the anchor layouts for a dpas operands (A, B, and C/D).
SliceAttr setupReductionResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, const uArch::uArch *uArch)
Sets up layout for Reduction operations by creating a SliceAttr for the result.
Include the generated interface declarations.
bool operator==(StringAttr lhs, std::nullptr_t)
Define comparisons for StringAttr against nullptr and itself to avoid the StringRef overloads from be...
llvm::TypeSwitch< T, ResultT > TypeSwitch
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
llvm::function_ref< Fn > function_ref