16#include "llvm/ADT/SmallVector.h"
18#define DEBUG_TYPE "xegpu-array-length-optimization"
26constexpr int64_t DEFAULT_SUBGROUP_SIZE = 16;
34 return DEFAULT_SUBGROUP_SIZE;
38 return DEFAULT_SUBGROUP_SIZE;
47 if (fcdSize <= subgroupSize)
49 return fcdSize / subgroupSize;
56static bool needsOptimization(xegpu::TensorDescType tdescType,
58 auto shape = tdescType.getShape();
59 if (
shape.size() != 2)
63 if (fcd % subgroupSize != 0)
66 return fcd > subgroupSize && tdescType.getArrayLength() == 1;
71static bool hasNonIdentityTranspose(xegpu::LoadNdOp loadOp) {
72 auto transpose = loadOp.getTranspose();
76 return !(perm.size() == 2 && perm[0] == 0 && perm[1] == 1);
84static bool hasTransposeLaneLayout(xegpu::TensorDescType tdescType) {
85 auto layout = tdescType.getLayoutAttr();
89 if (laneLayout.size() != 2)
91 return laneLayout[0] != 1 && laneLayout[1] == 1;
99static FailureOr<SmallVector<int64_t>>
100getRemappedExtractOffsets(vector::ExtractStridedSliceOp op,
101 xegpu::TensorDescType tdescType) {
102 if (tdescType.getRank() != 2)
105 auto offsets = op.getOffsets().getValue();
106 auto sizes = op.getSizes().getValue();
107 auto strides = op.getStrides().getValue();
108 if (offsets.size() != 2 || sizes.size() != 2 || strides.size() != 2)
111 int64_t origOffset0 = cast<IntegerAttr>(offsets[0]).getInt();
112 int64_t origOffset1 = cast<IntegerAttr>(offsets[1]).getInt();
113 int64_t size1 = cast<IntegerAttr>(sizes[1]).getInt();
114 int64_t blockHeight = tdescType.getShape()[0];
115 int64_t arrayWidth = tdescType.getShape()[1];
117 int64_t localOffset1 = origOffset1 % arrayWidth;
118 if (localOffset1 + size1 > arrayWidth)
120 if (origOffset1 < arrayWidth)
122 if (origOffset1 % arrayWidth != 0)
125 int64_t arrayIndex = origOffset1 / arrayWidth;
137class OptimizeCreateNdDescOp :
public OpRewritePattern<xegpu::CreateNdDescOp> {
141 LogicalResult matchAndRewrite(xegpu::CreateNdDescOp op,
144 if (op.getType().getElementTypeBitWidth() < 8)
146 int64_t subgroupSize = getSubgroupSize(op);
147 auto tdescType = op.getType();
148 if (!needsOptimization(tdescType, subgroupSize))
153 if (hasTransposeLaneLayout(tdescType))
156 Value source = op.getSource();
157 if (!isa<MemRefType, IntegerType>(source.
getType()))
162 if (
auto loadOp = dyn_cast<xegpu::LoadNdOp>(user))
163 if (hasNonIdentityTranspose(loadOp))
167 auto shape = tdescType.getShape();
168 int64_t arrayLength = computeArrayLength(
shape[1], subgroupSize);
170 if (
auto layout = tdescType.getLayoutAttr();
171 layout && !layout.isDistributable(newShape))
174 auto newTdescType = xegpu::TensorDescType::get(
175 newShape, tdescType.getElementType(), arrayLength,
176 tdescType.getBoundaryCheck(), tdescType.getMemorySpace(),
177 tdescType.getLayout());
181 if (
auto prefetchOp = dyn_cast<xegpu::PrefetchNdOp>(descriptorUser)) {
182 if (
auto layout = prefetchOp.getAnchorLayout();
183 layout && !layout.isDistributable(newShape))
188 auto loadOp = dyn_cast<xegpu::LoadNdOp>(descriptorUser);
192 if (
auto layout = loadOp.getAnchorLayout();
193 layout && !layout.isDistributable(newShape))
195 auto loadType = dyn_cast<VectorType>(loadOp.getType());
196 if (!loadType || loadType.getRank() != 2)
200 dyn_cast<vector::ExtractStridedSliceOp>(loadResultUser);
202 failed(getRemappedExtractOffsets(extractOp, newTdescType)))
205 loadOps.push_back(loadOp);
211 for (xegpu::LoadNdOp loadOp : loadOps) {
213 auto extractOp = cast<vector::ExtractStridedSliceOp>(loadResultUser);
215 *getRemappedExtractOffsets(extractOp, newTdescType);
221 auto loadType = cast<VectorType>(loadOp.getType());
225 VectorType::get(newLoadShape, loadType.getElementType());
227 loadOp, [&]() { loadOp.getResult().setType(newLoadType); });
230 [&]() { op.getResult().setType(newTdescType); });
ArrayAttr getI64ArrayAttr(ArrayRef< int64_t > values)
Operation is the basic unit of execution within MLIR.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
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.
user_range getUsers() const
const uArch * getUArch(llvm::StringRef archName)
void populateXeGPUArrayLengthOptimizationPatterns(RewritePatternSet &patterns)
Appends patterns for array length optimization into patterns.
std::optional< std::string > getChipStr(Operation *op)
Retrieves the chip string from the XeVM target attribute of the parent GPU module operation.
Include the generated interface declarations.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
virtual int getSubgroupSize() const =0