29#include "llvm/Support/Casting.h"
30#include "llvm/Support/FormatVariadic.h"
39 for (
const auto &vals : values)
40 llvm::append_range(
result, vals);
46 auto layout = llvm::dyn_cast_if_present<LayoutAttr>(tdescTy.getLayout());
49 if (!layout || !layout.isForSubgroup())
54 auto tdescShape = tdescTy.getShape();
55 auto elementType = tdescTy.getElementType();
60 int64_t sgSize = llvm::product_of(laneLayout);
64 for (
auto [tdescDim, laneDim, laneDataDim] :
65 llvm::zip_equal(tdescShape, laneLayout, laneData)) {
66 assert((tdescDim % (laneDim * laneDataDim) == 0) &&
67 "tensor descriptor shape is not distributable");
68 tensorSize *= tdescDim;
71 tensorSize *= tdescTy.getArrayLength();
73 return VectorType::get({tensorSize / sgSize}, elementType);
78 xegpu::LayoutAttr layout) {
79 int64_t rank = originalType.getRank();
86 while (
shape.size() > 2) {
87 arrayLength *=
shape[0];
92 auto laneLayout = layout.getEffectiveLaneLayoutAsInt();
93 auto laneData = layout.getEffectiveLaneDataAsInt();
94 while (!laneLayout.empty() && laneLayout.size() >
shape.size()) {
95 laneLayout.erase(laneLayout.begin());
96 laneData.erase(laneData.begin());
98 auto trimmedLayout = xegpu::LayoutAttr::get(
102 auto helperTdescTy = xegpu::TensorDescType::get(
103 shape, originalType.getElementType(), arrayLength,
105 xegpu::MemorySpace::Global, trimmedLayout);
111 VectorType originalType) {
114 assert((isa<xegpu::LayoutAttr>(layout) || isa<xegpu::SliceAttr>(layout)) &&
115 "Expecting a valid layout.");
117 int64_t vectorRank = originalType.getRank();
118 int64_t layoutRank = layout.getRank();
119 assert(vectorRank >= layoutRank &&
"Vector rank must be >= layout rank.");
123 int64_t offset = vectorRank - layoutRank;
127 auto distributedShapeOrFailure =
128 layout.computeDistributedShape(trailingShape);
129 if (
failed(distributedShapeOrFailure))
133 fullShape.begin() + offset);
134 resultShape.append(distributedShapeOrFailure->begin(),
135 distributedShapeOrFailure->end());
136 return VectorType::get(resultShape, originalType.getElementType());
140 const StringRef prefix(
"layout_operand_");
141 unsigned idx =
const_cast<OpOperand &
>(operand).getOperandNumber();
142 return llvm::formatv(
"{0}{1}", prefix, idx).str();
146 const StringRef prefix =
"layout_result_";
147 return llvm::formatv(
"{0}{1}", prefix,
result.getResultNumber()).str();
154 if (
auto result = dyn_cast<OpResult>(value)) {
156 assert(defOp &&
"result must have a defining op");
158 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(defOp)) {
159 auto layout = anchorOp.getAnchorLayout();
172 if (
auto arg = dyn_cast<BlockArgument>(value)) {
173 auto *parentOp = arg.getOwner()->getParentOp();
174 auto loop = dyn_cast_if_present<LoopLikeOpInterface>(parentOp);
176 if (
OpOperand *tiedInit = loop.getTiedLoopInit(arg))
182 if (
auto whileOp = dyn_cast_if_present<scf::WhileOp>(parentOp);
183 whileOp && arg.getOwner()->getParent() == &whileOp.getAfter()) {
184 Value forwarded = whileOp.getConditionOp().getArgs()[arg.getArgNumber()];
185 if (
auto beforeArg = dyn_cast<BlockArgument>(forwarded))
186 if (
OpOperand *tiedInit = whileOp.getTiedLoopInit(beforeArg))
192 dyn_cast_if_present<xegpu::TensorDescType>(value.
getType()))
193 return tdescTy.getLayoutAttr();
197xegpu::DistributeLayoutAttr
200 unsigned idx =
const_cast<OpOperand &
>(opr).getOperandNumber();
202 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(op)) {
203 if (
auto dpasOp = dyn_cast<xegpu::DpasOp>(op)) {
205 return dpasOp.getLayoutAAttr();
206 }
else if (idx == 1) {
207 return dpasOp.getLayoutBAttr();
208 }
else if (idx == 2) {
209 return dpasOp.getLayoutCdAttr();
212 if (
auto dpasMxOp = dyn_cast<xegpu::DpasMxOp>(op)) {
215 unsigned currentIdx = 0;
217 if (idx == currentIdx++)
218 return dpasMxOp.getLayoutAAttr();
220 if (idx == currentIdx++)
221 return dpasMxOp.getLayoutBAttr();
223 if (dpasMxOp.getAcc())
224 if (idx == currentIdx++)
225 return dpasMxOp.getLayoutCdAttr();
227 if (dpasMxOp.getScaleA())
228 if (idx == currentIdx++)
229 return dpasMxOp.getLayoutAScaleAttr();
231 if (dpasMxOp.getScaleB())
232 if (idx == currentIdx++)
233 return dpasMxOp.getLayoutBScaleAttr();
237 if (
auto convertOp = dyn_cast<xegpu::ConvertLayoutOp>(op)) {
238 return convertOp.getEffectiveInputLayout();
240 auto layout = anchorOp.getAnchorLayout();
247 if (isa<xegpu::StoreNdOp, xegpu::StoreMatrixOp>(op) && (idx < 2))
250 if (isa<xegpu::StoreScatterOp>(op)) {
251 xegpu::StoreScatterOp store(op);
252 int chunkSize = store.getChunkSize().value_or(1);
253 if (layout && idx >= 2 && chunkSize > 1)
254 return layout.dropDims(llvm::to_vector(
255 llvm::seq<int64_t>(layout.getRank() - 1, layout.getRank())));
258 if (isa<xegpu::LoadGatherOp>(op)) {
259 xegpu::LoadGatherOp
load(op);
260 int chunkSize =
load.getChunkSize().value_or(1);
261 if (layout && idx >= 1 && chunkSize > 1)
262 return layout.dropDims(llvm::to_vector(
263 llvm::seq<int64_t>(layout.getRank() - 1, layout.getRank())));
280xegpu::DistributeLayoutAttr
283 const std::string &name) {
284 xegpu::DistributeLayoutAttr candidate = layout;
286 if (
auto loadOp = dyn_cast<xegpu::LoadGatherOp>(owner)) {
287 if (
auto perm = loadOp.getLayoutAttr())
296xegpu::DistributeLayoutAttr
299 const std::string &name) {
300 xegpu::DistributeLayoutAttr candidate = layout;
301 unsigned idx =
const_cast<OpOperand &
>(operand).getOperandNumber();
303 if (
auto storeOp = dyn_cast<xegpu::StoreScatterOp>(owner)) {
305 if (
auto perm = storeOp.getLayoutAttr())
317 const mlir::xegpu::DistributeLayoutAttr layout) {
320 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(owner)) {
321 if (anchorOp.getAnchorLayout() == layout)
323 anchorOp.setAnchorLayout(layout);
339 const DistributeLayoutAttr layout) {
341 unsigned idx =
const_cast<OpOperand &
>(operand).getOperandNumber();
346 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(owner)) {
347 if (
auto dpasOp = dyn_cast<xegpu::DpasOp>(owner)) {
349 return dpasOp.setLayoutAAttr(layout);
350 }
else if (idx == 1) {
351 return dpasOp.setLayoutBAttr(layout);
352 }
else if (idx == 2) {
353 return dpasOp.setLayoutCdAttr(layout);
356 if (
auto convertOp = dyn_cast<xegpu::ConvertLayoutOp>(owner)) {
357 return convertOp.setInputLayoutAttr(layout);
363 if (isa<xegpu::StoreScatterOp, xegpu::StoreNdOp, xegpu::StoreMatrixOp>(
366 anchorOp.setAnchorLayout(layout);
370 anchorOp.setAnchorLayout(layout);
384template <
typename T,
typename>
385xegpu::DistributeLayoutAttr
387 Operation *op = operandOrResult.getOwner();
399template xegpu::DistributeLayoutAttr
401template xegpu::DistributeLayoutAttr
404template <
typename T,
typename>
406 const xegpu::DistributeLayoutAttr layout) {
407 Operation *owner = operandOrResult.getOwner();
419 const mlir::xegpu::DistributeLayoutAttr layout);
423 const mlir::xegpu::DistributeLayoutAttr layout);
428 auto vecTy = dyn_cast<VectorType>(value.
getType());
436 int64_t srcShapeRank = srcShape.size();
440 int64_t rankDiff = srcShapeRank - targetShapeRank;
441 std::fill(adjustedTargetShape.begin(), adjustedTargetShape.begin() + rankDiff,
443 llvm::copy(
shape, adjustedTargetShape.begin() + rankDiff);
449 Value slice = vector::ExtractStridedSliceOp::create(
450 builder, loc, value, offsets, adjustedTargetShape, staticStrides);
453 if (srcShapeRank > targetShapeRank) {
454 auto targetTy = VectorType::get(
shape, vecTy.getElementType());
455 slice = vector::ShapeCastOp::create(builder, loc, targetTy, slice);
466 VectorType inputTy = dyn_cast<VectorType>(values[0].
getType());
467 assert(llvm::all_of(values.
getTypes(),
468 [&](
Type type) { return type == inputTy; }) &&
469 "values must be of the same VectorType");
471 Type elemTy = inputTy.getElementType();
474 VectorType resultTy = VectorType::get(
shape, elemTy);
479 for (
auto [src, offsets] :
482 result = vector::InsertStridedSliceOp::create(builder, loc, src,
result,
483 offsets, staticStrides);
494 auto targetAttrs = gpuModuleOp.getTargets();
496 for (
auto &attr : *targetAttrs) {
497 auto xevmAttr = llvm::dyn_cast<xevm::XeVMTargetAttr>(attr);
499 return xevmAttr.getChip().str();
511 assert(lhs.size() == rhs.size() &&
"lhs and rhs must have the same size");
513 for (
auto [l, r] : llvm::zip_equal(lhs, rhs)) {
516 results.push_back(builder.
createOrFold<arith::AddIOp>(loc, lval, rval));
539 a = a.slice(a.size() -
b.size());
547 static_assert(std::is_integral<T>::value,
"T must be an integer type");
550 if (!candidateMultiples.empty())
552 SmallVector<T>(candidateMultiples.begin(), candidateMultiples.end());
553 for (T candidate : candidates) {
554 for (T multiple : multiples) {
555 int value =
static_cast<int>(candidate * multiple);
556 if (value != 0 && dim % value == 0 && value > largest)
564 vector::CombiningKind kind, uint32_t size) {
566 Value laneVal = vector::ReductionOp::create(builder, loc, kind, input);
568 for (uint64_t i = 1; i < size; i <<= 1) {
570 gpu::ShuffleOp::create(builder, loc, laneVal, i, size,
571 gpu::ShuffleMode::XOR)
573 laneVal = makeArithReduction(builder, loc, kind, laneVal, shuffled);
580 vector::CombiningKind kind,
583 VectorType sourceType = src.
getType();
584 int64_t sourceRank = sourceType.getRank();
587 assert(sourceRank >= 2 &&
"expected at least a 2D source vector");
588 for (
int64_t i = 0; i < sourceRank - 2; ++i)
589 assert(sourceType.getShape()[i] == 1 &&
590 "expected leading dimensions to be unit");
591 int64_t rowIdx = sourceRank - 2;
592 int64_t columnIdx = sourceRank - 1;
593 int64_t sourceH = sourceType.getShape()[rowIdx];
594 int64_t sourceW = sourceType.getShape()[columnIdx];
595 int nSlices = (reductionDim == rowIdx) ? sourceW : sourceH;
597 TypedAttr zeroAttr = rewriter.
getZeroAttr(sourceType.getElementType());
598 Value reductionResult = arith::ConstantOp::create(
599 rewriter, loc,
acc.getType(),
608 for (
int i = 0; i < nSlices; ++i) {
614 if (reductionDim == columnIdx) {
615 sliceOffsets[rowIdx] = i;
616 sliceSizes[columnIdx] = sourceW;
618 sliceOffsets[columnIdx] = i;
619 sliceSizes[rowIdx] = sourceH;
622 vector::ExtractStridedSliceOp extractOp =
623 vector::ExtractStridedSliceOp::create(rewriter, loc, src, sliceOffsets,
624 sliceSizes, strides);
628 int64_t nSliceElements = extractOp.getResult().getType().getNumElements();
630 vector::ShapeCastOp slice = vector::ShapeCastOp::create(
632 VectorType::get({nSliceElements}, sourceType.getElementType()),
633 extractOp.getResult());
643 accIdx[accRank - 1] = i;
644 Value accExtract = vector::ExtractOp::create(rewriter, loc,
acc, accIdx);
645 Value reduction = vector::ReductionOp::create(
646 rewriter, loc, kind, slice.getResult(), accExtract);
647 reductionResult = vector::InsertOp::create(rewriter, loc, reduction,
648 reductionResult, accIdx);
652 return reductionResult;
657 vector::CombiningKind kind,
int64_t reductionDim,
int64_t reductionSize,
659 VectorType sourceType = src.
getType();
660 int64_t sourceRank = sourceType.getRank();
663 assert(sourceRank >= 2 &&
"expected at least a 2D source vector");
664 for (
int64_t i = 0; i < sourceRank - 2; ++i)
665 assert(sourceType.getShape()[i] == 1 &&
666 "expected leading dimensions to be unit");
667 int64_t rowIdx = sourceRank - 2;
668 int64_t columnIdx = sourceRank - 1;
669 int64_t sourceH = sourceType.getShape()[rowIdx];
670 int64_t sourceW = sourceType.getShape()[columnIdx];
673 TypedAttr zeroAttr = rewriter.
getZeroAttr(sourceType.getElementType());
674 Value reductionResult = arith::ConstantOp::create(
675 rewriter, loc,
acc.getType(),
682 int nSlices = (reductionDim == rowIdx) ? sourceW : sourceH;
687 for (
int i = 0; i < nSlices; ++i) {
693 if (reductionDim == columnIdx) {
694 sliceOffsets[rowIdx] = i;
695 sliceSizes[columnIdx] = sourceW;
697 sliceOffsets[columnIdx] = i;
698 sliceSizes[rowIdx] = sourceH;
701 vector::ExtractStridedSliceOp extractOp =
702 vector::ExtractStridedSliceOp::create(rewriter, loc, src, sliceOffsets,
703 sliceSizes, strides);
704 int64_t nSliceElements = extractOp.getResult().getType().getNumElements();
705 vector::ShapeCastOp slice = vector::ShapeCastOp::create(
707 VectorType::get({nSliceElements}, sourceType.getElementType()),
708 extractOp.getResult());
711 accIdx[accRank - 1] = i;
712 Value accExtract = vector::ExtractOp::create(rewriter, loc,
acc, accIdx);
717 reductionResult = vector::InsertOp::create(rewriter, loc, fullReduce,
718 reductionResult, accIdx);
720 return reductionResult;
725 vector::CombiningKind kind) {
726 auto vecTy = dyn_cast<VectorType>(type);
727 Type elemTy = vecTy ? vecTy.getElementType() : type;
732 return arith::ConstantOp::create(
734 return arith::ConstantOp::create(builder, loc, cast<TypedAttr>(scalarAttr));
738 case vector::CombiningKind::ADD:
739 case vector::CombiningKind::XOR:
740 case vector::CombiningKind::OR:
741 case vector::CombiningKind::MAXUI:
744 case vector::CombiningKind::MUL:
745 case vector::CombiningKind::AND:
748 case vector::CombiningKind::MINSI:
749 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
751 elemTy, APInt::getSignedMaxValue(intTy.getWidth())));
754 case vector::CombiningKind::MINUI:
755 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
757 builder.
getIntegerAttr(elemTy, APInt::getMaxValue(intTy.getWidth())));
760 case vector::CombiningKind::MAXSI:
761 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
763 elemTy, APInt::getSignedMinValue(intTy.getWidth())));
766 case vector::CombiningKind::MINNUMF:
767 case vector::CombiningKind::MINIMUMF:
768 if (
auto floatTy = dyn_cast<FloatType>(elemTy))
770 elemTy, APFloat::getInf(floatTy.getFloatSemantics())));
773 case vector::CombiningKind::MAXNUMF:
774 case vector::CombiningKind::MAXIMUMF:
775 if (
auto floatTy = dyn_cast<FloatType>(elemTy))
777 elemTy, APFloat::getInf(floatTy.getFloatSemantics(),
true)));
790std::optional<SmallVector<int64_t>>
794 if (llvm::any_of(vals.drop_back(2), [](
int64_t v) { return v != 1; }))
803 getInner2DIfUnitLeadingDims(layout.getEffectiveLaneDataAsInt());
804 return laneData && (*laneData)[0] != 1;
811 if (!isa<xegpu::uArch::Xe2>(uArch) && !isa<xegpu::uArch::Xe3>(uArch))
816 getInner2DIfUnitLeadingDims(layout.getEffectiveLaneLayoutAsInt());
818 (*laneLayout)[1] == 1;
822 if (!type.hasStaticShape())
826 return succeeded(type.getStridesAndOffset(strides, offset)) &&
827 llvm::none_of(strides, ShapedType::isDynamic);
840 for (
size_t dstIdx = 0; dstIdx < dst.size(); ++dstIdx)
841 if (srcIdx < src.size() && src[srcIdx] == dst[dstIdx])
843 else if (dst[dstIdx] == 1)
844 expandedUnitDims.push_back(dstIdx);
847 return srcIdx == src.size();
864 splitDimGroups.clear();
865 for (
size_t dstIdx = 0; dstIdx < dst.size(); ++dstIdx) {
866 if (srcIdx >= src.size())
868 accumulatedSize *= dst[dstIdx];
869 currentDstDims.push_back(dstIdx);
871 if (accumulatedSize == src[srcIdx]) {
874 if (srcIdx == src.size() - 1) {
875 while (++dstIdx < dst.size() && dst[dstIdx] == 1)
876 currentDstDims.push_back(dstIdx);
879 splitDimGroups.push_back(currentDstDims);
883 currentDstDims.clear();
884 }
else if (accumulatedSize > src[srcIdx]) {
888 return srcIdx == src.size();
917 auto vecTy = dyn_cast<VectorType>(layoutSrc.
getType());
923 auto [subShape, count] = getSubShapeAndCount(vecTy, layout);
926 auto newTy = VectorType::get(subShape, vecTy.getElementType());
927 for (
Value dest : dests)
931 if (
auto whileOp = dyn_cast<scf::WhileOp>(op)) {
935 cast<scf::YieldOp>(whileOp.getAfterBody()->getTerminator());
936 for (
auto [init, beforeArg, yieldVal] :
937 llvm::zip(whileOp.getInits(), whileOp.getBeforeArguments(),
938 yieldOp.getOperands()))
939 recordTypes(init, {beforeArg, yieldVal});
942 scf::ConditionOp condOp = whileOp.getConditionOp();
943 for (
auto [condArg, afterArg, res] :
944 llvm::zip(condOp.getArgs(), whileOp.getAfterArguments(),
945 whileOp.getResults()))
946 recordTypes(condArg, {afterArg, res});
949 if (
auto forOp = dyn_cast<scf::ForOp>(op)) {
952 auto yieldOp = cast<scf::YieldOp>(forOp.getBody()->getTerminator());
953 for (
auto [init, arg, res, yieldVal] :
954 llvm::zip(forOp.getInitArgs(), forOp.getRegionIterArgs(),
955 forOp.getResults(), yieldOp.getOperands()))
956 recordTypes(init, {arg, res, yieldVal});
959 if (
auto ifOp = dyn_cast<scf::IfOp>(op)) {
962 scf::YieldOp thenYield = ifOp.thenYield();
963 scf::YieldOp elseYield = ifOp.elseBlock() ? ifOp.elseYield() :
nullptr;
964 for (
auto [idx, res] : llvm::enumerate(ifOp.getResults())) {
967 dests.push_back(elseYield.getOperand(idx));
968 recordTypes(res, dests);
983 auto loopArgTypeMap = std::make_shared<DenseMap<Value, SmallVector<Type>>>(
984 std::move(loopArgTypes));
985 converter.addConversion(
986 [loopArgTypeMap, getSubShapeAndCount](
989 if (!isa<VectorType>(v.
getType()))
995 auto it = loopArgTypeMap->find(v);
996 if (it != loopArgTypeMap->end()) {
997 result.append(it->second.begin(), it->second.end());
1004 return std::nullopt;
1006 auto vecType = cast<VectorType>(v.
getType());
1007 auto [subShape, count] = getSubShapeAndCount(vecType, layout);
1009 return std::nullopt;
1011 auto newTy = VectorType::get(subShape, vecType.getElementType());
1012 result.append(count, newTy);
1019 const llvm::SmallSetVector<UnrealizedConversionCastOp, 8> &existingCasts) {
1038 auto hasIdenticalVectorTypes = [](
ValueRange values) {
1039 auto types = values.getTypes();
1040 return !types.empty() && llvm::all_of(types, [&](
Type type) {
1041 return isa<VectorType>(type) && type == types.front();
1045 root->
walk([&](UnrealizedConversionCastOp op) {
1046 if (existingCasts.contains(op))
1049 if (op.getNumResults() == 1 && op.getNumOperands() >= 1) {
1051 op.getInputs()[0].getDefiningOp<UnrealizedConversionCastOp>();
1052 if (defOp && !existingCasts.contains(defOp) &&
1053 defOp.getNumOperands() == 1 &&
1054 defOp.getNumResults() == op.getNumOperands() &&
1055 llvm::all_of(op.getInputs(),
1056 [&](
Value v) { return v.getDefiningOp() == defOp; })) {
1057 Value orig = defOp.getInputs()[0];
1058 auto origTy = dyn_cast<VectorType>(orig.
getType());
1059 auto resTy = dyn_cast<VectorType>(op.getResult(0).getType());
1060 if (origTy && resTy &&
1061 origTy.getNumElements() == resTy.getNumElements() &&
1065 vector::ShapeCastOp::create(builder, op.getLoc(), resTy, orig);
1066 op.replaceAllUsesWith(
ValueRange{shapeCast.getResult()});
1074 auto outputTy = dyn_cast<VectorType>(op.getResult(0).getType());
1075 if (op.getNumOperands() > 1 && outputTy &&
1076 hasIdenticalVectorTypes(op.getInputs())) {
1079 builder, op.getLoc(), op.getInputs(), outputTy.getShape());
1085 if (op.getNumOperands() == 1 && op.getNumResults() > 1) {
1087 op.getInputs()[0].getDefiningOp<UnrealizedConversionCastOp>();
1088 if (defOp && !existingCasts.contains(defOp) &&
1089 defOp.getNumResults() == 1 &&
1090 defOp.getNumOperands() == op.getNumResults() &&
1092 op->getResultTypes())) {
1093 op.replaceAllUsesWith(defOp.getInputs());
1098 auto tileTy = dyn_cast<VectorType>(op.getResult(0).getType());
1099 if (tileTy && hasIdenticalVectorTypes(op.getResults())) {
1102 builder, op.getLoc(), op.getInputs()[0], tileTy.getShape());
1103 op->replaceAllUsesWith(results);
1110 bool changed =
true;
1113 root->
walk([&](UnrealizedConversionCastOp op) {
1114 if (existingCasts.contains(op))
1116 if (op.use_empty()) {
1138 collapseDims.clear();
1139 collapseDims.resize(dst.size());
1143 int64_t srcProd = std::accumulate(src.begin(), src.end(),
int64_t{1},
1144 std::multiplies<int64_t>());
1145 int64_t dstProd = std::accumulate(dst.begin(), dst.end(),
int64_t{1},
1146 std::multiplies<int64_t>());
1147 if (srcProd != dstProd)
1156 srcCompact.push_back(s);
1159 dstCompact.push_back(d);
1162 for (
int64_t need : dstCompact) {
1164 while (s < srcCompact.size() &&
acc < need)
1165 acc *= srcCompact[s++];
1169 if (s != srcCompact.size())
1180 while (dstIdx < dst.size() && dst[dstIdx] == 1)
1185 for (
size_t srcIdx = 0; srcIdx < src.size(); ++srcIdx) {
1186 if (dstIdx >= dst.size()) {
1189 if (lastNonEmpty >= 0)
1190 collapseDims[lastNonEmpty].push_back(srcIdx);
1194 collapseDims[dstIdx].push_back(srcIdx);
1195 lastNonEmpty = dstIdx;
1196 if (
acc == dst[dstIdx]) {
1199 while (dstIdx < dst.size() && dst[dstIdx] == 1)
xegpu::DistributeLayoutAttr maybePickPermanentLayout(xegpu::DistributeLayoutAttr layout, const OpResult &result, mlir::Operation *owner, const std::string &name)
Attributes are known-constant values of operations.
IntegerAttr getIntegerAttr(Type type, int64_t value)
FloatAttr getFloatAttr(Type type, double value)
TypedAttr getZeroAttr(Type type)
TypedAttr getOneAttr(Type type)
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class helps build Operations.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
This class represents an operand of an operation.
This is a value defined by a result of an operation.
Operation is the basic unit of execution within MLIR.
bool hasDiscardableAttrOfType(NameT &&name)
void setDiscardableAttr(StringAttr name, Attribute value)
Set a discardable attribute by name.
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
bool hasDiscardableAttr(StringRef name)
Return true if this operation has a discardable attribute with the provided name.
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),...
AttrClass getDiscardableAttrOfType(StringRef name)
Access a discardable attribute by name and cast it to AttrClass.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
A range-style iterator that allows for iterating over the offsets of all potential tiles of size tile...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getOwner() const
Return the owner of this operand.
Value makeArithReduction(OpBuilder &b, Location loc, CombiningKind kind, Value v1, Value acc, arith::FastMathFlagsAttr fastmath=nullptr, Value mask=nullptr)
Returns the result value of reducing two scalar/vector values with the corresponding arith operation.
bool matchDimCollapse(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &collapseDims)
Value createVectorWithShapeFromValues(OpBuilder &builder, Location loc, ValueRange values, ArrayRef< int64_t > shape)
Create a vector of shape from a set of values using vector.insert_stride_slice.
bool requirePacked(const DistributeLayoutAttr layout)
Helper function to check if the layout is packed.
void setTemporaryLayout(const T &operandOrResult, const DistributeLayoutAttr layout)
Value createReductionNeutralValue(OpBuilder &builder, Location loc, Type type, vector::CombiningKind kind)
Creates a constant filled with the neutral (identity) value for the given reduction kind.
void setDistributeLayoutAttr(const OpResult &Result, const DistributeLayoutAttr layout)
[to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult user should use setAnchorLayout...
Value subgroupReduction(Location loc, OpBuilder &builder, Value input, vector::CombiningKind kind, uint32_t size)
Given an input value representing per-lane data, this function returns the result after performing a ...
bool matchUnitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< int64_t > &expandedUnitDims)
std::optional< SmallVector< int64_t > > getInner2DIfUnitLeadingDims(ArrayRef< int64_t > vals)
Returns the innermost 2 entries of vals if it is at least 2D and all of its leading entries are unit;...
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 hasStaticShapeAndStrides(MemRefType type)
Returns true if type has a static shape and static strides.
FailureOr< VectorType > getDistVecTypeBasedOnLaneLayout(DistributeLayoutAttr layout, VectorType originalType)
Helper function to get distributed vector type for a source vector type according to the lane_layout.
Value lowerToVectorReductions(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, Location loc, PatternRewriter &rewriter)
Given a src and an acc argumments from a vector::MultiDimReductionOp, lower to a set of vector::Reduc...
bool requireTranspose(const DistributeLayoutAttr layout, const uArch::uArch *uArch)
Helper function to check if the layout requires a transpose effect.
bool matchSplitDimExpansion(ArrayRef< int64_t > src, ArrayRef< int64_t > dst, SmallVector< SmallVector< int64_t > > &splitDimGroups)
DistributeLayoutAttr getDistributeLayoutAttr(const Value value)
Retrieves the DistributeLayoutAttr associated with a given Value, or nullptr if none is found.
DenseMap< Value, SmallVector< Type > > precomputeLoopBlockArgTypes(Operation *topLevelOp, SubShapeAndCountFn getSubShapeAndCount)
Pre-computes distributed VectorType mappings for every value carried through an SCF loop under topLev...
std::string getTemporaryLayoutName(const OpOperand &operand)
Return the attribute name for the OpOperand to attach DistributeLayoutAttr.
std::optional< std::string > getChipStr(Operation *op)
Retrieves the chip string from the XeVM target attribute of the parent GPU module operation.
void addVectorTypeConversion(TypeConverter &converter, SubShapeAndCountFn getSubShapeAndCount, DenseMap< Value, SmallVector< Type > > loopArgTypes)
Adds a context-aware VectorType conversion to converter (1:1 shape-changing or 1:N,...
SmallVector< Value > extractVectorsWithShapeFromValue(OpBuilder &builder, Location loc, Value value, ArrayRef< int64_t > shape)
Extract a set of small vectors from a value with a given shape using vector.extract_stride_slice.
DistributeLayoutAttr getTemporaryLayout(const T &operandOrResult)
get and set distribute layout attribute for non-anchor operations (and offsets/masks of load/store op...
Value lowerCrossLaneReductionToShuffles(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, int64_t reductionSize, Location loc, PatternRewriter &rewriter)
Lowers cross-lane reductions to shuffle operations on a 2D vector.
std::function< std::pair< SmallVector< int64_t >, int >( VectorType, DistributeLayoutAttr)> SubShapeAndCountFn
Callback type for computing sub-shape and count for 1:N (or 1:1 shape-changing) VectorType conversion...
void cleanupUnrealizedConversionCasts(Operation *root, const llvm::SmallSetVector< UnrealizedConversionCastOp, 8 > &existingCasts)
Cleans up UnrealizedConversionCastOps inserted during SCF structural type conversion and/or XeGPU unr...
SmallVector< Value > flattenValues(ArrayRef< ValueRange > values)
Flatten a set of ValueRange into a single SmallVector<Value>
SmallVector< OpFoldResult > addWithRightAligned(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > lhs, ArrayRef< OpFoldResult > rhs)
Generates element-wise addition ops of two arrays with automatic alignment.
SmallVector< OpFoldResult > addElementwise(OpBuilder &builder, Location loc, ArrayRef< OpFoldResult > lhs, ArrayRef< OpFoldResult > rhs)
Generates element-wise addition ops of two arrays with same length.
FailureOr< VectorType > getDistributedVectorType(xegpu::TensorDescType tdescTy)
If tensor descriptor has a layout attribute it is used in SIMT mode.
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
Value getValueOrCreateConstantIndexOp(OpBuilder &b, Location loc, OpFoldResult ofr)
Converts an OpFoldResult to a Value.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
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.
virtual int getSubgroupSize() const =0