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);
76 auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(val.
getType());
77 if (!tensorDescTy || tensorDescTy.getLayoutAttr())
79 auto typeWithLayout = xegpu::TensorDescType::get(
80 tensorDescTy.getContext(), tensorDescTy.getShape(),
81 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
96 llvm::ReversePostOrderTraversal<Region *> rpot(®ion);
98 for (
Block *block : llvm::reverse(blocks)) {
100 for (
Operation &op : llvm::reverse(*block)) {
108 for (
Region &nested : op.getRegions())
117 xegpu::DistributeLayoutAttr layout =
nullptr;
152 if (op->
getNumResults() > 1 && !isa<vector::DeinterleaveOp>(op))
163 if (isa<xegpu::TensorDescType>(resultType))
168 if (isa<VectorType>(resultType) || isa<vector::MultiDimReductionOp>(op))
171 if (isa<vector::DeinterleaveOp>(op))
175 xegpu::DistributeLayoutAttr operandLayout =
177 if (isa<VectorType>(opr.get().getType()) && operandLayout)
189 mlir::RegionBranchTerminatorOpInterface yieldOp) {
190 auto regionBranchOp =
191 dyn_cast<RegionBranchOpInterface>(yieldOp->getParentOp());
197 yieldOp.getSuccessorRegions(operandAttrs, successors);
200 OperandRange succOps = yieldOp.getSuccessorOperands(successor);
204 ValueRange successorInputs = regionBranchOp.getSuccessorInputs(successor);
205 unsigned count = std::min<unsigned>(succOps.size(), successorInputs.size());
207 for (
unsigned i = 0; i < count; ++i) {
208 xegpu::DistributeLayoutAttr layout;
209 if (successor.isOperation()) {
212 auto regionResult = regionBranchOp->getResult(i);
217 if (isa<xegpu::TensorDescType>(regionResult.getType()))
228 auto operandType = succOps[i].
getType();
229 if (isa<VectorType>(operandType) ||
230 dyn_cast<xegpu::TensorDescType>(operandType))
247 for (
Region ®ion : regionOp->getRegions()) {
252 ValueRange successorInputs = regionOp.getSuccessorInputs(regionSuccessor);
253 for (
auto [inputIdx, regionArg] : llvm::enumerate(successorInputs)) {
254 auto layout = getLayoutOfValue(regionArg);
259 if (isa<xegpu::TensorDescType>(regionArg.getType()))
265 regionOp.getPredecessorValues(regionSuccessor, inputIdx, predValues);
266 for (
Value predVal : predValues) {
268 for (
OpOperand &operand : regionOp->getOpOperands()) {
269 if (operand.get() == predVal)
308 auto processFunc = [&](
Region &body, StringRef funcName) {
310 if (
auto regionOp = dyn_cast<mlir::RegionBranchOpInterface>(op)) {
313 }
else if (
auto yieldOp =
314 dyn_cast<mlir::RegionBranchTerminatorOpInterface>(op)) {
316 }
else if (!dyn_cast<xegpu::AnchorLayoutInterface>(op)) {
322 rootOp->
walk([&](func::FuncOp
func) {
323 processFunc(
func.getBody(),
func.getSymName());
325 rootOp->
walk([&](gpu::GPUFuncOp
func) {
326 processFunc(
func.getBody(),
func.getName());
332template <
typename T,
typename>
334 Operation *owner = operandOrResult.getOwner();
352 for (
auto namedAttr : nestOp->
getAttrs()) {
353 if (isa<DistributeLayoutAttr>(namedAttr.getValue()))
354 attrsToRemove.push_back(namedAttr.getName());
356 for (
auto attrName : attrsToRemove)
365 if (isa<xegpu::DistributeLayoutAttr>(namedAttr.getValue()))
366 attrsToRemove.push_back(namedAttr.getName());
368 for (
auto attrName : attrsToRemove)
377 int numLeading =
static_cast<int>(
shape.size()) - numInnerDims;
380 return llvm::all_of(
shape.take_front(numLeading),
381 [](
int64_t dim) { return dim == 1; });
388 auto toI32Attr = [&](
auto range) {
392 return xegpu::LayoutAttr::get(context,
nullptr,
393 nullptr, toI32Attr(instData),
394 toI32Attr(laneLayout), toI32Attr(laneData),
401 return !llvm::any_of(llvm::seq<int>(0, dataShape.size()), [&](
int dim) {
402 return dataShape[dim] % (laneLayout[dim] * laneData[dim]) != 0;
406static xegpu::LayoutAttr
410 auto toI32Attr = [&](
auto range) {
414 return xegpu::LayoutAttr::get(context,
nullptr,
416 nullptr, toI32Attr(laneLayout),
417 toI32Attr(laneData), orderAttr);
420static xegpu::LayoutAttr
425 auto toI32Attr = [&](
auto range) {
429 return xegpu::LayoutAttr::get(
430 context, sgLayout.empty() ?
nullptr : toI32Attr(sgLayout),
431 sgData.empty() ?
nullptr : toI32Attr(sgData),
432 instData.empty() ?
nullptr : toI32Attr(instData),
433 laneLayout.empty() ?
nullptr : toI32Attr(laneLayout),
434 laneData.empty() ?
nullptr : toI32Attr(laneData), orderAttr);
443 for (
int dim = 0; dim < (int)sgLayout.size(); ++dim) {
445 sgData[dim] = wgTileShape[dim];
447 sgData[dim] = wgTileShape[dim] / sgLayout[dim];
456xegpu::DistributeLayoutAttr
462 size_t dimDiff = resShape.size() - srcShape.size();
463 auto bcastSourceLayout = resLayout;
466 for (
size_t i = dimDiff; i < resShape.size(); i++) {
467 if ((srcShape[i - dimDiff] == 1) && (resShape[i] != 1))
468 bcastDims.push_back(i);
473 if (!bcastDims.empty())
474 bcastSourceLayout = bcastSourceLayout.setUnitDimData(bcastDims);
479 bool isOuterDimDiffUnitDims = llvm::all_of(
480 resShape.take_front(dimDiff), [&](
int64_t dim) { return dim == 1; });
481 if (dimDiff && bcastDims.size() == dimDiff && isOuterDimDiffUnitDims) {
484 sliceDims.assign(bcastDims.begin(), bcastDims.end());
488 llvm::append_range(sliceDims, llvm::seq<int64_t>(0, dimDiff));
490 bcastSourceLayout = xegpu::SliceAttr::get(
491 resLayout.getContext(), bcastSourceLayout,
494 return bcastSourceLayout;
499xegpu::DistributeLayoutAttr
503 assert(isa<xegpu::SliceAttr>(resLayout) &&
504 "reduction result layout must be slice layout");
506 xegpu::SliceAttr sliceLayout = dyn_cast<xegpu::SliceAttr>(resLayout);
508 assert((reduceDims == sliceLayout.getDims().asArrayRef()) &&
509 "reduction dims must match with slice dims");
511 return sliceLayout.getParent();
514xegpu::DistributeLayoutAttr
525xegpu::DistributeLayoutAttr
536xegpu::DistributeLayoutAttr
538 int resElemTyBitWidth,
int srcElemTyBitWidth) {
543 size_t sgDataSize = sgData.size();
544 size_t instDataSize = instData.size();
545 size_t laneDataSize = laneData.size();
549 int64_t dim = resLayout.getRank() - 1;
551 if (srcElemTyBitWidth <= resElemTyBitWidth) {
552 int bitWidthRatio = resElemTyBitWidth / srcElemTyBitWidth;
554 sgDataValue = sgData.back() * bitWidthRatio;
556 instDataValue = instData.back() * bitWidthRatio;
558 laneDataValue = laneData.back() * bitWidthRatio;
560 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
562 assert((sgData.back() % bitWidthRatio) == 0 &&
563 "sgData not divisible by bitWidthRatio");
564 sgDataValue = sgData.back() / bitWidthRatio;
567 assert((instData.back() % bitWidthRatio) == 0 &&
568 "instData not divisible by bitWidthRatio");
569 instDataValue = instData.back() / bitWidthRatio;
572 assert((laneData.back() % bitWidthRatio) == 0 &&
573 "laneData not divisible by bitWidthRatio");
574 laneDataValue = laneData.back() / bitWidthRatio;
578 xegpu::DistributeLayoutAttr finalSrcLayout;
580 resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
582 return finalSrcLayout;
589xegpu::DistributeLayoutAttr
595 size_t sgDataSize = sgData.size();
596 size_t instDataSize = instData.size();
597 size_t laneDataSize = laneData.size();
601 int64_t dim = resLayout.getRank() - 1;
605 constexpr int ratio = 2;
607 assert((sgData.back() % ratio) == 0 &&
608 "sgData not divisible by interleave ratio");
609 sgDataValue = sgData.back() / ratio;
612 assert((instData.back() % ratio) == 0 &&
613 "instData not divisible by interleave ratio");
614 instDataValue = instData.back() / ratio;
617 assert((laneData.back() % ratio) == 0 &&
618 "laneData not divisible by interleave ratio");
619 laneDataValue = laneData.back() / ratio;
622 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
629xegpu::DistributeLayoutAttr
635 size_t sgDataSize = sgData.size();
636 size_t instDataSize = instData.size();
637 size_t laneDataSize = laneData.size();
641 int64_t dim = resLayout.getRank() - 1;
645 constexpr int ratio = 2;
647 sgDataValue = sgData.back() * ratio;
649 instDataValue = instData.back() * ratio;
651 laneDataValue = laneData.back() * ratio;
653 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
663 int srcShapeSize = srcShape.size();
664 int resShapeSize = resShape.size();
665 int dimDiff = resShapeSize - srcShapeSize;
670 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
671 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
672 for (
int i = 0; i < dimDiff; i++) {
673 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
674 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
675 "Leading dimensions being sliced off must not be distributed");
677 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
686xegpu::DistributeLayoutAttr
691 int srcShapeSize = srcShape.size();
692 int resShapeSize = resShape.size();
693 int dimDiff = resShapeSize - srcShapeSize;
698 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
699 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
700 for (
int i = 0; i < dimDiff; i++) {
701 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
702 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
703 "Leading dimensions being sliced off must not be distributed");
705 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
715xegpu::DistributeLayoutAttr
720 int srcShapeSize = srcShape.size();
721 int resShapeSize = resShape.size();
722 int dimDiff = srcShapeSize - resShapeSize;
723 auto context = resLayout.getContext();
727 auto sgLayout = resLayout.getEffectiveSgLayoutAsInt();
728 auto sgData = resLayout.getEffectiveSgDataAsInt();
729 auto instData = resLayout.getEffectiveInstDataAsInt();
730 auto laneLayout = resLayout.getEffectiveLaneLayoutAsInt();
731 auto laneData = resLayout.getEffectiveLaneDataAsInt();
732 auto order = resLayout.getEffectiveOrderAsInt();
742 for (
auto &o : order)
748 for (
int i = 0; i < dimDiff; i++) {
749 if (!sgLayout.empty())
750 sgLayout.insert(sgLayout.begin(), 1);
752 sgData.insert(sgData.begin(), 1);
753 if (!instData.empty())
754 instData.insert(instData.begin(), 1);
755 if (!laneLayout.empty())
756 laneLayout.insert(laneLayout.begin(), 1);
757 if (!laneData.empty())
758 laneData.insert(laneData.begin(), 1);
759 order.push_back(dimDiff - 1 - i);
764 if (!resLayout.getOrder())
767 return buildLayout(context, sgLayout, sgData, instData, laneLayout,
768 laneData, orderAttr);
775xegpu::DistributeLayoutAttr
799 xegpu::SliceAttr::get(resLayout.getContext(), resLayout, sliceDimsAttr);
806 auto srcLayout = resLayout;
807 for (
const auto &dimGroup : splitDimGroups)
808 srcLayout = srcLayout.collapseDims(dimGroup);
817 auto srcLayout = resLayout;
818 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
819 dstIdx >= 0; --dstIdx) {
821 if (srcDims.empty()) {
822 srcLayout = srcLayout.dropDims({dstIdx});
825 if (srcDims.size() == 1)
828 targetShape.reserve(srcDims.size());
830 targetShape.push_back(srcShape[d]);
831 srcLayout = srcLayout.expandDim(dstIdx, targetShape);
841 xegpu::DistributeLayoutAttr payloadLayout,
int chunkSize) {
842 auto rank = payloadLayout.getRank();
844 return payloadLayout.dropDims(
845 llvm::to_vector(llvm::seq<int64_t>(rank - 1, rank)));
846 return payloadLayout;
866 auto getDivisors = [](
int64_t n) {
868 for (
int64_t i = 1; i * i <= n; ++i) {
872 divs.push_back(n / i);
881 if (dim == rank - 1) {
882 current[dim] = remaining;
886 for (
int64_t factor : getDivisors(remaining)) {
887 current[dim] = factor;
888 generate(dim + 1, remaining / factor);
910 assert(rank > 0 &&
"wgShape must be non-empty");
911 assert(
static_cast<int64_t>(instData.size()) == rank &&
912 "instData rank must match wgShape rank");
919 for (
const auto &sgLayout : allFactorizations) {
921 for (
int64_t dim = 0; dim < rank; ++dim) {
922 if (wgShape[dim] % sgLayout[dim] != 0) {
926 int64_t sgData = wgShape[dim] / sgLayout[dim];
927 if (sgData % instData[dim] != 0) {
933 candidates.push_back(sgLayout);
939 int64_t spreadLhs = *llvm::max_element(
lhs) - *llvm::min_element(
lhs);
940 int64_t spreadRhs = *llvm::max_element(
rhs) - *llvm::min_element(
rhs);
941 if (spreadLhs != spreadRhs)
942 return spreadLhs < spreadRhs;
953 bool transform =
false,
bool transpose =
false) {
954 int rank = dataShape.size();
959 auto [bWidths, bHeights, bCounts] = blockWHC.value();
965 assert(rank >= 2 &&
"dataShape must be at least 2D for 2D-block IO");
970 instData.back() = instWidth;
971 instData[rank - 2] = instHeight;
982 VectorType aTy, VectorType bTy, VectorType cdTy,
986 const unsigned dataALen = aTy.getShape()[aTy.getRank() - 2];
987 auto supportedALen = uArchInstruction->
getSupportedM(aTy.getElementType());
992 const unsigned dataBLen = bTy.getShape().back();
993 auto supportedBLen = uArchInstruction->
getSupportedN(bTy.getElementType());
997 auto supportedCLen = uArchInstruction->
getSupportedN(cdTy.getElementType());
1000 if (maxALen == -1 || maxBLen == -1 || maxCLen == -1)
1001 return std::nullopt;
1003 auto supportedKLen = uArchInstruction->
getSupportedK(aTy.getElementType());
1004 if (supportedKLen.empty())
1005 return std::nullopt;
1006 auto kDimSize = supportedKLen[0];
1009 instDataA[aTy.getRank() - 2] = maxALen;
1010 instDataA[aTy.getRank() - 1] = kDimSize;
1012 instDataB[bTy.getRank() - 2] = kDimSize;
1013 instDataB[bTy.getRank() - 1] = maxBLen;
1015 instDataCD[cdTy.getRank() - 2] = maxALen;
1016 instDataCD[cdTy.getRank() - 1] = maxCLen;
1017 return std::make_tuple(instDataA, instDataB, instDataCD);
1030 int64_t rank = instShape.size();
1033 laneLayout[innermost] = std::min(subgroupSize, instShape[innermost]);
1034 laneData[innermost] =
1035 std::min(instShape[innermost] / laneLayout[innermost], maxChunkSize);
1036 return {laneLayout, laneData};
1046 int64_t rank = instShape.size();
1048 int kDim =
transform ? rank - 2 : rank - 1;
1049 unsigned vnniFactor = packingSize / bitwidth;
1050 laneData[kDim] = bitwidth < packingSize ? vnniFactor : 1;
1052 std::min(subgroupSize, instShape.back() / laneData.back());
1055 for (
int64_t i = 0; i < rank; ++i) {
1056 int64_t laneProduct = laneLayout[i] * laneData[i];
1057 assert(instShape[i] % laneProduct == 0 &&
1058 "lane_layout * lane_data must evenly divide the inst shape");
1061 return {laneLayout, laneData};
1080 int subgroupSize,
int64_t maxReduceVectorSize,
1081 bool verticalLaneLayout =
false) {
1082 int srcRank = srcShape.size();
1085 int innermost = srcRank - 1;
1086 int secondInnermost = srcRank - 2;
1088 if (verticalLaneLayout && secondInnermost >= 0) {
1089 std::swap(innermost, secondInnermost);
1091 int laneDim = innermost;
1092 int vectorDim = secondInnermost;
1094 laneLayout[laneDim] =
1095 std::min(
static_cast<int64_t>(subgroupSize), srcShape[laneDim]);
1097 laneData[vectorDim] = std::min(maxReduceVectorSize, srcShape[vectorDim]);
1099 return {laneLayout, laneData};
1165static std::optional<
1166 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1167 xegpu::DistributeLayoutAttr>>
1170 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1173 auto [instDataA, instDataB, instDataCD] = instDataVecs;
1175 std::optional<LayoutRepresentation> consumerSgLayout = std::nullopt;
1176 if (consumerLayout && consumerLayout.isForWorkgroup()) {
1177 consumerSgLayout = consumerLayout.getEffectiveSgLayoutAsInt();
1184 if (layoutsA.empty() || layoutsB.empty() || layoutsCD.empty())
1185 return std::nullopt;
1188 std::optional<LayoutRepresentation> bestPick;
1190 return aTy.getShape().back() / sgLayout[1] ==
1191 bTy.getShape().front() / sgLayout[0];
1193 for (
auto &sgLayout : layoutsB) {
1194 if (llvm::is_contained(layoutsA, sgLayout) &&
1195 llvm::is_contained(layoutsCD, sgLayout)) {
1196 if (!checkAlignedSgDataAB(sgLayout))
1199 if (consumerSgLayout.has_value() && sgLayout == *consumerSgLayout) {
1200 bestPick = sgLayout;
1208 bestPick = sgLayout;
1212 return std::nullopt;
1214 const auto &picked = *bestPick;
1216 auto dpasALayout =
buildSgLayout(context, aTy.getShape(), picked,
1218 auto dpasBLayout =
buildSgLayout(context, bTy.getShape(), picked,
1220 auto dpasCDLayout =
buildSgLayout(context, cdTy.getShape(), picked);
1221 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout);
1228 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1229 xegpu::DistributeLayoutAttr>>
1231 VectorType bTy, VectorType cdTy,
1232 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1234 auto context = aTy.getContext();
1235 const auto *uArchInstruction =
1236 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1238 if (!uArchInstruction)
1239 return std::nullopt;
1243 aTy.getShape(), subgroupSize,
1244 aTy.getElementType().getIntOrFloatBitWidth(),
1245 uArchInstruction->getPackedFormatBitSizeA());
1247 bTy.getShape(), subgroupSize,
1248 bTy.getElementType().getIntOrFloatBitWidth(),
1249 uArchInstruction->getPackedFormatBitSizeB(),
true);
1251 cdTy.getShape(), subgroupSize,
1252 cdTy.getElementType().getIntOrFloatBitWidth(),
1253 cdTy.getElementType().getIntOrFloatBitWidth());
1257 return std::nullopt;
1261 "Number of subgroups must be provided for sg layout creation.");
1263 numSg, *instDataVecs);
1265 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1266 return std::make_tuple(
1275 return std::make_tuple(aLayout, bLayout, cdLayout);
1277 return std::nullopt;
1284static xegpu::DistributeLayoutAttr
1286 VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout,
1288 if (!scaleTy || !matrixLayout)
1296 if (scaleShape.empty())
1299 auto uArchInstruction =
1300 dyn_cast<xegpu::uArch::SubgroupScaledMatrixMultiplyAcc>(
1304 int64_t rank = matrixLayout.getRank();
1305 assert(rank >= 2 &&
"dpas layouts must be at least two dimensions");
1312 auto order = matrixLayout.getOrder();
1316 if (!sgLayout.empty() && !sgData.empty()) {
1317 scaleSgLayout.assign(sgLayout.begin(), sgLayout.end());
1318 scaleSgData.assign(sgData.begin(), sgData.end());
1319 scaleSgData[rank - 2] = std::max<int64_t>(
1320 scaleShape[rank - 2] / (matrixShape[rank - 2] / sgData[rank - 2]), 1);
1321 scaleSgData[rank - 1] = std::max<int64_t>(
1322 scaleShape[rank - 1] / (matrixShape[rank - 1] / sgData[rank - 1]), 1);
1329 if (!instData.empty()) {
1330 scaleInstData.assign(instData.begin(), instData.end());
1332 scaleInstData[rank - 2] = std::max<int64_t>(
1333 scaleShape[rank - 2] / (matrixShape[rank - 2] / instData[rank - 2]),
1336 scaleInstData[rank - 1] = std::max<int64_t>(
1337 scaleShape[rank - 1] / (matrixShape[rank - 1] / instData[rank - 1]),
1343 if (!laneLayout.empty() && !laneData.empty()) {
1344 scaleLaneLayout.assign(laneLayout.begin(), laneLayout.end());
1345 scaleLaneData.assign(laneData.size(), 1);
1347 bool isRowMajor = uArchInstruction->isLaneLayoutRowMajorOrder();
1348 if (isBScale ^ isRowMajor)
1349 std::swap(scaleLaneLayout[rank - 2], scaleLaneLayout[rank - 1]);
1354 auto layoutCap = scaleInstData.empty() ? scaleShape : scaleInstData;
1355 for (
int64_t d = rank - 2; d < rank; ++d)
1356 scaleLaneLayout[d] = std::min<int64_t>(layoutCap[d], scaleLaneLayout[d]);
1358 return buildLayout(context, scaleSgLayout, scaleSgData, scaleInstData,
1359 scaleLaneLayout, scaleLaneData, order);
1366 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1367 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1368 xegpu::DistributeLayoutAttr>>
1370 VectorType bTy, VectorType cdTy, VectorType aScaleTy,
1371 VectorType bScaleTy,
1372 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1374 auto context = aTy.getContext();
1375 const auto *uArchInstruction =
1376 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1378 if (!uArchInstruction)
1379 return std::nullopt;
1383 aTy.getShape(), subgroupSize,
1384 aTy.getElementType().getIntOrFloatBitWidth(),
1385 uArchInstruction->getPackedFormatBitSizeA());
1387 bTy.getShape(), subgroupSize,
1388 bTy.getElementType().getIntOrFloatBitWidth(),
1389 uArchInstruction->getPackedFormatBitSizeB(),
true);
1391 cdTy.getShape(), subgroupSize,
1392 cdTy.getElementType().getIntOrFloatBitWidth(),
1393 cdTy.getElementType().getIntOrFloatBitWidth());
1396 return std::nullopt;
1400 "Number of subgroups must be provided for sg layout creation.");
1402 context, aTy, bTy, cdTy, consumerLayout, numSg, *instDataVecs);
1404 return std::nullopt;
1406 auto [dpasALayout, dpasBLayout, dpasCDLayout] = *dpasLayouts;
1415 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1419 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1426 laneLayoutCD, laneDataCD);
1433 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1438 auto dpasCDLayout =
buildLaneLayout(context, laneLayoutCD, laneDataCD);
1445 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1448 return std::nullopt;
1454xegpu::DistributeLayoutAttr
1456 VectorType srcVecTy,
int numSg,
1458 const auto *uArchInstruction =
1459 dyn_cast<xegpu::uArch::Subgroup2DBlockStoreInstruction>(
1460 uArch->getInstruction(
1462 if (!uArchInstruction)
1465 auto context = srcVecTy.getContext();
1466 Type elemTy = srcVecTy.getElementType();
1467 auto subgroupSize =
uArch->getSubgroupSize();
1468 auto dataShape = srcVecTy.getShape();
1469 [[maybe_unused]]
int rank = srcVecTy.getRank();
1470 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1475 dataShape, subgroupSize, bitwidth,
1476 uArchInstruction->getPackedFormatBitSize());
1486 "Expected the store layout to satisfy uArch block constraints");
1493 "Number of subgroups must be provided for sg layout creation.");
1495 if (sgLayouts.empty())
1497 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1506xegpu::DistributeLayoutAttr
1508 xegpu::TensorDescType tdescTy,
int numSg,
1511 const auto *uArchInstruction =
1512 dyn_cast<xegpu::uArch::Subgroup2DBlockPrefetchInstruction>(
1515 if (!uArchInstruction)
1518 auto context = tdescTy.getContext();
1519 Type elemTy = tdescTy.getElementType();
1521 auto dataShape = tdescTy.getShape();
1522 [[maybe_unused]]
int rank = tdescTy.getRank();
1523 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1528 dataShape, subgroupSize, bitwidth,
1529 uArchInstruction->getPackedFormatBitSize());
1539 "Expected the prefetch layout to satisfy uArch block constraints");
1546 "Number of subgroups must be provided for sg layout creation.");
1548 if (sgLayouts.empty())
1550 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1561xegpu::DistributeLayoutAttr
1563 VectorType resVecTy,
1564 xegpu::DistributeLayoutAttr consumerLayout,
1567 assert(consumerLayout &&
"Expected a valid consumer layout");
1569 assert(consumerLayout.isForWorkgroup() &&
1570 "Expected consumer layout to be a complete workgroup-level layout");
1571 return consumerLayout;
1574 auto context = resVecTy.getContext();
1575 Type elemTy = resVecTy.getElementType();
1577 auto dataShape = resVecTy.getShape();
1578 const auto *uArchInstruction =
1579 dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
1582 if (!uArchInstruction)
1585 int rank = resVecTy.getRank();
1587 consumerLayout.getEffectiveInstDataAsInt();
1589 consumerLayout.getEffectiveLaneLayoutAsInt();
1591 consumerLayout.getEffectiveLaneDataAsInt();
1592 auto consumerOrderAttr = consumerLayout.getOrder();
1594 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1595 "Expected consumer layout to have lane_layout and lane_data");
1601 consumerLaneLayout[rank - 2] > 1 && consumerLaneLayout[rank - 1] == 1;
1602 bool hasTransform = !hasTranspose && consumerLaneData[rank - 2] > 1 &&
1603 consumerLaneData[rank - 1] == 1;
1604 assert((consumerLaneData[rank - 2] == 1 || consumerLaneData[rank - 1] == 1) &&
1605 "Expected consumer lane data to have at most one non-unit dim");
1608 auto blockWHC = uArchInstruction->getBlockWidthHeightCount(
1609 elemTy, hasTransform, hasTranspose,
1613 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1619 for (
int i = 0; i < rank; i++) {
1620 if (consumerLaneLayout[i] > 1)
1621 laneLayout.push_back(std::max(
static_cast<int64_t>(subgroupSize),
1622 consumerLaneLayout[i]));
1624 laneLayout.push_back(1);
1628 int64_t height = consumerInstData[rank - 2];
1629 int64_t width = consumerInstData[rank - 1];
1630 auto maxBlockCount = *llvm::max_element(bCounts);
1631 auto maxWidth = *llvm::max_element(bWidths);
1632 if (llvm::is_contained(bWidths,
static_cast<int>(width)) ||
1633 (width % maxWidth == 0 && width / maxWidth < maxBlockCount)) {
1634 if (llvm::is_contained(bHeights,
static_cast<int>(height))) {
1636 laneLayout, consumerLaneData,
1644 dataShape, elemTy, uArchInstruction, hasTransform, hasTranspose);
1649 "Expected the load layout to satisfy uArch block constraints");
1651 consumerLaneData, consumerOrderAttr);
1655 "Expected the lane layout to satisfy uArch block constraints");
1656 return consumerLayout;
1676 xegpu::DistributeLayoutAttr consumerLayout,
int maxChunkSize,
1680 return consumerLayout;
1683 consumerLayout.getEffectiveInstDataAsInt();
1685 consumerLayout.getEffectiveLaneLayoutAsInt();
1687 consumerLayout.getEffectiveLaneDataAsInt();
1694 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1695 "Expected consumer layout to have lane_layout and lane_data");
1696 laneLayout.assign(consumerLaneLayout.begin(), consumerLaneLayout.end());
1697 laneData.assign(consumerLaneData.begin(), consumerLaneData.end());
1703 if (!consumerInstData.empty()) {
1704 instData.assign(consumerInstData.begin(), consumerInstData.end());
1706 instData.resize(resShape.size());
1707 for (
size_t i = 0; i < resShape.size(); ++i)
1708 instData[i] = laneLayout[i] * laneData[i];
1720 xegpu::DistributeLayoutAttr consumerLayout,
const uArch::uArch *uArch) {
1722 const int subgroupSize = uArch->getSubgroupSize();
1724 auto context = resVecTy.getContext();
1726 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
1729 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
1732 maxChunkSize, resShape, subgroupSize);
1737xegpu::DistributeLayoutAttr
1739 VectorType resVecTy,
int contigChunkSize,
1740 xegpu::DistributeLayoutAttr consumerLayout,
1745 auto context = resVecTy.getContext();
1747 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
1750 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
1752 maxChunkSize, resShape, subgroupSize);
1762static xegpu::DistributeLayoutAttr
1769 "subgroup layout assignment not supported for storeScatter.");
1773 auto [laneLayout, laneData] =
1778 for (
size_t i = 0; i < srcShape.size(); ++i)
1779 instData[i] = laneLayout[i] * laneData[i];
1789xegpu::DistributeLayoutAttr
1791 VectorType srcVecTy,
int contigChunkSize,
1794 const int subgroupSize =
uArch->getSubgroupSize();
1796 auto context = srcVecTy.getContext();
1798 const auto *uArchInstruction =
1799 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
1802 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
1804 srcShape, subgroupSize);
1808xegpu::DistributeLayoutAttr
1810 VectorType srcVecTy,
int contigChunkSize,
1813 const int subgroupSize =
uArch->getSubgroupSize();
1815 auto context = srcVecTy.getContext();
1817 const auto *uArchInstruction =
1818 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
1821 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
1824 srcShape, subgroupSize);
1842std::optional<xegpu::DistributeLayoutAttr>
1844 xegpu::DistributeLayoutAttr specifiedLayout,
1845 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
1847 const int subgroupSize) {
1848 if (!specifiedLayout)
1849 return specifiedLayout;
1851 specifiedLayout.getEffectiveInstDataAsInt();
1852 if (specifiedInstData.empty())
1853 return specifiedLayout;
1854 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
1855 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
1856 return specifiedLayout;
1859 auto *context = specifiedLayout.getContext();
1861 if (consumerLayout) {
1862 auto consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
1863 auto consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
1864 if (!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1868 consumerLaneLayout, consumerLaneData);
1871 specifiedInstData, subgroupSize, maxChunkSize);
1873 return std::nullopt;
1881std::optional<xegpu::DistributeLayoutAttr>
1883 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
1885 const int subgroupSize) {
1886 if (!specifiedLayout)
1887 return specifiedLayout;
1889 specifiedLayout.getEffectiveInstDataAsInt();
1890 if (specifiedInstData.empty())
1891 return specifiedLayout;
1892 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
1893 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
1894 return specifiedLayout;
1897 auto *context = specifiedLayout.getContext();
1900 specifiedInstData, subgroupSize, maxChunkSize);
1902 return std::nullopt;
1911std::optional<xegpu::DistributeLayoutAttr>
1913 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
1915 const int subgroupSize) {
1916 if (!specifiedLayout)
1917 return specifiedLayout;
1919 specifiedLayout.getEffectiveInstDataAsInt();
1920 if (specifiedInstData.empty())
1921 return specifiedLayout;
1922 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
1923 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
1924 return specifiedLayout;
1926 auto *context = specifiedLayout.getContext();
1931 return std::nullopt;
1940std::optional<xegpu::DistributeLayoutAttr>
1942 xegpu::DistributeLayoutAttr specifiedLayout,
1943 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
1945 const int subgroupSize) {
1946 if (!specifiedLayout)
1947 return specifiedLayout;
1949 specifiedLayout.getEffectiveInstDataAsInt();
1950 if (specifiedInstData.empty())
1951 return specifiedLayout;
1952 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
1953 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
1954 return specifiedLayout;
1955 if (!consumerLayout)
1956 return specifiedLayout;
1958 consumerLayout.getEffectiveLaneLayoutAsInt();
1960 consumerLayout.getEffectiveLaneDataAsInt();
1961 if (consumerLaneLayout.empty() || consumerLaneData.empty())
1962 return specifiedLayout;
1964 auto *context = specifiedLayout.getContext();
1965 int rank = specifiedInstData.size();
1970 for (
int i = 0; i < rank; i++) {
1971 if (consumerLaneLayout[i] > 1) {
1972 laneLayout.push_back(
1973 std::max(
static_cast<int64_t>(subgroupSize), consumerLaneLayout[i]));
1975 laneLayout.push_back(1);
1980 return std::nullopt;
1983 consumerLayout.getOrder());
1991 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1992 xegpu::DistributeLayoutAttr>>
1994 xegpu::DistributeLayoutAttr bLayout,
1995 xegpu::DistributeLayoutAttr cdLayout,
1996 VectorType aTy, VectorType bTy,
1999 auto context = aTy.getContext();
2000 const auto *uArchInstruction =
2001 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
2003 if (!uArchInstruction)
2004 return std::nullopt;
2007 laneLayoutCD, laneDataCD;
2012 if (isa<xegpu::uArch::Xe2, xegpu::uArch::Xe3>(uArch)) {
2014 aTy.getShape(), subgroupSize,
2015 aTy.getElementType().getIntOrFloatBitWidth(),
2016 uArchInstruction->getPackedFormatBitSizeA());
2018 bTy.getShape(), subgroupSize,
2019 bTy.getElementType().getIntOrFloatBitWidth(),
2020 uArchInstruction->getPackedFormatBitSizeB(),
true);
2022 cdTy.getShape(), subgroupSize,
2023 cdTy.getElementType().getIntOrFloatBitWidth(),
2024 cdTy.getElementType().getIntOrFloatBitWidth());
2026 assert(
false &&
"Unsupported uArch for DPAS lane layout completion");
2032 return std::nullopt;
2033 return std::make_tuple(
2035 aLayout.getOrder()),
2037 bLayout.getOrder()),
2039 cdLayout.getOrder()));
2046 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2047 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2048 xegpu::DistributeLayoutAttr>>
2050 xegpu::DistributeLayoutAttr aLayout, xegpu::DistributeLayoutAttr bLayout,
2051 xegpu::DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy,
2052 VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy,
2055 aLayout, bLayout, cdLayout, aTy, bTy, cdTy, uArch);
2057 return std::nullopt;
2058 auto context = aTy.getContext();
2059 auto [completedA, completedB, completedCD] = *completed;
2066 return std::make_tuple(completedA, completedB, completedCD, aScaleLayout,
2198 auto srcShape = srcVecTy.getShape();
2199 int srcRank = srcShape.size();
2200 auto context = srcVecTy.getContext();
2202 const int subgroupSize =
uArch->getSubgroupSize();
2203 int64_t maxReduceVectorSize = 1;
2204 xegpu::DistributeLayoutAttr srcLayout;
2206 xegpu::SliceAttr consumerSliceLayout =
2207 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2208 if (consumerSliceLayout &&
2209 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2210 srcLayout = consumerSliceLayout.getParent();
2212 srcLayout.getEffectiveSgLayoutAsInt();
2215 for (
int dim = 0; dim < srcRank; dim++) {
2216 if (llvm::is_contained(reductionDims, dim))
2218 srcLayout.setDimData(dim, srcSgData.value()[dim], -1, -1);
2222 consumerLayout ? consumerLayout.getEffectiveSgLayoutAsInt()
2225 consumerLayout ? consumerLayout.getEffectiveSgDataAsInt()
2228 consumerLayout ? consumerLayout.getEffectiveOrderAsInt()
2231 consumerLayout ? consumerLayout.getOrder() :
nullptr;
2233 int remainingSgCount =
2234 consumerLayout ? consumerLayout.getNumSubgroups() : numSg;
2235 int consumerIdx = 0;
2238 for (
int i = 0; i < srcRank; i++) {
2239 if (!llvm::is_contained(reductionDims, i) &&
2240 consumerIdx <
static_cast<int>(consumerSgLayout.size())) {
2241 sgLayout[i] = consumerSgLayout[consumerIdx];
2242 sgData[i] = consumerSgData[consumerIdx];
2243 remainingSgCount /= sgLayout[i];
2244 order[i] = consumerOrder[consumerIdx];
2251 int64_t remainOrder = consumerSgLayout.size();
2252 for (
int i = 0; i < srcRank; i++) {
2253 if (llvm::is_contained(reductionDims, i)) {
2255 std::min(srcShape[i],
static_cast<int64_t>(remainingSgCount));
2256 assert((srcShape[i] % sgLayout[i] == 0) &&
2257 "source shape not divisible by sg_layout");
2258 sgData[i] = srcShape[i] / sgLayout[i];
2259 remainingSgCount /= sgLayout[i];
2260 order[i] = remainOrder++;
2265 if (!orderAttr || orderAttr.empty())
2266 resOrderAttr =
nullptr;
2267 assert(remainingSgCount == 1 &&
"not all subgroups distributed");
2268 srcLayout =
buildLayout(context, sgLayout, sgData,
2273 xegpu::SliceAttr consumerSliceLayout =
2274 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2275 auto consumerReductionDims =
2281 bool verticalLaneLayout = consumerReductionDims.empty() &&
2282 reductionDims.size() == 1 &&
2283 reductionDims[0] == (srcRank - 1);
2285 srcShape, reductionDims, subgroupSize, maxReduceVectorSize,
2286 verticalLaneLayout);
2290 for (
int i = 0; i < srcRank; i++)
2291 instData[i] = laneLayout[i] * laneData[i];
2298 "Lane reduction layout assumes all leading (non-innermost-two) "
2299 "dimensions are unit dimensions");
2300 xegpu::SliceAttr consumerSliceLayout =
2301 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2302 auto consumerReductionDims =
2306 if (consumerSliceLayout &&
2307 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2311 srcLayout = consumerSliceLayout.getParent();
2313 bool verticalLaneLayout = consumerReductionDims.empty() &&
2314 reductionDims.size() == 1 &&
2315 reductionDims[0] == (srcRank - 1);
2317 srcShape, reductionDims, subgroupSize, maxReduceVectorSize,
2318 verticalLaneLayout);
2323 return xegpu::SliceAttr::get(context, srcLayout,
2331 VectorType srcVecTy,
2334 auto srcShape = srcVecTy.getShape();
2335 auto context = srcVecTy.getContext();
2336 auto subgroupSize =
uArch->getSubgroupSize();
2337 xegpu::LayoutAttr srcLayout;
2341 "subgroup layout assignment not supported for reduction (op "
2342 "is not expected at this level).");
2345 "instData layout assignment not supported for reduction (op "
2346 "is not expected at this level).");
2349 laneLayout[0] = std::min(
static_cast<int64_t>(subgroupSize), srcShape[0]);
2354 auto result = xegpu::SliceAttr::get(context, srcLayout,
2372static xegpu::DistributeLayoutAttr
2375 size_t innerMostDim,
int ratio,
int64_t bound,
2381 consumerLayout.getEffectiveLaneLayoutAsInt();
2388 sgDataValue = sgData[innerMostDim];
2389 while ((sgDataValue <= bound) && (sgDataValue % ratio) != 0)
2392 instDataValue = instData[innerMostDim];
2393 const int innermostDimLaneLayout = laneLayout.empty()
2395 : laneLayout[innerMostDim];
2396 while ((instDataValue <= bound) &&
2397 (instDataValue % (innermostDimLaneLayout * ratio) != 0))
2399 assert((bound % instDataValue) == 0 &&
2400 "bound, instData, and laneLayout for innermost must be 2^n!");
2402 laneDataValue = laneData[innerMostDim];
2403 while ((laneDataValue <= bound) && (laneDataValue % ratio) != 0)
2407 return consumerLayout.setDimData(innerMostDim, sgDataValue, instDataValue,
2437 int srcElemTyBitWidth = srcVecTy.getElementType().getIntOrFloatBitWidth();
2438 int resElemTyBitWidth = resVecTy.getElementType().getIntOrFloatBitWidth();
2443 assert(consumerLayout.getRank() ==
static_cast<int64_t>(srcShape.size()) &&
2444 "laneData must be available for all dimensions");
2448 if (srcElemTyBitWidth <= resElemTyBitWidth)
2449 return consumerLayout;
2454 size_t innerMostDim = srcShape.size() - 1;
2455 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
2457 innerMostDim, bitWidthRatio,
2458 resShape[innerMostDim],
uArch);
2481 assert(consumerLayout.getRank() ==
static_cast<int64_t>(resShape.size()) &&
2482 "consumer layout rank must match source shape rank");
2487 const size_t innerMostDim = resShape.size() - 1;
2488 constexpr int ratio = 2;
2490 innerMostDim, ratio,
2491 resShape[innerMostDim],
uArch);
2499 VectorType resVectorTy, xegpu::DistributeLayoutAttr consumerLayout,
2502 xegpu::DistributeLayoutAttr requiredResLayout;
2504 consumerLayout.getEffectiveInstDataAsInt();
2506 consumerLayout.getEffectiveLaneDataAsInt();
2508 consumerLayout.getEffectiveLaneLayoutAsInt();
2512 requiredResLayout = consumerLayout;
2513 int srcRank = srcShape.size();
2517 assert(
false &&
"subgroup/instData layout assignment not supported for "
2518 "insertStridedSlice.");
2520 for (
int dim = 0; dim < srcRank; dim++) {
2521 assert(srcShape[dim] % consumerLaneLayout[dim] == 0 &&
2522 "srcShape must be divisible by laneLayout for all dimensions");
2523 laneDataValue = std::min(srcShape[dim] / consumerLaneLayout[dim],
2524 consumerLaneData[dim]);
2526 requiredResLayout.setDimData(dim, -1, -1, laneDataValue);
2529 return requiredResLayout;
2539 OpOperand &operand, xegpu::DistributeLayoutAttr resLayout) {
2546 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op)) {
2547 auto srcTy = dyn_cast<VectorType>(
broadcast.getSourceType());
2551 resLayout,
broadcast.getResultVectorType().getShape(),
2558 if (
auto reduction = dyn_cast<vector::MultiDimReductionOp>(op)) {
2567 if (
auto reduction = dyn_cast<vector::ReductionOp>(op))
2572 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
2573 int resElemBitWidth =
2574 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
2575 int srcElemBitWidth =
2576 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
2583 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
2585 resLayout, shapeCast.getResultVectorType().getShape(),
2586 shapeCast.getSourceVectorType().getShape());
2591 if (
auto insertSlice = dyn_cast<vector::InsertStridedSliceOp>(op)) {
2594 resLayout, insertSlice.getDestVectorType().getShape(),
2595 insertSlice.getSourceVectorType().getShape());
2603 if (
auto insert = dyn_cast<vector::InsertOp>(op)) {
2604 VectorType resVecTy = dyn_cast<VectorType>(insert.getResult().getType());
2605 VectorType valueToStoreTy =
2606 dyn_cast<VectorType>(insert.getValueToStore().getType());
2608 if ((idx == 0) && valueToStoreTy) {
2610 valueToStoreTy.getShape());
2618 if (
auto extract = dyn_cast<vector::ExtractOp>(op)) {
2619 VectorType srcVecTy = dyn_cast<VectorType>(extract.getSource().getType());
2620 VectorType resVecTy = dyn_cast<VectorType>(extract.getResult().getType());
2621 if (!srcVecTy || !resVecTy)
2624 srcVecTy.getShape());
2629 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
2631 transpose.getPermutation());
2636 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
2637 int resElemBitWidth =
2638 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
2639 int srcElemBitWidth =
2640 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
2646 if (
auto interleave = dyn_cast<vector::InterleaveOp>(op)) {
2651 if (
auto deinterleave = dyn_cast<vector::DeinterleaveOp>(op)) {
2656 if (dyn_cast<vector::ExtractStridedSliceOp>(op))
2675 if (isa<xegpu::AnchorLayoutInterface>(op))
2679 xegpu::DistributeLayoutAttr resLayout;
2680 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 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 bool leadingDimsAreUnit(ArrayRef< int64_t > shape, int numInnerDims)
Returns true if every dimension of shape except the innermost numInnerDims is a unit (size-1) dimensi...
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 > > compute2DBlockIOLaneLayoutAndData(ArrayRef< int64_t > instShape, int64_t subgroupSize, int64_t bitwidth, int64_t packingSize, bool transform=false)
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 std::pair< SmallVector< int64_t >, SmallVector< int64_t > > computeReductionLaneLayoutAndData(ArrayRef< int64_t > srcShape, ArrayRef< int64_t > reductionDims, int subgroupSize, int64_t maxReduceVectorSize, bool verticalLaneLayout=false)
Computes the (lane_layout, lane_data) for a multi-reduction's source layout.
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 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 xegpu::DistributeLayoutAttr setupGenericStoreAnchorLayout(xegpu::LayoutKind layoutKind, mlir::MLIRContext *context, int maxChunkSize, ArrayRef< int64_t > srcShape, int subgroupSize)
Sets up the anchor layout for store scatter and store matrix operation.
SmallVector< int64_t > LayoutRepresentation
static xegpu::DistributeLayoutAttr getLayoutFromUsePoints(Value result)
static SmallVector< LayoutRepresentation > getSgLayoutCandidates(ArrayRef< int64_t > wgShape, ArrayRef< int64_t > instData, int64_t sgCount)
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 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.
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
Operation is the basic unit of execution within MLIR.
bool hasAttrOfType(NameT &&name)
ArrayRef< NamedAttribute > getAttrs()
Return all of the attributes on this operation.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
unsigned getNumRegions()
Returns the number of regions held by this operation.
MutableArrayRef< OpOperand > getOpOperands()
auto getDiscardableAttrs()
Return a range of all of discardable attributes on this operation.
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),...
Attribute removeAttr(StringAttr name)
Remove the attribute with the specified name if it exists.
unsigned getNumResults()
Return the number of results held by this operation.
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...
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 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...
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.
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).
DistributeLayoutAttr setupStoreMatrixAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, const uArch::uArch *uArch)
Sets up the anchor layout for a store matrix operation.
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 setupBitCastResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Setup the result layout attribute for a bitcast operation based on element type bitwidths.
void removeLayoutAttr(const T &operandOrResult)
Removes the LayoutAttr for a given OpOperand or OpResult if it exists.
DistributeLayoutAttr inferMaskOffsetLayoutForScatterIO(DistributeLayoutAttr payloadLayout, int chunkSize)
Infers the layout attribute for mask and offset operand for Chunked load and store,...
DistributeLayoutAttr getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value.
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.
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 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 setupStoreScatterAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, const uArch::uArch *uArch)
Sets up the anchor layout for a store scatter operation.
std::optional< DistributeLayoutAttr > completeBlockLoadLaneLayoutFromInstData(DistributeLayoutAttr specifiedLayout, DistributeLayoutAttr consumerLayout, Type elemTy, const xegpu::uArch::BlockIOInstructionInterface *uArchInstruction, const int subgroupSize)
Like completeBlockStoreLaneLayoutFromInstData, but for load_nd.
LogicalResult propagateRegionArgsToInits(RegionBranchOpInterface regionOp, GetLayoutFnTy getLayoutOfValue)
Propagate layouts from a region branch op's region entry block arguments back to its init operands.
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > setupDpasLayout(LayoutKind layoutKind, VectorType aTy, VectorType bTy, VectorType cdTy, DistributeLayoutAttr consumerLayout, int numSg, const uArch::uArch *uArch)
Sets up the anchor layouts for a dpas operands (A, B, and C/D).
SliceAttr setupReductionResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, const uArch::uArch *uArch)
Sets up layout for Reduction operations by creating a SliceAttr for the result.
Include the generated interface declarations.
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.
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 int getSubgroupSize() const =0
const Instruction * getInstruction(InstructionKind instKind) const