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))
251 if (isa<xegpu::StoreScatterOp, xegpu::LoadGatherOp>(op))
267xegpu::DistributeLayoutAttr
270 const std::string &name) {
271 xegpu::DistributeLayoutAttr candidate = layout;
273 if (
auto loadOp = dyn_cast<xegpu::LoadGatherOp>(owner)) {
274 if (
auto perm = loadOp.getLayoutAttr())
283xegpu::DistributeLayoutAttr
286 const std::string &name) {
287 xegpu::DistributeLayoutAttr candidate = layout;
288 unsigned idx =
const_cast<OpOperand &
>(operand).getOperandNumber();
290 if (
auto storeOp = dyn_cast<xegpu::StoreScatterOp>(owner)) {
292 if (
auto perm = storeOp.getLayoutAttr())
304 const mlir::xegpu::DistributeLayoutAttr layout) {
307 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(owner)) {
308 if (anchorOp.getAnchorLayout() == layout)
310 anchorOp.setAnchorLayout(layout);
326 const DistributeLayoutAttr layout) {
328 unsigned idx =
const_cast<OpOperand &
>(operand).getOperandNumber();
333 if (
auto anchorOp = dyn_cast<xegpu::AnchorLayoutInterface>(owner)) {
334 if (
auto dpasOp = dyn_cast<xegpu::DpasOp>(owner)) {
336 return dpasOp.setLayoutAAttr(layout);
337 }
else if (idx == 1) {
338 return dpasOp.setLayoutBAttr(layout);
339 }
else if (idx == 2) {
340 return dpasOp.setLayoutCdAttr(layout);
343 if (
auto convertOp = dyn_cast<xegpu::ConvertLayoutOp>(owner)) {
344 return convertOp.setInputLayoutAttr(layout);
350 if (isa<xegpu::StoreScatterOp, xegpu::StoreNdOp, xegpu::StoreMatrixOp>(
353 anchorOp.setAnchorLayout(layout);
357 anchorOp.setAnchorLayout(layout);
371template <
typename T,
typename>
372xegpu::DistributeLayoutAttr
374 Operation *op = operandOrResult.getOwner();
386template xegpu::DistributeLayoutAttr
388template xegpu::DistributeLayoutAttr
391template <
typename T,
typename>
393 const xegpu::DistributeLayoutAttr layout) {
394 Operation *owner = operandOrResult.getOwner();
406 const mlir::xegpu::DistributeLayoutAttr layout);
410 const mlir::xegpu::DistributeLayoutAttr layout);
415 auto vecTy = dyn_cast<VectorType>(value.
getType());
423 int64_t srcShapeRank = srcShape.size();
427 int64_t rankDiff = srcShapeRank - targetShapeRank;
428 std::fill(adjustedTargetShape.begin(), adjustedTargetShape.begin() + rankDiff,
430 llvm::copy(
shape, adjustedTargetShape.begin() + rankDiff);
436 Value slice = vector::ExtractStridedSliceOp::create(
437 builder, loc, value, offsets, adjustedTargetShape, staticStrides);
440 if (srcShapeRank > targetShapeRank) {
441 auto targetTy = VectorType::get(
shape, vecTy.getElementType());
442 slice = vector::ShapeCastOp::create(builder, loc, targetTy,
slice);
453 VectorType inputTy = dyn_cast<VectorType>(values[0].
getType());
454 assert(llvm::all_of(values.
getTypes(),
455 [&](
Type type) { return type == inputTy; }) &&
456 "values must be of the same VectorType");
458 Type elemTy = inputTy.getElementType();
461 VectorType resultTy = VectorType::get(
shape, elemTy);
466 for (
auto [src, offsets] :
469 result = vector::InsertStridedSliceOp::create(builder, loc, src,
result,
470 offsets, staticStrides);
481 auto targetAttrs = gpuModuleOp.getTargets();
483 for (
auto &attr : *targetAttrs) {
484 auto xevmAttr = llvm::dyn_cast<xevm::XeVMTargetAttr>(attr);
486 return xevmAttr.getChip().str();
498 std::optional<ArrayRef<int32_t>> blockSize = gpuFunc.getKnownBlockSize();
501 if (!llvm::all_of(*blockSize, [](int32_t dim) {
502 return dim > 0 && llvm::isPowerOf2_32(dim);
505 int64_t numSubgroups = llvm::product_of(*blockSize) / subgroupSize;
506 if (numSubgroups < 1)
516 assert(lhs.size() == rhs.size() &&
"lhs and rhs must have the same size");
518 for (
auto [l, r] : llvm::zip_equal(lhs, rhs)) {
521 results.push_back(builder.
createOrFold<arith::AddIOp>(loc, lval, rval));
544 a = a.slice(a.size() -
b.size());
552 static_assert(std::is_integral<T>::value,
"T must be an integer type");
555 if (!candidateMultiples.empty())
557 SmallVector<T>(candidateMultiples.begin(), candidateMultiples.end());
558 for (T candidate : candidates) {
559 for (T multiple : multiples) {
560 int value =
static_cast<int>(candidate * multiple);
561 if (value != 0 && dim % value == 0 && value > largest)
569static arith::FastMathFlags
getFlags(arith::FastMathFlagsAttr fastmath) {
570 return fastmath ? fastmath.getValue() : arith::FastMathFlags::none;
574 vector::CombiningKind kind, uint32_t size,
575 arith::FastMathFlagsAttr fastmath) {
577 Value laneVal = vector::ReductionOp::create(builder, loc, kind, input,
580 for (uint64_t i = 1; i < size; i <<= 1) {
582 gpu::ShuffleOp::create(builder, loc, laneVal, i, size,
583 gpu::ShuffleMode::XOR)
586 makeArithReduction(builder, loc, kind, laneVal, shuffled, fastmath);
593 vector::CombiningKind kind,
596 arith::FastMathFlagsAttr fastmath) {
597 VectorType sourceType = src.
getType();
598 int64_t sourceRank = sourceType.getRank();
601 assert(sourceRank >= 2 &&
"expected at least a 2D source vector");
602 for (
int64_t i = 0; i < sourceRank - 2; ++i)
603 assert(sourceType.getShape()[i] == 1 &&
604 "expected leading dimensions to be unit");
605 int64_t rowIdx = sourceRank - 2;
606 int64_t columnIdx = sourceRank - 1;
607 int64_t sourceH = sourceType.getShape()[rowIdx];
608 int64_t sourceW = sourceType.getShape()[columnIdx];
609 int nSlices = (reductionDim == rowIdx) ? sourceW : sourceH;
611 TypedAttr zeroAttr = rewriter.
getZeroAttr(sourceType.getElementType());
612 Value reductionResult = arith::ConstantOp::create(
613 rewriter, loc,
acc.getType(),
622 for (
int i = 0; i < nSlices; ++i) {
628 if (reductionDim == columnIdx) {
629 sliceOffsets[rowIdx] = i;
630 sliceSizes[columnIdx] = sourceW;
632 sliceOffsets[columnIdx] = i;
633 sliceSizes[rowIdx] = sourceH;
636 vector::ExtractStridedSliceOp extractOp =
637 vector::ExtractStridedSliceOp::create(rewriter, loc, src, sliceOffsets,
638 sliceSizes, strides);
642 int64_t nSliceElements = extractOp.getResult().getType().getNumElements();
644 vector::ShapeCastOp
slice = vector::ShapeCastOp::create(
646 VectorType::get({nSliceElements}, sourceType.getElementType()),
647 extractOp.getResult());
657 accIdx[accRank - 1] = i;
658 Value accExtract = vector::ExtractOp::create(rewriter, loc,
acc, accIdx);
659 Value reduction = vector::ReductionOp::create(
660 rewriter, loc, kind,
slice.getResult(), accExtract,
getFlags(fastmath));
661 reductionResult = vector::InsertOp::create(rewriter, loc, reduction,
662 reductionResult, accIdx);
666 return reductionResult;
671 vector::CombiningKind kind,
int64_t reductionDim,
int64_t reductionSize,
673 arith::FastMathFlagsAttr fastmath) {
674 VectorType sourceType = src.
getType();
675 int64_t sourceRank = sourceType.getRank();
678 assert(sourceRank >= 2 &&
"expected at least a 2D source vector");
679 for (
int64_t i = 0; i < sourceRank - 2; ++i)
680 assert(sourceType.getShape()[i] == 1 &&
681 "expected leading dimensions to be unit");
682 int64_t rowIdx = sourceRank - 2;
683 int64_t columnIdx = sourceRank - 1;
684 int64_t sourceH = sourceType.getShape()[rowIdx];
685 int64_t sourceW = sourceType.getShape()[columnIdx];
688 TypedAttr zeroAttr = rewriter.
getZeroAttr(sourceType.getElementType());
689 Value reductionResult = arith::ConstantOp::create(
690 rewriter, loc,
acc.getType(),
697 int nSlices = (reductionDim == rowIdx) ? sourceW : sourceH;
702 for (
int i = 0; i < nSlices; ++i) {
708 if (reductionDim == columnIdx) {
709 sliceOffsets[rowIdx] = i;
710 sliceSizes[columnIdx] = sourceW;
712 sliceOffsets[columnIdx] = i;
713 sliceSizes[rowIdx] = sourceH;
716 vector::ExtractStridedSliceOp extractOp =
717 vector::ExtractStridedSliceOp::create(rewriter, loc, src, sliceOffsets,
718 sliceSizes, strides);
719 int64_t nSliceElements = extractOp.getResult().getType().getNumElements();
720 vector::ShapeCastOp
slice = vector::ShapeCastOp::create(
722 VectorType::get({nSliceElements}, sourceType.getElementType()),
723 extractOp.getResult());
726 accIdx[accRank - 1] = i;
727 Value accExtract = vector::ExtractOp::create(rewriter, loc,
acc, accIdx);
729 reductionSize, fastmath);
731 accExtract, fastmath);
732 reductionResult = vector::InsertOp::create(rewriter, loc, fullReduce,
733 reductionResult, accIdx);
735 return reductionResult;
750 vector::CombiningKind kind,
751 arith::FastMathFlags flags) {
752 bool isMax = kind == vector::CombiningKind::MAXIMUMF ||
753 kind == vector::CombiningKind::MAXNUMF ||
754 kind == vector::CombiningKind::MAXIMUMNUMF;
755 bool ignoresNaN = kind != vector::CombiningKind::MINIMUMF &&
756 kind != vector::CombiningKind::MAXIMUMF;
757 if (ignoresNaN && APFloat::semanticsHasNaN(semantics) &&
758 !arith::bitEnumContainsAny(flags, arith::FastMathFlags::nnan))
759 return APFloat::getQNaN(semantics);
760 bool useInf = APFloat::semanticsHasInf(semantics) &&
761 !arith::bitEnumContainsAny(flags, arith::FastMathFlags::ninf);
763 return useInf ? APFloat::getInf(semantics) : APFloat::getLargest(semantics);
766 if (!APFloat::semanticsHasSignedRepr(semantics))
767 return APFloat::semanticsHasZero(semantics)
768 ? APFloat::getZero(semantics)
769 : APFloat::getSmallest(semantics);
770 return useInf ? APFloat::getInf(semantics,
true)
771 : APFloat::getLargest(semantics,
true);
775 Type type, vector::CombiningKind kind,
776 arith::FastMathFlagsAttr fastmath) {
777 auto vecTy = dyn_cast<VectorType>(type);
778 Type elemTy = vecTy ? vecTy.getElementType() : type;
783 return arith::ConstantOp::create(
785 return arith::ConstantOp::create(builder, loc, cast<TypedAttr>(scalarAttr));
789 case vector::CombiningKind::ADD:
790 case vector::CombiningKind::XOR:
791 case vector::CombiningKind::OR:
792 case vector::CombiningKind::MAXUI:
795 case vector::CombiningKind::MUL:
798 case vector::CombiningKind::AND:
799 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
801 builder.
getIntegerAttr(elemTy, APInt::getAllOnes(intTy.getWidth())));
806 case vector::CombiningKind::MINSI:
807 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
809 elemTy, APInt::getSignedMaxValue(intTy.getWidth())));
812 case vector::CombiningKind::MINUI:
813 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
815 builder.
getIntegerAttr(elemTy, APInt::getMaxValue(intTy.getWidth())));
818 case vector::CombiningKind::MAXSI:
819 if (
auto intTy = dyn_cast<IntegerType>(elemTy))
821 elemTy, APInt::getSignedMinValue(intTy.getWidth())));
824 case vector::CombiningKind::MINIMUMF:
825 case vector::CombiningKind::MAXIMUMF:
826 case vector::CombiningKind::MINNUMF:
827 case vector::CombiningKind::MINIMUMNUMF:
828 case vector::CombiningKind::MAXNUMF:
829 case vector::CombiningKind::MAXIMUMNUMF:
830 if (
auto floatTy = dyn_cast<FloatType>(elemTy))
846std::optional<SmallVector<int64_t>>
850 if (llvm::any_of(vals.drop_back(2), [](
int64_t v) { return v != 1; }))
859 getInner2DIfUnitLeadingDims(layout.getEffectiveLaneDataAsInt());
860 return laneData && (*laneData)[0] != 1;
867 if (!isa<xegpu::uArch::Xe2>(uArch) && !isa<xegpu::uArch::Xe3p>(uArch))
872 getInner2DIfUnitLeadingDims(layout.getEffectiveLaneLayoutAsInt());
874 (*laneLayout)[1] == 1;
878 if (!type.hasStaticShape())
882 return succeeded(type.getStridesAndOffset(strides, offset)) &&
883 llvm::none_of(strides, ShapedType::isDynamic);
888 MemRefType memrefTy) {
890 assert(baseAddr.
getType() == type &&
891 "expected base address and offset of the same type");
893 return arith::ConstantOp::create(builder, loc, type,
898 unsigned elemBits = memrefTy.getElementTypeBitWidth();
900 if (elemBits % 8 == 0) {
904 byteOffset = arith::MulIOp::create(builder, loc, elemOffset,
905 makeConst(elemBits / 8));
910 Value bitSize = makeConst(elemBits);
911 Value eight = makeConst(8);
912 byteOffset = arith::DivUIOp::create(
913 builder, loc, arith::MulIOp::create(builder, loc, elemOffset, bitSize),
916 return arith::AddIOp::create(builder, loc, baseAddr, byteOffset);
929 for (
size_t dstIdx = 0; dstIdx < dst.size(); ++dstIdx)
930 if (srcIdx < src.size() && src[srcIdx] == dst[dstIdx])
932 else if (dst[dstIdx] == 1)
933 expandedUnitDims.push_back(dstIdx);
936 return srcIdx == src.size();
949 !expandedUnitDims.empty())
958 splitDimGroups.clear();
959 for (
size_t dstIdx = 0; dstIdx < dst.size(); ++dstIdx) {
960 if (srcIdx >= src.size())
962 accumulatedSize *= dst[dstIdx];
963 currentDstDims.push_back(dstIdx);
965 if (accumulatedSize == src[srcIdx]) {
968 if (srcIdx == src.size() - 1) {
969 while (++dstIdx < dst.size() && dst[dstIdx] == 1)
970 currentDstDims.push_back(dstIdx);
973 splitDimGroups.push_back(currentDstDims);
977 currentDstDims.clear();
978 }
else if (accumulatedSize > src[srcIdx]) {
982 return srcIdx == src.size();
1011 auto vecTy = dyn_cast<VectorType>(layoutSrc.
getType());
1017 auto [subShape, count] = getSubShapeAndCount(vecTy, layout);
1020 auto newTy = VectorType::get(subShape, vecTy.getElementType());
1021 for (
Value dest : dests)
1025 if (
auto whileOp = dyn_cast<scf::WhileOp>(op)) {
1029 cast<scf::YieldOp>(whileOp.getAfterBody()->getTerminator());
1030 for (
auto [init, beforeArg, yieldVal] :
1031 llvm::zip(whileOp.getInits(), whileOp.getBeforeArguments(),
1032 yieldOp.getOperands()))
1033 recordTypes(init, {beforeArg, yieldVal});
1036 scf::ConditionOp condOp = whileOp.getConditionOp();
1037 for (
auto [condArg, afterArg, res] :
1038 llvm::zip(condOp.getArgs(), whileOp.getAfterArguments(),
1039 whileOp.getResults()))
1040 recordTypes(condArg, {afterArg, res});
1043 if (
auto forOp = dyn_cast<scf::ForOp>(op)) {
1046 auto yieldOp = cast<scf::YieldOp>(forOp.getBody()->getTerminator());
1047 for (
auto [init, arg, res, yieldVal] :
1048 llvm::zip(forOp.getInitArgs(), forOp.getRegionIterArgs(),
1049 forOp.getResults(), yieldOp.getOperands()))
1050 recordTypes(init, {arg, res, yieldVal});
1053 if (
auto ifOp = dyn_cast<scf::IfOp>(op)) {
1056 scf::YieldOp thenYield = ifOp.thenYield();
1057 scf::YieldOp elseYield = ifOp.elseBlock() ? ifOp.elseYield() :
nullptr;
1058 for (
auto [idx, res] : llvm::enumerate(ifOp.getResults())) {
1061 dests.push_back(elseYield.getOperand(idx));
1062 recordTypes(res, dests);
1067 return loopArgTypes;
1077 auto loopArgTypeMap = std::make_shared<DenseMap<Value, SmallVector<Type>>>(
1078 std::move(loopArgTypes));
1079 converter.addConversion(
1080 [loopArgTypeMap, getSubShapeAndCount](
1083 if (!isa<VectorType>(v.
getType()))
1084 return std::nullopt;
1089 auto it = loopArgTypeMap->find(v);
1090 if (it != loopArgTypeMap->end()) {
1091 result.append(it->second.begin(), it->second.end());
1098 return std::nullopt;
1100 auto vecType = cast<VectorType>(v.
getType());
1101 auto [subShape, count] = getSubShapeAndCount(vecType, layout);
1103 return std::nullopt;
1105 auto newTy = VectorType::get(subShape, vecType.getElementType());
1106 result.append(count, newTy);
1113 const llvm::SmallSetVector<UnrealizedConversionCastOp, 8> &existingCasts) {
1132 auto hasIdenticalVectorTypes = [](
ValueRange values) {
1133 auto types = values.getTypes();
1134 return !types.empty() && llvm::all_of(types, [&](
Type type) {
1135 return isa<VectorType>(type) && type == types.front();
1139 root->
walk([&](UnrealizedConversionCastOp op) {
1140 if (existingCasts.contains(op))
1143 if (op.getNumResults() == 1 && op.getNumOperands() >= 1) {
1145 op.getInputs()[0].getDefiningOp<UnrealizedConversionCastOp>();
1146 if (defOp && !existingCasts.contains(defOp) &&
1147 defOp.getNumOperands() == 1 &&
1148 defOp.getNumResults() == op.getNumOperands() &&
1149 llvm::all_of(op.getInputs(),
1150 [&](
Value v) { return v.getDefiningOp() == defOp; })) {
1151 Value orig = defOp.getInputs()[0];
1152 auto origTy = dyn_cast<VectorType>(orig.
getType());
1153 auto resTy = dyn_cast<VectorType>(op.getResult(0).getType());
1154 if (origTy && resTy &&
1155 origTy.getNumElements() == resTy.getNumElements() &&
1159 vector::ShapeCastOp::create(builder, op.getLoc(), resTy, orig);
1160 op.replaceAllUsesWith(
ValueRange{shapeCast.getResult()});
1168 auto outputTy = dyn_cast<VectorType>(op.getResult(0).getType());
1169 if (op.getNumOperands() > 1 && outputTy &&
1170 hasIdenticalVectorTypes(op.getInputs())) {
1173 builder, op.getLoc(), op.getInputs(), outputTy.getShape());
1179 if (op.getNumOperands() == 1 && op.getNumResults() > 1) {
1181 op.getInputs()[0].getDefiningOp<UnrealizedConversionCastOp>();
1182 if (defOp && !existingCasts.contains(defOp) &&
1183 defOp.getNumResults() == 1 &&
1184 defOp.getNumOperands() == op.getNumResults() &&
1186 op->getResultTypes())) {
1187 op.replaceAllUsesWith(defOp.getInputs());
1192 auto tileTy = dyn_cast<VectorType>(op.getResult(0).getType());
1193 if (tileTy && hasIdenticalVectorTypes(op.getResults())) {
1196 builder, op.getLoc(), op.getInputs()[0], tileTy.getShape());
1197 op->replaceAllUsesWith(results);
1204 bool changed =
true;
1207 root->
walk([&](UnrealizedConversionCastOp op) {
1208 if (existingCasts.contains(op))
1210 if (op.use_empty()) {
1232 collapseDims.clear();
1233 collapseDims.resize(dst.size());
1237 int64_t srcProd = std::accumulate(src.begin(), src.end(),
int64_t{1},
1238 std::multiplies<int64_t>());
1239 int64_t dstProd = std::accumulate(dst.begin(), dst.end(),
int64_t{1},
1240 std::multiplies<int64_t>());
1241 if (srcProd != dstProd)
1250 srcCompact.push_back(s);
1253 dstCompact.push_back(d);
1256 for (
int64_t need : dstCompact) {
1258 while (s < srcCompact.size() &&
acc < need)
1259 acc *= srcCompact[s++];
1263 if (s != srcCompact.size())
1274 while (dstIdx < dst.size() && dst[dstIdx] == 1)
1279 for (
size_t srcIdx = 0; srcIdx < src.size(); ++srcIdx) {
1280 if (dstIdx >= dst.size()) {
1283 if (lastNonEmpty >= 0)
1284 collapseDims[lastNonEmpty].push_back(srcIdx);
1288 collapseDims[dstIdx].push_back(srcIdx);
1289 lastNonEmpty = dstIdx;
1290 if (
acc == dst[dstIdx]) {
1293 while (dstIdx < dst.size() && dst[dstIdx] == 1)
static SmallVector< Value > slice(OpBuilder &b, Location loc, Value value, VectorType nativeType)
xegpu::DistributeLayoutAttr maybePickPermanentLayout(xegpu::DistributeLayoutAttr layout, const OpResult &result, mlir::Operation *owner, const std::string &name)
static APFloat getMinMaxNeutral(const llvm::fltSemantics &semantics, vector::CombiningKind kind, arith::FastMathFlags flags)
Returns the neutral value of the float min or max reduction kind over elements of semantics.
static arith::FastMathFlags getFlags(arith::FastMathFlagsAttr fastmath)
Returns the flags held by fastmath, or none if it is null.
Attributes are known-constant values of operations.
IntegerAttr getIndexAttr(int64_t value)
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)
void setDistributeLayoutAttr(const OpResult &Result, const DistributeLayoutAttr layout)
[to-be-deprecated] Sets the DistributeLayoutAttr for a given OpResult user should use setAnchorLayout...
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...
FailureOr< int64_t > getNumSubgroupsFromBlockSize(Operation *op, int64_t subgroupSize)
Returns the number of subgroups the kernel enclosing op runs, derived from the known_block_size of it...
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.
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.
Value addElemOffsetInBytes(OpBuilder &builder, Location loc, Value baseAddr, Value elemOffset, MemRefType memrefTy)
Returns baseAddr + elemOffset * bitWidth / 8, i.e.
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,...
Value lowerToVectorReductions(TypedValue< VectorType > src, TypedValue< VectorType > acc, vector::CombiningKind kind, int64_t reductionDim, Location loc, PatternRewriter &rewriter, arith::FastMathFlagsAttr fastmath=nullptr)
Given a src and an acc argumments from a vector::MultiDimReductionOp, lower to a set of vector::Reduc...
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.
Value createReductionNeutralValue(OpBuilder &builder, Location loc, Type type, vector::CombiningKind kind, arith::FastMathFlagsAttr fastmath=nullptr)
Creates a constant filled with the neutral (identity) value for the given reduction kind.
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, arith::FastMathFlagsAttr fastmath=nullptr)
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.
Value subgroupReduction(Location loc, OpBuilder &builder, Value input, vector::CombiningKind kind, uint32_t size, arith::FastMathFlagsAttr fastmath=nullptr)
Given an input value representing per-lane data, this function returns the result after performing a ...
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