34#include "llvm/ADT/ArrayRef.h"
35#include "llvm/ADT/DenseMap.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/SetVector.h"
38#include "llvm/ADT/SmallSet.h"
39#include "llvm/ADT/SmallVector.h"
40#include "llvm/ADT/TypeSwitch.h"
41#include "llvm/Support/Casting.h"
42#include "llvm/Support/Debug.h"
43#include "llvm/Support/LogicalResult.h"
44#include "llvm/Support/MathExtras.h"
45#include "llvm/Support/raw_ostream.h"
50#define GEN_PASS_DEF_XEGPUPROPAGATELAYOUT
51#include "mlir/Dialect/XeGPU/Transforms/Passes.h.inc"
55#define DEBUG_TYPE "xegpu-propagate-layout"
56#define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE "]: ")
99 xegpu::DistributeLayoutAttr storage =
nullptr;
102 int64_t programOrder = std::numeric_limits<int64_t>::max();
105 LayoutInfo() =
default;
106 LayoutInfo(
const xegpu::DistributeLayoutAttr &layout,
int64_t programOrder)
107 : storage(layout), programOrder(programOrder) {}
113 bool operator==(
const LayoutInfo &other)
const {
114 if (isAssigned() != other.isAssigned())
118 return storage.isEqualTo(other.storage);
121 static LayoutInfo meet(
const LayoutInfo &lhs,
const LayoutInfo &rhs);
123 static LayoutInfo
join(
const LayoutInfo &lhs,
const LayoutInfo &rhs);
127 bool isAssigned()
const {
return storage !=
nullptr; }
141 bool isSliceLayout()
const {
144 return isa<xegpu::SliceAttr>(storage);
150 return storage.getRank();
154 void set(
const xegpu::DistributeLayoutAttr &layout) { storage = layout; }
161 os <<
"Not assigned.";
165LayoutInfo LayoutInfo::meet(
const LayoutInfo &lhs,
const LayoutInfo &rhs) {
166 if (!lhs.isAssigned())
168 if (!rhs.isAssigned())
173 if (rhs.programOrder < lhs.programOrder)
179LayoutInfo LayoutInfo::join(
const LayoutInfo &lhs,
const LayoutInfo &rhs) {
180 llvm_unreachable(
"Join should not be triggered by layout propagation.");
188struct LayoutInfoLattice :
public Lattice<LayoutInfo> {
190 using Lattice::Lattice;
202class LayoutInfoPropagation
224 int64_t currentProgramOrder = std::numeric_limits<int64_t>::max();
225 LayoutInfo makeLayoutInfo(
const xegpu::DistributeLayoutAttr &layout) {
226 return LayoutInfo(layout, currentProgramOrder);
232 void visitDpasMxOp(xegpu::DpasMxOp dpasMx,
236 void visitStoreNdOp(xegpu::StoreNdOp store,
240 void visitStoreScatterOp(xegpu::StoreScatterOp storeScatter,
244 void visitLoadNdOp(xegpu::LoadNdOp
load,
248 void visitLoadGatherOp(xegpu::LoadGatherOp
load,
252 void visitTransposeOp(vector::TransposeOp transpose,
256 void visitVectorBitcastOp(vector::BitCastOp bitcast,
260 void visitVectorInterleaveOp(vector::InterleaveOp interleave,
264 void visitVectorDeinterleaveOp(vector::DeinterleaveOp deinterleave,
268 void visitPrefetchNdOp(xegpu::PrefetchNdOp prefetch,
272 void visitVectorMultiReductionOp(vector::MultiDimReductionOp reduction,
276 void visitVectorReductionOp(vector::ReductionOp reduction,
280 void visitVectorBroadCastOp(vector::BroadcastOp
broadcast,
283 void visitShapeCastOp(vector::ShapeCastOp shapeCast,
287 visitInsertStridedSliceOp(vector::InsertStridedSliceOp insertStridedSlice,
291 void visitLoadMatrixOp(xegpu::LoadMatrixOp
load,
295 void visitStoreMatrixOp(xegpu::StoreMatrixOp store,
299 void visitLoadGatherOp(xegpu::LoadMatrixOp
load,
303 void visitStoreScatterOp(xegpu::StoreMatrixOp store,
307 void visitConvertLayoutOp(xegpu::ConvertLayoutOp convertLayout,
311 bool hasParamsOfLayoutKind(xegpu::DistributeLayoutAttr anchorLayout);
314 FailureOr<int64_t> getNumSgOrFail(
Operation *op,
int sgSize,
315 xegpu::DistributeLayoutAttr consumerLayout);
318 bool propagationFailed =
false;
322 void markFailure(
Operation *op,
const llvm::Twine &message) {
324 propagationFailed =
true;
328 bool hasFailed()
const {
return propagationFailed; }
335 layoutKind(layoutKind), indexBitWidth(indexBitWidth),
336 scopeRoot(scopeRoot) {}
340 visitOperation(Operation *op, ArrayRef<LayoutInfoLattice *> operands,
341 ArrayRef<const LayoutInfoLattice *> results)
override;
343 void visitBranchOperand(OpOperand &operand)
override {};
345 void visitCallOperand(OpOperand &operand)
override {};
348 visitNonControlFlowArguments(RegionSuccessor &successor,
349 ArrayRef<BlockArgument> arguments)
override {};
351 void visitExternalCall(CallOpInterface call,
352 ArrayRef<LayoutInfoLattice *> operands,
353 ArrayRef<const LayoutInfoLattice *> results)
override {
356 void setToExitState(LayoutInfoLattice *lattice)
override {
357 (void)lattice->meet(LayoutInfo());
362int64_t LayoutInfoPropagation::getProgramOrder(Operation *op) {
363 auto it = programOrder.find(op);
364 if (it != programOrder.end())
373 scopeRoot->
walk<WalkOrder::PreOrder>(
374 [&](Operation *o) { programOrder[o] = counter++; });
375 return programOrder.lookup(op);
378LogicalResult LayoutInfoPropagation::visitOperation(
379 Operation *op, ArrayRef<LayoutInfoLattice *> operands,
380 ArrayRef<const LayoutInfoLattice *> results) {
383 currentProgramOrder = getProgramOrder(op);
386 [&](xegpu::DpasOp dpasOp) { visitDpasOp(dpasOp, operands, results); })
387 .Case([&](xegpu::DpasMxOp dpasMxOp) {
388 visitDpasMxOp(dpasMxOp, operands, results);
390 .Case([&](xegpu::StoreNdOp storeNdOp) {
391 visitStoreNdOp(storeNdOp, operands, results);
393 .Case([&](xegpu::StoreScatterOp storeScatterOp) {
394 visitStoreScatterOp(storeScatterOp, operands, results);
396 .Case([&](xegpu::LoadNdOp loadNdOp) {
397 visitLoadNdOp(loadNdOp, operands, results);
399 .Case([&](xegpu::LoadGatherOp loadGatherOp) {
400 visitLoadGatherOp(loadGatherOp, operands, results);
402 .Case([&](xegpu::PrefetchNdOp prefetchNdOp) {
403 visitPrefetchNdOp(prefetchNdOp, operands, results);
405 .Case([&](vector::TransposeOp transposeOp) {
406 visitTransposeOp(transposeOp, operands, results);
408 .Case([&](vector::BitCastOp bitcastOp) {
409 visitVectorBitcastOp(bitcastOp, operands, results);
411 .Case([&](vector::InterleaveOp interleaveOp) {
412 visitVectorInterleaveOp(interleaveOp, operands, results);
414 .Case([&](vector::DeinterleaveOp deinterleaveOp) {
415 visitVectorDeinterleaveOp(deinterleaveOp, operands, results);
417 .Case([&](vector::MultiDimReductionOp reductionOp) {
418 visitVectorMultiReductionOp(reductionOp, operands, results);
420 .Case([&](vector::ReductionOp reductionOp) {
421 visitVectorReductionOp(reductionOp, operands, results);
423 .Case([&](vector::BroadcastOp broadcastOp) {
424 visitVectorBroadCastOp(broadcastOp, operands, results);
426 .Case([&](vector::ShapeCastOp shapeCastOp) {
427 visitShapeCastOp(shapeCastOp, operands, results);
429 .Case([&](vector::InsertStridedSliceOp insertStridedSliceOp) {
430 visitInsertStridedSliceOp(insertStridedSliceOp, operands, results);
432 .Case([&](xegpu::LoadMatrixOp loadMatrixOp) {
433 visitLoadMatrixOp(loadMatrixOp, operands, results);
435 .Case([&](xegpu::StoreMatrixOp storeMatrixOp) {
436 visitStoreMatrixOp(storeMatrixOp, operands, results);
438 .Case([&](xegpu::ConvertLayoutOp convertLayoutOp) {
439 visitConvertLayoutOp(convertLayoutOp, operands, results);
442 .Default([&](Operation *op) {
443 for (
const LayoutInfoLattice *resultInfo : results) {
444 if (!resultInfo->getValue().isAssigned())
446 for (
auto [operandInfo, operand] :
450 if (!isa<xegpu::TensorDescType, VectorType>(
451 operand.get().getType()))
454 meet(operandInfo, *resultInfo);
462bool LayoutInfoPropagation::hasParamsOfLayoutKind(
463 xegpu::DistributeLayoutAttr anchorLayout) {
464 if (anchorLayout ==
nullptr) {
467 if (layoutKind == xegpu::LayoutKind::InstData) {
468 return !(anchorLayout.getEffectiveInstDataAsInt().empty());
470 if (layoutKind == xegpu::LayoutKind::Lane) {
471 return !(anchorLayout.getEffectiveLaneLayoutAsInt().empty() ||
472 anchorLayout.getEffectiveLaneDataAsInt().empty());
474 if (layoutKind == xegpu::LayoutKind::Subgroup) {
475 return !(anchorLayout.getEffectiveSgLayoutAsInt().empty() ||
476 anchorLayout.getEffectiveSgDataAsInt().empty());
481FailureOr<int64_t> LayoutInfoPropagation::getNumSgOrFail(
482 Operation *op,
int sgSize, xegpu::DistributeLayoutAttr consumerLayout) {
484 if (consumerLayout) {
485 auto sgLayout = consumerLayout.getEffectiveSgLayoutAsInt();
486 if (!sgLayout.empty())
487 return llvm::product_of(sgLayout);
490 if (FailureOr<int64_t> numSg =
495 if (layoutKind == xegpu::LayoutKind::Subgroup) {
496 markFailure(op,
"Unable to determine the number of subgroups for the "
497 "operation. Please check @known_block_size is properly "
498 "attached as kernel attributes, with power-of-two "
499 "dimensions covering at least one subgroup.");
505void LayoutInfoPropagation::visitPrefetchNdOp(
506 xegpu::PrefetchNdOp prefetch, ArrayRef<LayoutInfoLattice *> operands,
507 ArrayRef<const LayoutInfoLattice *> results) {
509 LayoutInfo prefetchLayout;
513 xegpu::DistributeLayoutAttr anchorLayout = prefetch.getLayoutAttr();
514 if (hasParamsOfLayoutKind(anchorLayout)) {
515 prefetchLayout = makeLayoutInfo(anchorLayout);
516 if (layoutKind == xegpu::LayoutKind::InstData) {
517 const auto *uArchInstruction =
518 dyn_cast<xegpu::uArch::Subgroup2DBlockPrefetchInstruction>(
519 uArch->getInstruction(
520 xegpu::uArch::InstructionKind::Subgroup2DBlockPrefetch));
521 if (!uArchInstruction)
524 anchorLayout, prefetch.getTensorDescType().getElementType(),
525 uArchInstruction, uArch->getSubgroupSize());
527 prefetch.emitWarning(
528 "Failed to identify lane layouts for the specified inst_data.");
531 prefetch.setLayoutAttr(*completed);
532 prefetchLayout = makeLayoutInfo(*completed);
535 auto tdescTy = prefetch.getTensorDescType();
537 getNumSgOrFail(prefetch, uArch->getSubgroupSize(),
nullptr);
542 layoutKind, tdescTy, numSgOrErr.value_or(0), uArch);
544 prefetch.emitWarning(
545 "Failed to determine required layout for prefetch_nd.");
548 prefetchLayout = makeLayoutInfo(layoutAttr);
549 prefetch.setLayoutAttr(layoutAttr);
552 propagateIfChanged(operands[0], operands[0]->meet(prefetchLayout));
555void LayoutInfoPropagation::visitVectorMultiReductionOp(
556 vector::MultiDimReductionOp reduction,
557 ArrayRef<LayoutInfoLattice *> operands,
558 ArrayRef<const LayoutInfoLattice *> results) {
559 Type resultTy = reduction.getDestType();
561 LayoutInfo resLayoutInfo = results[0]->getValue();
563 xegpu::DistributeLayoutAttr consumerLayoutAttr;
565 if (!resLayoutInfo.isAssigned())
568 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
571 VectorType sourceTy = reduction.getSourceVectorType();
572 SmallVector<int64_t> reductionDims(reduction.getReductionDims());
580 getNumSgOrFail(reduction, uArch->getSubgroupSize(), consumerLayoutAttr);
590 layoutKind, sourceTy, consumerLayoutAttr, reductionDims,
591 numSgOrErr.value_or(0), uArch);
597 requiredResLayoutAttr, reductionDims);
599 propagateIfChanged(operands[0],
600 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
602 propagateIfChanged(operands[1],
603 operands[1]->meet(makeLayoutInfo(requiredResLayoutAttr)));
606void LayoutInfoPropagation::visitVectorReductionOp(
607 vector::ReductionOp reduction, ArrayRef<LayoutInfoLattice *> operands,
608 ArrayRef<const LayoutInfoLattice *> results) {
610 VectorType sourceTy = reduction.getSourceVectorType();
616 auto requiredResLayoutAttr =
621 propagateIfChanged(operands[0],
622 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
623 if (reduction.getAcc())
625 operands[1], operands[1]->meet(makeLayoutInfo(requiredResLayoutAttr)));
628void LayoutInfoPropagation::visitVectorBroadCastOp(
629 vector::BroadcastOp
broadcast, ArrayRef<LayoutInfoLattice *> operands,
630 ArrayRef<const LayoutInfoLattice *> results) {
632 LayoutInfo resLayoutInfo = results[0]->getValue();
633 if (!resLayoutInfo.isAssigned())
637 VectorType resultTy =
broadcast.getResultVectorType();
638 VectorType sourceTy = dyn_cast<VectorType>(
broadcast.getSourceType());
643 auto srcShape = sourceTy.getShape();
644 auto resShape = resultTy.getShape();
646 auto resultLayoutAttr =
647 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
649 xegpu::DistributeLayoutAttr srcLayoutAttr =
652 propagateIfChanged(operands[0],
653 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
656void LayoutInfoPropagation::visitShapeCastOp(
657 vector::ShapeCastOp shapeCast, ArrayRef<LayoutInfoLattice *> operands,
658 ArrayRef<const LayoutInfoLattice *> results) {
660 LayoutInfo resLayoutInfo = results[0]->getValue();
661 if (!resLayoutInfo.isAssigned())
663 ArrayRef<int64_t> resShape = shapeCast.getResultVectorType().getShape();
664 ArrayRef<int64_t> srcShape = shapeCast.getSourceVectorType().getShape();
665 auto resultLayoutAttr =
666 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
669 layoutKind, shapeCast.getSourceVectorType(),
670 shapeCast.getResultVectorType(), resultLayoutAttr);
675 if (!requiredResLayoutAttr) {
676 shapeCast.emitWarning(
"Failed to infer source layout for shape_cast; the "
677 "result layout required by its consumers cannot be "
678 "collapsed onto the source shape.");
684 requiredResLayoutAttr, resShape, srcShape);
687 if (!srcLayoutAttr) {
688 shapeCast.emitWarning(
"Failed to infer source layout for shape_cast; "
689 "unsupported shape-cast pattern.");
693 propagateIfChanged(operands[0],
694 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
698void LayoutInfoPropagation::visitDpasOp(
699 xegpu::DpasOp dpas, ArrayRef<LayoutInfoLattice *> operands,
700 ArrayRef<const LayoutInfoLattice *> results) {
701 LayoutInfo dpasALayout;
702 LayoutInfo dpasBLayout;
703 LayoutInfo dpasCDLayout;
708 VectorType aTy = dpas.getLhsType();
709 VectorType bTy = dpas.getRhsType();
710 VectorType cdTy = dpas.getResultType();
712 xegpu::DistributeLayoutAttr anchorLayoutCD = dpas.getLayoutCdAttr();
713 if (hasParamsOfLayoutKind(anchorLayoutCD)) {
714 xegpu::DistributeLayoutAttr anchorLayoutA = dpas.getLayoutAAttr();
715 xegpu::DistributeLayoutAttr anchorLayoutB = dpas.getLayoutBAttr();
716 assert(hasParamsOfLayoutKind(anchorLayoutA) &&
717 "Expected anchor layout for DPAS A operand.");
718 assert(hasParamsOfLayoutKind(anchorLayoutB) &&
719 "Expected anchor layout for DPAS B operand.");
720 dpasALayout = makeLayoutInfo(anchorLayoutA);
721 dpasBLayout = makeLayoutInfo(anchorLayoutB);
722 dpasCDLayout = makeLayoutInfo(anchorLayoutCD);
723 if (layoutKind == xegpu::LayoutKind::InstData) {
725 anchorLayoutA, anchorLayoutB, anchorLayoutCD, aTy, bTy, cdTy, uArch);
729 "Failed to identify lane layouts for the specified inst_data.");
732 auto [completedA, completedB, completedCD] = *completed;
733 dpas.setLayoutAAttr(completedA);
734 dpas.setLayoutBAttr(completedB);
735 dpas.setLayoutCdAttr(completedCD);
736 dpasALayout = makeLayoutInfo(completedA);
737 dpasBLayout = makeLayoutInfo(completedB);
738 dpasCDLayout = makeLayoutInfo(completedCD);
742 xegpu::DistributeLayoutAttr consumerLayoutAttr =
nullptr;
743 xegpu::DistributeLayoutAttr requiredCDLayoutAttr, requiredALayout,
746 LayoutInfo consumerLayout = results[0]->getValue();
747 if (!consumerLayout.isAssigned())
750 dyn_cast<xegpu::DistributeLayoutAttr>(consumerLayout.get());
753 getNumSgOrFail(dpas, uArch->getSubgroupSize(), consumerLayoutAttr);
759 numSgOrErr.value_or(0), uArch);
760 if (!layouts.has_value()) {
762 "Failed to determine required layouts for DPAS operands.");
766 std::tie(requiredALayout, requiredBLayout, requiredCDLayoutAttr) = *layouts;
768 dpas.setLayoutAAttr(requiredALayout);
769 dpas.setLayoutBAttr(requiredBLayout);
770 dpas.setLayoutCdAttr(requiredCDLayoutAttr);
771 dpasALayout = makeLayoutInfo(requiredALayout);
772 dpasBLayout = makeLayoutInfo(requiredBLayout);
773 dpasCDLayout = makeLayoutInfo(requiredCDLayoutAttr);
775 propagateIfChanged(operands[0], operands[0]->meet(dpasALayout));
776 propagateIfChanged(operands[1], operands[1]->meet(dpasBLayout));
777 if (operands.size() > 2)
778 propagateIfChanged(operands[2], operands[2]->meet(dpasCDLayout));
784void LayoutInfoPropagation::visitDpasMxOp(
785 xegpu::DpasMxOp dpasMx, ArrayRef<LayoutInfoLattice *> operands,
786 ArrayRef<const LayoutInfoLattice *> results) {
789 LayoutInfo dpasMxALayout, dpasMxBLayout, dpasMxCDLayout;
790 LayoutInfo dpasMxAScaleLayout, dpasMxBScaleLayout;
793 xegpu::DistributeLayoutAttr anchorLayoutA = dpasMx.getLayoutAAttr();
794 xegpu::DistributeLayoutAttr anchorLayoutB = dpasMx.getLayoutBAttr();
795 xegpu::DistributeLayoutAttr anchorLayoutCD = dpasMx.getLayoutCdAttr();
801 VectorType aTy = dpasMx.getAType();
802 VectorType bTy = dpasMx.getBType();
803 VectorType cdTy = dpasMx.getResultType();
808 Value scaleA = dpasMx.getScaleA();
809 Value scaleB = dpasMx.getScaleB();
811 aScaleTy = dyn_cast<VectorType>(scaleA.
getType());
813 bScaleTy = dyn_cast<VectorType>(scaleB.
getType());
816 if (anchorLayoutA && anchorLayoutB && anchorLayoutCD &&
817 hasParamsOfLayoutKind(anchorLayoutA) &&
818 hasParamsOfLayoutKind(anchorLayoutB) &&
819 hasParamsOfLayoutKind(anchorLayoutCD)) {
820 dpasMxALayout = makeLayoutInfo(anchorLayoutA);
821 dpasMxBLayout = makeLayoutInfo(anchorLayoutB);
822 dpasMxCDLayout = makeLayoutInfo(anchorLayoutCD);
825 xegpu::DistributeLayoutAttr anchorLayoutAScale =
826 dpasMx.getLayoutAScaleAttr();
827 xegpu::DistributeLayoutAttr anchorLayoutBScale =
828 dpasMx.getLayoutBScaleAttr();
829 if (anchorLayoutAScale)
830 dpasMxAScaleLayout = makeLayoutInfo(anchorLayoutAScale);
831 if (anchorLayoutBScale)
832 dpasMxBScaleLayout = makeLayoutInfo(anchorLayoutBScale);
834 if (layoutKind == xegpu::LayoutKind::InstData) {
836 anchorLayoutA, anchorLayoutB, anchorLayoutCD, aTy, bTy, cdTy,
837 aScaleTy, bScaleTy, uArch);
841 "Failed to identify lane layouts for the specified inst_data.");
844 auto [completedA, completedB, completedCD, completedAScale,
845 completedBScale] = *completed;
846 dpasMx.setLayoutAAttr(completedA);
847 dpasMx.setLayoutBAttr(completedB);
848 dpasMx.setLayoutCdAttr(completedCD);
849 dpasMxALayout = makeLayoutInfo(completedA);
850 dpasMxBLayout = makeLayoutInfo(completedB);
851 dpasMxCDLayout = makeLayoutInfo(completedCD);
852 if (completedAScale) {
853 dpasMx.setLayoutAScaleAttr(completedAScale);
854 dpasMxAScaleLayout = makeLayoutInfo(completedAScale);
856 if (completedBScale) {
857 dpasMx.setLayoutBScaleAttr(completedBScale);
858 dpasMxBScaleLayout = makeLayoutInfo(completedBScale);
862 xegpu::DistributeLayoutAttr consumerLayoutAttr =
nullptr;
863 xegpu::DistributeLayoutAttr requiredCDLayoutAttr, requiredALayout,
864 requiredBLayout, requiredAScaleLayout, requiredBScaleLayout;
866 LayoutInfo consumerLayout = results[0]->getValue();
867 if (!consumerLayout.isAssigned())
870 dyn_cast<xegpu::DistributeLayoutAttr>(consumerLayout.get());
873 getNumSgOrFail(dpasMx, uArch->getSubgroupSize(), consumerLayoutAttr);
878 layoutKind, aTy, bTy, cdTy, aScaleTy, bScaleTy, consumerLayoutAttr,
879 numSgOrErr.value_or(0), uArch);
880 if (!layouts.has_value()) {
882 "Failed to determine required layouts for DPAS_MX operands.");
886 std::tie(requiredALayout, requiredBLayout, requiredCDLayoutAttr,
887 requiredAScaleLayout, requiredBScaleLayout) = *layouts;
889 dpasMx.setLayoutAAttr(requiredALayout);
890 dpasMx.setLayoutBAttr(requiredBLayout);
891 dpasMx.setLayoutCdAttr(requiredCDLayoutAttr);
892 if (requiredAScaleLayout)
893 dpasMx.setLayoutAScaleAttr(requiredAScaleLayout);
894 if (requiredBScaleLayout)
895 dpasMx.setLayoutBScaleAttr(requiredBScaleLayout);
897 dpasMxALayout = makeLayoutInfo(requiredALayout);
898 dpasMxBLayout = makeLayoutInfo(requiredBLayout);
899 dpasMxCDLayout = makeLayoutInfo(requiredCDLayoutAttr);
900 if (requiredAScaleLayout)
901 dpasMxAScaleLayout = makeLayoutInfo(requiredAScaleLayout);
902 if (requiredBScaleLayout)
903 dpasMxBScaleLayout = makeLayoutInfo(requiredBScaleLayout);
910 propagateIfChanged(operands[0], operands[0]->meet(dpasMxALayout));
911 propagateIfChanged(operands[1], operands[1]->meet(dpasMxBLayout));
913 if (dpasMx.getAcc()) {
914 propagateIfChanged(operands[idx], operands[idx]->meet(dpasMxCDLayout));
917 if (dpasMx.getScaleA()) {
918 if (dpasMxAScaleLayout.isAssigned())
919 propagateIfChanged(operands[idx],
920 operands[idx]->meet(dpasMxAScaleLayout));
923 if (dpasMx.getScaleB()) {
924 if (dpasMxBScaleLayout.isAssigned())
925 propagateIfChanged(operands[idx],
926 operands[idx]->meet(dpasMxBScaleLayout));
932void LayoutInfoPropagation::visitStoreNdOp(
933 xegpu::StoreNdOp store, ArrayRef<LayoutInfoLattice *> operands,
934 ArrayRef<const LayoutInfoLattice *> results) {
935 LayoutInfo storeLayout;
939 xegpu::DistributeLayoutAttr anchorLayout = store.getLayoutAttr();
940 if (hasParamsOfLayoutKind(anchorLayout)) {
941 storeLayout = makeLayoutInfo(anchorLayout);
942 if (layoutKind == xegpu::LayoutKind::InstData) {
944 const auto *uArchInstruction =
945 dyn_cast<xegpu::uArch::Subgroup2DBlockStoreInstruction>(
946 uArch->getInstruction(
947 xegpu::uArch::InstructionKind::Subgroup2DBlockStore));
948 if (!uArchInstruction)
951 anchorLayout, store.getValueType().getElementType(), uArchInstruction,
952 uArch->getSubgroupSize());
956 "Failed to identify lane layouts for the specified inst_data.");
959 store.setLayoutAttr(*completed);
960 storeLayout = makeLayoutInfo(*completed);
963 auto numSgOrErr = getNumSgOrFail(store, uArch->getSubgroupSize(),
nullptr);
968 layoutKind, store.getValueType(), numSgOrErr.value_or(0), uArch);
970 markFailure(store,
"Failed to determine required layout for store_nd.");
973 storeLayout = makeLayoutInfo(layoutAttr);
974 store.setLayoutAttr(layoutAttr);
978 for (LayoutInfoLattice *operand : operands)
979 propagateIfChanged(operand, operand->meet(storeLayout));
984void LayoutInfoPropagation::visitLoadNdOp(
985 xegpu::LoadNdOp
load, ArrayRef<LayoutInfoLattice *> operands,
986 ArrayRef<const LayoutInfoLattice *> results) {
987 LayoutInfo loadLayout;
992 LayoutInfo valueLayout = results[0]->getValue();
993 if (!valueLayout.isAssigned())
995 auto consumerLayoutAttr =
996 dyn_cast<xegpu::DistributeLayoutAttr>(valueLayout.get());
997 xegpu::DistributeLayoutAttr anchorLayout =
load.getLayoutAttr();
998 if (hasParamsOfLayoutKind(anchorLayout)) {
999 loadLayout = makeLayoutInfo(anchorLayout);
1000 if (layoutKind == xegpu::LayoutKind::InstData &&
1001 !consumerLayoutAttr.getEffectiveLaneLayoutAsInt().empty()) {
1002 const auto *uArchInstruction =
1003 dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
1004 uArch->getInstruction(
1005 xegpu::uArch::InstructionKind::Subgroup2DBlockLoad));
1006 if (!uArchInstruction)
1009 anchorLayout, consumerLayoutAttr,
load.getType().getElementType(),
1010 uArchInstruction, uArch->getSubgroupSize());
1013 "Failed to identify lane layouts for the specified inst_data.");
1016 load.setLayoutAttr(*completed);
1017 loadLayout = makeLayoutInfo(*completed);
1021 getNumSgOrFail(
load, uArch->getSubgroupSize(), consumerLayoutAttr);
1025 layoutKind,
load.getType(), consumerLayoutAttr, numSgOrErr.value_or(0),
1028 load.emitWarning(
"Failed to determine required layout for load_nd.");
1031 loadLayout = makeLayoutInfo(layoutAttr);
1032 load.setLayoutAttr(layoutAttr);
1035 propagateIfChanged(operands[0], operands[0]->meet(loadLayout));
1040void LayoutInfoPropagation::visitConvertLayoutOp(
1041 xegpu::ConvertLayoutOp convert, ArrayRef<LayoutInfoLattice *> operands,
1042 ArrayRef<const LayoutInfoLattice *> results) {
1044 LayoutInfo resultLayout = results[0]->getValue();
1047 auto targetLayoutAttr =
1048 dyn_cast<xegpu::LayoutAttr>(convert.getTargetLayoutAttr());
1050 auto inputLayoutAttr =
1051 dyn_cast_if_present<xegpu::LayoutAttr>(convert.getInputLayoutAttr());
1057 auto resultLayoutAttr = resultLayout.isAssigned()
1058 ? dyn_cast<xegpu::LayoutAttr>(resultLayout.get())
1060 if (resultLayoutAttr && targetLayoutAttr) {
1061 if (layoutKind == xegpu::LayoutKind::InstData &&
1062 !targetLayoutAttr.getLaneLayout()) {
1063 targetLayoutAttr = xegpu::LayoutAttr::get(
1064 convert.getContext(), targetLayoutAttr.getSgLayout(),
1065 targetLayoutAttr.getSgData(), targetLayoutAttr.getInstData(),
1066 resultLayoutAttr.getLaneLayout(), resultLayoutAttr.getLaneData(),
1067 resultLayoutAttr.getOrder());
1068 convert.setTargetLayoutAttr(targetLayoutAttr);
1075 if (inputLayoutAttr && targetLayoutAttr) {
1076 if (layoutKind == xegpu::LayoutKind::InstData &&
1077 !inputLayoutAttr.getLaneLayout()) {
1078 auto merged = xegpu::LayoutAttr::get(
1079 convert.getContext(), inputLayoutAttr.getSgLayout(),
1080 inputLayoutAttr.getSgData(), inputLayoutAttr.getInstData(),
1081 targetLayoutAttr.getLaneLayout(), targetLayoutAttr.getLaneData(),
1082 targetLayoutAttr.getOrder());
1083 convert.setInputLayoutAttr(merged);
1087 xegpu::DistributeLayoutAttr anchorLayout = convert.getEffectiveInputLayout();
1088 LayoutInfo convertLayout = makeLayoutInfo(anchorLayout);
1090 propagateIfChanged(operands[0], operands[0]->meet(convertLayout));
1095void LayoutInfoPropagation::visitTransposeOp(
1096 vector::TransposeOp transpose, ArrayRef<LayoutInfoLattice *> operands,
1097 ArrayRef<const LayoutInfoLattice *> results) {
1099 LayoutInfo resultLayout = results[0]->getValue();
1100 if (!resultLayout.isAssigned())
1103 auto consumerLayoutAttr =
1104 dyn_cast<xegpu::DistributeLayoutAttr>(resultLayout.get());
1106 consumerLayoutAttr, transpose.getPermutation());
1109 propagateIfChanged(operands[0],
1110 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1115void LayoutInfoPropagation::visitVectorBitcastOp(
1116 vector::BitCastOp bitcast, ArrayRef<LayoutInfoLattice *> operands,
1117 ArrayRef<const LayoutInfoLattice *> results) {
1119 LayoutInfo resLayoutInfo = results[0]->getValue();
1120 if (!resLayoutInfo.isAssigned())
1123 auto srcVecType = bitcast.getSourceVectorType();
1124 auto resVecType = bitcast.getResultVectorType();
1126 auto consumerLayoutAttr =
1127 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1133 layoutKind, srcVecType, resVecType, consumerLayoutAttr, uArch);
1137 int inElemTyBitWidth = srcVecType.getElementType().getIntOrFloatBitWidth();
1138 int outElemTyBitWidth = resVecType.getElementType().getIntOrFloatBitWidth();
1142 requiredResLayoutAttr, outElemTyBitWidth, inElemTyBitWidth);
1144 propagateIfChanged(operands[0],
1145 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1151void LayoutInfoPropagation::visitVectorInterleaveOp(
1152 vector::InterleaveOp interleave, ArrayRef<LayoutInfoLattice *> operands,
1153 ArrayRef<const LayoutInfoLattice *> results) {
1155 LayoutInfo resLayoutInfo = results[0]->getValue();
1156 if (!resLayoutInfo.isAssigned())
1159 auto srcVecType = interleave.getSourceVectorType();
1160 auto resVecType = interleave.getResultVectorType();
1162 auto consumerLayoutAttr =
1163 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1171 layoutKind, srcVecType, resVecType, consumerLayoutAttr, uArch);
1176 auto srcLayoutAttr =
1180 propagateIfChanged(operands[0],
1181 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1182 propagateIfChanged(operands[1],
1183 operands[1]->meet(makeLayoutInfo(srcLayoutAttr)));
1189void LayoutInfoPropagation::visitVectorDeinterleaveOp(
1190 vector::DeinterleaveOp deinterleave, ArrayRef<LayoutInfoLattice *> operands,
1191 ArrayRef<const LayoutInfoLattice *> results) {
1194 LayoutInfo resLayoutInfo = results[0]->getValue();
1195 if (!resLayoutInfo.isAssigned())
1198 auto consumerLayoutAttr =
1199 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1205 propagateIfChanged(operands[0],
1206 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1209void LayoutInfoPropagation::visitInsertStridedSliceOp(
1210 vector::InsertStridedSliceOp insertStridedSlice,
1211 ArrayRef<LayoutInfoLattice *> operands,
1212 ArrayRef<const LayoutInfoLattice *> results) {
1214 LayoutInfo resLayoutInfo = results[0]->getValue();
1215 if (!resLayoutInfo.isAssigned())
1218 auto srcVecType = insertStridedSlice.getSourceVectorType();
1219 auto resVecType = insertStridedSlice.getDestVectorType();
1221 auto consumerLayoutAttr =
1222 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1229 layoutKind, srcVecType, resVecType, consumerLayoutAttr, uArch);
1231 requiredResLayoutAttr);
1234 requiredResLayoutAttr, resVecType.getShape(), srcVecType.getShape());
1235 propagateIfChanged(operands[0],
1236 operands[0]->meet(makeLayoutInfo(srcLayoutAttr)));
1237 propagateIfChanged(operands[1],
1238 operands[1]->meet(makeLayoutInfo(requiredResLayoutAttr)));
1243void LayoutInfoPropagation::visitLoadGatherOp(
1244 xegpu::LoadGatherOp
load, ArrayRef<LayoutInfoLattice *> operands,
1245 ArrayRef<const LayoutInfoLattice *> results) {
1246 xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
1247 xegpu::DistributeLayoutAttr anchorLayoutAttr =
load.getLayoutAttr();
1251 VectorType resVecTy =
load.getValueType();
1254 int contigChunkSize =
load.getContiguity().value_or(1);
1256 LayoutInfo resLayoutInfo = results[0]->getValue();
1257 if (!resLayoutInfo.isAssigned())
1259 auto consumerLayoutAttr =
1260 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1262 if (hasParamsOfLayoutKind(anchorLayoutAttr)) {
1263 requiredAnchorLayoutAttr = anchorLayoutAttr;
1264 if (layoutKind == xegpu::LayoutKind::InstData &&
1265 !consumerLayoutAttr.getEffectiveLaneLayoutAsInt().empty()) {
1266 const auto uArchInstruction =
1267 dyn_cast<xegpu::uArch::LoadGatherInstruction>(
1268 uArch->getInstruction(xegpu::uArch::InstructionKind::LoadGather));
1269 if (!uArchInstruction)
1272 anchorLayoutAttr, consumerLayoutAttr, resVecTy.getElementType(),
1273 uArchInstruction, uArch->getSubgroupSize());
1276 "Failed to identify lane layouts for the specified inst_data.");
1279 requiredAnchorLayoutAttr = *completed;
1280 load.setLayoutAttr(requiredAnchorLayoutAttr);
1284 load.emitWarning(
"Not propagating, non-vector payload supplied.");
1288 layoutKind, resVecTy, contigChunkSize, consumerLayoutAttr, uArch);
1289 load.setLayoutAttr(requiredAnchorLayoutAttr);
1293 LayoutInfo maskLayoutInfo = makeLayoutInfo(requiredAnchorLayoutAttr);
1294 auto loadLayoutInfo = makeLayoutInfo(requiredAnchorLayoutAttr);
1297 if (isa<xegpu::TensorDescType>(
load.getSourceType()))
1298 propagateIfChanged(operands[0], operands[0]->meet(loadLayoutInfo));
1300 propagateIfChanged(operands[1], operands[1]->meet(maskLayoutInfo));
1301 propagateIfChanged(operands[2], operands[2]->meet(maskLayoutInfo));
1306void LayoutInfoPropagation::visitStoreScatterOp(
1307 xegpu::StoreScatterOp storeScatter, ArrayRef<LayoutInfoLattice *> operands,
1308 ArrayRef<const LayoutInfoLattice *> results) {
1310 xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
1311 xegpu::DistributeLayoutAttr anchorLayoutAttr = storeScatter.getLayoutAttr();
1316 VectorType srcVecTy = storeScatter.getValueType();
1319 int contigChunkSize = storeScatter.getContiguity().value_or(1);
1321 if (hasParamsOfLayoutKind(anchorLayoutAttr)) {
1322 requiredAnchorLayoutAttr = anchorLayoutAttr;
1323 if (layoutKind == xegpu::LayoutKind::InstData) {
1324 const auto uArchInstruction =
1325 dyn_cast<xegpu::uArch::StoreScatterInstruction>(uArch->getInstruction(
1326 xegpu::uArch::InstructionKind::StoreScatter));
1327 if (!uArchInstruction)
1330 anchorLayoutAttr, srcVecTy.getElementType(), uArchInstruction,
1331 uArch->getSubgroupSize());
1335 "Failed to identify lane layouts for the specified inst_data.");
1338 requiredAnchorLayoutAttr = *completed;
1339 storeScatter.setLayoutAttr(requiredAnchorLayoutAttr);
1343 storeScatter.emitWarning(
"Not propagating, non-vector payload supplied.");
1347 getNumSgOrFail(storeScatter, uArch->getSubgroupSize(),
nullptr);
1351 layoutKind, srcVecTy, contigChunkSize, numSgOrErr.value_or(0), uArch);
1352 if (!requiredAnchorLayoutAttr) {
1353 markFailure(storeScatter,
1354 "Failed to determine required layout for store scatter.");
1357 storeScatter.setLayoutAttr(requiredAnchorLayoutAttr);
1360 LayoutInfo srcLayoutInfo = makeLayoutInfo(requiredAnchorLayoutAttr);
1362 LayoutInfo maskLayoutInfo = makeLayoutInfo(requiredAnchorLayoutAttr);
1365 propagateIfChanged(operands[0], operands[0]->meet(srcLayoutInfo));
1367 if (isa<xegpu::TensorDescType>(storeScatter.getDestType()))
1368 propagateIfChanged(operands[1], operands[1]->meet(srcLayoutInfo));
1370 propagateIfChanged(operands[2], operands[2]->meet(maskLayoutInfo));
1371 propagateIfChanged(operands[3], operands[3]->meet(maskLayoutInfo));
1374void LayoutInfoPropagation::visitLoadMatrixOp(
1375 xegpu::LoadMatrixOp loadMatrixOp, ArrayRef<LayoutInfoLattice *> operands,
1376 ArrayRef<const LayoutInfoLattice *> results) {
1378 LayoutInfo resLayoutInfo = results[0]->getValue();
1379 if (!resLayoutInfo.isAssigned())
1382 auto consumerLayoutAttr =
1383 dyn_cast<xegpu::DistributeLayoutAttr>(resLayoutInfo.get());
1385 xegpu::DistributeLayoutAttr anchorLayout = loadMatrixOp.getLayoutAttr();
1389 if (!hasParamsOfLayoutKind(anchorLayout)) {
1390 VectorType resVecTy =
1391 llvm::cast<VectorType>(loadMatrixOp.getRes().getType());
1399 layoutKind, resVecTy, chunkSize, consumerLayoutAttr, uArch);
1400 loadMatrixOp.setLayoutAttr(requiredAnchorLayoutAttr);
1404void LayoutInfoPropagation::visitStoreMatrixOp(
1405 xegpu::StoreMatrixOp storeMatrix, ArrayRef<LayoutInfoLattice *> operands,
1406 ArrayRef<const LayoutInfoLattice *> results) {
1407 xegpu::DistributeLayoutAttr requiredAnchorLayoutAttr;
1408 xegpu::DistributeLayoutAttr anchorLayoutAttr = storeMatrix.getLayoutAttr();
1410 VectorType srcVecTy = llvm::cast<VectorType>(storeMatrix.getData().getType());
1415 if (hasParamsOfLayoutKind(anchorLayoutAttr)) {
1416 requiredAnchorLayoutAttr = anchorLayoutAttr;
1417 if (layoutKind == xegpu::LayoutKind::InstData) {
1418 const auto uArchInstruction =
1419 dyn_cast<xegpu::uArch::StoreScatterInstruction>(uArch->getInstruction(
1420 xegpu::uArch::InstructionKind::StoreScatter));
1421 if (!uArchInstruction)
1424 anchorLayoutAttr, srcVecTy.getElementType(), uArchInstruction,
1425 uArch->getSubgroupSize());
1429 "Failed to identify lane layouts for the specified inst_data.");
1432 requiredAnchorLayoutAttr = *completed;
1433 storeMatrix.setLayoutAttr(requiredAnchorLayoutAttr);
1439 getNumSgOrFail(storeMatrix, uArch->getSubgroupSize(),
nullptr);
1443 layoutKind, srcVecTy, chunkSize, numSgOrErr.value_or(0), uArch);
1444 if (!requiredAnchorLayoutAttr) {
1445 markFailure(storeMatrix,
1446 "Failed to determine required layout for store matrix.");
1449 storeMatrix.setLayoutAttr(requiredAnchorLayoutAttr);
1451 layout = makeLayoutInfo(requiredAnchorLayoutAttr);
1452 propagateIfChanged(operands[0], operands[0]->meet(layout));
1461class RunLayoutInfoPropagation {
1466 unsigned indexBitWidth)
1468 SymbolTableCollection symbolTable;
1470 analysis = solver.
load<LayoutInfoPropagation>(symbolTable, layoutKind,
1475 LayoutInfo getLayoutInfo(Value val);
1477 void printAnalysisResult(llvm::raw_ostream &os);
1479 bool hasFailed()
const {
return analysis && analysis->hasFailed(); }
1482 DataFlowSolver solver;
1484 LayoutInfoPropagation *analysis =
nullptr;
1488LayoutInfo RunLayoutInfoPropagation::getLayoutInfo(Value val) {
1489 auto *state = solver.
lookupState<LayoutInfoLattice>(val);
1492 return state->getValue();
1496void RunLayoutInfoPropagation::printAnalysisResult(llvm::raw_ostream &os) {
1497 auto printFunctionResult = [&](FunctionOpInterface funcOp) {
1498 os <<
"function: " << funcOp.getName() <<
":\n";
1500 for (BlockArgument arg : funcOp.getArguments()) {
1501 LayoutInfo layout = getLayoutInfo(arg);
1502 os <<
"argument: " << arg <<
"\n";
1508 funcOp.walk([&](Operation *op) {
1514 if (isa<BranchOpInterface>(op) || isa<RegionBranchOpInterface>(op))
1520 for (
auto [i, r] : llvm::enumerate(op->
getResults())) {
1521 LayoutInfo layout = getLayoutInfo(r);
1522 os <<
"layout for result #" << i <<
": ";
1529 SmallVector<FunctionOpInterface> funcOps;
1530 if (
auto modOp = dyn_cast<ModuleOp>(
target)) {
1531 for (
auto funcOp : modOp.getOps<FunctionOpInterface>())
1532 funcOps.push_back(funcOp);
1535 for (
auto gpuModOp : modOp.getOps<gpu::GPUModuleOp>()) {
1536 for (
auto gpuFuncOp : gpuModOp.getOps<FunctionOpInterface>())
1537 funcOps.push_back(gpuFuncOp);
1541 for (FunctionOpInterface funcOp : funcOps)
1542 printFunctionResult(funcOp);
1553static xegpu::CreateNdDescOp getDefiningCreateNdDescOp(Value tdescValue) {
1555 auto definingOp = tdescValue.
getDefiningOp<xegpu::CreateNdDescOp>();
1560 if (
auto arg = dyn_cast<BlockArgument>(tdescValue)) {
1561 auto *parentOp = arg.getOwner()->getParentOp();
1562 if (
auto loop = dyn_cast<LoopLikeOpInterface>(parentOp)) {
1563 OpOperand *tiedInit = loop.getTiedLoopInit(arg);
1565 return getDefiningCreateNdDescOp(tiedInit->
get());
1572struct ResolveLayoutConflicts {
1573 ResolveLayoutConflicts(Operation *parentOp)
1574 : parentOp(parentOp), builder(parentOp->
getContext()) {}
1575 LogicalResult run();
1578 Operation *parentOp;
1580 LogicalResult resolveTensorDescConsumer(OpOperand &operand);
1581 LogicalResult resolveVectorConsumer(OpOperand &operand);
1582 LogicalResult assignResultLayout(OpResult &
result);
1586LogicalResult ResolveLayoutConflicts::run() {
1589 auto r = parentOp->
walk([&](Operation *op) -> WalkResult {
1594 if (
result.getType().isIntOrFloat() &&
1595 (isa<vector::MultiDimReductionOp>(op) ||
1596 isa<vector::ReductionOp>(op))) {
1597 auto res = assignResultLayout(
result);
1599 DBGS() <<
"Failed to assign layout for scalar consumer of reduction "
1607 if (isa<VectorType>(
result.getType()) &&
result.use_empty() &&
1608 isa<RegionBranchOpInterface>(op)) {
1609 auto res = assignResultLayout(
result);
1611 DBGS() <<
"Failed to assign layout for vector consumer of region op "
1619 Type operandType = operand.get().getType();
1620 if (isa<xegpu::AnchorLayoutInterface>(op) &&
1621 isa<xegpu::TensorDescType>(operandType)) {
1622 auto res = resolveTensorDescConsumer(operand);
1624 DBGS() <<
"Failed to resolve tensor descriptor consumer: " << *op
1630 if (isa<VectorType>(operandType)) {
1631 auto res = resolveVectorConsumer(operand);
1633 DBGS() <<
"Failed to resolve vector consumer: " << *op <<
"\n";
1641 if (r.wasInterrupted())
1645 DBGS() <<
"IR after resolving layout conflicts:\n";
1652LogicalResult ResolveLayoutConflicts::assignResultLayout(OpResult &
result) {
1653 Operation *producerOp =
result.getDefiningOp();
1657 auto convertOp = xegpu::ConvertLayoutOp::create(
1660 result.replaceAllUsesExcept(convertOp.getResult(), convertOp);
1665ResolveLayoutConflicts::resolveVectorConsumer(OpOperand &operand) {
1666 Value vectorValue = operand.
get();
1667 Operation *consumerOp = operand.
getOwner();
1670 if (!producerLayout) {
1671 if (
auto vectorTy = dyn_cast<VectorType>(vectorValue.
getType());
1672 vectorTy && vectorTy.getRank() > 1)
1673 consumerOp->
emitWarning(
"Expected layout for non-1D vectors.");
1681 if (!consumerLayout) {
1682 if (isa<func::ReturnOp>(consumerOp) || isa<gpu::ReturnOp>(consumerOp))
1685 "No consumer layout found for vector operand.");
1689 if (consumerLayout.isEqualTo(producerLayout))
1695 if (
auto consumerConvert = dyn_cast<xegpu::ConvertLayoutOp>(consumerOp)) {
1696 consumerConvert.setInputLayoutAttr(producerLayout);
1702 if (
auto producerConvert =
1704 producerConvert && vectorValue.
hasOneUse()) {
1707 producerConvert.setInputLayoutAttr(
1708 producerConvert.getEffectiveInputLayout());
1709 producerConvert.setTargetLayoutAttr(consumerLayout);
1715 auto convertOp = xegpu::ConvertLayoutOp::create(
1716 builder, consumerOp->
getLoc(), vectorValue.
getType(), vectorValue,
1717 producerLayout, consumerLayout);
1720 operand.
set(convertOp.getResult());
1725ResolveLayoutConflicts::resolveTensorDescConsumer(OpOperand &operand) {
1726 Operation *consumerOp = operand.
getOwner();
1727 Value tdescValue = operand.
get();
1728 auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(consumerOp);
1729 auto currTDescType = dyn_cast<xegpu::TensorDescType>(tdescValue.
getType());
1730 assert(anchorOp && currTDescType &&
1731 "Expected anchor layout op and tensor descriptor consumer.");
1732 Attribute currLayout = currTDescType.getLayout();
1733 Attribute expectedLayout = anchorOp.getAnchorLayout();
1736 if (expectedLayout && currLayout && expectedLayout != currLayout) {
1738 auto conflictingCreateNdOp = getDefiningCreateNdDescOp(tdescValue);
1739 if (!conflictingCreateNdOp) {
1740 DBGS() <<
"Unable to find defining CreateNdDescOp for tensor descriptor: "
1741 << tdescValue <<
"\n";
1746 auto newTensorDescType = xegpu::TensorDescType::get(
1747 conflictingCreateNdOp.getContext(), currTDescType.getShape(),
1748 currTDescType.getElementType(), currTDescType.getEncoding(),
1750 auto newOp = xegpu::CreateNdDescOp::create(
1752 conflictingCreateNdOp->getOperands(),
1753 conflictingCreateNdOp.getProperties(),
1754 conflictingCreateNdOp->getDiscardableAttrDictionary().getValue());
1777 if (!isa<VectorType, xegpu::TensorDescType>(resultType))
1780 xegpu::DistributeLayoutAttr layout = getLayoutOfValue(
result);
1785 bool anyAssigned =
false;
1788 srcLayouts.push_back(srclayout);
1789 anyAssigned |= (srclayout !=
nullptr);
1796 if (!layout &&
result.getNumUses() > 0) {
1797 op->
emitWarning(
"op has users but no layout assigned for its result");
1801 if (
auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(resultType)) {
1802 auto typeWithLayout = xegpu::TensorDescType::get(
1803 tensorDescTy.getContext(), tensorDescTy.getShape(),
1804 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
1805 result.setType(typeWithLayout);
1841 [&](xegpu::ConvertLayoutOp convert) { conversions.push_back(convert); });
1842 for (xegpu::ConvertLayoutOp convert : conversions) {
1846 convert.getResult().replaceAllUsesWith(
clone);
1868 llvm::SmallSetVector<xegpu::ConvertLayoutOp, 8> deadConverts;
1873 if (!isa<VectorType>(
result.getType()))
1875 xegpu::DistributeLayoutAttr resultLayout =
1882 xegpu::DistributeLayoutAttr uniformConvSrcLayout;
1884 Value operandValue = operand.
get();
1885 if (!isa<VectorType>(operandValue.
getType()))
1887 auto operandConversionOp =
1891 if (!operandConversionOp) {
1897 xegpu::DistributeLayoutAttr input =
1898 operandConversionOp.getEffectiveInputLayout();
1901 if (!uniformConvSrcLayout)
1902 uniformConvSrcLayout = input;
1903 else if (!uniformConvSrcLayout.isEqualTo(input))
1905 conversions.emplace_back(&operand, operandConversionOp);
1908 if (!uniformConvSrcLayout)
1915 resultLayout.getEffectiveInstDataAsInt();
1917 uniformConvSrcLayout.getEffectiveInstDataAsInt();
1918 if (resultLayoutInstData.empty() || sourceInstData.empty() ||
1924 llvm::SmallDenseSet<unsigned> rewiredOpIdxs;
1925 for (
auto [operand, convert] : conversions) {
1926 operand->
set(convert.getSource());
1930 Value operandValue = operand.
get();
1931 if (!isa<VectorType>(operandValue.
getType()))
1937 "operand should have been rejected above");
1942 clone->getResult(cast<OpResult>(operandValue).getResultNumber());
1945 operand.
set(cloneResult);
1951 auto newConvOp = xegpu::ConvertLayoutOp::create(
1954 result.replaceAllUsesExcept(newConvOp.getResult(), newConvOp);
1958 for (
auto [operand, convert] : conversions)
1959 if (convert.getResult().use_empty())
1960 deadConverts.insert(convert);
1964 for (xegpu::ConvertLayoutOp convert : deadConverts)
1970 mlir::FunctionOpInterface funcOp,
1976 if (!isa<FunctionType>(funcOp.getFunctionType()))
1981 Type argType = arg.getType();
1982 newArgTypes.push_back(argType);
1983 if (!isa<VectorType, xegpu::TensorDescType>(argType))
1985 xegpu::DistributeLayoutAttr layout = getLayoutOfValue(arg);
1987 LLVM_DEBUG(
DBGS() <<
"Expecting layout for function argument: " << arg
1988 <<
" but got none.\n");
1991 if (
auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(argType)) {
1992 auto newTdescTy = xegpu::TensorDescType::get(
1993 tensorDescTy.getContext(), tensorDescTy.getShape(),
1994 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
1995 arg.setType(newTdescTy);
1996 newArgTypes.back() = newTdescTy;
2001 funcOp.setType(FunctionType::get(funcOp.getContext(), newArgTypes,
2002 funcOp.getResultTypes()));
2007struct XeGPUPropagateLayoutPass final
2008 :
public xegpu::impl::XeGPUPropagateLayoutBase<XeGPUPropagateLayoutPass> {
2009 XeGPUPropagateLayoutPass() =
default;
2010 XeGPUPropagateLayoutPass(
const XeGPUPropagateLayoutPass &other) =
default;
2011 XeGPUPropagateLayoutPass(xegpu::XeGPUPropagateLayoutOptions
options)
2012 : XeGPUPropagateLayoutBase(std::move(
options)) {}
2013 void runOnOperation()
override;
2019 unsigned indexBitWidth,
bool printOnly) {
2020 RunLayoutInfoPropagation analysis(
target, layoutKind, indexBitWidth);
2023 auto &os = llvm::outs();
2024 analysis.printAnalysisResult(os);
2029 if (analysis.hasFailed())
2032 auto getLayoutFromPropagation =
2033 [&](
Value val) -> xegpu::DistributeLayoutAttr {
2034 LayoutInfo layout = analysis.getLayoutInfo(val);
2035 if (
auto opResult = dyn_cast<OpResult>(val)) {
2036 Operation *defOp = opResult.getDefiningOp();
2037 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(defOp)) {
2038 auto anchorLayout = anchorOp.getAnchorLayout();
2039 if (anchorLayout !=
nullptr)
2040 return anchorLayout;
2042 xegpu::DistributeLayoutAttr requiredResLayoutAttr =
2044 if (requiredResLayoutAttr !=
nullptr)
2045 return requiredResLayoutAttr;
2047 if (!layout.isAssigned())
2049 xegpu::DistributeLayoutAttr layoutAttr =
2050 cast<xegpu::DistributeLayoutAttr>(layout.get());
2051 if (layout.isSliceLayout())
2052 return cast<xegpu::SliceAttr>(layoutAttr);
2054 return cast<xegpu::LayoutAttr>(layoutAttr);
2062 .Case([&](mlir::RegionBranchTerminatorOpInterface branchTermOp) {
2064 branchTermOp, getLayoutFromPropagation);
2066 .Case([&](mlir::RegionBranchOpInterface branchOp) {
2068 getLayoutFromPropagation);
2070 .Case([&](mlir::FunctionOpInterface funcOp) {
2072 getLayoutFromPropagation);
2078 op.
emitError(
"Failed to update operation with the layout.");
2084 if (walkResult.wasInterrupted())
2091 ResolveLayoutConflicts resolver(
target);
2092 return resolver.run();
2095void XeGPUPropagateLayoutPass::runOnOperation() {
2100 if (this->layoutKind ==
"lane") {
2102 }
else if (this->layoutKind ==
"inst") {
2104 }
else if (this->layoutKind ==
"subgroup") {
2105 layoutKind = xegpu::LayoutKind::Subgroup;
2107 getOperation()->emitError(
"Unsupported layout kind option: " +
2109 signalPassFailure();
2114 this->indexBitWidth, this->printOnly))) {
2115 signalPassFailure();
2120 signalPassFailure();
2124 if (layoutKind == xegpu::LayoutKind::InstData)
std::string join(const Ts &...args)
Helper function to concatenate arguments into a std::string.
static llvm::ManagedStatic< PassManagerOptions > options
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.
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.
unsigned getOperandNumber() const
Return which operand this is in the OpOperand list of the 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.
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...
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
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
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,...
void sinkElementwiseConversions(OpBuilder &builder, Operation *target)
Sink xegpu.convert_layout ops past the elementwise operations they feed, so that an elementwise op ru...
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.
FailureOr< int64_t > getNumSubgroupsFromBlockSize(Operation *op, int64_t subgroupSize)
Returns the number of subgroups the kernel enclosing op runs, derived from the known_block_size of it...
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 getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value, or nullptr if none is found.
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.
DistributeLayoutAttr setupShapeCastResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout)
Sets up the result layout for a shape cast that splits one source dim into several consecutive result...
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 the vector produced by op is cheap to recompute in any layout, i.e.
LogicalResult propagateLayouts(OpBuilder &builder, Operation *target, LayoutKind layoutKind, unsigned indexBitWidth, bool printOnly=false)
Value rematerialize(OpBuilder &builder, Value value)
Clone a bounded chain of pure vector generators and layout-preserving elementwise ops without layout ...
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).
void rematerializeConversionSources(OpBuilder &builder, Operation *target)
Replace layout conversions of cheap producer chains by recomputation.
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...
int64_t computeProduct(ArrayRef< int64_t > basis)
Self-explicit.
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