30#include "llvm/ADT/PostOrderIterator.h"
31#include "llvm/Support/FormatVariadic.h"
40 out.reserve(attrs.size());
42 for (
auto attr : attrs) {
43 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr.getValue())) {
44 auto newLayout = dist.dropSgLayoutAndData();
46 out.emplace_back(attr.getName(), newLayout);
58 out.reserve(attrs.size());
60 for (
auto attr : attrs) {
61 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr.getValue())) {
62 auto newLayout = dist.dropInstData();
64 out.emplace_back(attr.getName(), newLayout);
75 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr))
76 attr = dist.dropInstData();
83 auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(val.
getType());
84 if (!tensorDescTy || tensorDescTy.getLayoutAttr())
86 auto typeWithLayout = xegpu::TensorDescType::get(
87 tensorDescTy.getContext(), tensorDescTy.getShape(),
88 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
103 llvm::ReversePostOrderTraversal<Region *> rpot(®ion);
105 for (
Block *block : llvm::reverse(blocks)) {
107 for (
Operation &op : llvm::reverse(*block)) {
115 for (
Region &nested : op.getRegions())
124 xegpu::DistributeLayoutAttr layout =
nullptr;
159 if (op->
getNumResults() > 1 && !isa<vector::DeinterleaveOp>(op))
170 if (isa<xegpu::TensorDescType>(resultType))
175 if (isa<VectorType>(resultType) || isa<vector::MultiDimReductionOp>(op))
178 if (isa<vector::DeinterleaveOp>(op))
182 xegpu::DistributeLayoutAttr operandLayout =
184 if (isa<VectorType>(opr.get().getType()) && operandLayout)
196 mlir::RegionBranchTerminatorOpInterface yieldOp) {
197 auto regionBranchOp =
198 dyn_cast<RegionBranchOpInterface>(yieldOp->getParentOp());
204 yieldOp.getSuccessorRegions(operandAttrs, successors);
207 OperandRange succOps = yieldOp.getSuccessorOperands(successor);
211 ValueRange successorInputs = regionBranchOp.getSuccessorInputs(successor);
212 unsigned count = std::min<unsigned>(succOps.size(), successorInputs.size());
214 for (
unsigned i = 0; i < count; ++i) {
215 xegpu::DistributeLayoutAttr layout;
216 if (successor.isOperation()) {
219 auto regionResult = regionBranchOp->getResult(i);
224 if (isa<xegpu::TensorDescType>(regionResult.getType()))
235 auto operandType = succOps[i].
getType();
236 if (isa<VectorType>(operandType) ||
237 dyn_cast<xegpu::TensorDescType>(operandType))
258 mlir::RegionBranchTerminatorOpInterface terminator,
261 auto branchOp = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
266 branchOp.getSuccessorOperandInputMapping(mapping,
268 for (
const auto &[successorOperand, successorInputs] : mapping) {
269 for (
Value successorInput : successorInputs) {
270 Type inputType = successorInput.getType();
272 if (!isa<VectorType>(inputType))
274 xegpu::DistributeLayoutAttr successorOperandLayout =
275 getLayoutOfValue(successorOperand->get());
278 if (!successorOperandLayout)
281 if (
auto result = dyn_cast<OpResult>(successorInput))
287 if (
auto arg = dyn_cast<BlockArgument>(successorInput)) {
289 dyn_cast<LoopLikeOpInterface>(arg.getOwner()->getParentOp());
290 bool tiedToInit = loop && loop.getTiedLoopInit(arg);
291 if (!tiedToInit && !isa<BlockArgument>(successorOperand->get()))
292 return terminator->emitError(
293 "unsupported region structure: the successor argument it feeds "
294 "is not tied to an init operand, so its value must be passed "
295 "through from predecessor region argument.");
312 for (
Region ®ion : regionOp->getRegions()) {
317 ValueRange successorInputs = regionOp.getSuccessorInputs(regionSuccessor);
318 for (
auto [inputIdx, regionArg] : llvm::enumerate(successorInputs)) {
319 auto layout = getLayoutOfValue(regionArg);
324 if (isa<xegpu::TensorDescType>(regionArg.getType()))
330 regionOp.getPredecessorValues(regionSuccessor, inputIdx, predValues);
331 for (
Value predVal : predValues) {
333 for (
OpOperand &operand : regionOp->getOpOperands()) {
334 if (operand.get() == predVal)
373 auto processFunc = [&](
Region &body, StringRef funcName) {
375 if (
auto regionOp = dyn_cast<mlir::RegionBranchOpInterface>(op)) {
378 }
else if (
auto yieldOp =
379 dyn_cast<mlir::RegionBranchTerminatorOpInterface>(op)) {
381 }
else if (!dyn_cast<xegpu::AnchorLayoutInterface>(op)) {
387 rootOp->
walk([&](func::FuncOp
func) {
388 processFunc(
func.getBody(),
func.getSymName());
390 rootOp->
walk([&](gpu::GPUFuncOp
func) {
391 processFunc(
func.getBody(),
func.getName());
397template <
typename T,
typename>
399 Operation *owner = operandOrResult.getOwner();
418 if (isa<DistributeLayoutAttr>(namedAttr.getValue()))
419 attrsToRemove.push_back(namedAttr.getName());
421 for (
auto attrName : attrsToRemove)
430 if (isa<xegpu::DistributeLayoutAttr>(namedAttr.getValue()))
431 attrsToRemove.push_back(namedAttr.getName());
433 for (
auto attrName : attrsToRemove)
442 auto toI32Attr = [&](
auto range) {
446 return xegpu::LayoutAttr::get(context,
nullptr,
447 nullptr, toI32Attr(instData),
448 toI32Attr(laneLayout), toI32Attr(laneData),
455 return !llvm::any_of(llvm::seq<int>(0, dataShape.size()), [&](
int dim) {
456 return dataShape[dim] % (laneLayout[dim] * laneData[dim]) != 0;
460static xegpu::LayoutAttr
464 auto toI32Attr = [&](
auto range) {
468 return xegpu::LayoutAttr::get(context,
nullptr,
470 nullptr, toI32Attr(laneLayout),
471 toI32Attr(laneData), orderAttr);
474static xegpu::LayoutAttr
479 auto toI32Attr = [&](
auto range) {
483 return xegpu::LayoutAttr::get(
484 context, sgLayout.empty() ?
nullptr : toI32Attr(sgLayout),
485 sgData.empty() ?
nullptr : toI32Attr(sgData),
486 instData.empty() ?
nullptr : toI32Attr(instData),
487 laneLayout.empty() ?
nullptr : toI32Attr(laneLayout),
488 laneData.empty() ?
nullptr : toI32Attr(laneData), orderAttr);
497 for (
int dim = 0; dim < (int)sgLayout.size(); ++dim) {
499 sgData[dim] = wgTileShape[dim];
501 sgData[dim] = wgTileShape[dim] / sgLayout[dim];
510xegpu::DistributeLayoutAttr
516 size_t dimDiff = resShape.size() - srcShape.size();
517 auto bcastSourceLayout = resLayout;
520 for (
size_t i = dimDiff; i < resShape.size(); i++) {
521 if ((srcShape[i - dimDiff] == 1) && (resShape[i] != 1))
522 bcastDims.push_back(i);
527 if (!bcastDims.empty())
528 bcastSourceLayout = bcastSourceLayout.setUnitDimData(bcastDims);
533 bool isOuterDimDiffUnitDims = llvm::all_of(
534 resShape.take_front(dimDiff), [&](
int64_t dim) { return dim == 1; });
535 if (dimDiff && bcastDims.size() == dimDiff && isOuterDimDiffUnitDims) {
538 sliceDims.assign(bcastDims.begin(), bcastDims.end());
542 llvm::append_range(sliceDims, llvm::seq<int64_t>(0, dimDiff));
544 bcastSourceLayout = xegpu::SliceAttr::get(
545 resLayout.getContext(), bcastSourceLayout,
548 return bcastSourceLayout;
553xegpu::DistributeLayoutAttr
557 assert(isa<xegpu::SliceAttr>(resLayout) &&
558 "reduction result layout must be slice layout");
560 xegpu::SliceAttr sliceLayout = dyn_cast<xegpu::SliceAttr>(resLayout);
562 assert((reduceDims == sliceLayout.getDims().asArrayRef()) &&
563 "reduction dims must match with slice dims");
565 return sliceLayout.getParent();
568xegpu::DistributeLayoutAttr
579xegpu::DistributeLayoutAttr
590xegpu::DistributeLayoutAttr
592 int resElemTyBitWidth,
int srcElemTyBitWidth) {
597 size_t sgDataSize = sgData.size();
598 size_t instDataSize = instData.size();
599 size_t laneDataSize = laneData.size();
603 int64_t dim = resLayout.getRank() - 1;
605 if (srcElemTyBitWidth <= resElemTyBitWidth) {
606 int bitWidthRatio = resElemTyBitWidth / srcElemTyBitWidth;
608 sgDataValue = sgData.back() * bitWidthRatio;
610 instDataValue = instData.back() * bitWidthRatio;
612 laneDataValue = laneData.back() * bitWidthRatio;
614 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
616 assert((sgData.back() % bitWidthRatio) == 0 &&
617 "sgData not divisible by bitWidthRatio");
618 sgDataValue = sgData.back() / bitWidthRatio;
621 assert((instData.back() % bitWidthRatio) == 0 &&
622 "instData not divisible by bitWidthRatio");
623 instDataValue = instData.back() / bitWidthRatio;
626 assert((laneData.back() % bitWidthRatio) == 0 &&
627 "laneData not divisible by bitWidthRatio");
628 laneDataValue = laneData.back() / bitWidthRatio;
632 xegpu::DistributeLayoutAttr finalSrcLayout;
634 resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
636 return finalSrcLayout;
643xegpu::DistributeLayoutAttr
649 size_t sgDataSize = sgData.size();
650 size_t instDataSize = instData.size();
651 size_t laneDataSize = laneData.size();
655 int64_t dim = resLayout.getRank() - 1;
659 constexpr int ratio = 2;
661 assert((sgData.back() % ratio) == 0 &&
662 "sgData not divisible by interleave ratio");
663 sgDataValue = sgData.back() / ratio;
666 assert((instData.back() % ratio) == 0 &&
667 "instData not divisible by interleave ratio");
668 instDataValue = instData.back() / ratio;
671 assert((laneData.back() % ratio) == 0 &&
672 "laneData not divisible by interleave ratio");
673 laneDataValue = laneData.back() / ratio;
676 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
683xegpu::DistributeLayoutAttr
689 size_t sgDataSize = sgData.size();
690 size_t instDataSize = instData.size();
691 size_t laneDataSize = laneData.size();
695 int64_t dim = resLayout.getRank() - 1;
699 constexpr int ratio = 2;
701 sgDataValue = sgData.back() * ratio;
703 instDataValue = instData.back() * ratio;
705 laneDataValue = laneData.back() * ratio;
707 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
717 int srcShapeSize = srcShape.size();
718 int resShapeSize = resShape.size();
719 int dimDiff = resShapeSize - srcShapeSize;
724 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
725 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
726 for (
int i = 0; i < dimDiff; i++) {
727 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
728 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
729 "Leading dimensions being sliced off must not be distributed");
731 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
740xegpu::DistributeLayoutAttr
745 int srcShapeSize = srcShape.size();
746 int resShapeSize = resShape.size();
747 int dimDiff = resShapeSize - srcShapeSize;
752 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
753 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
754 for (
int i = 0; i < dimDiff; i++) {
755 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
756 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
757 "Leading dimensions being sliced off must not be distributed");
759 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
769xegpu::DistributeLayoutAttr
774 int srcShapeSize = srcShape.size();
775 int resShapeSize = resShape.size();
776 int dimDiff = srcShapeSize - resShapeSize;
777 auto context = resLayout.getContext();
781 auto sgLayout = resLayout.getEffectiveSgLayoutAsInt();
782 auto sgData = resLayout.getEffectiveSgDataAsInt();
783 auto instData = resLayout.getEffectiveInstDataAsInt();
784 auto laneLayout = resLayout.getEffectiveLaneLayoutAsInt();
785 auto laneData = resLayout.getEffectiveLaneDataAsInt();
786 auto order = resLayout.getEffectiveOrderAsInt();
796 for (
auto &o : order)
802 for (
int i = 0; i < dimDiff; i++) {
803 if (!sgLayout.empty())
804 sgLayout.insert(sgLayout.begin(), 1);
806 sgData.insert(sgData.begin(), 1);
807 if (!instData.empty())
808 instData.insert(instData.begin(), 1);
809 if (!laneLayout.empty())
810 laneLayout.insert(laneLayout.begin(), 1);
811 if (!laneData.empty())
812 laneData.insert(laneData.begin(), 1);
813 order.push_back(dimDiff - 1 - i);
818 if (!resLayout.getOrder())
821 return buildLayout(context, sgLayout, sgData, instData, laneLayout,
822 laneData, orderAttr);
829xegpu::DistributeLayoutAttr
853 xegpu::SliceAttr::get(resLayout.getContext(), resLayout, sliceDimsAttr);
860 auto srcLayout = resLayout;
861 for (
const auto &dimGroup : splitDimGroups)
862 srcLayout = srcLayout.collapseDims(dimGroup);
871 auto srcLayout = resLayout;
872 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
873 dstIdx >= 0; --dstIdx) {
875 if (srcDims.empty()) {
876 srcLayout = srcLayout.dropDims({dstIdx});
879 if (srcDims.size() == 1)
882 targetShape.reserve(srcDims.size());
884 targetShape.push_back(srcShape[d]);
885 srcLayout = srcLayout.expandDim(dstIdx, targetShape);
903xegpu::DistributeLayoutAttr
906 return srcLayout.transposeDims(permutation);
917xegpu::DistributeLayoutAttr
926 auto resLayout = srcLayout;
929 for (
int64_t srcIdx =
static_cast<int64_t>(splitDimGroups.size()) - 1;
930 srcIdx >= 0; --srcIdx) {
932 if (resDims.size() <= 1)
935 targetShape.reserve(resDims.size());
937 targetShape.push_back(resShape[d]);
938 resLayout = resLayout.expandDim(srcIdx, targetShape);
947 auto resLayout = srcLayout;
950 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
951 dstIdx >= 0; --dstIdx) {
957 if (srcDims.size() == 1)
959 resLayout = resLayout.collapseDims(llvm::to_vector(srcDims));
976 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
977 if (!operandLayouts[0])
980 transpose.getPermutation());
984 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
985 if (!operandLayouts[0])
988 operandLayouts[0], shapeCast.getSourceVectorType().getShape(),
989 shapeCast.getResultVectorType().getShape());
995 for (xegpu::DistributeLayoutAttr layout : operandLayouts)
1032 auto getDivisors = [](
int64_t n) {
1034 for (
int64_t i = 1; i * i <= n; ++i) {
1038 divs.push_back(n / i);
1047 if (dim == rank - 1) {
1048 current[dim] = remaining;
1052 for (
int64_t factor : getDivisors(remaining)) {
1053 current[dim] = factor;
1054 generate(dim + 1, remaining / factor);
1080 int64_t rank = wgShape.size();
1081 assert(rank > 0 &&
"wgShape must be non-empty");
1082 assert(
static_cast<int64_t>(instData.size()) == rank &&
1083 "instData rank must match wgShape rank");
1090 for (
const auto &sgLayout : allFactorizations) {
1092 for (
int64_t dim = 0; dim < rank; ++dim) {
1096 if (dim == broadcastDim) {
1097 sgData = wgShape[dim];
1099 if (wgShape[dim] % sgLayout[dim] != 0) {
1103 sgData = wgShape[dim] / sgLayout[dim];
1105 if (sgData % instData[dim] != 0) {
1111 candidates.push_back(sgLayout);
1117 int64_t spreadLhs = *llvm::max_element(lhs) - *llvm::min_element(lhs);
1118 int64_t spreadRhs = *llvm::max_element(rhs) - *llvm::min_element(rhs);
1119 if (spreadLhs != spreadRhs)
1120 return spreadLhs < spreadRhs;
1131 bool transform =
false,
bool transpose =
false) {
1132 int rank = dataShape.size();
1136 return std::nullopt;
1137 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1143 assert(rank >= 2 &&
"dataShape must be at least 2D for 2D-block IO");
1150 if (instWidth < 0 || instHeight < 0)
1151 return std::nullopt;
1152 instData.back() = instWidth;
1153 instData[rank - 2] = instHeight;
1164 VectorType aTy, VectorType bTy, VectorType cdTy,
1168 const unsigned dataALen = aTy.getShape()[aTy.getRank() - 2];
1169 auto supportedALen = uArchInstruction->
getSupportedM(aTy.getElementType());
1174 const unsigned dataBLen = bTy.getShape().back();
1175 auto supportedBLen = uArchInstruction->
getSupportedN(bTy.getElementType());
1179 auto supportedCLen = uArchInstruction->
getSupportedN(cdTy.getElementType());
1182 if (maxALen == -1 || maxBLen == -1 || maxCLen == -1)
1183 return std::nullopt;
1185 auto supportedKLen = uArchInstruction->
getSupportedK(aTy.getElementType());
1186 if (supportedKLen.empty())
1187 return std::nullopt;
1188 auto kDimSize = supportedKLen[0];
1191 instDataA[aTy.getRank() - 2] = maxALen;
1192 instDataA[aTy.getRank() - 1] = kDimSize;
1194 instDataB[bTy.getRank() - 2] = kDimSize;
1195 instDataB[bTy.getRank() - 1] = maxBLen;
1197 instDataCD[cdTy.getRank() - 2] = maxALen;
1198 instDataCD[cdTy.getRank() - 1] = maxCLen;
1199 return std::make_tuple(instDataA, instDataB, instDataCD);
1212 int64_t rank = instShape.size();
1215 laneLayout[innermost] = std::min(subgroupSize, instShape[innermost]);
1216 laneData[innermost] =
1217 std::min(instShape[innermost] / laneLayout[innermost], maxChunkSize);
1218 return {laneLayout, laneData};
1233 bool transform =
false,
bool transpose =
false) {
1234 int64_t rank = instShape.size();
1235 assert(rank >= 2 &&
"Expected at least a 2D shape for a 2D block op");
1239 laneData[packDim] = llvm::divideCeil(packingSize, bitwidth);
1241 int64_t laneDim = transpose ? rank - 2 : rank - 1;
1242 laneLayout[laneDim] =
1243 std::min(subgroupSize, instShape[laneDim] / laneData[laneDim]);
1246 for (
int64_t i = 0; i < rank; ++i)
1247 order.push_back(rank - 1 - i);
1248 std::swap(order[0], order[1]);
1252 for (
int64_t i = 0; i < rank; ++i) {
1253 int64_t laneProduct = laneLayout[i] * laneData[i];
1254 assert(instShape[i] % laneProduct == 0 &&
1255 "lane_layout * lane_data must evenly divide the inst shape");
1258 return {laneLayout, laneData, order};
1296 int subgroupSize,
int64_t maxReduceVectorSize,
1297 xegpu::DistributeLayoutAttr consumerLayout =
nullptr) {
1298 int srcRank = srcShape.size();
1300 auto isReduced = [&](
int dim) {
1301 return llvm::is_contained(reductionDims, dim);
1307 auto consumerSlice = dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
1308 bool reusedParent =
false;
1309 if (consumerSlice &&
1310 consumerSlice.getDims().asArrayRef().equals(reductionDims)) {
1311 auto parent = consumerSlice.getParent();
1313 parent.getEffectiveLaneLayoutAsInt();
1315 if (
static_cast<int>(parentLaneLayout.size()) == srcRank &&
1316 static_cast<int>(parentLaneData.size()) == srcRank &&
1318 laneLayout = std::move(parentLaneLayout);
1319 laneData = std::move(parentLaneData);
1320 reusedParent =
true;
1324 if (!reusedParent) {
1326 if (consumerLayout) {
1327 consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
1328 consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
1330 for (
int i = 0, c = 0; i < srcRank; ++i) {
1333 if (c <
static_cast<int>(consumerLaneLayout.size()))
1334 laneLayout[i] = consumerLaneLayout[c];
1335 if (c <
static_cast<int>(consumerLaneData.size()))
1336 laneData[i] = consumerLaneData[c];
1343 for (
int i = 0; i < srcRank; ++i) {
1344 maxLanes[i] = std::max<int64_t>(1, srcShape[i] / laneData[i]);
1345 laneLayout[i] = std::min(laneLayout[i], maxLanes[i]);
1353 int innermost = srcRank - 1;
1356 if (spareLanes > 1 && isReduced(innermost))
1357 laneLayout[innermost] =
1358 std::min(laneLayout[innermost] * spareLanes, maxLanes[innermost]);
1362 maxReduceVectorSize /
1365 bool canCarryVector = laneLayout[innermost] == 1 && isReduced(innermost) &&
1366 srcShape[innermost] > 1;
1368 if (vectorBudget > 1 && canCarryVector)
1369 laneData[innermost] =
1370 std::min(vectorBudget * laneData[innermost], srcShape[innermost]);
1373 for (
int i = 0; i < srcRank; ++i)
1374 instData[i] = laneLayout[i] * laneData[i];
1376 return {laneLayout, laneData, instData};
1442static std::optional<
1443 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1444 xegpu::DistributeLayoutAttr>>
1447 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1450 auto [instDataA, instDataB, instDataCD] = instDataVecs;
1452 std::optional<LayoutRepresentation> consumerSgLayout = std::nullopt;
1453 if (consumerLayout && consumerLayout.isForWorkgroup()) {
1454 consumerSgLayout = consumerLayout.getEffectiveSgLayoutAsInt();
1463 if (layoutsA.empty() || layoutsB.empty() || layoutsCD.empty())
1464 return std::nullopt;
1467 std::optional<LayoutRepresentation> bestPick;
1468 for (
auto &sgLayout : layoutsB) {
1469 if (llvm::is_contained(layoutsA, sgLayout) &&
1470 llvm::is_contained(layoutsCD, sgLayout)) {
1472 if (consumerSgLayout.has_value() && sgLayout == *consumerSgLayout) {
1473 bestPick = sgLayout;
1481 bestPick = sgLayout;
1485 return std::nullopt;
1487 const auto &picked = *bestPick;
1489 auto dpasALayout =
buildSgLayout(context, aTy.getShape(), picked,
1491 auto dpasBLayout =
buildSgLayout(context, bTy.getShape(), picked,
1493 auto dpasCDLayout =
buildSgLayout(context, cdTy.getShape(), picked);
1494 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout);
1501 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1502 xegpu::DistributeLayoutAttr>>
1504 VectorType bTy, VectorType cdTy,
1505 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1507 auto context = aTy.getContext();
1508 const auto *uArchInstruction =
1509 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1511 if (!uArchInstruction)
1512 return std::nullopt;
1515 auto [laneLayoutA, laneDataA, orderA] =
1517 aTy.getElementType().getIntOrFloatBitWidth(),
1518 uArchInstruction->getPackedFormatBitSizeA());
1520 bTy.getShape(), subgroupSize,
1521 bTy.getElementType().getIntOrFloatBitWidth(),
1522 uArchInstruction->getPackedFormatBitSizeB(),
true);
1523 auto [laneLayoutCD, laneDataCD, orderCD] =
1525 cdTy.getElementType().getIntOrFloatBitWidth(),
1526 cdTy.getElementType().getIntOrFloatBitWidth());
1530 return std::nullopt;
1534 "Number of subgroups must be provided for sg layout creation.");
1536 numSg, *instDataVecs);
1538 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1539 return std::make_tuple(
1548 return std::make_tuple(aLayout, bLayout, cdLayout);
1550 return std::nullopt;
1557static xegpu::DistributeLayoutAttr
1559 VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout,
1561 if (!scaleTy || !matrixLayout)
1569 if (scaleShape.empty())
1572 auto uArchInstruction =
1573 dyn_cast<xegpu::uArch::SubgroupScaledMatrixMultiplyAcc>(
1577 int64_t rank = matrixLayout.getRank();
1578 assert(rank >= 2 &&
"dpas layouts must be at least two dimensions");
1585 auto order = matrixLayout.getOrder();
1589 if (!sgLayout.empty() && !sgData.empty()) {
1590 scaleSgLayout.assign(sgLayout.begin(), sgLayout.end());
1591 scaleSgData.assign(sgData.begin(), sgData.end());
1592 scaleSgData[rank - 2] = std::max<int64_t>(
1593 scaleShape[rank - 2] / (matrixShape[rank - 2] / sgData[rank - 2]), 1);
1594 scaleSgData[rank - 1] = std::max<int64_t>(
1595 scaleShape[rank - 1] / (matrixShape[rank - 1] / sgData[rank - 1]), 1);
1602 if (!instData.empty()) {
1603 scaleInstData.assign(instData.begin(), instData.end());
1605 scaleInstData[rank - 2] = std::max<int64_t>(
1606 scaleShape[rank - 2] / (matrixShape[rank - 2] / instData[rank - 2]),
1609 scaleInstData[rank - 1] = std::max<int64_t>(
1610 scaleShape[rank - 1] / (matrixShape[rank - 1] / instData[rank - 1]),
1616 if (!laneLayout.empty() && !laneData.empty()) {
1617 scaleLaneLayout.assign(laneLayout.begin(), laneLayout.end());
1618 scaleLaneData.assign(laneData.size(), 1);
1620 bool isRowMajor = uArchInstruction->isLaneLayoutRowMajorOrder();
1621 if (isBScale ^ isRowMajor)
1622 std::swap(scaleLaneLayout[rank - 2], scaleLaneLayout[rank - 1]);
1627 auto layoutCap = scaleInstData.empty() ? scaleShape : scaleInstData;
1628 for (
int64_t d = rank - 2; d < rank; ++d)
1629 scaleLaneLayout[d] = std::min<int64_t>(layoutCap[d], scaleLaneLayout[d]);
1631 return buildLayout(context, scaleSgLayout, scaleSgData, scaleInstData,
1632 scaleLaneLayout, scaleLaneData, order);
1639 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1640 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1641 xegpu::DistributeLayoutAttr>>
1643 VectorType bTy, VectorType cdTy, VectorType aScaleTy,
1644 VectorType bScaleTy,
1645 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1647 auto context = aTy.getContext();
1648 const auto *uArchInstruction =
1649 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1651 if (!uArchInstruction)
1652 return std::nullopt;
1655 auto [laneLayoutA, laneDataA, orderA] =
1657 aTy.getElementType().getIntOrFloatBitWidth(),
1658 uArchInstruction->getPackedFormatBitSizeA());
1660 bTy.getShape(), subgroupSize,
1661 bTy.getElementType().getIntOrFloatBitWidth(),
1662 uArchInstruction->getPackedFormatBitSizeB(),
true);
1663 auto [laneLayoutCD, laneDataCD, orderCD] =
1665 cdTy.getElementType().getIntOrFloatBitWidth(),
1666 cdTy.getElementType().getIntOrFloatBitWidth());
1669 return std::nullopt;
1673 "Number of subgroups must be provided for sg layout creation.");
1675 context, aTy, bTy, cdTy, consumerLayout, numSg, *instDataVecs);
1677 return std::nullopt;
1679 auto [dpasALayout, dpasBLayout, dpasCDLayout] = *dpasLayouts;
1688 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1692 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1699 laneLayoutCD, laneDataCD);
1706 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1711 auto dpasCDLayout =
buildLaneLayout(context, laneLayoutCD, laneDataCD);
1718 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1721 return std::nullopt;
1727xegpu::DistributeLayoutAttr
1729 VectorType srcVecTy,
int numSg,
1731 const auto *uArchInstruction =
1732 dyn_cast<xegpu::uArch::Subgroup2DBlockStoreInstruction>(
1733 uArch->getInstruction(
1735 if (!uArchInstruction)
1738 auto context = srcVecTy.getContext();
1739 Type elemTy = srcVecTy.getElementType();
1740 auto subgroupSize =
uArch->getSubgroupSize();
1741 auto dataShape = srcVecTy.getShape();
1742 [[maybe_unused]]
int rank = srcVecTy.getRank();
1743 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1747 auto [laneLayout, laneData, order] =
1749 uArchInstruction->getPackedFormatBitSize());
1762 "Expected the store layout to satisfy uArch block constraints");
1769 "Number of subgroups must be provided for sg layout creation.");
1771 if (sgLayouts.empty())
1773 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1782xegpu::DistributeLayoutAttr
1784 xegpu::TensorDescType tdescTy,
int numSg,
1787 const auto *uArchInstruction =
1788 dyn_cast<xegpu::uArch::Subgroup2DBlockPrefetchInstruction>(
1791 if (!uArchInstruction)
1794 auto context = tdescTy.getContext();
1795 Type elemTy = tdescTy.getElementType();
1797 auto dataShape = tdescTy.getShape();
1798 [[maybe_unused]]
int rank = tdescTy.getRank();
1799 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1803 auto [laneLayout, laneData, order] =
1805 uArchInstruction->getPackedFormatBitSize());
1818 "Expected the prefetch layout to satisfy uArch block constraints");
1825 "Number of subgroups must be provided for sg layout creation.");
1827 if (sgLayouts.empty())
1829 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1840xegpu::DistributeLayoutAttr
1842 VectorType resVecTy,
1843 xegpu::DistributeLayoutAttr consumerLayout,
1846 assert(consumerLayout &&
"Expected a valid consumer layout");
1848 assert(consumerLayout.isForWorkgroup() &&
1849 "Expected consumer layout to be a complete workgroup-level layout");
1850 return consumerLayout;
1853 auto context = resVecTy.getContext();
1854 Type elemTy = resVecTy.getElementType();
1856 auto dataShape = resVecTy.getShape();
1857 const auto *uArchInstruction =
1858 dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
1861 if (!uArchInstruction)
1864 int rank = resVecTy.getRank();
1866 consumerLayout.getEffectiveInstDataAsInt();
1868 consumerLayout.getEffectiveLaneLayoutAsInt();
1870 consumerLayout.getEffectiveLaneDataAsInt();
1872 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1873 "Expected consumer layout to have lane_layout and lane_data");
1879 consumerLaneLayout[rank - 2] > 1 && consumerLaneLayout[rank - 1] == 1;
1884 bool hasTransform = !hasTranspose && canTransform &&
1885 consumerLaneData[rank - 2] > 1 &&
1886 consumerLaneData[rank - 1] == 1;
1887 assert((consumerLaneData[rank - 2] == 1 || consumerLaneData[rank - 1] == 1) &&
1888 "Expected consumer lane data to have at most one non-unit dim");
1891 auto blockWHC = uArchInstruction->getBlockWidthHeightCount(
1892 elemTy, hasTransform, hasTranspose,
1896 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1901 unsigned packingSize = hasTransform || hasTranspose
1903 : uArchInstruction->getPackedFormatBitSize();
1906 hasTransform, hasTranspose);
1914 int64_t height = consumerInstData[rank - 2];
1915 int64_t width = consumerInstData[rank - 1];
1916 auto maxBlockCount = *llvm::max_element(bCounts);
1917 auto maxWidth = *llvm::max_element(bWidths);
1918 if (llvm::is_contained(bWidths,
static_cast<int>(width)) ||
1919 (width % maxWidth == 0 && width / maxWidth < maxBlockCount)) {
1920 if (llvm::is_contained(bHeights,
static_cast<int>(height))) {
1922 "Expected the load layout to satisfy uArch block constraints");
1924 laneLayout, laneData, orderAttr);
1933 if (!hasTranspose && !hasTransform &&
1934 consumerInstData[rank - 1] %
1935 (laneLayout[rank - 1] * laneData[rank - 1]) !=
1937 hasTransform =
true;
1944 dataShape, elemTy, uArchInstruction, hasTransform, hasTranspose);
1949 "Expected the load layout to satisfy uArch block constraints");
1955 "Expected the lane layout to satisfy uArch block constraints");
1956 return consumerLayout;
1982 xegpu::DistributeLayoutAttr consumerLayout,
int maxChunkSize,
1986 return consumerLayout;
1989 consumerLayout.getEffectiveInstDataAsInt();
1991 consumerLayout.getEffectiveLaneLayoutAsInt();
1993 consumerLayout.getEffectiveLaneDataAsInt();
1995 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1996 "Expected consumer layout to have lane_layout and lane_data");
2003 std::min(consumerLaneData.back(),
static_cast<int64_t>(maxChunkSize));
2007 instData.resize(resShape.size());
2008 for (
size_t i = 0; i < resShape.size(); ++i)
2009 instData[i] = laneLayout[i] * laneData[i];
2020 xegpu::DistributeLayoutAttr consumerLayout,
const uArch::uArch *uArch) {
2022 const int subgroupSize = uArch->getSubgroupSize();
2024 auto context = resVecTy.getContext();
2028 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
2031 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2034 maxChunkSize, resShape, subgroupSize);
2039xegpu::DistributeLayoutAttr
2041 VectorType resVecTy,
int contigChunkSize,
2042 xegpu::DistributeLayoutAttr consumerLayout,
2047 auto context = resVecTy.getContext();
2049 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
2052 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2054 maxChunkSize, resShape, subgroupSize);
2060static xegpu::DistributeLayoutAttr
2064 if (candidates.empty())
2067 return buildSgLayout(context, wgShape, candidates.front(), -1);
2077 auto [laneLayout, laneData] =
2081 for (
size_t i = 0; i < srcShape.size(); ++i)
2082 instData[i] = laneLayout[i] * laneData[i];
2086 "Number of subgroups must be provided for sg layout creation.");
2099xegpu::DistributeLayoutAttr
2101 VectorType srcVecTy,
int contigChunkSize,
2104 const int subgroupSize =
uArch->getSubgroupSize();
2106 auto context = srcVecTy.getContext();
2110 const auto *uArchInstruction =
2111 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2114 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2116 srcShape, subgroupSize, numSg);
2124 const int subgroupSize =
uArch->getSubgroupSize();
2126 auto context = srcVecTy.getContext();
2128 const auto *uArchInstruction =
2129 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2132 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2135 srcShape, subgroupSize, numSg);
2153std::optional<xegpu::DistributeLayoutAttr>
2155 xegpu::DistributeLayoutAttr specifiedLayout,
2156 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2158 const int subgroupSize) {
2159 if (!specifiedLayout)
2160 return specifiedLayout;
2162 specifiedLayout.getEffectiveInstDataAsInt();
2163 if (specifiedInstData.empty())
2164 return specifiedLayout;
2165 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2166 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2167 return specifiedLayout;
2170 auto *context = specifiedLayout.getContext();
2172 if (consumerLayout) {
2173 auto consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
2174 auto consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
2175 if (!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
2179 consumerLaneLayout, consumerLaneData);
2182 specifiedInstData, subgroupSize, maxChunkSize);
2184 return std::nullopt;
2192std::optional<xegpu::DistributeLayoutAttr>
2194 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2196 const int subgroupSize) {
2197 if (!specifiedLayout)
2198 return specifiedLayout;
2200 specifiedLayout.getEffectiveInstDataAsInt();
2201 if (specifiedInstData.empty())
2202 return specifiedLayout;
2203 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2204 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2205 return specifiedLayout;
2208 auto *context = specifiedLayout.getContext();
2211 specifiedInstData, subgroupSize, maxChunkSize);
2213 return std::nullopt;
2222std::optional<xegpu::DistributeLayoutAttr>
2224 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2226 const int subgroupSize) {
2227 if (!specifiedLayout)
2228 return specifiedLayout;
2230 specifiedLayout.getEffectiveInstDataAsInt();
2231 if (specifiedInstData.empty())
2232 return specifiedLayout;
2233 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2234 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2235 return specifiedLayout;
2237 auto *context = specifiedLayout.getContext();
2242 return std::nullopt;
2251std::optional<xegpu::DistributeLayoutAttr>
2253 xegpu::DistributeLayoutAttr specifiedLayout,
2254 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2256 const int subgroupSize) {
2257 if (!specifiedLayout)
2258 return specifiedLayout;
2260 specifiedLayout.getEffectiveInstDataAsInt();
2261 if (specifiedInstData.empty())
2262 return specifiedLayout;
2263 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2264 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2265 return specifiedLayout;
2266 if (!consumerLayout)
2267 return specifiedLayout;
2269 consumerLayout.getEffectiveLaneLayoutAsInt();
2271 consumerLayout.getEffectiveLaneDataAsInt();
2272 if (consumerLaneLayout.empty() || consumerLaneData.empty())
2273 return specifiedLayout;
2275 auto *context = specifiedLayout.getContext();
2276 int rank = specifiedInstData.size();
2281 for (
int i = 0; i < rank; i++) {
2282 if (consumerLaneLayout[i] > 1) {
2283 laneLayout.push_back(
2284 std::max(
static_cast<int64_t>(subgroupSize), consumerLaneLayout[i]));
2286 laneLayout.push_back(1);
2291 return std::nullopt;
2294 consumerLayout.getOrder());
2302 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2303 xegpu::DistributeLayoutAttr>>
2305 xegpu::DistributeLayoutAttr bLayout,
2306 xegpu::DistributeLayoutAttr cdLayout,
2307 VectorType aTy, VectorType bTy,
2310 auto context = aTy.getContext();
2311 const auto *uArchInstruction =
2312 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
2314 if (!uArchInstruction)
2315 return std::nullopt;
2318 laneLayoutCD, laneDataCD;
2325 if (isa<xegpu::uArch::Xe2, xegpu::uArch::Xe3>(uArch)) {
2326 std::tie(laneLayoutA, laneDataA, orderA) =
2328 aTy.getElementType().getIntOrFloatBitWidth(),
2329 uArchInstruction->getPackedFormatBitSizeA());
2331 bTy.getShape(), subgroupSize,
2332 bTy.getElementType().getIntOrFloatBitWidth(),
2333 uArchInstruction->getPackedFormatBitSizeB(),
true);
2335 cdTy.getShape(), subgroupSize,
2336 cdTy.getElementType().getIntOrFloatBitWidth(),
2337 cdTy.getElementType().getIntOrFloatBitWidth());
2339 assert(
false &&
"Unsupported uArch for DPAS lane layout completion");
2345 return std::nullopt;
2346 return std::make_tuple(
2348 aLayout.getOrder()),
2350 bLayout.getOrder()),
2352 cdLayout.getOrder()));
2359 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2360 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2361 xegpu::DistributeLayoutAttr>>
2363 xegpu::DistributeLayoutAttr aLayout, xegpu::DistributeLayoutAttr bLayout,
2364 xegpu::DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy,
2365 VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy,
2368 aLayout, bLayout, cdLayout, aTy, bTy, cdTy, uArch);
2370 return std::nullopt;
2371 auto context = aTy.getContext();
2372 auto [completedA, completedB, completedCD] = *completed;
2379 return std::make_tuple(completedA, completedB, completedCD, aScaleLayout,
2514 auto srcShape = srcVecTy.getShape();
2515 int srcRank = srcShape.size();
2516 auto context = srcVecTy.getContext();
2518 const int subgroupSize =
uArch->getSubgroupSize();
2519 int64_t maxReduceVectorSize = 16;
2520 xegpu::DistributeLayoutAttr srcLayout;
2522 xegpu::SliceAttr consumerSliceLayout =
2523 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2524 if (consumerSliceLayout &&
2525 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2526 srcLayout = consumerSliceLayout.getParent();
2528 srcLayout.getEffectiveSgLayoutAsInt();
2531 for (
int dim = 0; dim < srcRank; dim++) {
2532 if (llvm::is_contained(reductionDims, dim))
2534 srcLayout.setDimData(dim, srcSgData.value()[dim], -1, -1);
2538 consumerLayout ? consumerLayout.getEffectiveSgLayoutAsInt()
2541 consumerLayout ? consumerLayout.getEffectiveSgDataAsInt()
2544 consumerLayout ? consumerLayout.getEffectiveOrderAsInt()
2547 consumerLayout ? consumerLayout.getOrder() :
nullptr;
2549 int remainingSgCount =
2550 consumerLayout ? consumerLayout.getNumSubgroups() : numSg;
2551 int consumerIdx = 0;
2554 for (
int i = 0; i < srcRank; i++) {
2555 if (!llvm::is_contained(reductionDims, i) &&
2556 consumerIdx <
static_cast<int>(consumerSgLayout.size())) {
2557 sgLayout[i] = consumerSgLayout[consumerIdx];
2558 sgData[i] = consumerSgData[consumerIdx];
2559 remainingSgCount /= sgLayout[i];
2566 for (
int i = 0; i < srcRank; i++) {
2567 if (llvm::is_contained(reductionDims, i)) {
2569 std::min(srcShape[i],
static_cast<int64_t>(remainingSgCount));
2570 assert((srcShape[i] % sgLayout[i] == 0) &&
2571 "source shape not divisible by sg_layout");
2572 sgData[i] = srcShape[i] / sgLayout[i];
2573 remainingSgCount /= sgLayout[i];
2579 int numRetainedDims = srcRank -
static_cast<int>(reductionDims.size());
2580 if (orderAttr && !orderAttr.empty() &&
2581 static_cast<int>(consumerOrder.size()) == numRetainedDims) {
2583 int retainedRank = 0;
2584 for (
int dim = 0; dim < srcRank; dim++)
2585 if (!llvm::is_contained(reductionDims, dim))
2586 order[dim] = consumerOrder[retainedRank++];
2589 for (
int reducedDim = 0; reducedDim < srcRank; reducedDim++) {
2590 if (!llvm::is_contained(reductionDims, reducedDim))
2595 insertRank = order[reducedDim - 1];
2598 else if (srcRank > 1)
2599 insertRank = order[reducedDim + 1] + 1;
2600 for (
int otherDim = 0; otherDim < srcRank; otherDim++)
2601 if (order[otherDim] >= insertRank)
2603 order[reducedDim] = insertRank;
2608 assert(remainingSgCount == 1 &&
"not all subgroups distributed");
2609 srcLayout =
buildLayout(context, sgLayout, sgData,
2614 auto [laneLayout, laneData, instData] =
2616 maxReduceVectorSize, consumerLayout);
2620 xegpu::SliceAttr consumerSliceLayout =
2621 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2622 if (consumerSliceLayout &&
2623 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2627 srcLayout = consumerSliceLayout.getParent();
2630 srcShape, reductionDims, subgroupSize, maxReduceVectorSize,
2637 return xegpu::SliceAttr::get(context, srcLayout,
2645 VectorType srcVecTy,
2648 auto srcShape = srcVecTy.getShape();
2649 auto context = srcVecTy.getContext();
2650 auto subgroupSize =
uArch->getSubgroupSize();
2651 xegpu::LayoutAttr srcLayout;
2655 "subgroup layout assignment not supported for reduction (op "
2656 "is not expected at this level).");
2659 "instData layout assignment not supported for reduction (op "
2660 "is not expected at this level).");
2663 laneLayout[0] = std::min(
static_cast<int64_t>(subgroupSize), srcShape[0]);
2668 auto result = xegpu::SliceAttr::get(context, srcLayout,
2686static xegpu::DistributeLayoutAttr
2689 size_t innerMostDim,
int ratio,
int64_t bound,
2695 consumerLayout.getEffectiveLaneLayoutAsInt();
2702 sgDataValue = sgData[innerMostDim];
2703 while ((sgDataValue <= bound) && (sgDataValue % ratio) != 0)
2706 instDataValue = instData[innerMostDim];
2707 const int innermostDimLaneLayout = laneLayout.empty()
2709 : laneLayout[innerMostDim];
2710 while ((instDataValue <= bound) &&
2711 (instDataValue % (innermostDimLaneLayout * ratio) != 0))
2713 assert((bound % instDataValue) == 0 &&
2714 "bound, instData, and laneLayout for innermost must be 2^n!");
2716 laneDataValue = laneData[innerMostDim];
2717 while ((laneDataValue <= bound) && (laneDataValue % ratio) != 0)
2721 return consumerLayout.setDimData(innerMostDim, sgDataValue, instDataValue,
2751 int srcElemTyBitWidth = srcVecTy.getElementType().getIntOrFloatBitWidth();
2752 int resElemTyBitWidth = resVecTy.getElementType().getIntOrFloatBitWidth();
2757 assert(consumerLayout.getRank() ==
static_cast<int64_t>(srcShape.size()) &&
2758 "laneData must be available for all dimensions");
2762 if (srcElemTyBitWidth <= resElemTyBitWidth)
2763 return consumerLayout;
2768 size_t innerMostDim = srcShape.size() - 1;
2769 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
2771 innerMostDim, bitWidthRatio,
2772 resShape[innerMostDim],
uArch);
2795 assert(consumerLayout.getRank() ==
static_cast<int64_t>(resShape.size()) &&
2796 "consumer layout rank must match source shape rank");
2801 const size_t innerMostDim = resShape.size() - 1;
2802 constexpr int ratio = 2;
2804 innerMostDim, ratio,
2805 resShape[innerMostDim],
uArch);
2824 for (
int64_t dim : llvm::reverse(dimGroup)) {
2825 int64_t tileSize = tileShape.empty() ? 1 : tileShape[dim];
2826 if (counts[dim] != 1) {
2827 if (stride * tileSize != expectedStride)
2829 expectedStride = stride * tileSize * counts[dim];
2831 stride *=
shape[dim];
2836xegpu::DistributeLayoutAttr
2838 VectorType srcVecTy, VectorType resVecTy,
2839 DistributeLayoutAttr consumerLayout) {
2842 return consumerLayout;
2848 return consumerLayout;
2851 consumerLayout.getEffectiveLaneLayoutAsInt();
2854 xegpu::DistributeLayoutAttr resLayout = [&]() -> DistributeLayoutAttr {
2855 DistributeLayoutAttr layout = consumerLayout;
2858 while (i < dimGroup.size() && laneLayout[dimGroup[i]] == 1)
2861 for (++i; i < dimGroup.size(); ++i) {
2863 int64_t dimSize = resShape[dim];
2864 int64_t lanes = laneLayout[dim];
2865 if (lanes <= 0 || dimSize % lanes != 0)
2866 return consumerLayout;
2868 layout.setDimData(dim, -1,
2869 instData.empty() ? -1 : dimSize, dimSize / lanes);
2887 int64_t collapsedLaneData = 1;
2889 collapsedLaneData *= resLaneData[dim];
2895 if (!resInstData.empty() &&
2908 VectorType resVectorTy, xegpu::DistributeLayoutAttr consumerLayout,
2911 xegpu::DistributeLayoutAttr requiredResLayout;
2913 consumerLayout.getEffectiveInstDataAsInt();
2915 consumerLayout.getEffectiveLaneDataAsInt();
2917 consumerLayout.getEffectiveLaneLayoutAsInt();
2921 requiredResLayout = consumerLayout;
2922 int srcRank = srcShape.size();
2926 assert(
false &&
"subgroup/instData layout assignment not supported for "
2927 "insertStridedSlice.");
2929 for (
int dim = 0; dim < srcRank; dim++) {
2931 if (srcShape[dim] == 1) {
2934 assert(srcShape[dim] % consumerLaneLayout[dim] == 0 &&
2935 "srcShape must be divisible by laneLayout for all dimensions");
2936 laneDataValue = std::min(srcShape[dim] / consumerLaneLayout[dim],
2937 consumerLaneData[dim]);
2940 requiredResLayout.setDimData(dim, -1, -1, laneDataValue);
2943 return requiredResLayout;
2953 OpOperand &operand, xegpu::DistributeLayoutAttr resLayout) {
2960 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op)) {
2961 auto srcTy = dyn_cast<VectorType>(
broadcast.getSourceType());
2965 resLayout,
broadcast.getResultVectorType().getShape(),
2972 if (
auto reduction = dyn_cast<vector::MultiDimReductionOp>(op)) {
2981 if (
auto reduction = dyn_cast<vector::ReductionOp>(op))
2986 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
2987 int resElemBitWidth =
2988 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
2989 int srcElemBitWidth =
2990 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
2997 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
2999 resLayout, shapeCast.getResultVectorType().getShape(),
3000 shapeCast.getSourceVectorType().getShape());
3005 if (
auto insertSlice = dyn_cast<vector::InsertStridedSliceOp>(op)) {
3008 resLayout, insertSlice.getDestVectorType().getShape(),
3009 insertSlice.getSourceVectorType().getShape());
3017 if (
auto insert = dyn_cast<vector::InsertOp>(op)) {
3018 VectorType resVecTy = dyn_cast<VectorType>(insert.getResult().getType());
3019 VectorType valueToStoreTy =
3020 dyn_cast<VectorType>(insert.getValueToStore().getType());
3022 if ((idx == 0) && valueToStoreTy) {
3024 valueToStoreTy.getShape());
3032 if (
auto extract = dyn_cast<vector::ExtractOp>(op)) {
3033 VectorType srcVecTy = dyn_cast<VectorType>(extract.getSource().getType());
3034 VectorType resVecTy = dyn_cast<VectorType>(extract.getResult().getType());
3035 if (!srcVecTy || !resVecTy)
3038 srcVecTy.getShape());
3043 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
3045 transpose.getPermutation());
3050 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
3051 int resElemBitWidth =
3052 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
3053 int srcElemBitWidth =
3054 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
3060 if (
auto interleave = dyn_cast<vector::InterleaveOp>(op)) {
3065 if (
auto deinterleave = dyn_cast<vector::DeinterleaveOp>(op)) {
3070 if (dyn_cast<vector::ExtractStridedSliceOp>(op))
3086 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
3087 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
3091 branch.getSuccessorOperandInputMapping(mapping,
3093 auto it = mapping.find(&operand);
3094 if (it == mapping.end())
3096 xegpu::DistributeLayoutAttr iterArgLayout;
3097 for (
auto arg : llvm::make_isa_range<BlockArgument>(it->second)) {
3099 assert((!iterArgLayout || !layout || iterArgLayout.isEqualTo(layout)) &&
3100 "region inputs fed by one terminator operand disagree on layout");
3102 iterArgLayout = layout;
3104 return iterArgLayout;
3110 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
3111 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
3115 branch.getSuccessorOperandInputMapping(mapping,
3117 auto it = mapping.find(&operand);
3118 if (it == mapping.end())
3120 for (
Value input : it->second)
3121 if (
auto result = dyn_cast<OpResult>(input))
3134 if (isa<xegpu::AnchorLayoutInterface>(op))
3142 if (isa<RegionBranchOpInterface>(op))
3147 if (
auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(op)) {
3154 xegpu::DistributeLayoutAttr resLayout;
3155 if (op->
getNumResults() == 1 || isa<vector::DeinterleaveOp>(op))
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
static xegpu::LayoutAttr buildLayout(mlir::MLIRContext *context, ArrayRef< int64_t > sgLayout, ArrayRef< int64_t > sgData, ArrayRef< int64_t > instData, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData, DenseI32ArrayAttr orderAttr=nullptr)
static xegpu::DistributeLayoutAttr getStoreSubgroupLayouts(mlir::MLIRContext *context, ArrayRef< int64_t > wgShape, ArrayRef< int64_t > instData, int numSg)
Picks the subgroup layout for a scatter-style store (store_scatter / store_matrix): the most balanced...
static xegpu::DistributeLayoutAttr createScaleLayout(mlir::MLIRContext *context, VectorType matrixTy, VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout, bool isBScale, const xegpu::uArch::uArch *uArch)
Helper to create a scale layout derived from a matrix operand layout.
static xegpu::DistributeLayoutAttr adjustInnermostDimForDivisibility(xegpu::DistributeLayoutAttr consumerLayout, xegpu::LayoutKind layoutKind, size_t innerMostDim, int ratio, int64_t bound, const xegpu::uArch::uArch *uArch)
Adjusts consumerLayout's innermost-dim data field selected by layoutKind so that the source layout ca...
static std::pair< SmallVector< int64_t >, SmallVector< int64_t > > computeScatterIOLaneLayoutAndData(ArrayRef< int64_t > instShape, int64_t subgroupSize, int64_t maxChunkSize)
Computes lane_layout and lane_data for scatter-style store anchor layouts (store scatter,...
static xegpu::LayoutAttr buildInstDataLayoutWithLane(mlir::MLIRContext *context, ArrayRef< int64_t > instData, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData, DenseI32ArrayAttr orderAttr=nullptr)
static xegpu::LayoutAttr buildSgLayout(mlir::MLIRContext *context, ArrayRef< int64_t > wgTileShape, ArrayRef< int64_t > sgLayout, int dimK=-1, DenseI32ArrayAttr orderAttr=nullptr)
static xegpu::DistributeLayoutAttr getParentResultLayoutForYieldOperand(RegionBranchTerminatorOpInterface terminator, OpOperand &operand)
static std::optional< SmallVector< int64_t > > get2DBlockIOInstDataLayout(ArrayRef< int64_t > dataShape, Type elemTy, const xegpu::uArch::BlockIOInstructionInterface *uArchInstruction, bool transform=false, bool transpose=false)
Helper function to compute inst_data vectors for DPAS operands A, B, and C/D.
static SmallVector< LayoutRepresentation > getSgLayoutCandidates(ArrayRef< int64_t > wgShape, ArrayRef< int64_t > instData, int64_t sgCount, int64_t broadcastDim=-1)
static std::optional< std::tuple< xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr > > getDpasSubgroupLayouts(mlir::MLIRContext *context, VectorType aTy, VectorType bTy, VectorType cdTy, xegpu::DistributeLayoutAttr consumerLayout, int numSg, std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > instDataVecs)
Helper function to set up subgroup layouts for DPAS operands A, B, and C/D.
static SmallVector< LayoutRepresentation > enumerateFactorizations(int64_t total, int64_t rank)
Enumerates all ways to split total into rank factors whose product equals total.
static xegpu::DistributeLayoutAttr setupGenericLoadAnchorLayout(xegpu::LayoutKind layoutKind, mlir::MLIRContext *context, xegpu::DistributeLayoutAttr consumerLayout, int maxChunkSize, ArrayRef< int64_t > resShape, int subgroupSize)
Sets up the anchor layout for load gather and load matrix operation.
static bool isContiguousTiling(ArrayRef< int64_t > dimGroup, ArrayRef< int64_t > shape, ArrayRef< int64_t > counts, ArrayRef< int64_t > tileShape, int64_t expectedStride)
Checks that the tiles a split group is cut into walk the collapsed source dim with one constant strid...
SmallVector< int64_t > LayoutRepresentation
static xegpu::DistributeLayoutAttr getLayoutFromUsePoints(Value result)
static xegpu::DistributeLayoutAttr setupGenericStoreAnchorLayout(xegpu::LayoutKind layoutKind, mlir::MLIRContext *context, int maxChunkSize, ArrayRef< int64_t > srcShape, int subgroupSize, int numSg)
Sets up the anchor layout for store scatter and store matrix operation, which share the same logic.
static std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > compute2DBlockIOLaneLayout(ArrayRef< int64_t > instShape, int64_t subgroupSize, int64_t bitwidth, int64_t packingSize, bool transform=false, bool transpose=false)
static xegpu::DistributeLayoutAttr getLoopCarriedLayoutForYieldOperand(RegionBranchTerminatorOpInterface terminator, OpOperand &operand)
static void propagateResultsToRegularOperands(Operation *op)
static void propagateRegionResultsToYieldOperands(mlir::RegionBranchTerminatorOpInterface yieldOp)
static bool isValidLaneLayout(ArrayRef< int64_t > dataShape, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData)
static void setTensorDescLayout(Value val, xegpu::DistributeLayoutAttr layout)
static std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > computeReductionLaneLayoutAndData(ArrayRef< int64_t > srcShape, ArrayRef< int64_t > reductionDims, int subgroupSize, int64_t maxReduceVectorSize, xegpu::DistributeLayoutAttr consumerLayout=nullptr)
Computes a multi_reduction's source layout as (lane_layout, lane_data, inst_data),...
static void walkRegionBackward(Region ®ion, llvm::function_ref< void(Operation *)> visit)
static xegpu::LayoutAttr buildLaneLayout(mlir::MLIRContext *context, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData, DenseI32ArrayAttr orderAttr=nullptr)
static std::optional< std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > > getDpasInstDataLayouts(VectorType aTy, VectorType bTy, VectorType cdTy, const xegpu::uArch::MMAInstructionInterface *uArchInstruction)
Helper function to compute inst_data vectors for DPAS operands A, B, and C/D.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
MLIRContext is the top-level object for a collection of MLIR operations.
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.
This class implements the operand iterators for the Operation class.
unsigned getBeginOperandIndex() const
Return the operand index of the first element of this range.
type_range getType() const
void walkInherentAttrs(Operation *op, InherentAttrVisitor visitor) const
Visit the inherent attributes stored in the properties of op.
Operation is the basic unit of execution within MLIR.
bool hasDiscardableAttrOfType(NameT &&name)
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
unsigned getNumRegions()
Returns the number of regions held by this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
MutableArrayRef< OpOperand > getOpOperands()
OperationName getName()
The name of an operation is the key identifier for it.
DictionaryAttr getDiscardableAttrDictionary()
Return all of the discardable attributes on this operation as a DictionaryAttr.
Attribute removeDiscardableAttr(StringAttr name)
Remove the discardable attribute with the specified name if it exists.
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),...
unsigned getNumResults()
Return the number of results held by this operation.
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
This class represents a successor of a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
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.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
void setType(Type newType)
Mutate the type of this Value to be of the specified type.
Type getType() const
Return the type of this value.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
Operation * getOwner() const
Return the owner of this operand.
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
@ Subgroup2DBlockPrefetch
@ SubgroupMatrixMultiplyAcc
@ SubgroupScaledMatrixMultiplyAcc
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,...
bool matchDimCollapse(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &collapseDims)
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...
DistributeLayoutAttr inferInsertSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for an insert operation.
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...
SmallVector< NamedAttribute > dropInstDataOnAttrs(ArrayRef< NamedAttribute > attrs)
Updates the NamedAttribute sequence by dropping inst-data information from any DistributeLayoutAttr f...
DistributeLayoutAttr inferSourceLayoutFromResultForNonAnchorOp(OpOperand &operand, DistributeLayoutAttr resLayout)
Infers the source layout attribute for an operand using result layout attribute.
DistributeLayoutAttr inferInterleaveSourceLayout(DistributeLayoutAttr resLayout)
Infers the source layout attribute for an interleave operation given the result layout attribute.
bool matchUnitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< int64_t > &expandedUnitDims)
int getLargestDivisor(T dim, ArrayRef< T > candidates, ArrayRef< T > candidateMultiples={})
Helper Function to find a proper instruction multiple for the user-supplied sg-level data shape (dive...
bool recoverTemporaryLayouts(Operation *rootOp)
Attach layout attributes to all vector-type operands of operations within the given operation's neste...
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.
llvm::function_ref< DistributeLayoutAttr(Value)> GetLayoutFnTy
Callable returning the propagated layout for a given Value, used by the layout-propagation helpers be...
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...
bool matchSplitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &splitDimGroups)
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.
void dropInstDataOnInherentAttrs(Operation *op)
Drops inst-data information from DistributeLayoutAttrs stored as inherent attributes on the operation...
DistributeLayoutAttr getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value, or nullptr if none is found.
SmallVector< NamedAttribute > dropSgLayoutAndDataOnAttrs(ArrayRef< NamedAttribute > attrs)
Updates the NamedAttribute sequence by dropping sg-layout and sg-data information from any Distribute...
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...
DistributeLayoutAttr inferShapeCastResultLayout(DistributeLayoutAttr srcLayout, ArrayRef< int64_t > srcShape, ArrayRef< int64_t > resShape)
Infers the result layout attribute for a shape cast operation given the source layout attribute,...
DistributeLayoutAttr inferExtractSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for an extract operation.
std::string getTemporaryLayoutName(const OpOperand &operand)
Return the attribute name for the OpOperand to attach DistributeLayoutAttr.
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...
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)...
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.
void removeLayoutAttrs(Operation *op)
Removes the DistributeLayoutAttr for each OpOperand and OpResult of the given operation if they exist...
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,...
DistributeLayoutAttr setupStoreNdAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a store_nd operation.
DistributeLayoutAttr inferTransposeResultLayout(DistributeLayoutAttr srcLayout, ArrayRef< int64_t > permutation)
Infers the result layout attribute for a transpose operation given the source layout attribute and pe...
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.
DenseMap< OpOperand *, SmallVector< Value > > RegionBranchSuccessorMapping
A mapping from successor operands to successor inputs.
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
int64_t computeProduct(ArrayRef< int64_t > basis)
Self-explicit.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
std::optional< SmallVector< int64_t > > computeShapeRatio(ArrayRef< int64_t > shape, ArrayRef< int64_t > subShape)
Return the multi-dimensional integral ratio of subShape to the trailing dimensions of shape.
SmallVector< int64_t > invertPermutationVector(ArrayRef< int64_t > permutation)
Helper method to apply to inverse a permutation.
virtual int32_t getPackedFormatBitSize() const =0
std::optional< BlockShapes > getBlockWidthHeightCount(Type elemTy, bool hasTransform=false, bool hasTranspose=false, bool upConv=false) const
int32_t getMaxLaneAccessSizeBytes() const override
virtual llvm::SmallVector< uint32_t, 8 > getSupportedN(Type type) const =0
virtual llvm::SmallVector< uint32_t, 8 > getSupportedK(Type type) const =0
virtual llvm::SmallVector< uint32_t, 8 > getSupportedM(Type type) const =0
int32_t getMaxLaneAccessSizeBytes() const override
virtual unsigned getGeneralPackedFormatBitSize() const =0
virtual int getSubgroupSize() const =0
const Instruction * getInstruction(InstructionKind instKind) const