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 int numLeading =
static_cast<int>(
shape.size()) - numInnerDims;
445 return llvm::all_of(
shape.take_front(numLeading),
446 [](
int64_t dim) { return dim == 1; });
453 auto toI32Attr = [&](
auto range) {
457 return xegpu::LayoutAttr::get(context,
nullptr,
458 nullptr, toI32Attr(instData),
459 toI32Attr(laneLayout), toI32Attr(laneData),
466 return !llvm::any_of(llvm::seq<int>(0, dataShape.size()), [&](
int dim) {
467 return dataShape[dim] % (laneLayout[dim] * laneData[dim]) != 0;
471static xegpu::LayoutAttr
475 auto toI32Attr = [&](
auto range) {
479 return xegpu::LayoutAttr::get(context,
nullptr,
481 nullptr, toI32Attr(laneLayout),
482 toI32Attr(laneData), orderAttr);
485static xegpu::LayoutAttr
490 auto toI32Attr = [&](
auto range) {
494 return xegpu::LayoutAttr::get(
495 context, sgLayout.empty() ?
nullptr : toI32Attr(sgLayout),
496 sgData.empty() ?
nullptr : toI32Attr(sgData),
497 instData.empty() ?
nullptr : toI32Attr(instData),
498 laneLayout.empty() ?
nullptr : toI32Attr(laneLayout),
499 laneData.empty() ?
nullptr : toI32Attr(laneData), orderAttr);
508 for (
int dim = 0; dim < (int)sgLayout.size(); ++dim) {
510 sgData[dim] = wgTileShape[dim];
512 sgData[dim] = wgTileShape[dim] / sgLayout[dim];
521xegpu::DistributeLayoutAttr
527 size_t dimDiff = resShape.size() - srcShape.size();
528 auto bcastSourceLayout = resLayout;
531 for (
size_t i = dimDiff; i < resShape.size(); i++) {
532 if ((srcShape[i - dimDiff] == 1) && (resShape[i] != 1))
533 bcastDims.push_back(i);
538 if (!bcastDims.empty())
539 bcastSourceLayout = bcastSourceLayout.setUnitDimData(bcastDims);
544 bool isOuterDimDiffUnitDims = llvm::all_of(
545 resShape.take_front(dimDiff), [&](
int64_t dim) { return dim == 1; });
546 if (dimDiff && bcastDims.size() == dimDiff && isOuterDimDiffUnitDims) {
549 sliceDims.assign(bcastDims.begin(), bcastDims.end());
553 llvm::append_range(sliceDims, llvm::seq<int64_t>(0, dimDiff));
555 bcastSourceLayout = xegpu::SliceAttr::get(
556 resLayout.getContext(), bcastSourceLayout,
559 return bcastSourceLayout;
564xegpu::DistributeLayoutAttr
568 assert(isa<xegpu::SliceAttr>(resLayout) &&
569 "reduction result layout must be slice layout");
571 xegpu::SliceAttr sliceLayout = dyn_cast<xegpu::SliceAttr>(resLayout);
573 assert((reduceDims == sliceLayout.getDims().asArrayRef()) &&
574 "reduction dims must match with slice dims");
576 return sliceLayout.getParent();
579xegpu::DistributeLayoutAttr
590xegpu::DistributeLayoutAttr
601xegpu::DistributeLayoutAttr
603 int resElemTyBitWidth,
int srcElemTyBitWidth) {
608 size_t sgDataSize = sgData.size();
609 size_t instDataSize = instData.size();
610 size_t laneDataSize = laneData.size();
614 int64_t dim = resLayout.getRank() - 1;
616 if (srcElemTyBitWidth <= resElemTyBitWidth) {
617 int bitWidthRatio = resElemTyBitWidth / srcElemTyBitWidth;
619 sgDataValue = sgData.back() * bitWidthRatio;
621 instDataValue = instData.back() * bitWidthRatio;
623 laneDataValue = laneData.back() * bitWidthRatio;
625 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
627 assert((sgData.back() % bitWidthRatio) == 0 &&
628 "sgData not divisible by bitWidthRatio");
629 sgDataValue = sgData.back() / bitWidthRatio;
632 assert((instData.back() % bitWidthRatio) == 0 &&
633 "instData not divisible by bitWidthRatio");
634 instDataValue = instData.back() / bitWidthRatio;
637 assert((laneData.back() % bitWidthRatio) == 0 &&
638 "laneData not divisible by bitWidthRatio");
639 laneDataValue = laneData.back() / bitWidthRatio;
643 xegpu::DistributeLayoutAttr finalSrcLayout;
645 resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
647 return finalSrcLayout;
654xegpu::DistributeLayoutAttr
660 size_t sgDataSize = sgData.size();
661 size_t instDataSize = instData.size();
662 size_t laneDataSize = laneData.size();
666 int64_t dim = resLayout.getRank() - 1;
670 constexpr int ratio = 2;
672 assert((sgData.back() % ratio) == 0 &&
673 "sgData not divisible by interleave ratio");
674 sgDataValue = sgData.back() / ratio;
677 assert((instData.back() % ratio) == 0 &&
678 "instData not divisible by interleave ratio");
679 instDataValue = instData.back() / ratio;
682 assert((laneData.back() % ratio) == 0 &&
683 "laneData not divisible by interleave ratio");
684 laneDataValue = laneData.back() / ratio;
687 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
694xegpu::DistributeLayoutAttr
700 size_t sgDataSize = sgData.size();
701 size_t instDataSize = instData.size();
702 size_t laneDataSize = laneData.size();
706 int64_t dim = resLayout.getRank() - 1;
710 constexpr int ratio = 2;
712 sgDataValue = sgData.back() * ratio;
714 instDataValue = instData.back() * ratio;
716 laneDataValue = laneData.back() * ratio;
718 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
728 int srcShapeSize = srcShape.size();
729 int resShapeSize = resShape.size();
730 int dimDiff = resShapeSize - srcShapeSize;
735 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
736 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
737 for (
int i = 0; i < dimDiff; i++) {
738 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
739 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
740 "Leading dimensions being sliced off must not be distributed");
742 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
751xegpu::DistributeLayoutAttr
756 int srcShapeSize = srcShape.size();
757 int resShapeSize = resShape.size();
758 int dimDiff = resShapeSize - srcShapeSize;
763 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
764 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
765 for (
int i = 0; i < dimDiff; i++) {
766 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
767 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
768 "Leading dimensions being sliced off must not be distributed");
770 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
780xegpu::DistributeLayoutAttr
785 int srcShapeSize = srcShape.size();
786 int resShapeSize = resShape.size();
787 int dimDiff = srcShapeSize - resShapeSize;
788 auto context = resLayout.getContext();
792 auto sgLayout = resLayout.getEffectiveSgLayoutAsInt();
793 auto sgData = resLayout.getEffectiveSgDataAsInt();
794 auto instData = resLayout.getEffectiveInstDataAsInt();
795 auto laneLayout = resLayout.getEffectiveLaneLayoutAsInt();
796 auto laneData = resLayout.getEffectiveLaneDataAsInt();
797 auto order = resLayout.getEffectiveOrderAsInt();
807 for (
auto &o : order)
813 for (
int i = 0; i < dimDiff; i++) {
814 if (!sgLayout.empty())
815 sgLayout.insert(sgLayout.begin(), 1);
817 sgData.insert(sgData.begin(), 1);
818 if (!instData.empty())
819 instData.insert(instData.begin(), 1);
820 if (!laneLayout.empty())
821 laneLayout.insert(laneLayout.begin(), 1);
822 if (!laneData.empty())
823 laneData.insert(laneData.begin(), 1);
824 order.push_back(dimDiff - 1 - i);
829 if (!resLayout.getOrder())
832 return buildLayout(context, sgLayout, sgData, instData, laneLayout,
833 laneData, orderAttr);
840xegpu::DistributeLayoutAttr
864 xegpu::SliceAttr::get(resLayout.getContext(), resLayout, sliceDimsAttr);
871 auto srcLayout = resLayout;
872 for (
const auto &dimGroup : splitDimGroups)
873 srcLayout = srcLayout.collapseDims(dimGroup);
882 auto srcLayout = resLayout;
883 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
884 dstIdx >= 0; --dstIdx) {
886 if (srcDims.empty()) {
887 srcLayout = srcLayout.dropDims({dstIdx});
890 if (srcDims.size() == 1)
893 targetShape.reserve(srcDims.size());
895 targetShape.push_back(srcShape[d]);
896 srcLayout = srcLayout.expandDim(dstIdx, targetShape);
914xegpu::DistributeLayoutAttr
917 return srcLayout.transposeDims(permutation);
928xegpu::DistributeLayoutAttr
937 auto resLayout = srcLayout;
940 for (
int64_t srcIdx =
static_cast<int64_t>(splitDimGroups.size()) - 1;
941 srcIdx >= 0; --srcIdx) {
943 if (resDims.size() <= 1)
946 targetShape.reserve(resDims.size());
948 targetShape.push_back(resShape[d]);
949 resLayout = resLayout.expandDim(srcIdx, targetShape);
958 auto resLayout = srcLayout;
961 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
962 dstIdx >= 0; --dstIdx) {
968 if (srcDims.size() == 1)
970 resLayout = resLayout.collapseDims(llvm::to_vector(srcDims));
987 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
988 if (!operandLayouts[0])
991 transpose.getPermutation());
995 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
996 if (!operandLayouts[0])
999 operandLayouts[0], shapeCast.getSourceVectorType().getShape(),
1000 shapeCast.getResultVectorType().getShape());
1006 for (xegpu::DistributeLayoutAttr layout : operandLayouts)
1029 xegpu::DistributeLayoutAttr payloadLayout,
int chunkSize) {
1030 auto rank = payloadLayout.getRank();
1032 return payloadLayout.dropDims(
1033 llvm::to_vector(llvm::seq<int64_t>(rank - 1, rank)));
1034 return payloadLayout;
1054 auto getDivisors = [](
int64_t n) {
1056 for (
int64_t i = 1; i * i <= n; ++i) {
1060 divs.push_back(n / i);
1069 if (dim == rank - 1) {
1070 current[dim] = remaining;
1074 for (
int64_t factor : getDivisors(remaining)) {
1075 current[dim] = factor;
1076 generate(dim + 1, remaining / factor);
1102 int64_t rank = wgShape.size();
1103 assert(rank > 0 &&
"wgShape must be non-empty");
1104 assert(
static_cast<int64_t>(instData.size()) == rank &&
1105 "instData rank must match wgShape rank");
1112 for (
const auto &sgLayout : allFactorizations) {
1114 for (
int64_t dim = 0; dim < rank; ++dim) {
1118 if (dim == broadcastDim) {
1119 sgData = wgShape[dim];
1121 if (wgShape[dim] % sgLayout[dim] != 0) {
1125 sgData = wgShape[dim] / sgLayout[dim];
1127 if (sgData % instData[dim] != 0) {
1133 candidates.push_back(sgLayout);
1139 int64_t spreadLhs = *llvm::max_element(
lhs) - *llvm::min_element(
lhs);
1140 int64_t spreadRhs = *llvm::max_element(
rhs) - *llvm::min_element(
rhs);
1141 if (spreadLhs != spreadRhs)
1142 return spreadLhs < spreadRhs;
1153 bool transform =
false,
bool transpose =
false) {
1154 int rank = dataShape.size();
1158 return std::nullopt;
1159 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1165 assert(rank >= 2 &&
"dataShape must be at least 2D for 2D-block IO");
1172 if (instWidth < 0 || instHeight < 0)
1173 return std::nullopt;
1174 instData.back() = instWidth;
1175 instData[rank - 2] = instHeight;
1186 VectorType aTy, VectorType bTy, VectorType cdTy,
1190 const unsigned dataALen = aTy.getShape()[aTy.getRank() - 2];
1191 auto supportedALen = uArchInstruction->
getSupportedM(aTy.getElementType());
1196 const unsigned dataBLen = bTy.getShape().back();
1197 auto supportedBLen = uArchInstruction->
getSupportedN(bTy.getElementType());
1201 auto supportedCLen = uArchInstruction->
getSupportedN(cdTy.getElementType());
1204 if (maxALen == -1 || maxBLen == -1 || maxCLen == -1)
1205 return std::nullopt;
1207 auto supportedKLen = uArchInstruction->
getSupportedK(aTy.getElementType());
1208 if (supportedKLen.empty())
1209 return std::nullopt;
1210 auto kDimSize = supportedKLen[0];
1213 instDataA[aTy.getRank() - 2] = maxALen;
1214 instDataA[aTy.getRank() - 1] = kDimSize;
1216 instDataB[bTy.getRank() - 2] = kDimSize;
1217 instDataB[bTy.getRank() - 1] = maxBLen;
1219 instDataCD[cdTy.getRank() - 2] = maxALen;
1220 instDataCD[cdTy.getRank() - 1] = maxCLen;
1221 return std::make_tuple(instDataA, instDataB, instDataCD);
1234 int64_t rank = instShape.size();
1237 laneLayout[innermost] = std::min(subgroupSize, instShape[innermost]);
1238 laneData[innermost] =
1239 std::min(instShape[innermost] / laneLayout[innermost], maxChunkSize);
1240 return {laneLayout, laneData};
1250 int64_t rank = instShape.size();
1252 int kDim =
transform ? rank - 2 : rank - 1;
1253 unsigned vnniFactor = packingSize / bitwidth;
1254 laneData[kDim] = bitwidth < packingSize ? vnniFactor : 1;
1256 std::min(subgroupSize, instShape.back() / laneData.back());
1259 for (
int64_t i = 0; i < rank; ++i) {
1260 int64_t laneProduct = laneLayout[i] * laneData[i];
1261 assert(instShape[i] % laneProduct == 0 &&
1262 "lane_layout * lane_data must evenly divide the inst shape");
1265 return {laneLayout, laneData};
1284 int subgroupSize,
int64_t maxReduceVectorSize,
1285 bool verticalLaneLayout =
false) {
1286 int srcRank = srcShape.size();
1289 int innermost = srcRank - 1;
1290 int secondInnermost = srcRank - 2;
1292 if (verticalLaneLayout && secondInnermost >= 0) {
1293 std::swap(innermost, secondInnermost);
1295 int laneDim = innermost;
1296 int vectorDim = secondInnermost;
1298 laneLayout[laneDim] =
1299 std::min(
static_cast<int64_t>(subgroupSize), srcShape[laneDim]);
1301 laneData[vectorDim] = std::min(maxReduceVectorSize, srcShape[vectorDim]);
1303 return {laneLayout, laneData};
1369static std::optional<
1370 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1371 xegpu::DistributeLayoutAttr>>
1374 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1377 auto [instDataA, instDataB, instDataCD] = instDataVecs;
1379 std::optional<LayoutRepresentation> consumerSgLayout = std::nullopt;
1380 if (consumerLayout && consumerLayout.isForWorkgroup()) {
1381 consumerSgLayout = consumerLayout.getEffectiveSgLayoutAsInt();
1390 if (layoutsA.empty() || layoutsB.empty() || layoutsCD.empty())
1391 return std::nullopt;
1394 std::optional<LayoutRepresentation> bestPick;
1395 for (
auto &sgLayout : layoutsB) {
1396 if (llvm::is_contained(layoutsA, sgLayout) &&
1397 llvm::is_contained(layoutsCD, sgLayout)) {
1399 if (consumerSgLayout.has_value() && sgLayout == *consumerSgLayout) {
1400 bestPick = sgLayout;
1408 bestPick = sgLayout;
1412 return std::nullopt;
1414 const auto &picked = *bestPick;
1416 auto dpasALayout =
buildSgLayout(context, aTy.getShape(), picked,
1418 auto dpasBLayout =
buildSgLayout(context, bTy.getShape(), picked,
1420 auto dpasCDLayout =
buildSgLayout(context, cdTy.getShape(), picked);
1421 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout);
1428 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1429 xegpu::DistributeLayoutAttr>>
1431 VectorType bTy, VectorType cdTy,
1432 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1434 auto context = aTy.getContext();
1435 const auto *uArchInstruction =
1436 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1438 if (!uArchInstruction)
1439 return std::nullopt;
1443 aTy.getShape(), subgroupSize,
1444 aTy.getElementType().getIntOrFloatBitWidth(),
1445 uArchInstruction->getPackedFormatBitSizeA());
1447 bTy.getShape(), subgroupSize,
1448 bTy.getElementType().getIntOrFloatBitWidth(),
1449 uArchInstruction->getPackedFormatBitSizeB(),
true);
1451 cdTy.getShape(), subgroupSize,
1452 cdTy.getElementType().getIntOrFloatBitWidth(),
1453 cdTy.getElementType().getIntOrFloatBitWidth());
1457 return std::nullopt;
1461 "Number of subgroups must be provided for sg layout creation.");
1463 numSg, *instDataVecs);
1465 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1466 return std::make_tuple(
1475 return std::make_tuple(aLayout, bLayout, cdLayout);
1477 return std::nullopt;
1484static xegpu::DistributeLayoutAttr
1486 VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout,
1488 if (!scaleTy || !matrixLayout)
1496 if (scaleShape.empty())
1499 auto uArchInstruction =
1500 dyn_cast<xegpu::uArch::SubgroupScaledMatrixMultiplyAcc>(
1504 int64_t rank = matrixLayout.getRank();
1505 assert(rank >= 2 &&
"dpas layouts must be at least two dimensions");
1512 auto order = matrixLayout.getOrder();
1516 if (!sgLayout.empty() && !sgData.empty()) {
1517 scaleSgLayout.assign(sgLayout.begin(), sgLayout.end());
1518 scaleSgData.assign(sgData.begin(), sgData.end());
1519 scaleSgData[rank - 2] = std::max<int64_t>(
1520 scaleShape[rank - 2] / (matrixShape[rank - 2] / sgData[rank - 2]), 1);
1521 scaleSgData[rank - 1] = std::max<int64_t>(
1522 scaleShape[rank - 1] / (matrixShape[rank - 1] / sgData[rank - 1]), 1);
1529 if (!instData.empty()) {
1530 scaleInstData.assign(instData.begin(), instData.end());
1532 scaleInstData[rank - 2] = std::max<int64_t>(
1533 scaleShape[rank - 2] / (matrixShape[rank - 2] / instData[rank - 2]),
1536 scaleInstData[rank - 1] = std::max<int64_t>(
1537 scaleShape[rank - 1] / (matrixShape[rank - 1] / instData[rank - 1]),
1543 if (!laneLayout.empty() && !laneData.empty()) {
1544 scaleLaneLayout.assign(laneLayout.begin(), laneLayout.end());
1545 scaleLaneData.assign(laneData.size(), 1);
1547 bool isRowMajor = uArchInstruction->isLaneLayoutRowMajorOrder();
1548 if (isBScale ^ isRowMajor)
1549 std::swap(scaleLaneLayout[rank - 2], scaleLaneLayout[rank - 1]);
1554 auto layoutCap = scaleInstData.empty() ? scaleShape : scaleInstData;
1555 for (
int64_t d = rank - 2; d < rank; ++d)
1556 scaleLaneLayout[d] = std::min<int64_t>(layoutCap[d], scaleLaneLayout[d]);
1558 return buildLayout(context, scaleSgLayout, scaleSgData, scaleInstData,
1559 scaleLaneLayout, scaleLaneData, order);
1566 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1567 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1568 xegpu::DistributeLayoutAttr>>
1570 VectorType bTy, VectorType cdTy, VectorType aScaleTy,
1571 VectorType bScaleTy,
1572 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1574 auto context = aTy.getContext();
1575 const auto *uArchInstruction =
1576 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1578 if (!uArchInstruction)
1579 return std::nullopt;
1583 aTy.getShape(), subgroupSize,
1584 aTy.getElementType().getIntOrFloatBitWidth(),
1585 uArchInstruction->getPackedFormatBitSizeA());
1587 bTy.getShape(), subgroupSize,
1588 bTy.getElementType().getIntOrFloatBitWidth(),
1589 uArchInstruction->getPackedFormatBitSizeB(),
true);
1591 cdTy.getShape(), subgroupSize,
1592 cdTy.getElementType().getIntOrFloatBitWidth(),
1593 cdTy.getElementType().getIntOrFloatBitWidth());
1596 return std::nullopt;
1600 "Number of subgroups must be provided for sg layout creation.");
1602 context, aTy, bTy, cdTy, consumerLayout, numSg, *instDataVecs);
1604 return std::nullopt;
1606 auto [dpasALayout, dpasBLayout, dpasCDLayout] = *dpasLayouts;
1615 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1619 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1626 laneLayoutCD, laneDataCD);
1633 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1638 auto dpasCDLayout =
buildLaneLayout(context, laneLayoutCD, laneDataCD);
1645 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1648 return std::nullopt;
1654xegpu::DistributeLayoutAttr
1656 VectorType srcVecTy,
int numSg,
1658 const auto *uArchInstruction =
1659 dyn_cast<xegpu::uArch::Subgroup2DBlockStoreInstruction>(
1660 uArch->getInstruction(
1662 if (!uArchInstruction)
1665 auto context = srcVecTy.getContext();
1666 Type elemTy = srcVecTy.getElementType();
1667 auto subgroupSize =
uArch->getSubgroupSize();
1668 auto dataShape = srcVecTy.getShape();
1669 [[maybe_unused]]
int rank = srcVecTy.getRank();
1670 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1675 dataShape, subgroupSize, bitwidth,
1676 uArchInstruction->getPackedFormatBitSize());
1689 "Expected the store layout to satisfy uArch block constraints");
1696 "Number of subgroups must be provided for sg layout creation.");
1698 if (sgLayouts.empty())
1700 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1709xegpu::DistributeLayoutAttr
1711 xegpu::TensorDescType tdescTy,
int numSg,
1714 const auto *uArchInstruction =
1715 dyn_cast<xegpu::uArch::Subgroup2DBlockPrefetchInstruction>(
1718 if (!uArchInstruction)
1721 auto context = tdescTy.getContext();
1722 Type elemTy = tdescTy.getElementType();
1724 auto dataShape = tdescTy.getShape();
1725 [[maybe_unused]]
int rank = tdescTy.getRank();
1726 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1731 dataShape, subgroupSize, bitwidth,
1732 uArchInstruction->getPackedFormatBitSize());
1745 "Expected the prefetch layout to satisfy uArch block constraints");
1752 "Number of subgroups must be provided for sg layout creation.");
1754 if (sgLayouts.empty())
1756 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1767xegpu::DistributeLayoutAttr
1769 VectorType resVecTy,
1770 xegpu::DistributeLayoutAttr consumerLayout,
1773 assert(consumerLayout &&
"Expected a valid consumer layout");
1775 assert(consumerLayout.isForWorkgroup() &&
1776 "Expected consumer layout to be a complete workgroup-level layout");
1777 return consumerLayout;
1780 auto context = resVecTy.getContext();
1781 Type elemTy = resVecTy.getElementType();
1783 auto dataShape = resVecTy.getShape();
1784 const auto *uArchInstruction =
1785 dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
1788 if (!uArchInstruction)
1791 int rank = resVecTy.getRank();
1793 consumerLayout.getEffectiveInstDataAsInt();
1795 consumerLayout.getEffectiveLaneLayoutAsInt();
1797 consumerLayout.getEffectiveLaneDataAsInt();
1798 auto consumerOrderAttr = consumerLayout.getOrder();
1800 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1801 "Expected consumer layout to have lane_layout and lane_data");
1807 consumerLaneLayout[rank - 2] > 1 && consumerLaneLayout[rank - 1] == 1;
1808 bool hasTransform = !hasTranspose && consumerLaneData[rank - 2] > 1 &&
1809 consumerLaneData[rank - 1] == 1;
1810 assert((consumerLaneData[rank - 2] == 1 || consumerLaneData[rank - 1] == 1) &&
1811 "Expected consumer lane data to have at most one non-unit dim");
1814 auto blockWHC = uArchInstruction->getBlockWidthHeightCount(
1815 elemTy, hasTransform, hasTranspose,
1819 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1825 for (
int i = 0; i < rank; i++) {
1826 if (consumerLaneLayout[i] > 1)
1827 laneLayout.push_back(std::max(
static_cast<int64_t>(subgroupSize),
1828 consumerLaneLayout[i]));
1830 laneLayout.push_back(1);
1834 int64_t height = consumerInstData[rank - 2];
1835 int64_t width = consumerInstData[rank - 1];
1836 auto maxBlockCount = *llvm::max_element(bCounts);
1837 auto maxWidth = *llvm::max_element(bWidths);
1838 if (llvm::is_contained(bWidths,
static_cast<int>(width)) ||
1839 (width % maxWidth == 0 && width / maxWidth < maxBlockCount)) {
1840 if (llvm::is_contained(bHeights,
static_cast<int>(height))) {
1842 laneLayout, consumerLaneData,
1850 dataShape, elemTy, uArchInstruction, hasTransform, hasTranspose);
1855 "Expected the load layout to satisfy uArch block constraints");
1857 consumerLaneData, consumerOrderAttr);
1861 "Expected the lane layout to satisfy uArch block constraints");
1862 return consumerLayout;
1882 xegpu::DistributeLayoutAttr consumerLayout,
int maxChunkSize,
1886 return consumerLayout;
1889 consumerLayout.getEffectiveInstDataAsInt();
1891 consumerLayout.getEffectiveLaneLayoutAsInt();
1893 consumerLayout.getEffectiveLaneDataAsInt();
1897 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1898 "Expected consumer layout to have lane_layout and lane_data");
1899 laneLayout.assign(consumerLaneLayout.begin(), consumerLaneLayout.end());
1900 laneData.assign(consumerLaneData.begin(), consumerLaneData.end());
1904 instData.resize(resShape.size());
1905 for (
size_t i = 0; i < resShape.size(); ++i)
1906 instData[i] = laneLayout[i] * laneData[i];
1917 xegpu::DistributeLayoutAttr consumerLayout,
const uArch::uArch *uArch) {
1919 const int subgroupSize = uArch->getSubgroupSize();
1921 auto context = resVecTy.getContext();
1923 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
1926 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
1929 maxChunkSize, resShape, subgroupSize);
1934xegpu::DistributeLayoutAttr
1936 VectorType resVecTy,
int contigChunkSize,
1937 xegpu::DistributeLayoutAttr consumerLayout,
1942 auto context = resVecTy.getContext();
1944 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
1947 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
1949 maxChunkSize, resShape, subgroupSize);
1955static xegpu::DistributeLayoutAttr
1959 if (candidates.empty())
1962 return buildSgLayout(context, wgShape, candidates.front(), -1);
1972 auto [laneLayout, laneData] =
1976 for (
size_t i = 0; i < srcShape.size(); ++i)
1977 instData[i] = laneLayout[i] * laneData[i];
1981 "Number of subgroups must be provided for sg layout creation.");
1994xegpu::DistributeLayoutAttr
1996 VectorType srcVecTy,
int contigChunkSize,
1999 const int subgroupSize =
uArch->getSubgroupSize();
2001 auto context = srcVecTy.getContext();
2003 const auto *uArchInstruction =
2004 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2007 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2009 srcShape, subgroupSize, numSg);
2017 const int subgroupSize =
uArch->getSubgroupSize();
2019 auto context = srcVecTy.getContext();
2021 const auto *uArchInstruction =
2022 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2025 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2028 srcShape, subgroupSize, numSg);
2046std::optional<xegpu::DistributeLayoutAttr>
2048 xegpu::DistributeLayoutAttr specifiedLayout,
2049 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2051 const int subgroupSize) {
2052 if (!specifiedLayout)
2053 return specifiedLayout;
2055 specifiedLayout.getEffectiveInstDataAsInt();
2056 if (specifiedInstData.empty())
2057 return specifiedLayout;
2058 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2059 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2060 return specifiedLayout;
2063 auto *context = specifiedLayout.getContext();
2065 if (consumerLayout) {
2066 auto consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
2067 auto consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
2068 if (!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
2072 consumerLaneLayout, consumerLaneData);
2075 specifiedInstData, subgroupSize, maxChunkSize);
2077 return std::nullopt;
2085std::optional<xegpu::DistributeLayoutAttr>
2087 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2089 const int subgroupSize) {
2090 if (!specifiedLayout)
2091 return specifiedLayout;
2093 specifiedLayout.getEffectiveInstDataAsInt();
2094 if (specifiedInstData.empty())
2095 return specifiedLayout;
2096 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2097 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2098 return specifiedLayout;
2101 auto *context = specifiedLayout.getContext();
2104 specifiedInstData, subgroupSize, maxChunkSize);
2106 return std::nullopt;
2115std::optional<xegpu::DistributeLayoutAttr>
2117 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2119 const int subgroupSize) {
2120 if (!specifiedLayout)
2121 return specifiedLayout;
2123 specifiedLayout.getEffectiveInstDataAsInt();
2124 if (specifiedInstData.empty())
2125 return specifiedLayout;
2126 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2127 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2128 return specifiedLayout;
2130 auto *context = specifiedLayout.getContext();
2135 return std::nullopt;
2144std::optional<xegpu::DistributeLayoutAttr>
2146 xegpu::DistributeLayoutAttr specifiedLayout,
2147 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2149 const int subgroupSize) {
2150 if (!specifiedLayout)
2151 return specifiedLayout;
2153 specifiedLayout.getEffectiveInstDataAsInt();
2154 if (specifiedInstData.empty())
2155 return specifiedLayout;
2156 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2157 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2158 return specifiedLayout;
2159 if (!consumerLayout)
2160 return specifiedLayout;
2162 consumerLayout.getEffectiveLaneLayoutAsInt();
2164 consumerLayout.getEffectiveLaneDataAsInt();
2165 if (consumerLaneLayout.empty() || consumerLaneData.empty())
2166 return specifiedLayout;
2168 auto *context = specifiedLayout.getContext();
2169 int rank = specifiedInstData.size();
2174 for (
int i = 0; i < rank; i++) {
2175 if (consumerLaneLayout[i] > 1) {
2176 laneLayout.push_back(
2177 std::max(
static_cast<int64_t>(subgroupSize), consumerLaneLayout[i]));
2179 laneLayout.push_back(1);
2184 return std::nullopt;
2187 consumerLayout.getOrder());
2195 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2196 xegpu::DistributeLayoutAttr>>
2198 xegpu::DistributeLayoutAttr bLayout,
2199 xegpu::DistributeLayoutAttr cdLayout,
2200 VectorType aTy, VectorType bTy,
2203 auto context = aTy.getContext();
2204 const auto *uArchInstruction =
2205 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
2207 if (!uArchInstruction)
2208 return std::nullopt;
2211 laneLayoutCD, laneDataCD;
2216 if (isa<xegpu::uArch::Xe2, xegpu::uArch::Xe3>(uArch)) {
2218 aTy.getShape(), subgroupSize,
2219 aTy.getElementType().getIntOrFloatBitWidth(),
2220 uArchInstruction->getPackedFormatBitSizeA());
2222 bTy.getShape(), subgroupSize,
2223 bTy.getElementType().getIntOrFloatBitWidth(),
2224 uArchInstruction->getPackedFormatBitSizeB(),
true);
2226 cdTy.getShape(), subgroupSize,
2227 cdTy.getElementType().getIntOrFloatBitWidth(),
2228 cdTy.getElementType().getIntOrFloatBitWidth());
2230 assert(
false &&
"Unsupported uArch for DPAS lane layout completion");
2236 return std::nullopt;
2237 return std::make_tuple(
2239 aLayout.getOrder()),
2241 bLayout.getOrder()),
2243 cdLayout.getOrder()));
2250 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2251 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2252 xegpu::DistributeLayoutAttr>>
2254 xegpu::DistributeLayoutAttr aLayout, xegpu::DistributeLayoutAttr bLayout,
2255 xegpu::DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy,
2256 VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy,
2259 aLayout, bLayout, cdLayout, aTy, bTy, cdTy, uArch);
2261 return std::nullopt;
2262 auto context = aTy.getContext();
2263 auto [completedA, completedB, completedCD] = *completed;
2270 return std::make_tuple(completedA, completedB, completedCD, aScaleLayout,
2402 auto srcShape = srcVecTy.getShape();
2403 int srcRank = srcShape.size();
2404 auto context = srcVecTy.getContext();
2406 const int subgroupSize =
uArch->getSubgroupSize();
2407 int64_t maxReduceVectorSize = 1;
2408 xegpu::DistributeLayoutAttr srcLayout;
2410 xegpu::SliceAttr consumerSliceLayout =
2411 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2412 if (consumerSliceLayout &&
2413 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2414 srcLayout = consumerSliceLayout.getParent();
2416 srcLayout.getEffectiveSgLayoutAsInt();
2419 for (
int dim = 0; dim < srcRank; dim++) {
2420 if (llvm::is_contained(reductionDims, dim))
2422 srcLayout.setDimData(dim, srcSgData.value()[dim], -1, -1);
2426 consumerLayout ? consumerLayout.getEffectiveSgLayoutAsInt()
2429 consumerLayout ? consumerLayout.getEffectiveSgDataAsInt()
2432 consumerLayout ? consumerLayout.getEffectiveOrderAsInt()
2435 consumerLayout ? consumerLayout.getOrder() :
nullptr;
2437 int remainingSgCount =
2438 consumerLayout ? consumerLayout.getNumSubgroups() : numSg;
2439 int consumerIdx = 0;
2442 for (
int i = 0; i < srcRank; i++) {
2443 if (!llvm::is_contained(reductionDims, i) &&
2444 consumerIdx <
static_cast<int>(consumerSgLayout.size())) {
2445 sgLayout[i] = consumerSgLayout[consumerIdx];
2446 sgData[i] = consumerSgData[consumerIdx];
2447 remainingSgCount /= sgLayout[i];
2448 order[i] = consumerOrder[consumerIdx];
2455 int64_t remainOrder = consumerSgLayout.size();
2456 for (
int i = 0; i < srcRank; i++) {
2457 if (llvm::is_contained(reductionDims, i)) {
2459 std::min(srcShape[i],
static_cast<int64_t>(remainingSgCount));
2460 assert((srcShape[i] % sgLayout[i] == 0) &&
2461 "source shape not divisible by sg_layout");
2462 sgData[i] = srcShape[i] / sgLayout[i];
2463 remainingSgCount /= sgLayout[i];
2464 order[i] = remainOrder++;
2469 if (!orderAttr || orderAttr.empty())
2470 resOrderAttr =
nullptr;
2471 assert(remainingSgCount == 1 &&
"not all subgroups distributed");
2472 srcLayout =
buildLayout(context, sgLayout, sgData,
2477 xegpu::SliceAttr consumerSliceLayout =
2478 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2479 auto consumerReductionDims =
2485 bool verticalLaneLayout = consumerReductionDims.empty() &&
2486 reductionDims.size() == 1 &&
2487 reductionDims[0] == (srcRank - 1);
2489 srcShape, reductionDims, subgroupSize, maxReduceVectorSize,
2490 verticalLaneLayout);
2494 for (
int i = 0; i < srcRank; i++)
2495 instData[i] = laneLayout[i] * laneData[i];
2502 "Lane reduction layout assumes all leading (non-innermost-two) "
2503 "dimensions are unit dimensions");
2504 xegpu::SliceAttr consumerSliceLayout =
2505 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2506 auto consumerReductionDims =
2510 if (consumerSliceLayout &&
2511 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2515 srcLayout = consumerSliceLayout.getParent();
2517 bool verticalLaneLayout = consumerReductionDims.empty() &&
2518 reductionDims.size() == 1 &&
2519 reductionDims[0] == (srcRank - 1);
2521 srcShape, reductionDims, subgroupSize, maxReduceVectorSize,
2522 verticalLaneLayout);
2527 return xegpu::SliceAttr::get(context, srcLayout,
2535 VectorType srcVecTy,
2538 auto srcShape = srcVecTy.getShape();
2539 auto context = srcVecTy.getContext();
2540 auto subgroupSize =
uArch->getSubgroupSize();
2541 xegpu::LayoutAttr srcLayout;
2545 "subgroup layout assignment not supported for reduction (op "
2546 "is not expected at this level).");
2549 "instData layout assignment not supported for reduction (op "
2550 "is not expected at this level).");
2553 laneLayout[0] = std::min(
static_cast<int64_t>(subgroupSize), srcShape[0]);
2558 auto result = xegpu::SliceAttr::get(context, srcLayout,
2576static xegpu::DistributeLayoutAttr
2579 size_t innerMostDim,
int ratio,
int64_t bound,
2585 consumerLayout.getEffectiveLaneLayoutAsInt();
2592 sgDataValue = sgData[innerMostDim];
2593 while ((sgDataValue <= bound) && (sgDataValue % ratio) != 0)
2596 instDataValue = instData[innerMostDim];
2597 const int innermostDimLaneLayout = laneLayout.empty()
2599 : laneLayout[innerMostDim];
2600 while ((instDataValue <= bound) &&
2601 (instDataValue % (innermostDimLaneLayout * ratio) != 0))
2603 assert((bound % instDataValue) == 0 &&
2604 "bound, instData, and laneLayout for innermost must be 2^n!");
2606 laneDataValue = laneData[innerMostDim];
2607 while ((laneDataValue <= bound) && (laneDataValue % ratio) != 0)
2611 return consumerLayout.setDimData(innerMostDim, sgDataValue, instDataValue,
2641 int srcElemTyBitWidth = srcVecTy.getElementType().getIntOrFloatBitWidth();
2642 int resElemTyBitWidth = resVecTy.getElementType().getIntOrFloatBitWidth();
2647 assert(consumerLayout.getRank() ==
static_cast<int64_t>(srcShape.size()) &&
2648 "laneData must be available for all dimensions");
2652 if (srcElemTyBitWidth <= resElemTyBitWidth)
2653 return consumerLayout;
2658 size_t innerMostDim = srcShape.size() - 1;
2659 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
2661 innerMostDim, bitWidthRatio,
2662 resShape[innerMostDim],
uArch);
2685 assert(consumerLayout.getRank() ==
static_cast<int64_t>(resShape.size()) &&
2686 "consumer layout rank must match source shape rank");
2691 const size_t innerMostDim = resShape.size() - 1;
2692 constexpr int ratio = 2;
2694 innerMostDim, ratio,
2695 resShape[innerMostDim],
uArch);
2703 VectorType resVectorTy, xegpu::DistributeLayoutAttr consumerLayout,
2706 xegpu::DistributeLayoutAttr requiredResLayout;
2708 consumerLayout.getEffectiveInstDataAsInt();
2710 consumerLayout.getEffectiveLaneDataAsInt();
2712 consumerLayout.getEffectiveLaneLayoutAsInt();
2716 requiredResLayout = consumerLayout;
2717 int srcRank = srcShape.size();
2721 assert(
false &&
"subgroup/instData layout assignment not supported for "
2722 "insertStridedSlice.");
2724 for (
int dim = 0; dim < srcRank; dim++) {
2726 if (srcShape[dim] == 1) {
2729 assert(srcShape[dim] % consumerLaneLayout[dim] == 0 &&
2730 "srcShape must be divisible by laneLayout for all dimensions");
2731 laneDataValue = std::min(srcShape[dim] / consumerLaneLayout[dim],
2732 consumerLaneData[dim]);
2735 requiredResLayout.setDimData(dim, -1, -1, laneDataValue);
2738 return requiredResLayout;
2748 OpOperand &operand, xegpu::DistributeLayoutAttr resLayout) {
2755 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op)) {
2756 auto srcTy = dyn_cast<VectorType>(
broadcast.getSourceType());
2760 resLayout,
broadcast.getResultVectorType().getShape(),
2767 if (
auto reduction = dyn_cast<vector::MultiDimReductionOp>(op)) {
2776 if (
auto reduction = dyn_cast<vector::ReductionOp>(op))
2781 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
2782 int resElemBitWidth =
2783 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
2784 int srcElemBitWidth =
2785 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
2792 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
2794 resLayout, shapeCast.getResultVectorType().getShape(),
2795 shapeCast.getSourceVectorType().getShape());
2800 if (
auto insertSlice = dyn_cast<vector::InsertStridedSliceOp>(op)) {
2803 resLayout, insertSlice.getDestVectorType().getShape(),
2804 insertSlice.getSourceVectorType().getShape());
2812 if (
auto insert = dyn_cast<vector::InsertOp>(op)) {
2813 VectorType resVecTy = dyn_cast<VectorType>(insert.getResult().getType());
2814 VectorType valueToStoreTy =
2815 dyn_cast<VectorType>(insert.getValueToStore().getType());
2817 if ((idx == 0) && valueToStoreTy) {
2819 valueToStoreTy.getShape());
2827 if (
auto extract = dyn_cast<vector::ExtractOp>(op)) {
2828 VectorType srcVecTy = dyn_cast<VectorType>(extract.getSource().getType());
2829 VectorType resVecTy = dyn_cast<VectorType>(extract.getResult().getType());
2830 if (!srcVecTy || !resVecTy)
2833 srcVecTy.getShape());
2838 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
2840 transpose.getPermutation());
2845 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
2846 int resElemBitWidth =
2847 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
2848 int srcElemBitWidth =
2849 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
2855 if (
auto interleave = dyn_cast<vector::InterleaveOp>(op)) {
2860 if (
auto deinterleave = dyn_cast<vector::DeinterleaveOp>(op)) {
2865 if (dyn_cast<vector::ExtractStridedSliceOp>(op))
2881 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
2882 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
2886 branch.getSuccessorOperandInputMapping(mapping,
2888 auto it = mapping.find(&operand);
2889 if (it == mapping.end())
2891 xegpu::DistributeLayoutAttr iterArgLayout;
2892 for (
Value input : it->second) {
2893 auto arg = dyn_cast<BlockArgument>(input);
2897 assert((!iterArgLayout || !layout || iterArgLayout.isEqualTo(layout)) &&
2898 "region inputs fed by one terminator operand disagree on layout");
2900 iterArgLayout = layout;
2902 return iterArgLayout;
2908 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
2909 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
2913 branch.getSuccessorOperandInputMapping(mapping,
2915 auto it = mapping.find(&operand);
2916 if (it == mapping.end())
2918 for (
Value input : it->second)
2919 if (
auto result = dyn_cast<OpResult>(input))
2932 if (isa<xegpu::AnchorLayoutInterface>(op))
2940 if (isa<RegionBranchOpInterface>(op))
2945 if (
auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(op)) {
2952 xegpu::DistributeLayoutAttr resLayout;
2953 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 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 xegpu::DistributeLayoutAttr getParentResultLayoutForYieldOperand(RegionBranchTerminatorOpInterface terminator, OpOperand &operand)
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 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.
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 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 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...
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 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, 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 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.
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