32#include "llvm/ADT/DenseSet.h"
33#include "llvm/ADT/PostOrderIterator.h"
34#include "llvm/Support/FormatVariadic.h"
43 out.reserve(attrs.size());
45 for (
auto attr : attrs) {
46 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr.getValue())) {
47 auto newLayout = dist.dropSgLayoutAndData();
49 out.emplace_back(attr.getName(), newLayout);
61 out.reserve(attrs.size());
63 for (
auto attr : attrs) {
64 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr.getValue())) {
65 auto newLayout = dist.dropInstData();
67 out.emplace_back(attr.getName(), newLayout);
78 if (
auto dist = dyn_cast<xegpu::DistributeLayoutAttr>(attr))
79 attr = dist.dropInstData();
86 auto tensorDescTy = dyn_cast<xegpu::TensorDescType>(val.
getType());
87 if (!tensorDescTy || tensorDescTy.getLayoutAttr())
89 auto typeWithLayout = xegpu::TensorDescType::get(
90 tensorDescTy.getContext(), tensorDescTy.getShape(),
91 tensorDescTy.getElementType(), tensorDescTy.getEncoding(), layout);
106 llvm::ReversePostOrderTraversal<Region *> rpot(®ion);
108 for (
Block *block : llvm::reverse(blocks)) {
110 for (
Operation &op : llvm::reverse(*block)) {
118 for (
Region &nested : op.getRegions())
127 xegpu::DistributeLayoutAttr layout =
nullptr;
148 if (
auto constant = dyn_cast<arith::ConstantOp>(op)) {
149 auto value = dyn_cast<DenseElementsAttr>(constant.getValue());
150 return value && value.isSplat();
152 if (isa<vector::StepOp, vector::CreateMaskOp>(op))
154 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op))
155 return !isa<VectorType>(
broadcast.getSource().getType());
167 while (!worklist.empty()) {
168 auto [op, expanded] = worklist.pop_back_val();
173 if (!visited.insert(op).second)
178 worklist.emplace_back(op,
true);
179 for (
Value operand : op->getOperands()) {
180 if (!isa<VectorType>(operand.getType()))
182 Operation *producer = operand.getDefiningOp();
185 if (!visited.contains(producer))
186 worklist.emplace_back(producer,
false);
213 return mapping.
lookup(value);
221 if (op->
getNumResults() > 1 && !isa<vector::DeinterleaveOp>(op))
232 if (isa<xegpu::TensorDescType>(resultType))
237 if (isa<VectorType>(resultType) || isa<vector::MultiDimReductionOp>(op))
240 if (isa<vector::DeinterleaveOp>(op))
244 xegpu::DistributeLayoutAttr operandLayout =
246 if (isa<VectorType>(opr.get().getType()) && operandLayout)
258 mlir::RegionBranchTerminatorOpInterface yieldOp) {
259 auto regionBranchOp =
260 dyn_cast<RegionBranchOpInterface>(yieldOp->getParentOp());
266 yieldOp.getSuccessorRegions(operandAttrs, successors);
269 OperandRange succOps = yieldOp.getSuccessorOperands(successor);
273 ValueRange successorInputs = regionBranchOp.getSuccessorInputs(successor);
274 unsigned count = std::min<unsigned>(succOps.size(), successorInputs.size());
276 for (
unsigned i = 0; i < count; ++i) {
277 xegpu::DistributeLayoutAttr layout;
278 if (successor.isOperation()) {
281 auto regionResult = regionBranchOp->getResult(i);
286 if (isa<xegpu::TensorDescType>(regionResult.getType()))
297 auto operandType = succOps[i].
getType();
298 if (isa<VectorType>(operandType) ||
299 dyn_cast<xegpu::TensorDescType>(operandType))
320 mlir::RegionBranchTerminatorOpInterface terminator,
323 auto branchOp = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
328 branchOp.getSuccessorOperandInputMapping(mapping,
330 for (
const auto &[successorOperand, successorInputs] : mapping) {
331 for (
Value successorInput : successorInputs) {
332 Type inputType = successorInput.getType();
334 if (!isa<VectorType>(inputType))
336 xegpu::DistributeLayoutAttr successorOperandLayout =
337 getLayoutOfValue(successorOperand->get());
340 if (!successorOperandLayout)
343 if (
auto result = dyn_cast<OpResult>(successorInput))
349 if (
auto arg = dyn_cast<BlockArgument>(successorInput)) {
351 dyn_cast<LoopLikeOpInterface>(arg.getOwner()->getParentOp());
352 bool tiedToInit = loop && loop.getTiedLoopInit(arg);
353 if (!tiedToInit && !isa<BlockArgument>(successorOperand->get()))
354 return terminator->emitError(
355 "unsupported region structure: the successor argument it feeds "
356 "is not tied to an init operand, so its value must be passed "
357 "through from predecessor region argument.");
374 for (
Region ®ion : regionOp->getRegions()) {
379 ValueRange successorInputs = regionOp.getSuccessorInputs(regionSuccessor);
380 for (
auto [inputIdx, regionArg] : llvm::enumerate(successorInputs)) {
381 auto layout = getLayoutOfValue(regionArg);
386 if (isa<xegpu::TensorDescType>(regionArg.getType()))
392 regionOp.getPredecessorValues(regionSuccessor, inputIdx, predValues);
393 for (
Value predVal : predValues) {
395 for (
OpOperand &operand : regionOp->getOpOperands()) {
396 if (operand.get() == predVal)
435 auto processFunc = [&](
Region &body, StringRef funcName) {
437 if (
auto regionOp = dyn_cast<mlir::RegionBranchOpInterface>(op)) {
440 }
else if (
auto yieldOp =
441 dyn_cast<mlir::RegionBranchTerminatorOpInterface>(op)) {
443 }
else if (!dyn_cast<xegpu::AnchorLayoutInterface>(op)) {
449 rootOp->
walk([&](func::FuncOp
func) {
450 processFunc(
func.getBody(),
func.getSymName());
452 rootOp->
walk([&](gpu::GPUFuncOp
func) {
453 processFunc(
func.getBody(),
func.getName());
459template <
typename T,
typename>
461 Operation *owner = operandOrResult.getOwner();
480 if (isa<DistributeLayoutAttr>(namedAttr.getValue()))
481 attrsToRemove.push_back(namedAttr.getName());
483 for (
auto attrName : attrsToRemove)
492 if (isa<xegpu::DistributeLayoutAttr>(namedAttr.getValue()))
493 attrsToRemove.push_back(namedAttr.getName());
495 for (
auto attrName : attrsToRemove)
504 auto toI32Attr = [&](
auto range) {
508 return xegpu::LayoutAttr::get(context,
nullptr,
509 nullptr, toI32Attr(instData),
510 toI32Attr(laneLayout), toI32Attr(laneData),
517 return !llvm::any_of(llvm::seq<int>(0, dataShape.size()), [&](
int dim) {
518 return dataShape[dim] % (laneLayout[dim] * laneData[dim]) != 0;
522static xegpu::LayoutAttr
526 auto toI32Attr = [&](
auto range) {
530 return xegpu::LayoutAttr::get(context,
nullptr,
532 nullptr, toI32Attr(laneLayout),
533 toI32Attr(laneData), orderAttr);
536static xegpu::LayoutAttr
541 auto toI32Attr = [&](
auto range) {
545 return xegpu::LayoutAttr::get(
546 context, sgLayout.empty() ?
nullptr : toI32Attr(sgLayout),
547 sgData.empty() ?
nullptr : toI32Attr(sgData),
548 instData.empty() ?
nullptr : toI32Attr(instData),
549 laneLayout.empty() ?
nullptr : toI32Attr(laneLayout),
550 laneData.empty() ?
nullptr : toI32Attr(laneData), orderAttr);
559 for (
int dim = 0; dim < (int)sgLayout.size(); ++dim) {
561 sgData[dim] = wgTileShape[dim];
563 sgData[dim] = wgTileShape[dim] / sgLayout[dim];
572xegpu::DistributeLayoutAttr
578 size_t dimDiff = resShape.size() - srcShape.size();
579 auto bcastSourceLayout = resLayout;
582 for (
size_t i = dimDiff; i < resShape.size(); i++) {
583 if ((srcShape[i - dimDiff] == 1) && (resShape[i] != 1))
584 bcastDims.push_back(i);
589 if (!bcastDims.empty())
590 bcastSourceLayout = bcastSourceLayout.setUnitDimData(bcastDims);
595 bool isOuterDimDiffUnitDims = llvm::all_of(
596 resShape.take_front(dimDiff), [&](
int64_t dim) { return dim == 1; });
597 if (dimDiff && bcastDims.size() == dimDiff && isOuterDimDiffUnitDims) {
600 sliceDims.assign(bcastDims.begin(), bcastDims.end());
604 llvm::append_range(sliceDims, llvm::seq<int64_t>(0, dimDiff));
606 bcastSourceLayout = xegpu::SliceAttr::get(
607 resLayout.getContext(), bcastSourceLayout,
610 return bcastSourceLayout;
615xegpu::DistributeLayoutAttr
619 assert(isa<xegpu::SliceAttr>(resLayout) &&
620 "reduction result layout must be slice layout");
622 xegpu::SliceAttr sliceLayout = dyn_cast<xegpu::SliceAttr>(resLayout);
624 assert((reduceDims == sliceLayout.getDims().asArrayRef()) &&
625 "reduction dims must match with slice dims");
627 return sliceLayout.getParent();
630xegpu::DistributeLayoutAttr
641xegpu::DistributeLayoutAttr
652xegpu::DistributeLayoutAttr
654 int resElemTyBitWidth,
int srcElemTyBitWidth) {
659 size_t sgDataSize = sgData.size();
660 size_t instDataSize = instData.size();
661 size_t laneDataSize = laneData.size();
665 int64_t dim = resLayout.getRank() - 1;
667 if (srcElemTyBitWidth <= resElemTyBitWidth) {
668 int bitWidthRatio = resElemTyBitWidth / srcElemTyBitWidth;
670 sgDataValue = sgData.back() * bitWidthRatio;
672 instDataValue = instData.back() * bitWidthRatio;
674 laneDataValue = laneData.back() * bitWidthRatio;
676 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
678 assert((sgData.back() % bitWidthRatio) == 0 &&
679 "sgData not divisible by bitWidthRatio");
680 sgDataValue = sgData.back() / bitWidthRatio;
683 assert((instData.back() % bitWidthRatio) == 0 &&
684 "instData not divisible by bitWidthRatio");
685 instDataValue = instData.back() / bitWidthRatio;
688 assert((laneData.back() % bitWidthRatio) == 0 &&
689 "laneData not divisible by bitWidthRatio");
690 laneDataValue = laneData.back() / bitWidthRatio;
694 xegpu::DistributeLayoutAttr finalSrcLayout;
696 resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
698 return finalSrcLayout;
705xegpu::DistributeLayoutAttr
711 size_t sgDataSize = sgData.size();
712 size_t instDataSize = instData.size();
713 size_t laneDataSize = laneData.size();
717 int64_t dim = resLayout.getRank() - 1;
721 constexpr int ratio = 2;
723 assert((sgData.back() % ratio) == 0 &&
724 "sgData not divisible by interleave ratio");
725 sgDataValue = sgData.back() / ratio;
728 assert((instData.back() % ratio) == 0 &&
729 "instData not divisible by interleave ratio");
730 instDataValue = instData.back() / ratio;
733 assert((laneData.back() % ratio) == 0 &&
734 "laneData not divisible by interleave ratio");
735 laneDataValue = laneData.back() / ratio;
738 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
745xegpu::DistributeLayoutAttr
751 size_t sgDataSize = sgData.size();
752 size_t instDataSize = instData.size();
753 size_t laneDataSize = laneData.size();
757 int64_t dim = resLayout.getRank() - 1;
761 constexpr int ratio = 2;
763 sgDataValue = sgData.back() * ratio;
765 instDataValue = instData.back() * ratio;
767 laneDataValue = laneData.back() * ratio;
769 return resLayout.setDimData(dim, sgDataValue, instDataValue, laneDataValue);
779 int srcShapeSize = srcShape.size();
780 int resShapeSize = resShape.size();
781 int dimDiff = resShapeSize - srcShapeSize;
786 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
787 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
788 for (
int i = 0; i < dimDiff; i++) {
789 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
790 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
791 "Leading dimensions being sliced off must not be distributed");
793 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
802xegpu::DistributeLayoutAttr
807 int srcShapeSize = srcShape.size();
808 int resShapeSize = resShape.size();
809 int dimDiff = resShapeSize - srcShapeSize;
814 auto resSgLayout = resLayout.getEffectiveSgLayoutAsInt();
815 auto resLaneLayout = resLayout.getEffectiveLaneLayoutAsInt();
816 for (
int i = 0; i < dimDiff; i++) {
817 assert((resSgLayout.size() == 0 || resSgLayout[i] == 1) &&
818 (resLaneLayout.size() == 0 || resLaneLayout[i] == 1) &&
819 "Leading dimensions being sliced off must not be distributed");
821 return resLayout.dropDims(llvm::to_vector(llvm::seq<int64_t>(0, dimDiff)));
831xegpu::DistributeLayoutAttr
836 int srcShapeSize = srcShape.size();
837 int resShapeSize = resShape.size();
838 int dimDiff = srcShapeSize - resShapeSize;
839 auto context = resLayout.getContext();
843 auto sgLayout = resLayout.getEffectiveSgLayoutAsInt();
844 auto sgData = resLayout.getEffectiveSgDataAsInt();
845 auto instData = resLayout.getEffectiveInstDataAsInt();
846 auto laneLayout = resLayout.getEffectiveLaneLayoutAsInt();
847 auto laneData = resLayout.getEffectiveLaneDataAsInt();
848 auto order = resLayout.getEffectiveOrderAsInt();
858 for (
auto &o : order)
864 for (
int i = 0; i < dimDiff; i++) {
865 if (!sgLayout.empty())
866 sgLayout.insert(sgLayout.begin(), 1);
868 sgData.insert(sgData.begin(), 1);
869 if (!instData.empty())
870 instData.insert(instData.begin(), 1);
871 if (!laneLayout.empty())
872 laneLayout.insert(laneLayout.begin(), 1);
873 if (!laneData.empty())
874 laneData.insert(laneData.begin(), 1);
875 order.push_back(dimDiff - 1 - i);
880 if (!resLayout.getOrder())
883 return buildLayout(context, sgLayout, sgData, instData, laneLayout,
884 laneData, orderAttr);
891xegpu::DistributeLayoutAttr
915 xegpu::SliceAttr::get(resLayout.getContext(), resLayout, sliceDimsAttr);
922 auto srcLayout = resLayout;
923 for (
const auto &dimGroup : splitDimGroups)
924 srcLayout = srcLayout.collapseDims(dimGroup);
933 auto srcLayout = resLayout;
934 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
935 dstIdx >= 0; --dstIdx) {
937 if (srcDims.empty()) {
938 srcLayout = srcLayout.dropDims({dstIdx});
941 if (srcDims.size() == 1)
944 targetShape.reserve(srcDims.size());
946 targetShape.push_back(srcShape[d]);
947 srcLayout = srcLayout.expandDim(dstIdx, targetShape);
965xegpu::DistributeLayoutAttr
968 return srcLayout.transposeDims(permutation);
979xegpu::DistributeLayoutAttr
988 auto resLayout = srcLayout;
991 for (
int64_t srcIdx =
static_cast<int64_t>(splitDimGroups.size()) - 1;
992 srcIdx >= 0; --srcIdx) {
994 if (resDims.size() <= 1)
997 targetShape.reserve(resDims.size());
999 targetShape.push_back(resShape[d]);
1000 resLayout = resLayout.expandDim(srcIdx, targetShape);
1009 auto resLayout = srcLayout;
1012 for (
int64_t dstIdx =
static_cast<int64_t>(collapseDims.size()) - 1;
1013 dstIdx >= 0; --dstIdx) {
1017 if (srcDims.empty())
1019 if (srcDims.size() == 1)
1021 resLayout = resLayout.collapseDims(llvm::to_vector(srcDims));
1038 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
1039 if (!operandLayouts[0])
1042 transpose.getPermutation());
1046 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
1047 if (!operandLayouts[0])
1050 operandLayouts[0], shapeCast.getSourceVectorType().getShape(),
1051 shapeCast.getResultVectorType().getShape());
1057 for (xegpu::DistributeLayoutAttr layout : operandLayouts)
1094 auto getDivisors = [](
int64_t n) {
1096 for (
int64_t i = 1; i * i <= n; ++i) {
1100 divs.push_back(n / i);
1109 if (dim == rank - 1) {
1110 current[dim] = remaining;
1114 for (
int64_t factor : getDivisors(remaining)) {
1115 current[dim] = factor;
1116 generate(dim + 1, remaining / factor);
1142 int64_t rank = wgShape.size();
1143 assert(rank > 0 &&
"wgShape must be non-empty");
1144 assert(
static_cast<int64_t>(instData.size()) == rank &&
1145 "instData rank must match wgShape rank");
1152 for (
const auto &sgLayout : allFactorizations) {
1154 for (
int64_t dim = 0; dim < rank; ++dim) {
1158 if (dim == broadcastDim) {
1159 sgData = wgShape[dim];
1161 if (wgShape[dim] % sgLayout[dim] != 0) {
1165 sgData = wgShape[dim] / sgLayout[dim];
1167 if (sgData % instData[dim] != 0) {
1173 candidates.push_back(sgLayout);
1179 int64_t spreadLhs = *llvm::max_element(lhs) - *llvm::min_element(lhs);
1180 int64_t spreadRhs = *llvm::max_element(rhs) - *llvm::min_element(rhs);
1181 if (spreadLhs != spreadRhs)
1182 return spreadLhs < spreadRhs;
1193 bool transform =
false,
bool transpose =
false) {
1194 int rank = dataShape.size();
1198 return std::nullopt;
1199 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1205 assert(rank >= 2 &&
"dataShape must be at least 2D for 2D-block IO");
1212 if (instWidth < 0 || instHeight < 0)
1213 return std::nullopt;
1214 instData.back() = instWidth;
1215 instData[rank - 2] = instHeight;
1226 VectorType aTy, VectorType bTy, VectorType cdTy,
1230 const unsigned dataALen = aTy.getShape()[aTy.getRank() - 2];
1231 auto supportedALen = uArchInstruction->
getSupportedM(aTy.getElementType());
1236 const unsigned dataBLen = bTy.getShape().back();
1237 auto supportedBLen = uArchInstruction->
getSupportedN(bTy.getElementType());
1241 auto supportedCLen = uArchInstruction->
getSupportedN(cdTy.getElementType());
1244 if (maxALen == -1 || maxBLen == -1 || maxCLen == -1)
1245 return std::nullopt;
1247 auto supportedKLen = uArchInstruction->
getSupportedK(aTy.getElementType());
1248 if (supportedKLen.empty())
1249 return std::nullopt;
1250 auto kDimSize = supportedKLen[0];
1253 instDataA[aTy.getRank() - 2] = maxALen;
1254 instDataA[aTy.getRank() - 1] = kDimSize;
1256 instDataB[bTy.getRank() - 2] = kDimSize;
1257 instDataB[bTy.getRank() - 1] = maxBLen;
1259 instDataCD[cdTy.getRank() - 2] = maxALen;
1260 instDataCD[cdTy.getRank() - 1] = maxCLen;
1261 return std::make_tuple(instDataA, instDataB, instDataCD);
1274 int64_t rank = instShape.size();
1277 laneLayout[innermost] = std::min(subgroupSize, instShape[innermost]);
1278 laneData[innermost] =
1279 std::min(instShape[innermost] / laneLayout[innermost], maxChunkSize);
1280 return {laneLayout, laneData};
1295 bool transform =
false,
bool transpose =
false) {
1296 int64_t rank = instShape.size();
1297 assert(rank >= 2 &&
"Expected at least a 2D shape for a 2D block op");
1301 laneData[packDim] = llvm::divideCeil(packingSize, bitwidth);
1303 int64_t laneDim = transpose ? rank - 2 : rank - 1;
1304 laneLayout[laneDim] =
1305 std::min(subgroupSize, instShape[laneDim] / laneData[laneDim]);
1308 for (
int64_t i = 0; i < rank; ++i)
1309 order.push_back(rank - 1 - i);
1310 std::swap(order[0], order[1]);
1314 for (
int64_t i = 0; i < rank; ++i) {
1315 int64_t laneProduct = laneLayout[i] * laneData[i];
1316 assert(instShape[i] % laneProduct == 0 &&
1317 "lane_layout * lane_data must evenly divide the inst shape");
1320 return {laneLayout, laneData, order};
1358 int subgroupSize,
int64_t maxReduceVectorSize,
1359 xegpu::DistributeLayoutAttr consumerLayout =
nullptr) {
1360 int srcRank = srcShape.size();
1362 auto isReduced = [&](
int dim) {
1363 return llvm::is_contained(reductionDims, dim);
1369 auto consumerSlice = dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
1370 bool reusedParent =
false;
1371 if (consumerSlice &&
1372 consumerSlice.getDims().asArrayRef().equals(reductionDims)) {
1373 auto parent = consumerSlice.getParent();
1375 parent.getEffectiveLaneLayoutAsInt();
1377 if (
static_cast<int>(parentLaneLayout.size()) == srcRank &&
1378 static_cast<int>(parentLaneData.size()) == srcRank &&
1380 laneLayout = std::move(parentLaneLayout);
1381 laneData = std::move(parentLaneData);
1382 reusedParent =
true;
1386 if (!reusedParent) {
1388 if (consumerLayout) {
1389 consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
1390 consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
1392 for (
int i = 0, c = 0; i < srcRank; ++i) {
1395 if (c <
static_cast<int>(consumerLaneLayout.size()))
1396 laneLayout[i] = consumerLaneLayout[c];
1397 if (c <
static_cast<int>(consumerLaneData.size()))
1398 laneData[i] = consumerLaneData[c];
1405 for (
int i = 0; i < srcRank; ++i) {
1406 maxLanes[i] = std::max<int64_t>(1, srcShape[i] / laneData[i]);
1407 laneLayout[i] = std::min(laneLayout[i], maxLanes[i]);
1415 int innermost = srcRank - 1;
1418 if (spareLanes > 1 && isReduced(innermost))
1419 laneLayout[innermost] =
1420 std::min(laneLayout[innermost] * spareLanes, maxLanes[innermost]);
1424 maxReduceVectorSize /
1427 bool canCarryVector = laneLayout[innermost] == 1 && isReduced(innermost) &&
1428 srcShape[innermost] > 1;
1430 if (vectorBudget > 1 && canCarryVector)
1431 laneData[innermost] =
1432 std::min(vectorBudget * laneData[innermost], srcShape[innermost]);
1435 for (
int i = 0; i < srcRank; ++i)
1436 instData[i] = laneLayout[i] * laneData[i];
1438 return {laneLayout, laneData, instData};
1504static std::optional<
1505 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1506 xegpu::DistributeLayoutAttr>>
1509 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1512 auto [instDataA, instDataB, instDataCD] = instDataVecs;
1514 std::optional<LayoutRepresentation> consumerSgLayout = std::nullopt;
1515 if (consumerLayout && consumerLayout.isForWorkgroup()) {
1516 consumerSgLayout = consumerLayout.getEffectiveSgLayoutAsInt();
1525 if (layoutsA.empty() || layoutsB.empty() || layoutsCD.empty())
1526 return std::nullopt;
1529 std::optional<LayoutRepresentation> bestPick;
1530 for (
auto &sgLayout : layoutsB) {
1531 if (llvm::is_contained(layoutsA, sgLayout) &&
1532 llvm::is_contained(layoutsCD, sgLayout)) {
1534 if (consumerSgLayout.has_value() && sgLayout == *consumerSgLayout) {
1535 bestPick = sgLayout;
1543 bestPick = sgLayout;
1547 return std::nullopt;
1549 const auto &picked = *bestPick;
1551 auto dpasALayout =
buildSgLayout(context, aTy.getShape(), picked,
1553 auto dpasBLayout =
buildSgLayout(context, bTy.getShape(), picked,
1555 auto dpasCDLayout =
buildSgLayout(context, cdTy.getShape(), picked);
1556 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout);
1563 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1564 xegpu::DistributeLayoutAttr>>
1566 VectorType bTy, VectorType cdTy,
1567 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1569 auto context = aTy.getContext();
1570 const auto *uArchInstruction =
1571 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1573 if (!uArchInstruction)
1574 return std::nullopt;
1577 auto [laneLayoutA, laneDataA, orderA] =
1579 aTy.getElementType().getIntOrFloatBitWidth(),
1580 uArchInstruction->getPackedFormatBitSizeA());
1582 bTy.getShape(), subgroupSize,
1583 bTy.getElementType().getIntOrFloatBitWidth(),
1584 uArchInstruction->getPackedFormatBitSizeB(),
true);
1585 auto [laneLayoutCD, laneDataCD, orderCD] =
1587 cdTy.getElementType().getIntOrFloatBitWidth(),
1588 cdTy.getElementType().getIntOrFloatBitWidth());
1592 return std::nullopt;
1596 "Number of subgroups must be provided for sg layout creation.");
1598 numSg, *instDataVecs);
1600 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1601 return std::make_tuple(
1610 return std::make_tuple(aLayout, bLayout, cdLayout);
1612 return std::nullopt;
1619static xegpu::DistributeLayoutAttr
1621 VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout,
1623 if (!scaleTy || !matrixLayout)
1631 if (scaleShape.empty())
1634 auto uArchInstruction =
1635 dyn_cast<xegpu::uArch::SubgroupScaledMatrixMultiplyAcc>(
1639 int64_t rank = matrixLayout.getRank();
1640 assert(rank >= 2 &&
"dpas layouts must be at least two dimensions");
1647 auto order = matrixLayout.getOrder();
1651 if (!sgLayout.empty() && !sgData.empty()) {
1652 scaleSgLayout.assign(sgLayout.begin(), sgLayout.end());
1653 scaleSgData.assign(sgData.begin(), sgData.end());
1654 scaleSgData[rank - 2] = std::max<int64_t>(
1655 scaleShape[rank - 2] / (matrixShape[rank - 2] / sgData[rank - 2]), 1);
1656 scaleSgData[rank - 1] = std::max<int64_t>(
1657 scaleShape[rank - 1] / (matrixShape[rank - 1] / sgData[rank - 1]), 1);
1664 if (!instData.empty()) {
1665 scaleInstData.assign(instData.begin(), instData.end());
1667 scaleInstData[rank - 2] = std::max<int64_t>(
1668 scaleShape[rank - 2] / (matrixShape[rank - 2] / instData[rank - 2]),
1671 scaleInstData[rank - 1] = std::max<int64_t>(
1672 scaleShape[rank - 1] / (matrixShape[rank - 1] / instData[rank - 1]),
1678 if (!laneLayout.empty() && !laneData.empty()) {
1679 scaleLaneLayout.assign(laneLayout.begin(), laneLayout.end());
1680 scaleLaneData.assign(laneData.size(), 1);
1682 bool isRowMajor = uArchInstruction->isLaneLayoutRowMajorOrder();
1683 if (isBScale ^ isRowMajor)
1684 std::swap(scaleLaneLayout[rank - 2], scaleLaneLayout[rank - 1]);
1689 auto layoutCap = scaleInstData.empty() ? scaleShape : scaleInstData;
1690 for (
int64_t d = rank - 2; d < rank; ++d)
1691 scaleLaneLayout[d] = std::min<int64_t>(layoutCap[d], scaleLaneLayout[d]);
1693 return buildLayout(context, scaleSgLayout, scaleSgData, scaleInstData,
1694 scaleLaneLayout, scaleLaneData, order);
1701 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1702 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
1703 xegpu::DistributeLayoutAttr>>
1705 VectorType bTy, VectorType cdTy, VectorType aScaleTy,
1706 VectorType bScaleTy,
1707 xegpu::DistributeLayoutAttr consumerLayout,
int numSg,
1709 auto context = aTy.getContext();
1710 const auto *uArchInstruction =
1711 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
1713 if (!uArchInstruction)
1714 return std::nullopt;
1717 auto [laneLayoutA, laneDataA, orderA] =
1719 aTy.getElementType().getIntOrFloatBitWidth(),
1720 uArchInstruction->getPackedFormatBitSizeA());
1722 bTy.getShape(), subgroupSize,
1723 bTy.getElementType().getIntOrFloatBitWidth(),
1724 uArchInstruction->getPackedFormatBitSizeB(),
true);
1725 auto [laneLayoutCD, laneDataCD, orderCD] =
1727 cdTy.getElementType().getIntOrFloatBitWidth(),
1728 cdTy.getElementType().getIntOrFloatBitWidth());
1731 return std::nullopt;
1735 "Number of subgroups must be provided for sg layout creation.");
1737 context, aTy, bTy, cdTy, consumerLayout, numSg, *instDataVecs);
1739 return std::nullopt;
1741 auto [dpasALayout, dpasBLayout, dpasCDLayout] = *dpasLayouts;
1750 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1754 auto [instDataA, instDataB, instDataCD] = *instDataVecs;
1761 laneLayoutCD, laneDataCD);
1768 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1773 auto dpasCDLayout =
buildLaneLayout(context, laneLayoutCD, laneDataCD);
1780 return std::make_tuple(dpasALayout, dpasBLayout, dpasCDLayout, aScaleLayout,
1783 return std::nullopt;
1789xegpu::DistributeLayoutAttr
1791 VectorType srcVecTy,
int numSg,
1793 const auto *uArchInstruction =
1794 dyn_cast<xegpu::uArch::Subgroup2DBlockStoreInstruction>(
1795 uArch->getInstruction(
1797 if (!uArchInstruction)
1800 auto context = srcVecTy.getContext();
1801 Type elemTy = srcVecTy.getElementType();
1802 auto subgroupSize =
uArch->getSubgroupSize();
1803 auto dataShape = srcVecTy.getShape();
1804 [[maybe_unused]]
int rank = srcVecTy.getRank();
1805 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1809 auto [laneLayout, laneData, order] =
1811 uArchInstruction->getPackedFormatBitSize());
1824 "Expected the store layout to satisfy uArch block constraints");
1831 "Number of subgroups must be provided for sg layout creation.");
1833 if (sgLayouts.empty())
1835 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1844xegpu::DistributeLayoutAttr
1846 xegpu::TensorDescType tdescTy,
int numSg,
1849 const auto *uArchInstruction =
1850 dyn_cast<xegpu::uArch::Subgroup2DBlockPrefetchInstruction>(
1853 if (!uArchInstruction)
1856 auto context = tdescTy.getContext();
1857 Type elemTy = tdescTy.getElementType();
1859 auto dataShape = tdescTy.getShape();
1860 [[maybe_unused]]
int rank = tdescTy.getRank();
1861 assert(rank >= 2 &&
"Expected at least 2D shape for ND op");
1865 auto [laneLayout, laneData, order] =
1867 uArchInstruction->getPackedFormatBitSize());
1880 "Expected the prefetch layout to satisfy uArch block constraints");
1887 "Number of subgroups must be provided for sg layout creation.");
1889 if (sgLayouts.empty())
1891 return buildSgLayout(context, dataShape, sgLayouts.front(), -1);
1902xegpu::DistributeLayoutAttr
1904 VectorType resVecTy,
1905 xegpu::DistributeLayoutAttr consumerLayout,
1908 assert(consumerLayout &&
"Expected a valid consumer layout");
1910 assert(consumerLayout.isForWorkgroup() &&
1911 "Expected consumer layout to be a complete workgroup-level layout");
1912 return consumerLayout;
1915 auto context = resVecTy.getContext();
1916 Type elemTy = resVecTy.getElementType();
1918 auto dataShape = resVecTy.getShape();
1919 const auto *uArchInstruction =
1920 dyn_cast<xegpu::uArch::Subgroup2DBlockLoadInstruction>(
1923 if (!uArchInstruction)
1926 int rank = resVecTy.getRank();
1928 consumerLayout.getEffectiveInstDataAsInt();
1930 consumerLayout.getEffectiveLaneLayoutAsInt();
1932 consumerLayout.getEffectiveLaneDataAsInt();
1934 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
1935 "Expected consumer layout to have lane_layout and lane_data");
1941 consumerLaneLayout[rank - 2] > 1 && consumerLaneLayout[rank - 1] == 1;
1946 bool hasTransform = !hasTranspose && canTransform &&
1947 consumerLaneData[rank - 2] > 1 &&
1948 consumerLaneData[rank - 1] == 1;
1949 assert((consumerLaneData[rank - 2] == 1 || consumerLaneData[rank - 1] == 1) &&
1950 "Expected consumer lane data to have at most one non-unit dim");
1953 auto blockWHC = uArchInstruction->getBlockWidthHeightCount(
1954 elemTy, hasTransform, hasTranspose,
1958 auto [bWidths, bHeights, bCounts] = blockWHC.value();
1963 unsigned packingSize = hasTransform || hasTranspose
1965 : uArchInstruction->getPackedFormatBitSize();
1968 hasTransform, hasTranspose);
1976 int64_t height = consumerInstData[rank - 2];
1977 int64_t width = consumerInstData[rank - 1];
1978 auto maxBlockCount = *llvm::max_element(bCounts);
1979 auto maxWidth = *llvm::max_element(bWidths);
1980 if (llvm::is_contained(bWidths,
static_cast<int>(width)) ||
1981 (width % maxWidth == 0 && width / maxWidth < maxBlockCount)) {
1982 if (llvm::is_contained(bHeights,
static_cast<int>(height))) {
1984 "Expected the load layout to satisfy uArch block constraints");
1986 laneLayout, laneData, orderAttr);
1995 if (!hasTranspose && !hasTransform &&
1996 consumerInstData[rank - 1] %
1997 (laneLayout[rank - 1] * laneData[rank - 1]) !=
1999 hasTransform =
true;
2006 dataShape, elemTy, uArchInstruction, hasTransform, hasTranspose);
2011 "Expected the load layout to satisfy uArch block constraints");
2017 "Expected the lane layout to satisfy uArch block constraints");
2018 return consumerLayout;
2044 xegpu::DistributeLayoutAttr consumerLayout,
int maxChunkSize,
2048 return consumerLayout;
2051 consumerLayout.getEffectiveInstDataAsInt();
2053 consumerLayout.getEffectiveLaneLayoutAsInt();
2055 consumerLayout.getEffectiveLaneDataAsInt();
2057 assert(!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
2058 "Expected consumer layout to have lane_layout and lane_data");
2065 std::min(consumerLaneData.back(),
static_cast<int64_t>(maxChunkSize));
2069 instData.resize(resShape.size());
2070 for (
size_t i = 0; i < resShape.size(); ++i)
2071 instData[i] = laneLayout[i] * laneData[i];
2082 xegpu::DistributeLayoutAttr consumerLayout,
const uArch::uArch *uArch) {
2084 const int subgroupSize = uArch->getSubgroupSize();
2086 auto context = resVecTy.getContext();
2090 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
2093 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2096 maxChunkSize, resShape, subgroupSize);
2101xegpu::DistributeLayoutAttr
2103 VectorType resVecTy,
int contigChunkSize,
2104 xegpu::DistributeLayoutAttr consumerLayout,
2109 auto context = resVecTy.getContext();
2111 const auto *uArchInstruction = dyn_cast<xegpu::uArch::LoadGatherInstruction>(
2114 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2116 maxChunkSize, resShape, subgroupSize);
2122static xegpu::DistributeLayoutAttr
2126 if (candidates.empty())
2129 return buildSgLayout(context, wgShape, candidates.front(), -1);
2139 auto [laneLayout, laneData] =
2143 for (
size_t i = 0; i < srcShape.size(); ++i)
2144 instData[i] = laneLayout[i] * laneData[i];
2148 "Number of subgroups must be provided for sg layout creation.");
2161xegpu::DistributeLayoutAttr
2163 VectorType srcVecTy,
int contigChunkSize,
2166 const int subgroupSize =
uArch->getSubgroupSize();
2168 auto context = srcVecTy.getContext();
2172 const auto *uArchInstruction =
2173 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2176 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2178 srcShape, subgroupSize, numSg);
2186 const int subgroupSize =
uArch->getSubgroupSize();
2188 auto context = srcVecTy.getContext();
2190 const auto *uArchInstruction =
2191 dyn_cast<xegpu::uArch::StoreScatterInstruction>(
2194 std::min(uArchInstruction->getMaxLaneAccessSizeBytes(), contigChunkSize);
2197 srcShape, subgroupSize, numSg);
2215std::optional<xegpu::DistributeLayoutAttr>
2217 xegpu::DistributeLayoutAttr specifiedLayout,
2218 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2220 const int subgroupSize) {
2221 if (!specifiedLayout)
2222 return specifiedLayout;
2224 specifiedLayout.getEffectiveInstDataAsInt();
2225 if (specifiedInstData.empty())
2226 return specifiedLayout;
2227 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2228 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2229 return specifiedLayout;
2232 auto *context = specifiedLayout.getContext();
2234 if (consumerLayout) {
2235 auto consumerLaneLayout = consumerLayout.getEffectiveLaneLayoutAsInt();
2236 auto consumerLaneData = consumerLayout.getEffectiveLaneDataAsInt();
2237 if (!consumerLaneLayout.empty() && !consumerLaneData.empty() &&
2241 consumerLaneLayout, consumerLaneData);
2244 specifiedInstData, subgroupSize, maxChunkSize);
2246 return std::nullopt;
2254std::optional<xegpu::DistributeLayoutAttr>
2256 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2258 const int subgroupSize) {
2259 if (!specifiedLayout)
2260 return specifiedLayout;
2262 specifiedLayout.getEffectiveInstDataAsInt();
2263 if (specifiedInstData.empty())
2264 return specifiedLayout;
2265 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2266 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2267 return specifiedLayout;
2270 auto *context = specifiedLayout.getContext();
2273 specifiedInstData, subgroupSize, maxChunkSize);
2275 return std::nullopt;
2284std::optional<xegpu::DistributeLayoutAttr>
2286 xegpu::DistributeLayoutAttr specifiedLayout,
Type elemTy,
2288 const int subgroupSize) {
2289 if (!specifiedLayout)
2290 return specifiedLayout;
2292 specifiedLayout.getEffectiveInstDataAsInt();
2293 if (specifiedInstData.empty())
2294 return specifiedLayout;
2295 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2296 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2297 return specifiedLayout;
2299 auto *context = specifiedLayout.getContext();
2304 return std::nullopt;
2313std::optional<xegpu::DistributeLayoutAttr>
2315 xegpu::DistributeLayoutAttr specifiedLayout,
2316 xegpu::DistributeLayoutAttr consumerLayout,
Type elemTy,
2318 const int subgroupSize) {
2319 if (!specifiedLayout)
2320 return specifiedLayout;
2322 specifiedLayout.getEffectiveInstDataAsInt();
2323 if (specifiedInstData.empty())
2324 return specifiedLayout;
2325 if (!specifiedLayout.getEffectiveLaneLayoutAsInt().empty() &&
2326 !specifiedLayout.getEffectiveLaneDataAsInt().empty())
2327 return specifiedLayout;
2328 if (!consumerLayout)
2329 return specifiedLayout;
2331 consumerLayout.getEffectiveLaneLayoutAsInt();
2333 consumerLayout.getEffectiveLaneDataAsInt();
2334 if (consumerLaneLayout.empty() || consumerLaneData.empty())
2335 return specifiedLayout;
2337 auto *context = specifiedLayout.getContext();
2338 int rank = specifiedInstData.size();
2343 for (
int i = 0; i < rank; i++) {
2344 if (consumerLaneLayout[i] > 1) {
2345 laneLayout.push_back(
2346 std::max(
static_cast<int64_t>(subgroupSize), consumerLaneLayout[i]));
2348 laneLayout.push_back(1);
2353 return std::nullopt;
2356 consumerLayout.getOrder());
2364 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2365 xegpu::DistributeLayoutAttr>>
2367 xegpu::DistributeLayoutAttr bLayout,
2368 xegpu::DistributeLayoutAttr cdLayout,
2369 VectorType aTy, VectorType bTy,
2372 auto context = aTy.getContext();
2373 const auto *uArchInstruction =
2374 dyn_cast<xegpu::uArch::SubgroupMatrixMultiplyAcc>(uArch->
getInstruction(
2376 if (!uArchInstruction)
2377 return std::nullopt;
2380 laneLayoutCD, laneDataCD;
2387 if (isa<xegpu::uArch::Xe2, xegpu::uArch::Xe3p>(uArch)) {
2388 std::tie(laneLayoutA, laneDataA, orderA) =
2390 aTy.getElementType().getIntOrFloatBitWidth(),
2391 uArchInstruction->getPackedFormatBitSizeA());
2393 bTy.getShape(), subgroupSize,
2394 bTy.getElementType().getIntOrFloatBitWidth(),
2395 uArchInstruction->getPackedFormatBitSizeB(),
true);
2397 cdTy.getShape(), subgroupSize,
2398 cdTy.getElementType().getIntOrFloatBitWidth(),
2399 cdTy.getElementType().getIntOrFloatBitWidth());
2401 assert(
false &&
"Unsupported uArch for DPAS lane layout completion");
2407 return std::nullopt;
2408 return std::make_tuple(
2410 aLayout.getOrder()),
2412 bLayout.getOrder()),
2414 cdLayout.getOrder()));
2421 std::tuple<xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2422 xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr,
2423 xegpu::DistributeLayoutAttr>>
2425 xegpu::DistributeLayoutAttr aLayout, xegpu::DistributeLayoutAttr bLayout,
2426 xegpu::DistributeLayoutAttr cdLayout, VectorType aTy, VectorType bTy,
2427 VectorType cdTy, VectorType aScaleTy, VectorType bScaleTy,
2430 aLayout, bLayout, cdLayout, aTy, bTy, cdTy, uArch);
2432 return std::nullopt;
2433 auto context = aTy.getContext();
2434 auto [completedA, completedB, completedCD] = *completed;
2441 return std::make_tuple(completedA, completedB, completedCD, aScaleLayout,
2576 auto srcShape = srcVecTy.getShape();
2577 int srcRank = srcShape.size();
2578 auto context = srcVecTy.getContext();
2580 const int subgroupSize =
uArch->getSubgroupSize();
2581 int64_t maxReduceVectorSize = 16;
2582 xegpu::DistributeLayoutAttr srcLayout;
2584 xegpu::SliceAttr consumerSliceLayout =
2585 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2586 if (consumerSliceLayout &&
2587 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2588 srcLayout = consumerSliceLayout.getParent();
2590 srcLayout.getEffectiveSgLayoutAsInt();
2593 for (
int dim = 0; dim < srcRank; dim++) {
2594 if (llvm::is_contained(reductionDims, dim))
2596 srcLayout.setDimData(dim, srcSgData.value()[dim], -1, -1);
2600 consumerLayout ? consumerLayout.getEffectiveSgLayoutAsInt()
2603 consumerLayout ? consumerLayout.getEffectiveSgDataAsInt()
2606 consumerLayout ? consumerLayout.getEffectiveOrderAsInt()
2609 consumerLayout ? consumerLayout.getOrder() :
nullptr;
2611 int remainingSgCount =
2612 consumerLayout ? consumerLayout.getNumSubgroups() : numSg;
2613 int consumerIdx = 0;
2616 for (
int i = 0; i < srcRank; i++) {
2617 if (!llvm::is_contained(reductionDims, i) &&
2618 consumerIdx <
static_cast<int>(consumerSgLayout.size())) {
2619 sgLayout[i] = consumerSgLayout[consumerIdx];
2620 sgData[i] = consumerSgData[consumerIdx];
2621 remainingSgCount /= sgLayout[i];
2628 for (
int i = 0; i < srcRank; i++) {
2629 if (llvm::is_contained(reductionDims, i)) {
2631 std::min(srcShape[i],
static_cast<int64_t>(remainingSgCount));
2632 assert((srcShape[i] % sgLayout[i] == 0) &&
2633 "source shape not divisible by sg_layout");
2634 sgData[i] = srcShape[i] / sgLayout[i];
2635 remainingSgCount /= sgLayout[i];
2641 int numRetainedDims = srcRank -
static_cast<int>(reductionDims.size());
2642 if (orderAttr && !orderAttr.empty() &&
2643 static_cast<int>(consumerOrder.size()) == numRetainedDims) {
2645 int retainedRank = 0;
2646 for (
int dim = 0; dim < srcRank; dim++)
2647 if (!llvm::is_contained(reductionDims, dim))
2648 order[dim] = consumerOrder[retainedRank++];
2651 for (
int reducedDim = 0; reducedDim < srcRank; reducedDim++) {
2652 if (!llvm::is_contained(reductionDims, reducedDim))
2657 insertRank = order[reducedDim - 1];
2660 else if (srcRank > 1)
2661 insertRank = order[reducedDim + 1] + 1;
2662 for (
int otherDim = 0; otherDim < srcRank; otherDim++)
2663 if (order[otherDim] >= insertRank)
2665 order[reducedDim] = insertRank;
2670 assert(remainingSgCount == 1 &&
"not all subgroups distributed");
2671 srcLayout =
buildLayout(context, sgLayout, sgData,
2676 auto [laneLayout, laneData, instData] =
2678 maxReduceVectorSize, consumerLayout);
2682 xegpu::SliceAttr consumerSliceLayout =
2683 dyn_cast_if_present<xegpu::SliceAttr>(consumerLayout);
2684 if (consumerSliceLayout &&
2685 consumerSliceLayout.getDims().asArrayRef().equals(reductionDims)) {
2689 srcLayout = consumerSliceLayout.getParent();
2692 srcShape, reductionDims, subgroupSize, maxReduceVectorSize,
2699 return xegpu::SliceAttr::get(context, srcLayout,
2707 VectorType srcVecTy,
2710 auto srcShape = srcVecTy.getShape();
2711 auto context = srcVecTy.getContext();
2712 auto subgroupSize =
uArch->getSubgroupSize();
2713 xegpu::LayoutAttr srcLayout;
2717 "subgroup layout assignment not supported for reduction (op "
2718 "is not expected at this level).");
2721 "instData layout assignment not supported for reduction (op "
2722 "is not expected at this level).");
2725 laneLayout[0] = std::min(
static_cast<int64_t>(subgroupSize), srcShape[0]);
2730 auto result = xegpu::SliceAttr::get(context, srcLayout,
2748static xegpu::DistributeLayoutAttr
2751 size_t innerMostDim,
int ratio,
int64_t bound,
2757 consumerLayout.getEffectiveLaneLayoutAsInt();
2764 sgDataValue = sgData[innerMostDim];
2765 while ((sgDataValue <= bound) && (sgDataValue % ratio) != 0)
2768 instDataValue = instData[innerMostDim];
2769 const int innermostDimLaneLayout = laneLayout.empty()
2771 : laneLayout[innerMostDim];
2772 while ((instDataValue <= bound) &&
2773 (instDataValue % (innermostDimLaneLayout * ratio) != 0))
2775 assert((bound % instDataValue) == 0 &&
2776 "bound, instData, and laneLayout for innermost must be 2^n!");
2778 laneDataValue = laneData[innerMostDim];
2779 while ((laneDataValue <= bound) && (laneDataValue % ratio) != 0)
2783 return consumerLayout.setDimData(innerMostDim, sgDataValue, instDataValue,
2813 int srcElemTyBitWidth = srcVecTy.getElementType().getIntOrFloatBitWidth();
2814 int resElemTyBitWidth = resVecTy.getElementType().getIntOrFloatBitWidth();
2819 assert(consumerLayout.getRank() ==
static_cast<int64_t>(srcShape.size()) &&
2820 "laneData must be available for all dimensions");
2824 if (srcElemTyBitWidth <= resElemTyBitWidth)
2825 return consumerLayout;
2830 size_t innerMostDim = srcShape.size() - 1;
2831 int bitWidthRatio = srcElemTyBitWidth / resElemTyBitWidth;
2833 innerMostDim, bitWidthRatio,
2834 resShape[innerMostDim],
uArch);
2857 assert(consumerLayout.getRank() ==
static_cast<int64_t>(resShape.size()) &&
2858 "consumer layout rank must match source shape rank");
2863 const size_t innerMostDim = resShape.size() - 1;
2864 constexpr int ratio = 2;
2866 innerMostDim, ratio,
2867 resShape[innerMostDim],
uArch);
2886 for (
int64_t dim : llvm::reverse(dimGroup)) {
2887 int64_t tileSize = tileShape.empty() ? 1 : tileShape[dim];
2888 if (counts[dim] != 1) {
2889 if (stride * tileSize != expectedStride)
2891 expectedStride = stride * tileSize * counts[dim];
2893 stride *=
shape[dim];
2898xegpu::DistributeLayoutAttr
2900 VectorType srcVecTy, VectorType resVecTy,
2901 DistributeLayoutAttr consumerLayout) {
2904 return consumerLayout;
2910 return consumerLayout;
2913 consumerLayout.getEffectiveLaneLayoutAsInt();
2916 xegpu::DistributeLayoutAttr resLayout = [&]() -> DistributeLayoutAttr {
2917 DistributeLayoutAttr layout = consumerLayout;
2920 while (i < dimGroup.size() && laneLayout[dimGroup[i]] == 1)
2923 for (++i; i < dimGroup.size(); ++i) {
2925 int64_t dimSize = resShape[dim];
2926 int64_t lanes = laneLayout[dim];
2927 if (lanes <= 0 || dimSize % lanes != 0)
2928 return consumerLayout;
2930 layout.setDimData(dim, -1,
2931 instData.empty() ? -1 : dimSize, dimSize / lanes);
2949 int64_t collapsedLaneData = 1;
2951 collapsedLaneData *= resLaneData[dim];
2957 if (!resInstData.empty() &&
2970 VectorType resVectorTy, xegpu::DistributeLayoutAttr consumerLayout,
2973 xegpu::DistributeLayoutAttr requiredResLayout;
2975 consumerLayout.getEffectiveInstDataAsInt();
2977 consumerLayout.getEffectiveLaneDataAsInt();
2979 consumerLayout.getEffectiveLaneLayoutAsInt();
2983 requiredResLayout = consumerLayout;
2984 int srcRank = srcShape.size();
2988 assert(
false &&
"subgroup/instData layout assignment not supported for "
2989 "insertStridedSlice.");
2991 for (
int dim = 0; dim < srcRank; dim++) {
2993 if (srcShape[dim] == 1) {
2996 assert(srcShape[dim] % consumerLaneLayout[dim] == 0 &&
2997 "srcShape must be divisible by laneLayout for all dimensions");
2998 laneDataValue = std::min(srcShape[dim] / consumerLaneLayout[dim],
2999 consumerLaneData[dim]);
3002 requiredResLayout.setDimData(dim, -1, -1, laneDataValue);
3005 return requiredResLayout;
3015 OpOperand &operand, xegpu::DistributeLayoutAttr resLayout) {
3022 if (
auto broadcast = dyn_cast<vector::BroadcastOp>(op)) {
3023 auto srcTy = dyn_cast<VectorType>(
broadcast.getSourceType());
3027 resLayout,
broadcast.getResultVectorType().getShape(),
3034 if (
auto reduction = dyn_cast<vector::MultiDimReductionOp>(op)) {
3043 if (
auto reduction = dyn_cast<vector::ReductionOp>(op))
3048 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
3049 int resElemBitWidth =
3050 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
3051 int srcElemBitWidth =
3052 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
3059 if (
auto shapeCast = dyn_cast<vector::ShapeCastOp>(op)) {
3061 resLayout, shapeCast.getResultVectorType().getShape(),
3062 shapeCast.getSourceVectorType().getShape());
3067 if (
auto insertSlice = dyn_cast<vector::InsertStridedSliceOp>(op)) {
3070 resLayout, insertSlice.getDestVectorType().getShape(),
3071 insertSlice.getSourceVectorType().getShape());
3079 if (
auto insert = dyn_cast<vector::InsertOp>(op)) {
3080 VectorType resVecTy = dyn_cast<VectorType>(insert.getResult().getType());
3081 VectorType valueToStoreTy =
3082 dyn_cast<VectorType>(insert.getValueToStore().getType());
3084 if ((idx == 0) && valueToStoreTy) {
3086 valueToStoreTy.getShape());
3094 if (
auto extract = dyn_cast<vector::ExtractOp>(op)) {
3095 VectorType srcVecTy = dyn_cast<VectorType>(extract.getSource().getType());
3096 VectorType resVecTy = dyn_cast<VectorType>(extract.getResult().getType());
3097 if (!srcVecTy || !resVecTy)
3100 srcVecTy.getShape());
3105 if (
auto transpose = dyn_cast<vector::TransposeOp>(op)) {
3107 transpose.getPermutation());
3112 if (
auto bitcast = dyn_cast<vector::BitCastOp>(op)) {
3113 int resElemBitWidth =
3114 bitcast.getResultVectorType().getElementType().getIntOrFloatBitWidth();
3115 int srcElemBitWidth =
3116 bitcast.getSourceVectorType().getElementType().getIntOrFloatBitWidth();
3122 if (
auto interleave = dyn_cast<vector::InterleaveOp>(op)) {
3127 if (
auto deinterleave = dyn_cast<vector::DeinterleaveOp>(op)) {
3132 if (dyn_cast<vector::ExtractStridedSliceOp>(op))
3148 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
3149 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
3153 branch.getSuccessorOperandInputMapping(mapping,
3155 auto it = mapping.find(&operand);
3156 if (it == mapping.end())
3158 xegpu::DistributeLayoutAttr iterArgLayout;
3159 for (
auto arg : llvm::make_isa_range<BlockArgument>(it->second)) {
3161 assert((!iterArgLayout || !layout || iterArgLayout.isEqualTo(layout)) &&
3162 "region inputs fed by one terminator operand disagree on layout");
3164 iterArgLayout = layout;
3166 return iterArgLayout;
3172 RegionBranchTerminatorOpInterface terminator,
OpOperand &operand) {
3173 auto branch = dyn_cast<RegionBranchOpInterface>(terminator->getParentOp());
3177 branch.getSuccessorOperandInputMapping(mapping,
3179 auto it = mapping.find(&operand);
3180 if (it == mapping.end())
3182 for (
Value input : it->second)
3183 if (
auto result = dyn_cast<OpResult>(input))
3196 if (isa<xegpu::AnchorLayoutInterface>(op))
3204 if (isa<RegionBranchOpInterface>(op))
3209 if (
auto terminator = dyn_cast<RegionBranchTerminatorOpInterface>(op)) {
3216 xegpu::DistributeLayoutAttr resLayout;
3217 if (op->
getNumResults() == 1 || isa<vector::DeinterleaveOp>(op))
static void visit(Operation *op, DenseSet< Operation * > &visited)
Visits all the pdl.operand(s), pdl.result(s), and pdl.operation(s) connected to the given operation.
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
static xegpu::LayoutAttr buildLayout(mlir::MLIRContext *context, ArrayRef< int64_t > sgLayout, ArrayRef< int64_t > sgData, ArrayRef< int64_t > instData, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData, DenseI32ArrayAttr orderAttr=nullptr)
static xegpu::DistributeLayoutAttr getStoreSubgroupLayouts(mlir::MLIRContext *context, ArrayRef< int64_t > wgShape, ArrayRef< int64_t > instData, int numSg)
Picks the subgroup layout for a scatter-style store (store_scatter / store_matrix): the most balanced...
static xegpu::DistributeLayoutAttr createScaleLayout(mlir::MLIRContext *context, VectorType matrixTy, VectorType scaleTy, xegpu::DistributeLayoutAttr matrixLayout, bool isBScale, const xegpu::uArch::uArch *uArch)
Helper to create a scale layout derived from a matrix operand layout.
static xegpu::DistributeLayoutAttr adjustInnermostDimForDivisibility(xegpu::DistributeLayoutAttr consumerLayout, xegpu::LayoutKind layoutKind, size_t innerMostDim, int ratio, int64_t bound, const xegpu::uArch::uArch *uArch)
Adjusts consumerLayout's innermost-dim data field selected by layoutKind so that the source layout ca...
static std::pair< SmallVector< int64_t >, SmallVector< int64_t > > computeScatterIOLaneLayoutAndData(ArrayRef< int64_t > instShape, int64_t subgroupSize, int64_t maxChunkSize)
Computes lane_layout and lane_data for scatter-style store anchor layouts (store scatter,...
static xegpu::LayoutAttr buildInstDataLayoutWithLane(mlir::MLIRContext *context, ArrayRef< int64_t > instData, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData, DenseI32ArrayAttr orderAttr=nullptr)
static xegpu::LayoutAttr buildSgLayout(mlir::MLIRContext *context, ArrayRef< int64_t > wgTileShape, ArrayRef< int64_t > sgLayout, int dimK=-1, DenseI32ArrayAttr orderAttr=nullptr)
static 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 std::optional< std::tuple< xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr, xegpu::DistributeLayoutAttr > > getDpasSubgroupLayouts(mlir::MLIRContext *context, VectorType aTy, VectorType bTy, VectorType cdTy, xegpu::DistributeLayoutAttr consumerLayout, int numSg, std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > instDataVecs)
Helper function to set up subgroup layouts for DPAS operands A, B, and C/D.
static SmallVector< LayoutRepresentation > enumerateFactorizations(int64_t total, int64_t rank)
Enumerates all ways to split total into rank factors whose product equals total.
static xegpu::DistributeLayoutAttr setupGenericLoadAnchorLayout(xegpu::LayoutKind layoutKind, mlir::MLIRContext *context, xegpu::DistributeLayoutAttr consumerLayout, int maxChunkSize, ArrayRef< int64_t > resShape, int subgroupSize)
Sets up the anchor layout for load gather and load matrix operation.
static bool isContiguousTiling(ArrayRef< int64_t > dimGroup, ArrayRef< int64_t > shape, ArrayRef< int64_t > counts, ArrayRef< int64_t > tileShape, int64_t expectedStride)
Checks that the tiles a split group is cut into walk the collapsed source dim with one constant strid...
SmallVector< int64_t > LayoutRepresentation
static xegpu::DistributeLayoutAttr getLayoutFromUsePoints(Value result)
static xegpu::DistributeLayoutAttr setupGenericStoreAnchorLayout(xegpu::LayoutKind layoutKind, mlir::MLIRContext *context, int maxChunkSize, ArrayRef< int64_t > srcShape, int subgroupSize, int numSg)
Sets up the anchor layout for store scatter and store matrix operation, which share the same logic.
static std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > compute2DBlockIOLaneLayout(ArrayRef< int64_t > instShape, int64_t subgroupSize, int64_t bitwidth, int64_t packingSize, bool transform=false, bool transpose=false)
static xegpu::DistributeLayoutAttr getLoopCarriedLayoutForYieldOperand(RegionBranchTerminatorOpInterface terminator, OpOperand &operand)
static 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)
Computes a multi_reduction's source layout as (lane_layout, lane_data, inst_data),...
static void walkRegionBackward(Region ®ion, llvm::function_ref< void(Operation *)> visit)
static xegpu::LayoutAttr buildLaneLayout(mlir::MLIRContext *context, ArrayRef< int64_t > laneLayout, ArrayRef< int64_t > laneData, DenseI32ArrayAttr orderAttr=nullptr)
static std::optional< std::tuple< SmallVector< int64_t >, SmallVector< int64_t >, SmallVector< int64_t > > > getDpasInstDataLayouts(VectorType aTy, VectorType bTy, VectorType cdTy, const xegpu::uArch::MMAInstructionInterface *uArchInstruction)
Helper function to compute inst_data vectors for DPAS operands A, B, and C/D.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
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