32#include "llvm/ADT/DenseSet.h"
33#include "llvm/ADT/PostOrderIterator.h"
34#include "llvm/Support/FormatVariadic.h"
44 out.reserve(attrs.size());
46 for (
auto attr : attrs) {
47 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr.getValue())) {
48 auto newLayout = dist.dropSgLayoutAndData();
50 out.emplace_back(attr.getName(), newLayout);
62 out.reserve(attrs.size());
64 for (
auto attr : attrs) {
65 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr.getValue())) {
66 auto newLayout = dist.dropInstData();
68 out.emplace_back(attr.getName(), newLayout);
79 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr))
80 attr = dist.dropInstData();
87 auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(val.
getType());
88 if (!tensorDescTy || tensorDescTy.getLayoutAttr())
90 auto typeWithLayout = xegpu::TensorDescType::get(
91 tensorDescTy.getContext(), tensorDescTy.getShape(),
92 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
107 llvm::ReversePostOrderTraversal<Region *> rpot(®ion);
109 for (
Block *block : llvm::reverse(blocks)) {
111 for (
Operation &op : llvm::reverse(*block)) {
119 for (
Region &nested : op.getRegions())
128 xegpu::DistributeLayoutAttr layout =
nullptr;
149 if (
auto constant = dyn_cast<arith::ConstantOp>(op)) {
150 auto value = dyn_cast<DenseElementsAttr>(constant.getValue());
151 return value && value.isSplat();
153 if (isa<vector::StepOp, vector::CreateMaskOp>(op))
155 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op))
156 return !isa<VectorType>(
broadcast.getSource().getType());
168 while (!worklist.empty()) {
169 auto [op, expanded] = worklist.pop_back_val();
174 if (!visited.insert(op).second)
179 worklist.emplace_back(op,
true);
180 for (
Value operand : op->getOperands()) {
181 if (!isa<VectorType>(operand.getType()))
183 Operation *producer = operand.getDefiningOp();
186 if (!visited.contains(producer))
187 worklist.emplace_back(producer,
false);
214 return mapping.
lookup(value);
222 if (op->
getNumResults() > 1 && !isa<vector::DeinterleaveOp>(op))
233 if (isa<xegpu::TensorDescType>(resultType))
238 if (isa<VectorType>(resultType) || isa<vector::MultiDimReductionOp>(op))
241 if (isa<vector::DeinterleaveOp>(op))
245 xegpu::DistributeLayoutAttr operandLayout =
247 if (isa<VectorType>(opr.get().getType()) && operandLayout)
259 mlir::RegionBranchTerminatorOpInterface yieldOp) {
260 auto regionBranchOp =
261 dyn_cast<RegionBranchOpInterface>(yieldOp->getParentOp());
267 yieldOp.getSuccessorRegions(operandAttrs, successors);
270 OperandRange succOps = yieldOp.getSuccessorOperands(successor);
274 ValueRange successorInputs = regionBranchOp.getSuccessorInputs(successor);
275 unsigned count = std::min<unsigned>(succOps.size(), successorInputs.size());
277 for (
unsigned i = 0; i < count; ++i) {
278 xegpu::DistributeLayoutAttr layout;
279 if (successor.isOperation()) {
282 auto regionResult = regionBranchOp->getResult(i);
287 if (isa<xegpu::TensorDescType>(regionResult.getType()))
298 auto operandType = succOps[i].
getType();
299 if (isa<VectorType>(operandType) ||
300 dyn_cast<xegpu::TensorDescType>(operandType))
321 mlir::RegionBranchTerminatorOpInterface terminator,
324 auto branchOp = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
329 branchOp.getSuccessorOperandInputMapping(mapping,
331 for (
const auto &[successorOperand, successorInputs] : mapping) {
332 for (
Value successorInput : successorInputs) {
333 Type inputType = successorInput.getType();
335 if (!isa<VectorType>(inputType))
337 xegpu::DistributeLayoutAttr successorOperandLayout =
338 getLayoutOfValue(successorOperand->get());
341 if (!successorOperandLayout)
344 if (
auto result = dyn_cast<OpResult>(successorInput))
350 if (
auto arg = dyn_cast<BlockArgument>(successorInput)) {
352 dyn_cast<LoopLikeOpInterface>(arg.getOwner()->getParentOp());
353 bool tiedToInit = loop && loop.getTiedLoopInit(arg);
354 if (!tiedToInit && !isa<BlockArgument>(successorOperand->get()))
355 return terminator->emitError(
356 "unsupported region structure: the successor argument it feeds "
357 "is not tied to an init operand, so its value must be passed "
358 "through from predecessor region argument.");
375 for (
Region ®ion : regionOp->getRegions()) {
380 ValueRange successorInputs = regionOp.getSuccessorInputs(regionSuccessor);
381 for (
auto [inputIdx, regionArg] : llvm::enumerate(successorInputs)) {
382 auto layout = getLayoutOfValue(regionArg);
387 if (isa<xegpu::TensorDescType>(regionArg.getType()))
393 regionOp.getPredecessorValues(regionSuccessor, inputIdx, predValues);
394 for (
Value predVal : predValues) {
396 for (
OpOperand &operand : regionOp->getOpOperands()) {
397 if (operand.get() == predVal)
436 auto processFunc = [&](
Region &body, StringRef funcName) {
438 if (
auto regionOp = dyn_cast<mlir::RegionBranchOpInterface>(op)) {
441 }
else if (
auto yieldOp =
442 dyn_cast<mlir::RegionBranchTerminatorOpInterface>(op)) {
444 }
else if (!dyn_cast<xegpu::AnchorLayoutInterface>(op)) {
450 rootOp->
walk([&](func::FuncOp
func) {
451 processFunc(
func.getBody(),
func.getSymName());
453 rootOp->
walk([&](gpu::GPUFuncOp
func) {
454 processFunc(
func.getBody(),
func.getName());
460template <
typename T,
typename>
462 Operation *owner = operandOrResult.getOwner();
481 if (isa<DistributeLayoutAttr>(namedAttr.getValue()))
482 attrsToRemove.push_back(namedAttr.getName());
484 for (
auto attrName : attrsToRemove)
493 if (isa<xegpu::DistributeLayoutAttr>(namedAttr.getValue()))
494 attrsToRemove.push_back(namedAttr.getName());
496 for (
auto attrName : attrsToRemove)
505 auto toI32Attr = [&](
auto range) {
509 return xegpu::LayoutAttr::get(context,
nullptr,
510 nullptr, toI32Attr(instData),
511 toI32Attr(laneLayout), toI32Attr(laneData),
518 return !llvm::any_of(llvm::seq<int>(0, dataShape.size()), [&](
int dim) {
519 return dataShape[dim] % (laneLayout[dim] * laneData[dim]) != 0;
523static xegpu::LayoutAttr
527 auto toI32Attr = [&](
auto range) {
531 return xegpu::LayoutAttr::get(context,
nullptr,
533 nullptr, toI32Attr(laneLayout),
534 toI32Attr(laneData), orderAttr);
537static xegpu::LayoutAttr
542 auto toI32Attr = [&](
auto range) {
546 return xegpu::LayoutAttr::get(
547 context, sgLayout.empty() ?
nullptr : toI32Attr(sgLayout),
548 sgData.empty() ?
nullptr : toI32Attr(sgData),
549 instData.empty() ?
nullptr : toI32Attr(instData),
550 laneLayout.empty() ?
nullptr : toI32Attr(laneLayout),
551 laneData.empty() ?
nullptr : toI32Attr(laneData), orderAttr);
560 for (
int dim = 0; dim < (int)sgLayout.size(); ++dim) {
562 sgData[dim] = wgTileShape[dim];
564 sgData[dim] = wgTileShape[dim] / sgLayout[dim];
573xegpu::DistributeLayoutAttr
579 size_t dimDiff = resShape.size() - srcShape.size();
580 auto bcastSourceLayout = resLayout;
583 for (
size_t i = dimDiff; i < resShape.size(); i++) {
584 if ((srcShape[i - dimDiff] == 1) && (resShape[i] != 1))
585 bcastDims.push_back(i);
590 if (!bcastDims.empty())
591 bcastSourceLayout = bcastSourceLayout.setUnitDimData(bcastDims);
596 bool isOuterDimDiffUnitDims = llvm::all_of(
597 resShape.take_front(dimDiff), [&](
int64_t dim) { return dim == 1; });
598 if (dimDiff && bcastDims.size() == dimDiff && isOuterDimDiffUnitDims) {
601 sliceDims.assign(bcastDims.begin(), bcastDims.end());
605 llvm::append_range(sliceDims, llvm::seq<int64_t>(0, dimDiff));
607 bcastSourceLayout = xegpu::SliceAttr::get(
608 resLayout.getContext(), bcastSourceLayout,
611 return bcastSourceLayout;
616xegpu::DistributeLayoutAttr
620 assert(isa<xegpu::SliceAttr>(resLayout) &&
621 "reduction result layout must be slice layout");
623 xegpu::SliceAttr sliceLayout = dyn_cast<xegpu::SliceAttr>(resLayout);
625 assert((reduceDims == sliceLayout.getDims().asArrayRef()) &&
626 "reduction dims must match with slice dims");
628 return sliceLayout.getParent();
631xegpu::DistributeLayoutAttr
642xegpu::DistributeLayoutAttr
653xegpu::DistributeLayoutAttr
655 int resElemTyBitWidth,
int srcElemTyBitWidth) {
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;
668 if (srcElemTyBitWidth <= resElemTyBitWidth) {
669 int bitWidthRatio = resElemTyBitWidth / srcElemTyBitWidth;
671 sgDataValue = sgData.back() * bitWidthRatio;
673 instDataValue = instData.back() * bitWidthRatio;
675 laneDataValue = laneData.back() * bitWidthRatio;
677 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
679 assert((sgData.back() % bitWidthRatio) == 0 &&
680 "sgData not divisible by bitWidthRatio");
681 sgDataValue = sgData.back() / bitWidthRatio;
684 assert((instData.back() % bitWidthRatio) == 0 &&
685 "instData not divisible by bitWidthRatio");
686 instDataValue = instData.back() / bitWidthRatio;
689 assert((laneData.back() % bitWidthRatio) == 0 &&
690 "laneData not divisible by bitWidthRatio");
691 laneDataValue = laneData.back() / bitWidthRatio;
695 xegpu::DistributeLayoutAttr finalSrcLayout;
697 resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
699 return finalSrcLayout;
706xegpu::DistributeLayoutAttr
712 size_t sgDataSize = sgData.size();
713 size_t instDataSize = instData.size();
714 size_t laneDataSize = laneData.size();
718 int64_t dim = resLayout.getRank() - 1;
722 constexpr int ratio = 2;
724 assert((sgData.back() % ratio) == 0 &&
725 "sgData not divisible by interleave ratio");
726 sgDataValue = sgData.back() / ratio;
729 assert((instData.back() % ratio) == 0 &&
730 "instData not divisible by interleave ratio");
731 instDataValue = instData.back() / ratio;
734 assert((laneData.back() % ratio) == 0 &&
735 "laneData not divisible by interleave ratio");
736 laneDataValue = laneData.back() / ratio;
739 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
746xegpu::DistributeLayoutAttr
752 size_t sgDataSize = sgData.size();
753 size_t instDataSize = instData.size();
754 size_t laneDataSize = laneData.size();
758 int64_t dim = resLayout.getRank() - 1;
762 constexpr int ratio = 2;
764 sgDataValue = sgData.back() * ratio;
766 instDataValue = instData.back() * ratio;
768 laneDataValue = laneData.back() * ratio;
770 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
780 int srcShapeSize = srcShape.size();
781 int resShapeSize = resShape.size();
782 int dimDiff = resShapeSize - srcShapeSize;
787 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
788 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
789 for (
int i = 0; i < dimDiff; i++) {
790 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
791 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
792 "Leading dimensions being sliced off must not be distributed");
794 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
803xegpu::DistributeLayoutAttr
808 int srcShapeSize = srcShape.size();
809 int resShapeSize = resShape.size();
810 int dimDiff = resShapeSize - srcShapeSize;
815 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
816 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
817 for (
int i = 0; i < dimDiff; i++) {
818 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
819 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
820 "Leading dimensions being sliced off must not be distributed");
822 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
832xegpu::DistributeLayoutAttr
837 int srcShapeSize = srcShape.size();
838 int resShapeSize = resShape.size();
839 int dimDiff = srcShapeSize - resShapeSize;
840 auto context = resLayout.getContext();
844 auto sgLayout = resLayout.getEffectiveSgLayoutAsInt();
845 auto sgData = resLayout.getEffectiveSgDataAsInt();
846 auto instData = resLayout.getEffectiveInstDataAsInt();
847 auto laneLayout = resLayout.getEffectiveLaneLayoutAsInt();
848 auto laneData = resLayout.getEffectiveLaneDataAsInt();
849 auto order = resLayout.getEffectiveOrderAsInt();
859 for (
auto &o : order)
865 for (
int i = 0; i < dimDiff; i++) {
866 if (!sgLayout.empty())
867 sgLayout.insert(sgLayout.begin(), 1);
869 sgData.insert(sgData.begin(), 1);
870 if (!instData.empty())
871 instData.insert(instData.begin(), 1);
872 if (!laneLayout.empty())
873 laneLayout.insert(laneLayout.begin(), 1);
874 if (!laneData.empty())
875 laneData.insert(laneData.begin(), 1);
876 order.push_back(dimDiff - 1 - i);
881 if (!resLayout.getOrder())
884 return buildLayout(context, sgLayout, sgData, instData, laneLayout,
885 laneData, orderAttr);
892xegpu::DistributeLayoutAttr
916 xegpu::SliceAttr::get(resLayout.getContext(), resLayout, sliceDimsAttr);
923 auto srcLayout = resLayout;
924 for (
const auto &dimGroup : splitDimGroups)
925 srcLayout = srcLayout.collapseDims(dimGroup);
934 auto srcLayout = resLayout;
935 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
936 dstIdx >= 0; --dstIdx) {
938 if (srcDims.empty()) {
939 srcLayout = srcLayout.dropDims({dstIdx});
942 if (srcDims.size() == 1)
945 targetShape.reserve(srcDims.size());
947 targetShape.push_back(srcShape[d]);
948 srcLayout = srcLayout.expandDim(dstIdx, targetShape);
966xegpu::DistributeLayoutAttr
969 return srcLayout.transposeDims(permutation);
980xegpu::DistributeLayoutAttr
989 auto resLayout = srcLayout;
992 for (
int64_t srcIdx =
static_cast<int64_t>(splitDimGroups.size()) - 1;
993 srcIdx >= 0; --srcIdx) {
995 if (resDims.size() <= 1)
998 targetShape.reserve(resDims.size());
1000 targetShape.push_back(resShape[d]);
1001 resLayout = resLayout.expandDim(srcIdx, targetShape);
1010 auto resLayout = srcLayout;
1013 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
1014 dstIdx >= 0; --dstIdx) {
1018 if (srcDims.empty())
1020 if (srcDims.size() == 1)
1022 resLayout = resLayout.collapseDims(llvm::to_vector(srcDims));
1039 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
1040 if (!operandLayouts[0])
1043 transpose.getPermutation());
1047 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
1048 if (!operandLayouts[0])
1051 operandLayouts[0], shapeCast.getSourceVectorType().getShape(),
1052 shapeCast.getResultVectorType().getShape());
1058 for (xegpu::DistributeLayoutAttr layout : operandLayouts)
1095 auto getDivisors = [](
int64_t n) {
1097 for (
int64_t i = 1; i * i <= n; ++i) {
1101 divs.push_back(n / i);
1110 if (dim == rank - 1) {
1111 current[dim] = remaining;
1115 for (
int64_t factor : getDivisors(remaining)) {
1116 current[dim] = factor;
1117 generate(dim + 1, remaining / factor);
1143 int64_t rank = wgShape.size();
1144 assert(rank > 0 &&
"wgShape must be non-empty");
1145 assert(
static_cast<int64_t>(instData.size()) == rank &&
1146 "instData rank must match wgShape rank");
1153 for (
const auto &sgLayout : allFactorizations) {
1155 for (
int64_t dim = 0; dim < rank; ++dim) {
1159 if (dim == broadcastDim) {
1160 sgData = wgShape[dim];
1162 if (wgShape[dim] % sgLayout[dim] != 0) {
1166 sgData = wgShape[dim] / sgLayout[dim];
1168 if (sgData % instData[dim] != 0) {
1174 candidates.push_back(sgLayout);
1180 int64_t spreadLhs = *llvm::max_element(lhs) - *llvm::min_element(lhs);
1181 int64_t spreadRhs = *llvm::max_element(rhs) - *llvm::min_element(rhs);
1182 if (spreadLhs != spreadRhs)
1183 return spreadLhs < spreadRhs;
1194 bool transform =
false,
bool transpose =
false) {
1195 int rank = dataShape.size();
1199 return std::nullopt;
1200 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1206 assert(rank >= 2 &&
"dataShape must be at least 2D for 2D-block IO");
1213 if (instWidth < 0 || instHeight < 0)
1214 return std::nullopt;
1215 instData.back() = instWidth;
1216 instData[rank - 2] = instHeight;
1232 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1233 int rank = dataShape.size();
1234 assert(rank >= 2 &&
"dataShape must be at least 2D for 2D-block IO");
1237 for (
int width : bWidths) {
1238 if (width <= 0 || dataShape[rank - 1] % width != 0)
1240 for (
int height : bHeights) {
1241 if (height <= 0 || dataShape[rank - 2] % height != 0)
1244 instData[rank - 1] = width;
1245 instData[rank - 2] = height;
1246 instDataCandidates.push_back(std::move(instData));
1253 int64_t hL = lhs[rank - 2], wL = lhs[rank - 1];
1254 int64_t hR = rhs[rank - 2], wR = rhs[rank - 1];
1255 if (hL * wL != hR * wR)
1256 return hL * wL > hR * wR;
1257 if (std::min(hL, wL) != std::min(hR, wR))
1258 return std::min(hL, wL) > std::min(hR, wR);
1264 if (!sgLayouts.empty())
1265 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1276 VectorType aTy, VectorType bTy, VectorType cdTy,
1280 const unsigned dataALen = aTy.getShape()[aTy.getRank() - 2];
1281 auto supportedALen = uArchInstruction->
getSupportedM(aTy.getElementType());
1286 const unsigned dataBLen = bTy.getShape().back();
1287 auto supportedBLen = uArchInstruction->
getSupportedN(bTy.getElementType());
1291 auto supportedCLen = uArchInstruction->
getSupportedN(cdTy.getElementType());
1294 if (maxALen == -1 || maxBLen == -1 || maxCLen == -1)
1295 return std::nullopt;
1297 auto supportedKLen = uArchInstruction->
getSupportedK(aTy.getElementType());
1298 if (supportedKLen.empty())
1299 return std::nullopt;
1300 auto kDimSize = supportedKLen[0];
1303 instDataA[aTy.getRank() - 2] = maxALen;
1304 instDataA[aTy.getRank() - 1] = kDimSize;
1306 instDataB[bTy.getRank() - 2] = kDimSize;
1307 instDataB[bTy.getRank() - 1] = maxBLen;
1309 instDataCD[cdTy.getRank() - 2] = maxALen;
1310 instDataCD[cdTy.getRank() - 1] = maxCLen;
1311 return std::make_tuple(instDataA, instDataB, instDataCD);
1324 int64_t rank = instShape.size();
1327 laneLayout[innermost] = std::min(subgroupSize, instShape[innermost]);
1328 laneData[innermost] =
1329 std::min(instShape[innermost] / laneLayout[innermost], maxChunkSize);
1330 return {laneLayout, laneData};
1345 bool transform =
false,
bool transpose =
false) {
1346 int64_t rank = instShape.size();
1347 assert(rank >= 2 &&
"Expected at least a 2D shape for a 2D block op");
1351 laneData[packDim] = llvm::divideCeil(packingSize, bitwidth);
1353 int64_t laneDim = transpose ? rank - 2 : rank - 1;
1354 laneLayout[laneDim] =
1355 std::min(subgroupSize, instShape[laneDim] / laneData[laneDim]);
1358 for (
int64_t i = 0; i < rank; ++i)
1359 order.push_back(rank - 1 - i);
1360 std::swap(order[0], order[1]);
1364 for (
int64_t i = 0; i < rank; ++i) {
1365 int64_t laneProduct = laneLayout[i] * laneData[i];
1366 assert(instShape[i] % laneProduct == 0 &&
1367 "lane_layout * lane_data must evenly divide the inst shape");
1370 return {laneLayout, laneData, order};
1430 int subgroupSize,
int64_t maxReduceVectorSize,
1431 xegpu::DistributeLayoutAttr consumerLayout =
nullptr) {
1432 int srcRank = srcShape.size();
1434 auto isReduced = [&](
int dim) {
1435 return llvm::is_contained(reductionDims, dim);
1441 auto consumerSlice = dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
1442 bool reusedParent =
false;
1443 if (consumerSlice &&
1444 consumerSlice.getDims().asArrayRef().equals(reductionDims)) {
1445 auto parent = consumerSlice.getParent();
1447 parent.getEffectiveLaneLayoutAsInt();
1449 if (
static_cast<int>(parentLaneLayout.size()) == srcRank &&
1450 static_cast<int>(parentLaneData.size()) == srcRank &&
1452 laneLayout = std::move(parentLaneLayout);
1453 laneData = std::move(parentLaneData);
1454 reusedParent =
true;
1455 parentInstData = parent.getEffectiveInstDataAsInt();
1456 if (
static_cast<int>(parentInstData.size()) != srcRank)
1457 parentInstData.clear();
1461 for (
int i = 0; i < srcRank; ++i)
1462 laneLayout[i] = std::min(
1463 laneLayout[i], std::max<int64_t>(1, srcShape[i] / laneData[i]));
1469 if (!reusedParent) {
1471 if (consumerLayout) {
1472 consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
1473 consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
1475 for (
int i = 0, c = 0; i < srcRank; ++i) {
1478 if (c <
static_cast<int>(consumerLaneLayout.size()))
1479 laneLayout[i] = consumerLaneLayout[c];
1480 if (c <
static_cast<int>(consumerLaneData.size()))
1481 laneData[i] = consumerLaneData[c];
1486 for (
int i = 0; i < srcRank; ++i)
1487 laneLayout[i] = std::min(laneLayout[i],
1488 std::max<int64_t>(1, srcShape[i] / laneData[i]));
1493 int innermost = srcRank - 1;
1494 if (isReduced(innermost)) {
1498 laneLayout[innermost] =
1499 std::min(spareLanes, std::max<int64_t>(1, srcShape[innermost]));
1501 if (laneLayout[innermost] == 1) {
1505 if (vectorBudget > 1)
1506 laneData[innermost] =
1507 std::min(vectorBudget * laneData[innermost], srcShape[innermost]);
1515 for (
int i = 0; i < srcRank; ++i) {
1516 instData[i] = laneLayout[i] * laneData[i];
1517 if (isReduced(i) || parentInstData.empty())
1521 int64_t wider = parentInstData[i];
1522 if (wider > instData[i] && wider % instData[i] == 0 &&
1523 srcShape[i] % wider == 0)
1524 instData[i] = wider;
1527 return {laneLayout, laneData, instData};
1590static std::optional<
1591 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1592 xegpu::DistributeLayoutAttr>>
1595 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1603 std::optional<LayoutRepresentation> consumerSgLayout = std::nullopt;
1604 if (consumerLayout && consumerLayout.isForWorkgroup()) {
1605 consumerSgLayout = consumerLayout.getEffectiveSgLayoutAsInt();
1610 auto pickSgLayout = [&]() -> std::optional<LayoutRepresentation> {
1616 if (layoutsA.empty() || layoutsB.empty() || layoutsCD.empty())
1617 return std::nullopt;
1619 std::optional<LayoutRepresentation> bestPick;
1620 for (
auto &sgLayout : layoutsB) {
1621 if (llvm::is_contained(layoutsA, sgLayout) &&
1622 llvm::is_contained(layoutsCD, sgLayout)) {
1624 if (consumerSgLayout.has_value() && sgLayout == *consumerSgLayout)
1631 bestPick = sgLayout;
1639 int64_t mDimA = aTy.getRank() - 2;
1640 int64_t mDimCD = cdTy.getRank() - 2;
1641 auto supportedM = uArchInstruction->
getSupportedM(aTy.getElementType());
1642 llvm::sort(supportedM, std::greater<uint32_t>());
1644 std::optional<LayoutRepresentation> bestPick;
1645 for (
unsigned m : supportedM) {
1646 if (m == 0 || aTy.getShape()[mDimA] % m != 0)
1648 instDataA[mDimA] = m;
1649 instDataCD[mDimCD] = m;
1650 if ((bestPick = pickSgLayout()))
1654 return std::nullopt;
1656 const auto &picked = *bestPick;
1658 auto dpasALayout =
buildSgLayout(context, aTy.getShape(), picked,
1660 auto dpasBLayout =
buildSgLayout(context, bTy.getShape(), picked,
1662 auto dpasCDLayout =
buildSgLayout(context, cdTy.getShape(), picked);
1663 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout);
1670 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1671 xegpu::DistributeLayoutAttr>>
1673 VectorType bTy, VectorType cdTy,
1674 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1676 auto context = aTy.getContext();
1677 const auto *uArchInstruction =
1678 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1680 if (!uArchInstruction)
1681 return std::nullopt;
1684 auto [laneLayoutA, laneDataA, orderA] =
1686 aTy.getElementType().getIntOrFloatBitWidth(),
1687 uArchInstruction->getPackedFormatBitSizeA());
1689 bTy.getShape(), subgroupSize,
1690 bTy.getElementType().getIntOrFloatBitWidth(),
1691 uArchInstruction->getPackedFormatBitSizeB(),
true);
1692 auto [laneLayoutCD, laneDataCD, orderCD] =
1694 cdTy.getElementType().getIntOrFloatBitWidth(),
1695 cdTy.getElementType().getIntOrFloatBitWidth());
1699 return std::nullopt;
1703 "Number of subgroups must be provided for sg layout creation.");
1705 numSg, *instDataVecs, uArchInstruction);
1707 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1708 return std::make_tuple(
1717 return std::make_tuple(aLayout, bLayout, cdLayout);
1719 return std::nullopt;
1726static xegpu::DistributeLayoutAttr
1728 VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout,
1730 if (!scaleTy || !matrixLayout)
1738 if (scaleShape.empty())
1741 auto uArchInstruction =
1742 dyn_cast<xegpu::uArch::SubgroupScaledMatrixMultiplyAcc>(
1746 int64_t rank = matrixLayout.getRank();
1747 assert(rank >= 2 &&
"dpas layouts must be at least two dimensions");
1754 auto order = matrixLayout.getOrder();
1758 if (!sgLayout.empty() && !sgData.empty()) {
1759 scaleSgLayout.assign(sgLayout.begin(), sgLayout.end());
1760 scaleSgData.assign(sgData.begin(), sgData.end());
1761 scaleSgData[rank - 2] = std::max<int64_t>(
1762 scaleShape[rank - 2] / (matrixShape[rank - 2] / sgData[rank - 2]), 1);
1763 scaleSgData[rank - 1] = std::max<int64_t>(
1764 scaleShape[rank - 1] / (matrixShape[rank - 1] / sgData[rank - 1]), 1);
1771 if (!instData.empty()) {
1772 scaleInstData.assign(instData.begin(), instData.end());
1774 scaleInstData[rank - 2] = std::max<int64_t>(
1775 scaleShape[rank - 2] / (matrixShape[rank - 2] / instData[rank - 2]),
1778 scaleInstData[rank - 1] = std::max<int64_t>(
1779 scaleShape[rank - 1] / (matrixShape[rank - 1] / instData[rank - 1]),
1785 if (!laneLayout.empty() && !laneData.empty()) {
1786 scaleLaneLayout.assign(laneLayout.begin(), laneLayout.end());
1787 scaleLaneData.assign(laneData.size(), 1);
1789 bool isRowMajor = uArchInstruction->isLaneLayoutRowMajorOrder();
1790 if (isBScale ^ isRowMajor)
1791 std::swap(scaleLaneLayout[rank - 2], scaleLaneLayout[rank - 1]);
1796 auto layoutCap = scaleInstData.empty() ? scaleShape : scaleInstData;
1797 for (
int64_t d = rank - 2; d < rank; ++d)
1798 scaleLaneLayout[d] = std::min<int64_t>(layoutCap[d], scaleLaneLayout[d]);
1800 return buildLayout(context, scaleSgLayout, scaleSgData, scaleInstData,
1801 scaleLaneLayout, scaleLaneData, order);
1808 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1809 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1810 xegpu::DistributeLayoutAttr>>
1812 VectorType bTy, VectorType cdTy, VectorType aScaleTy,
1813 VectorType bScaleTy,
1814 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1816 auto context = aTy.getContext();
1817 const auto *uArchInstruction =
1818 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1820 if (!uArchInstruction)
1821 return std::nullopt;
1824 auto [laneLayoutA, laneDataA, orderA] =
1826 aTy.getElementType().getIntOrFloatBitWidth(),
1827 uArchInstruction->getPackedFormatBitSizeA());
1829 bTy.getShape(), subgroupSize,
1830 bTy.getElementType().getIntOrFloatBitWidth(),
1831 uArchInstruction->getPackedFormatBitSizeB(),
true);
1832 auto [laneLayoutCD, laneDataCD, orderCD] =
1834 cdTy.getElementType().getIntOrFloatBitWidth(),
1835 cdTy.getElementType().getIntOrFloatBitWidth());
1838 return std::nullopt;
1842 "Number of subgroups must be provided for sg layout creation.");
1845 *instDataVecs, uArchInstruction);
1847 return std::nullopt;
1849 auto [dpasALayout, dpasBLayout, dpasCDLayout] = *dpasLayouts;
1858 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1862 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1869 laneLayoutCD, laneDataCD);
1876 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1881 auto dpasCDLayout =
buildLaneLayout(context, laneLayoutCD, laneDataCD);
1888 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1891 return std::nullopt;
1897xegpu::DistributeLayoutAttr
1899 VectorType srcVecTy,
int numSg,
1901 const auto *uArchInstruction =
1902 dyn_cast<xegpu::uArch::Subgroup2DBlockStoreInstruction>(
1903 uArch->getInstruction(
1905 if (!uArchInstruction)
1908 auto context = srcVecTy.getContext();
1909 Type elemTy = srcVecTy.getElementType();
1910 auto subgroupSize =
uArch->getSubgroupSize();
1911 auto dataShape = srcVecTy.getShape();
1912 [[maybe_unused]]
int rank = srcVecTy.getRank();
1913 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1917 auto [laneLayout, laneData, order] =
1919 uArchInstruction->getPackedFormatBitSize());
1932 "Expected the store layout to satisfy uArch block constraints");
1939 "Number of subgroups must be provided for sg layout creation.");
1941 uArchInstruction, numSg);
1950xegpu::DistributeLayoutAttr
1952 xegpu::TensorDescType tdescTy,
int numSg,
1955 const auto *uArchInstruction =
1956 dyn_cast<xegpu::uArch::Subgroup2DBlockPrefetchInstruction>(
1959 if (!uArchInstruction)
1962 auto context = tdescTy.getContext();
1963 Type elemTy = tdescTy.getElementType();
1965 auto dataShape = tdescTy.getShape();
1966 [[maybe_unused]]
int rank = tdescTy.getRank();
1967 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1971 auto [laneLayout, laneData, order] =
1973 uArchInstruction->getPackedFormatBitSize());
1986 "Expected the prefetch layout to satisfy uArch block constraints");
1993 "Number of subgroups must be provided for sg layout creation.");
1995 uArchInstruction, numSg);
2006xegpu::DistributeLayoutAttr
2008 VectorType resVecTy,
2009 xegpu::DistributeLayoutAttr consumerLayout,
2012 assert(consumerLayout &&
"Expected a valid consumer layout");
2014 assert(consumerLayout.isForWorkgroup() &&
2015 "Expected consumer layout to be a complete workgroup-level layout");
2016 return consumerLayout;
2019 auto context = resVecTy.getContext();
2020 Type elemTy = resVecTy.getElementType();
2022 auto dataShape = resVecTy.getShape();
2023 const auto *uArchInstruction =
2024 dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
2027 if (!uArchInstruction)
2030 int rank = resVecTy.getRank();
2032 consumerLayout.getEffectiveInstDataAsInt();
2034 consumerLayout.getEffectiveLaneLayoutAsInt();
2036 consumerLayout.getEffectiveLaneDataAsInt();
2038 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
2039 "Expected consumer layout to have lane_layout and lane_data");
2045 consumerLaneLayout[rank - 2] > 1 && consumerLaneLayout[rank - 1] == 1;
2050 bool hasTransform = !hasTranspose && canTransform &&
2051 consumerLaneData[rank - 2] > 1 &&
2052 consumerLaneData[rank - 1] == 1;
2053 assert((consumerLaneData[rank - 2] == 1 || consumerLaneData[rank - 1] == 1) &&
2054 "Expected consumer lane data to have at most one non-unit dim");
2057 auto blockWHC = uArchInstruction->getBlockWidthHeightCount(
2058 elemTy, hasTransform, hasTranspose,
2062 auto [bWidths, bHeights, bCounts] = blockWHC.value();
2067 unsigned packingSize = hasTransform || hasTranspose
2069 : uArchInstruction->getPackedFormatBitSize();
2072 hasTransform, hasTranspose);
2080 int64_t height = consumerInstData[rank - 2];
2081 int64_t width = consumerInstData[rank - 1];
2082 auto maxBlockCount = *llvm::max_element(bCounts);
2083 auto maxWidth = *llvm::max_element(bWidths);
2084 if (llvm::is_contained(bWidths,
static_cast<int>(width)) ||
2085 (width % maxWidth == 0 && width / maxWidth < maxBlockCount)) {
2086 if (llvm::is_contained(bHeights,
static_cast<int>(height))) {
2088 "Expected the load layout to satisfy uArch block constraints");
2090 laneLayout, laneData, orderAttr);
2102 if (!hasTranspose && !hasTransform &&
2103 consumerInstData[rank - 1] %
2104 (laneLayout[rank - 1] * laneData[rank - 1]) !=
2109 hasTransform =
true;
2116 dataShape, elemTy, uArchInstruction, hasTransform, hasTranspose);
2121 "Expected the load layout to satisfy uArch block constraints");
2127 "Expected the lane layout to satisfy uArch block constraints");
2128 return consumerLayout;
2154 xegpu::DistributeLayoutAttr consumerLayout,
int maxChunkSize,
2158 return consumerLayout;
2161 consumerLayout.getEffectiveInstDataAsInt();
2163 consumerLayout.getEffectiveLaneLayoutAsInt();
2165 consumerLayout.getEffectiveLaneDataAsInt();
2167 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
2168 "Expected consumer layout to have lane_layout and lane_data");
2175 std::min(consumerLaneData.back(),
static_cast<int64_t>(maxChunkSize));
2179 instData.resize(resShape.size());
2180 for (
size_t i = 0; i < resShape.size(); ++i)
2181 instData[i] = laneLayout[i] * laneData[i];
2192 xegpu::DistributeLayoutAttr consumerLayout,
const uArch::uArch *uArch) {
2194 const int subgroupSize = uArch->getSubgroupSize();
2196 auto context = resVecTy.getContext();
2200 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
2203 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2206 maxChunkSize, resShape, subgroupSize);
2211xegpu::DistributeLayoutAttr
2213 VectorType resVecTy,
int contigChunkSize,
2214 xegpu::DistributeLayoutAttr consumerLayout,
2219 auto context = resVecTy.getContext();
2221 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
2224 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2226 maxChunkSize, resShape, subgroupSize);
2232static xegpu::DistributeLayoutAttr
2236 if (candidates.empty())
2239 return buildSgLayout(context, wgShape, candidates.front(), -1);
2249 auto [laneLayout, laneData] =
2253 for (
size_t i = 0; i < srcShape.size(); ++i)
2254 instData[i] = laneLayout[i] * laneData[i];
2258 "Number of subgroups must be provided for sg layout creation.");
2271xegpu::DistributeLayoutAttr
2273 VectorType srcVecTy,
int contigChunkSize,
2276 const int subgroupSize =
uArch->getSubgroupSize();
2278 auto context = srcVecTy.getContext();
2282 const auto *uArchInstruction =
2283 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2286 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2288 srcShape, subgroupSize, numSg);
2296 const int subgroupSize =
uArch->getSubgroupSize();
2298 auto context = srcVecTy.getContext();
2300 const auto *uArchInstruction =
2301 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2304 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2307 srcShape, subgroupSize, numSg);
2325std::optional<xegpu::DistributeLayoutAttr>
2327 xegpu::DistributeLayoutAttr specifiedLayout,
2328 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2330 const int subgroupSize) {
2331 if (!specifiedLayout)
2332 return specifiedLayout;
2334 specifiedLayout.getEffectiveInstDataAsInt();
2335 if (specifiedInstData.empty())
2336 return specifiedLayout;
2337 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2338 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2339 return specifiedLayout;
2342 auto *context = specifiedLayout.getContext();
2344 if (consumerLayout) {
2345 auto consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
2346 auto consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
2347 if (!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
2351 consumerLaneLayout, consumerLaneData);
2354 specifiedInstData, subgroupSize, maxChunkSize);
2356 return std::nullopt;
2364std::optional<xegpu::DistributeLayoutAttr>
2366 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2368 const int subgroupSize) {
2369 if (!specifiedLayout)
2370 return specifiedLayout;
2372 specifiedLayout.getEffectiveInstDataAsInt();
2373 if (specifiedInstData.empty())
2374 return specifiedLayout;
2375 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2376 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2377 return specifiedLayout;
2380 auto *context = specifiedLayout.getContext();
2383 specifiedInstData, subgroupSize, maxChunkSize);
2385 return std::nullopt;
2394std::optional<xegpu::DistributeLayoutAttr>
2396 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2398 const int subgroupSize) {
2399 if (!specifiedLayout)
2400 return specifiedLayout;
2402 specifiedLayout.getEffectiveInstDataAsInt();
2403 if (specifiedInstData.empty())
2404 return specifiedLayout;
2405 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2406 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2407 return specifiedLayout;
2409 auto *context = specifiedLayout.getContext();
2414 return std::nullopt;
2423std::optional<xegpu::DistributeLayoutAttr>
2425 xegpu::DistributeLayoutAttr specifiedLayout,
2426 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2428 const int subgroupSize) {
2429 if (!specifiedLayout)
2430 return specifiedLayout;
2432 specifiedLayout.getEffectiveInstDataAsInt();
2433 if (specifiedInstData.empty())
2434 return specifiedLayout;
2435 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2436 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2437 return specifiedLayout;
2438 if (!consumerLayout)
2439 return specifiedLayout;
2441 consumerLayout.getEffectiveLaneLayoutAsInt();
2443 consumerLayout.getEffectiveLaneDataAsInt();
2444 if (consumerLaneLayout.empty() || consumerLaneData.empty())
2445 return specifiedLayout;
2447 auto *context = specifiedLayout.getContext();
2448 int rank = specifiedInstData.size();
2453 for (
int i = 0; i < rank; i++) {
2454 if (consumerLaneLayout[i] > 1) {
2455 laneLayout.push_back(
2456 std::max(
static_cast<int64_t>(subgroupSize), consumerLaneLayout[i]));
2458 laneLayout.push_back(1);
2463 return std::nullopt;
2466 consumerLayout.getOrder());
2474 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2475 xegpu::DistributeLayoutAttr>>
2477 xegpu::DistributeLayoutAttr bLayout,
2478 xegpu::DistributeLayoutAttr cdLayout,
2479 VectorType aTy, VectorType bTy,
2482 auto context = aTy.getContext();
2483 const auto *uArchInstruction =
2484 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
2486 if (!uArchInstruction)
2487 return std::nullopt;
2490 laneLayoutCD, laneDataCD;
2497 if (isa<xegpu::uArch::Xe2, xegpu::uArch::Xe3p>(uArch)) {
2498 std::tie(laneLayoutA, laneDataA, orderA) =
2500 aTy.getElementType().getIntOrFloatBitWidth(),
2501 uArchInstruction->getPackedFormatBitSizeA());
2503 bTy.getShape(), subgroupSize,
2504 bTy.getElementType().getIntOrFloatBitWidth(),
2505 uArchInstruction->getPackedFormatBitSizeB(),
true);
2507 cdTy.getShape(), subgroupSize,
2508 cdTy.getElementType().getIntOrFloatBitWidth(),
2509 cdTy.getElementType().getIntOrFloatBitWidth());
2511 assert(
false &&
"Unsupported uArch for DPAS lane layout completion");
2517 return std::nullopt;
2518 return std::make_tuple(
2520 aLayout.getOrder()),
2522 bLayout.getOrder()),
2524 cdLayout.getOrder()));
2531 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2532 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2533 xegpu::DistributeLayoutAttr>>
2535 xegpu::DistributeLayoutAttr aLayout, xegpu::DistributeLayoutAttr bLayout,
2536 xegpu::DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy,
2537 VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy,
2540 aLayout, bLayout, cdLayout, aTy, bTy, cdTy, uArch);
2542 return std::nullopt;
2543 auto context = aTy.getContext();
2544 auto [completedA, completedB, completedCD] = *completed;
2551 return std::make_tuple(completedA, completedB, completedCD, aScaleLayout,
2637 auto srcShape = srcVecTy.getShape();
2638 int srcRank = srcShape.size();
2639 auto context = srcVecTy.getContext();
2641 const int subgroupSize =
uArch->getSubgroupSize();
2642 int64_t maxReduceVectorSize = 16;
2643 xegpu::DistributeLayoutAttr srcLayout;
2645 xegpu::SliceAttr consumerSliceLayout =
2646 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2647 if (consumerSliceLayout &&
2648 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2649 srcLayout = consumerSliceLayout.getParent();
2651 srcLayout.getEffectiveSgLayoutAsInt();
2654 for (
int dim = 0; dim < srcRank; dim++) {
2655 if (llvm::is_contained(reductionDims, dim))
2657 srcLayout.setDimData(dim, srcSgData.value()[dim], -1, -1);
2661 consumerLayout ? consumerLayout.getEffectiveSgLayoutAsInt()
2664 consumerLayout ? consumerLayout.getEffectiveSgDataAsInt()
2667 consumerLayout ? consumerLayout.getEffectiveOrderAsInt()
2670 consumerLayout ? consumerLayout.getOrder() :
nullptr;
2672 int remainingSgCount =
2673 consumerLayout ? consumerLayout.getNumSubgroups() : numSg;
2674 int consumerIdx = 0;
2677 for (
int i = 0; i < srcRank; i++) {
2678 if (!llvm::is_contained(reductionDims, i) &&
2679 consumerIdx <
static_cast<int>(consumerSgLayout.size())) {
2680 sgLayout[i] = consumerSgLayout[consumerIdx];
2681 sgData[i] = consumerSgData[consumerIdx];
2682 remainingSgCount /= sgLayout[i];
2689 for (
int i = 0; i < srcRank; i++) {
2690 if (llvm::is_contained(reductionDims, i)) {
2692 std::min(srcShape[i],
static_cast<int64_t>(remainingSgCount));
2693 assert((srcShape[i] % sgLayout[i] == 0) &&
2694 "source shape not divisible by sg_layout");
2695 sgData[i] = srcShape[i] / sgLayout[i];
2696 remainingSgCount /= sgLayout[i];
2702 int numRetainedDims = srcRank -
static_cast<int>(reductionDims.size());
2703 if (orderAttr && !orderAttr.empty() &&
2704 static_cast<int>(consumerOrder.size()) == numRetainedDims) {
2706 int retainedRank = 0;
2707 for (
int dim = 0; dim < srcRank; dim++)
2708 if (!llvm::is_contained(reductionDims, dim))
2709 order[dim] = consumerOrder[retainedRank++];
2712 for (
int reducedDim = 0; reducedDim < srcRank; reducedDim++) {
2713 if (!llvm::is_contained(reductionDims, reducedDim))
2718 insertRank = order[reducedDim - 1];
2721 else if (srcRank > 1)
2722 insertRank = order[reducedDim + 1] + 1;
2723 for (
int otherDim = 0; otherDim < srcRank; otherDim++)
2724 if (order[otherDim] >= insertRank)
2726 order[reducedDim] = insertRank;
2731 assert(remainingSgCount == 1 &&
"not all subgroups distributed");
2732 srcLayout =
buildLayout(context, sgLayout, sgData,
2737 auto [laneLayout, laneData, instData] =
2739 maxReduceVectorSize, consumerLayout);
2743 xegpu::SliceAttr consumerSliceLayout =
2744 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2745 if (consumerSliceLayout &&
2746 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2750 srcLayout = consumerSliceLayout.getParent();
2753 srcShape, reductionDims, subgroupSize, maxReduceVectorSize,
2760 return xegpu::SliceAttr::get(context, srcLayout,
2768 VectorType srcVecTy,
2771 auto srcShape = srcVecTy.getShape();
2772 auto context = srcVecTy.getContext();
2773 auto subgroupSize =
uArch->getSubgroupSize();
2774 xegpu::LayoutAttr srcLayout;
2778 "subgroup layout assignment not supported for reduction (op "
2779 "is not expected at this level).");
2782 "instData layout assignment not supported for reduction (op "
2783 "is not expected at this level).");
2786 laneLayout[0] = std::min(
static_cast<int64_t>(subgroupSize), srcShape[0]);
2791 auto result = xegpu::SliceAttr::get(context, srcLayout,
2809static xegpu::DistributeLayoutAttr
2812 size_t innerMostDim,
int ratio,
int64_t bound,
2818 consumerLayout.getEffectiveLaneLayoutAsInt();
2825 sgDataValue = sgData[innerMostDim];
2826 while ((sgDataValue <= bound) && (sgDataValue % ratio) != 0)
2829 instDataValue = instData[innerMostDim];
2830 const int innermostDimLaneLayout = laneLayout.empty()
2832 : laneLayout[innerMostDim];
2833 while ((instDataValue <= bound) &&
2834 (instDataValue % (innermostDimLaneLayout * ratio) != 0))
2836 assert((bound % instDataValue) == 0 &&
2837 "bound, instData, and laneLayout for innermost must be 2^n!");
2839 laneDataValue = laneData[innerMostDim];
2840 while ((laneDataValue <= bound) && (laneDataValue % ratio) != 0)
2844 return consumerLayout.setDimData(innerMostDim, sgDataValue, instDataValue,
2874 int srcElemTyBitWidth = srcVecTy.getElementType().getIntOrFloatBitWidth();
2875 int resElemTyBitWidth = resVecTy.getElementType().getIntOrFloatBitWidth();
2880 assert(consumerLayout.getRank() ==
static_cast<int64_t>(srcShape.size()) &&
2881 "laneData must be available for all dimensions");
2885 if (srcElemTyBitWidth <= resElemTyBitWidth)
2886 return consumerLayout;
2891 size_t innerMostDim = srcShape.size() - 1;
2892 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
2894 innerMostDim, bitWidthRatio,
2895 resShape[innerMostDim],
uArch);
2918 assert(consumerLayout.getRank() ==
static_cast<int64_t>(resShape.size()) &&
2919 "consumer layout rank must match source shape rank");
2924 const size_t innerMostDim = resShape.size() - 1;
2925 constexpr int ratio = 2;
2927 innerMostDim, ratio,
2928 resShape[innerMostDim],
uArch);
2947 for (
int64_t dim : llvm::reverse(dimGroup)) {
2948 int64_t tileSize = tileShape.empty() ? 1 : tileShape[dim];
2949 if (counts[dim] != 1) {
2950 if (stride * tileSize != expectedStride)
2952 expectedStride = stride * tileSize * counts[dim];
2954 stride *=
shape[dim];
2959xegpu::DistributeLayoutAttr
2961 VectorType srcVecTy, VectorType resVecTy,
2962 DistributeLayoutAttr consumerLayout) {
2965 return consumerLayout;
2971 return consumerLayout;
2974 consumerLayout.getEffectiveLaneLayoutAsInt();
2977 xegpu::DistributeLayoutAttr resLayout = [&]() -> DistributeLayoutAttr {
2978 DistributeLayoutAttr layout = consumerLayout;
2981 while (i < dimGroup.size() && laneLayout[dimGroup[i]] == 1)
2984 for (++i; i < dimGroup.size(); ++i) {
2986 int64_t dimSize = resShape[dim];
2987 int64_t lanes = laneLayout[dim];
2988 if (lanes <= 0 || dimSize % lanes != 0)
2989 return consumerLayout;
2991 layout.setDimData(dim, -1,
2992 instData.empty() ? -1 : dimSize, dimSize / lanes);
3010 int64_t collapsedLaneData = 1;
3012 collapsedLaneData *= resLaneData[dim];
3018 if (!resInstData.empty() &&
3031 VectorType resVectorTy, xegpu::DistributeLayoutAttr consumerLayout,
3034 xegpu::DistributeLayoutAttr requiredResLayout;
3036 consumerLayout.getEffectiveInstDataAsInt();
3038 consumerLayout.getEffectiveLaneDataAsInt();
3040 consumerLayout.getEffectiveLaneLayoutAsInt();
3044 requiredResLayout = consumerLayout;
3045 int srcRank = srcShape.size();
3049 assert(
false &&
"subgroup/instData layout assignment not supported for "
3050 "insertStridedSlice.");
3052 for (
int dim = 0; dim < srcRank; dim++) {
3054 if (srcShape[dim] == 1) {
3057 assert(srcShape[dim] % consumerLaneLayout[dim] == 0 &&
3058 "srcShape must be divisible by laneLayout for all dimensions");
3059 laneDataValue = std::min(srcShape[dim] / consumerLaneLayout[dim],
3060 consumerLaneData[dim]);
3063 requiredResLayout.setDimData(dim, -1, -1, laneDataValue);
3066 return requiredResLayout;
3076 OpOperand &operand, xegpu::DistributeLayoutAttr resLayout) {
3083 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op)) {
3084 auto srcTy = dyn_cast<VectorType>(
broadcast.getSourceType());
3088 resLayout,
broadcast.getResultVectorType().getShape(),
3095 if (
auto reduction = dyn_cast<vector::MultiDimReductionOp>(op)) {
3104 if (
auto reduction = dyn_cast<vector::ReductionOp>(op))
3109 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
3110 int resElemBitWidth =
3111 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
3112 int srcElemBitWidth =
3113 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
3120 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
3122 resLayout, shapeCast.getResultVectorType().getShape(),
3123 shapeCast.getSourceVectorType().getShape());
3128 if (
auto insertSlice = dyn_cast<vector::InsertStridedSliceOp>(op)) {
3131 resLayout, insertSlice.getDestVectorType().getShape(),
3132 insertSlice.getSourceVectorType().getShape());
3140 if (
auto insert = dyn_cast<vector::InsertOp>(op)) {
3141 VectorType resVecTy = dyn_cast<VectorType>(insert.getResult().getType());
3142 VectorType valueToStoreTy =
3143 dyn_cast<VectorType>(insert.getValueToStore().getType());
3145 if ((idx == 0) && valueToStoreTy) {
3147 valueToStoreTy.getShape());
3155 if (
auto extract = dyn_cast<vector::ExtractOp>(op)) {
3156 VectorType srcVecTy = dyn_cast<VectorType>(extract.getSource().getType());
3157 VectorType resVecTy = dyn_cast<VectorType>(extract.getResult().getType());
3158 if (!srcVecTy || !resVecTy)
3161 srcVecTy.getShape());
3166 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
3168 transpose.getPermutation());
3173 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
3174 int resElemBitWidth =
3175 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
3176 int srcElemBitWidth =
3177 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
3183 if (
auto interleave = dyn_cast<vector::InterleaveOp>(op)) {
3188 if (
auto deinterleave = dyn_cast<vector::DeinterleaveOp>(op)) {
3193 if (dyn_cast<vector::ExtractStridedSliceOp>(op))
3209 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
3210 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
3214 branch.getSuccessorOperandInputMapping(mapping,
3216 auto it = mapping.find(&operand);
3217 if (it == mapping.end())
3219 xegpu::DistributeLayoutAttr iterArgLayout;
3220 for (
auto arg : llvm::make_isa_range<BlockArgument>(it->second)) {
3222 assert((!iterArgLayout || !layout || iterArgLayout.isEqualTo(layout)) &&
3223 "region inputs fed by one terminator operand disagree on layout");
3225 iterArgLayout = layout;
3227 return iterArgLayout;
3233 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
3234 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
3238 branch.getSuccessorOperandInputMapping(mapping,
3240 auto it = mapping.find(&operand);
3241 if (it == mapping.end())
3243 for (
Value input : it->second)
3244 if (
auto result = dyn_cast<OpResult>(input))
3257 if (isa<xegpu::AnchorLayoutInterface>(op))
3265 if (isa<RegionBranchOpInterface>(op))
3270 if (
auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(op)) {
3277 xegpu::DistributeLayoutAttr resLayout;
3278 if (op->
getNumResults() == 1 || isa<vector::DeinterleaveOp>(op))
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
static xegpu::LayoutAttr buildLayout(mlir::MLIRContext *context, ArrayRef< int64_t > sgLayout, ArrayRef< int64_t > sgData, ArrayRef< int64_t > instData, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData, DenseI32ArrayAttr orderAttr=nullptr)
static xegpu::DistributeLayoutAttr getStoreSubgroupLayouts(mlir::MLIRContext *context, ArrayRef< int64_t > wgShape, ArrayRef< int64_t > instData, int numSg)
Picks the subgroup layout for a scatter-style store (store_scatter / store_matrix): the most balanced...
static xegpu::DistributeLayoutAttr createScaleLayout(mlir::MLIRContext *context, VectorType matrixTy, VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout, bool isBScale, const xegpu::uArch::uArch *uArch)
Helper to create a scale layout derived from a matrix operand layout.
static xegpu::DistributeLayoutAttr adjustInnermostDimForDivisibility(xegpu::DistributeLayoutAttr consumerLayout, xegpu::LayoutKind layoutKind, size_t innerMostDim, int ratio, int64_t bound, const xegpu::uArch::uArch *uArch)
Adjusts consumerLayout's innermost-dim data field selected by layoutKind so that the source layout ca...
static xegpu::DistributeLayoutAttr get2DBlockIOSubgroupLayout(MLIRContext *context, ArrayRef< int64_t > dataShape, Type elemTy, const xegpu::uArch::BlockIOInstructionInterface *uArchInstruction, int numSg)
Picks the subgroup layout for a 2D block IO op (store_nd / prefetch_nd).
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 bool isLayoutPreservingVectorProducer(Operation *op)
Accept pure vector generators and elementwise ops that preserve vector shape.
static xegpu::DistributeLayoutAttr getParentResultLayoutForYieldOperand(RegionBranchTerminatorOpInterface terminator, OpOperand &operand)
static std::optional< SmallVector< int64_t > > get2DBlockIOInstDataLayout(ArrayRef< int64_t > dataShape, Type elemTy, const xegpu::uArch::BlockIOInstructionInterface *uArchInstruction, bool transform=false, bool transpose=false)
Helper function to compute inst_data vectors for DPAS operands A, B, and C/D.
static SmallVector< LayoutRepresentation > getSgLayoutCandidates(ArrayRef< int64_t > wgShape, ArrayRef< int64_t > instData, int64_t sgCount, int64_t broadcastDim=-1)
static SmallVector< LayoutRepresentation > enumerateFactorizations(int64_t total, int64_t rank)
Enumerates all ways to split total into rank factors whose product equals total.
static xegpu::DistributeLayoutAttr setupGenericLoadAnchorLayout(xegpu::LayoutKind layoutKind, mlir::MLIRContext *context, xegpu::DistributeLayoutAttr consumerLayout, int maxChunkSize, ArrayRef< int64_t > resShape, int subgroupSize)
Sets up the anchor layout for load gather and load matrix operation.
static bool isContiguousTiling(ArrayRef< int64_t > dimGroup, ArrayRef< int64_t > shape, ArrayRef< int64_t > counts, ArrayRef< int64_t > tileShape, int64_t expectedStride)
Checks that the tiles a split group is cut into walk the collapsed source dim with one constant strid...
SmallVector< int64_t > LayoutRepresentation
static xegpu::DistributeLayoutAttr getLayoutFromUsePoints(Value result)
static xegpu::DistributeLayoutAttr setupGenericStoreAnchorLayout(xegpu::LayoutKind layoutKind, mlir::MLIRContext *context, int maxChunkSize, ArrayRef< int64_t > srcShape, int subgroupSize, int numSg)
Sets up the anchor layout for store scatter and store matrix operation, which share the same logic.
static std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > compute2DBlockIOLaneLayout(ArrayRef< int64_t > instShape, int64_t subgroupSize, int64_t bitwidth, int64_t packingSize, bool transform=false, bool transpose=false)
static xegpu::DistributeLayoutAttr getLoopCarriedLayoutForYieldOperand(RegionBranchTerminatorOpInterface terminator, OpOperand &operand)
static constexpr unsigned kMaxRematerializableChainOps
static void propagateResultsToRegularOperands(Operation *op)
static void propagateRegionResultsToYieldOperands(mlir::RegionBranchTerminatorOpInterface yieldOp)
static bool collectRematerializableChain(Operation *root, SmallVectorImpl< Operation * > &chain)
Collect each eligible producer once, producers first, for cloning with an IRMapping.
static bool isValidLaneLayout(ArrayRef< int64_t > dataShape, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData)
static void setTensorDescLayout(Value val, xegpu::DistributeLayoutAttr layout)
static std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > computeReductionLaneLayoutAndData(ArrayRef< int64_t > srcShape, ArrayRef< int64_t > reductionDims, int subgroupSize, int64_t maxReduceVectorSize, xegpu::DistributeLayoutAttr consumerLayout=nullptr)
Derives (lane_layout, lane_data, inst_data) for a vector.multi_reduction source from the layout reque...
static void walkRegionBackward(Region ®ion, llvm::function_ref< void(Operation *)> visit)
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, const xegpu::uArch::MMAInstructionInterface *uArchInstruction)
Helper function to set up subgroup layouts for DPAS operands A, B, and C/D.
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.
This is a utility class for mapping one set of IR entities to another.
auto lookup(T from) const
Lookup a mapped value within the map.
MLIRContext is the top-level object for a collection of MLIR operations.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents an operand of an operation.
unsigned getOperandNumber() const
Return which operand this is in the OpOperand list of the Operation.
This is a value defined by a result of an operation.
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.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
unsigned getNumResults()
Return the number of results held by this operation.
This class represents a point being branched from in the methods of the RegionBranchOpInterface.
This class represents a successor of a region.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
void setType(Type newType)
Mutate the type of this Value to be of the specified type.
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
Operation * getOwner() const
Return the owner of this operand.
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
@ Subgroup2DBlockPrefetch
@ SubgroupMatrixMultiplyAcc
@ SubgroupScaledMatrixMultiplyAcc
DistributeLayoutAttr inferShapeCastSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for a shape cast operation given the result layout attribute,...
bool matchDimCollapse(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &collapseDims)
DistributeLayoutAttr setupLoadNdAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, DistributeLayoutAttr consumerLayout, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a load_nd operation.
DistributeLayoutAttr inferResultLayoutFromSourceForNonAnchorOp(Operation *op, ArrayRef< DistributeLayoutAttr > operandLayouts)
Infers the result layout attribute for a non-anchor operation from the layouts of its source operands...
DistributeLayoutAttr setupLoadMatrixAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the anchor layout for load matrix operation.
DistributeLayoutAttr setupInterleaveResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the result layout for an interleave operation to ensure the source layout can be safely deriv...
DistributeLayoutAttr inferTransposeSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > permutation)
Infers the source layout attribute for a transpose operation given the result layout attribute and pe...
DistributeLayoutAttr inferInsertSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for an insert operation.
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > completeDpasMxLaneLayoutFromInstData(DistributeLayoutAttr aLayout, DistributeLayoutAttr bLayout, DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy, VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy, const uArch::uArch *uArch)
Like completeDpasLaneLayoutFromInstData, but for dpas_mx: additionally re-derives the A_scale / B_sca...
DistributeLayoutAttr inferInsertStridedSliceSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for an insert strided slice operation given the result layout attr...
DistributeLayoutAttr setupStoreMatrixAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a store matrix operation.
void removeTemporaryLayoutAttrs(Operation *op)
Removes the temporary layout attributes for each OpOperand and OpResult of the given operation.
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > completeDpasLaneLayoutFromInstData(DistributeLayoutAttr aLayout, DistributeLayoutAttr bLayout, DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy, VectorType cdTy, const uArch::uArch *uArch)
Completes user-provided DPAS A/B/C-D anchors that carry only inst_data by filling in lane_layout / la...
void setTemporaryLayout(const T &operandOrResult, const DistributeLayoutAttr layout)
LayoutKind
Specifies the level of a layout hierarchy for comparison or propagation.
void setDistributeLayoutAttr(const OpResult &Result, const DistributeLayoutAttr layout)
[to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult user should use setAnchorLayout...
SmallVector< NamedAttribute > dropInstDataOnAttrs(ArrayRef< NamedAttribute > attrs)
Updates the NamedAttribute sequence by dropping inst-data information from any DistributeLayoutAttr f...
DistributeLayoutAttr inferSourceLayoutFromResultForNonAnchorOp(OpOperand &operand, DistributeLayoutAttr resLayout)
Infers the source layout attribute for an operand using result layout attribute.
DistributeLayoutAttr inferInterleaveSourceLayout(DistributeLayoutAttr resLayout)
Infers the source layout attribute for an interleave operation given the result layout attribute.
bool matchUnitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< int64_t > &expandedUnitDims)
int getLargestDivisor(T dim, ArrayRef< T > candidates, ArrayRef< T > candidateMultiples={})
Helper Function to find a proper instruction multiple for the user-supplied sg-level data shape (dive...
bool recoverTemporaryLayouts(Operation *rootOp)
Attach layout attributes to all vector-type operands of operations within the given operation's neste...
DistributeLayoutAttr inferBroadcastSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for a broadcast operation given the result layout attribute,...
std::optional< std::tuple< DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr, DistributeLayoutAttr > > setupDpasMxLayout(LayoutKind layoutKind, VectorType aTy, VectorType bTy, VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy, DistributeLayoutAttr consumerLayout, int numSg, const uArch::uArch *uArch)
Sets up the anchor layouts for dpas_mx operands (A, B, C/D, A_scale, and B_scale).
SliceAttr setupMultiReductionResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, DistributeLayoutAttr consumerLayout, SmallVector< int64_t > reductionDims, int numSg, const uArch::uArch *uArch)
Note on the consumerLayout argument used by the consumer-driven setup* / complete* helpers below:
DistributeLayoutAttr setupLoadGatherAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the anchor layout for a load gather operation.
llvm::function_ref< DistributeLayoutAttr(Value)> GetLayoutFnTy
Callable returning the propagated layout for a given Value, used by the layout-propagation helpers be...
std::optional< DistributeLayoutAttr > completeScatterLoadLaneLayoutFromInstData(DistributeLayoutAttr userSpecifiedLayout, DistributeLayoutAttr consumerLayout, Type elemTy, const xegpu::uArch::LoadGatherInstruction *uArchInstruction, const int subgroupSize)
If the consumer layout has only inst_data (no lane_layout/lane_data), completes it by running the cor...
bool matchSplitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &splitDimGroups)
DistributeLayoutAttr setupStoreScatterAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int contigChunkSize, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a store scatter operation.
DistributeLayoutAttr setupBitCastResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Setup the result layout attribute for a bitcast operation based on element type bitwidths.
void removeLayoutAttr(const T &operandOrResult)
Removes the LayoutAttr for a given OpOperand or OpResult if it exists.
void dropInstDataOnInherentAttrs(Operation *op)
Drops inst-data information from DistributeLayoutAttrs stored as inherent attributes on the operation...
DistributeLayoutAttr getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value, or nullptr if none is found.
SmallVector< NamedAttribute > dropSgLayoutAndDataOnAttrs(ArrayRef< NamedAttribute > attrs)
Updates the NamedAttribute sequence by dropping sg-layout and sg-data information from any Distribute...
DistributeLayoutAttr setupPrefetchNdAnchorLayout(LayoutKind layoutKind, TensorDescType tdescTy, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a prefetch_nd operation.
LogicalResult propagateYieldOperandsToRegionResults(RegionBranchTerminatorOpInterface terminator, GetLayoutFnTy getLayoutOfValue)
Propagate layouts from a region branch terminator's forwarded operands to the matching region results...
DistributeLayoutAttr inferShapeCastResultLayout(DistributeLayoutAttr srcLayout, ArrayRef< int64_t > srcShape, ArrayRef< int64_t > resShape)
Infers the result layout attribute for a shape cast operation given the source layout attribute,...
DistributeLayoutAttr inferExtractSourceLayout(DistributeLayoutAttr resLayout, ArrayRef< int64_t > resShape, ArrayRef< int64_t > srcShape)
Infers the source layout attribute for an extract operation.
std::string getTemporaryLayoutName(const OpOperand &operand)
Return the attribute name for the OpOperand to attach DistributeLayoutAttr.
DistributeLayoutAttr inferBitCastSourceLayout(DistributeLayoutAttr resLayout, int resElemTyBitWidth, int srcElemTyBitWidth)
Infers the source layout attribute for a bitcast operation given the result layout attribute,...
DistributeLayoutAttr setupInsertStridedSliceResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout, const uArch::uArch *uArch)
Sets up the result layout for an insert strided slice operation.
DistributeLayoutAttr setupShapeCastResultLayout(LayoutKind layoutKind, VectorType srcVectorTy, VectorType resVectorTy, DistributeLayoutAttr consumerLayout)
Sets up the result layout for a shape cast that splits one source dim into several consecutive result...
DistributeLayoutAttr inferReductionSourceLayout(DistributeLayoutAttr resLayout)
Infers the source layout attribute for a reduction operation given the result layout attribute and re...
std::optional< DistributeLayoutAttr > completeScatterStoreLaneLayoutFromInstData(DistributeLayoutAttr specifiedLayout, Type elemTy, const xegpu::uArch::StoreScatterInstruction *uArchInstruction, const int subgroupSize)
Like completeScatterLoadLaneLayoutFromInstData, but for scatter stores (store_scatter / store_matrix)...
std::optional< DistributeLayoutAttr > completeBlockStoreLaneLayoutFromInstData(DistributeLayoutAttr specifiedLayout, Type elemTy, const xegpu::uArch::BlockIOInstructionInterface *uArchInstruction, const int subgroupSize)
Completes a user-provided 2D-block store_nd / prefetch_nd anchor that has only inst_data.
DistributeLayoutAttr inferDeinterleaveSourceLayout(DistributeLayoutAttr resLayout)
Infers the source layout attribute for a deinterleave operation given the result layout attribute.
DistributeLayoutAttr getConsumerLayoutAt(OpOperand &operand)
Gets the expected layout for a given consumer operand.
void removeLayoutAttrs(Operation *op)
Removes the DistributeLayoutAttr for each OpOperand and OpResult of the given operation if they exist...
DistributeLayoutAttr inferMultiReductionSourceLayout(DistributeLayoutAttr resLayout, SmallVector< int64_t > reduceDims)
Infers the source layout attribute for a reduction operation given the result layout attribute and re...
bool isTriviallyRematerializable(Operation *op)
Returns true if the vector produced by op is cheap to recompute in any layout, i.e.
Value rematerialize(OpBuilder &builder, Value value)
Clone a bounded chain of pure vector generators and layout-preserving elementwise ops without layout ...
DistributeLayoutAttr setupStoreNdAnchorLayout(LayoutKind layoutKind, VectorType vectorTy, int numSg, const uArch::uArch *uArch)
Sets up the anchor layout for a store_nd operation.
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.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
int64_t computeProduct(ArrayRef< int64_t > basis)
Self-explicit.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
std::optional< SmallVector< int64_t > > computeShapeRatio(ArrayRef< int64_t > shape, ArrayRef< int64_t > subShape)
Return the multi-dimensional integral ratio of subShape to the trailing dimensions of shape.
SmallVector< int64_t > invertPermutationVector(ArrayRef< int64_t > permutation)
Helper method to apply to inverse a permutation.
virtual int32_t getPackedFormatBitSize() const =0
std::optional< BlockShapes > getBlockWidthHeightCount(Type elemTy, bool hasTransform=false, bool hasTranspose=false, bool upConv=false) const
int32_t getMaxLaneAccessSizeBytes() const override
virtual llvm::SmallVector< uint32_t, 8 > getSupportedN(Type type) const =0
virtual llvm::SmallVector< uint32_t, 8 > getSupportedK(Type type) const =0
virtual llvm::SmallVector< uint32_t, 8 > getSupportedM(Type type) const =0
int32_t getMaxLaneAccessSizeBytes() const override
virtual unsigned getGeneralPackedFormatBitSize() const =0
virtual int getSubgroupSize() const =0
const Instruction * getInstruction(InstructionKind instKind) const