22#include "llvm/Support/FormatVariadic.h"
23#include "llvm/Support/MathExtras.h"
45struct BreakDownSubgroupReduce final :
OpRewritePattern<gpu::SubgroupReduceOp> {
46 BreakDownSubgroupReduce(MLIRContext *ctx,
unsigned maxShuffleBitwidth,
47 PatternBenefit benefit)
48 : OpRewritePattern(ctx, benefit), maxShuffleBitwidth(maxShuffleBitwidth) {
51 LogicalResult matchAndRewrite(gpu::SubgroupReduceOp op,
52 PatternRewriter &rewriter)
const override {
53 auto vecTy = dyn_cast<VectorType>(op.getType());
54 if (!vecTy || vecTy.getNumElements() < 2)
57 assert(vecTy.getRank() == 1 &&
"Unexpected vector type");
58 assert(!vecTy.isScalable() &&
"Unexpected vector type");
60 Type elemTy = vecTy.getElementType();
62 if (elemBitwidth >= maxShuffleBitwidth)
64 op, llvm::formatv(
"element type too large ({0}), cannot break down "
65 "into vectors of bitwidth {1} or less",
66 elemBitwidth, maxShuffleBitwidth));
68 unsigned elementsPerShuffle = maxShuffleBitwidth / elemBitwidth;
69 assert(elementsPerShuffle >= 1);
71 unsigned numNewReductions =
72 llvm::divideCeil(vecTy.getNumElements(), elementsPerShuffle);
73 assert(numNewReductions >= 1);
74 if (numNewReductions == 1)
77 Location loc = op.getLoc();
79 arith::ConstantOp::create(rewriter, loc, rewriter.
getZeroAttr(vecTy));
81 for (
unsigned i = 0; i != numNewReductions; ++i) {
82 int64_t startIdx = i * elementsPerShuffle;
84 std::min(startIdx + elementsPerShuffle, vecTy.getNumElements());
85 int64_t numElems = endIdx - startIdx;
90 vector::ExtractOp::create(rewriter, loc, op.getValue(), startIdx);
92 extracted = vector::ExtractStridedSliceOp::create(
93 rewriter, loc, op.getValue(), startIdx,
98 Value
reduce = gpu::SubgroupReduceOp::create(
99 rewriter, loc, extracted, op.getOp(), op.getUniform(),
100 op.getClusterSize(), op.getClusterStride());
102 res = vector::InsertOp::create(rewriter, loc,
reduce, res, startIdx);
106 res = vector::InsertStridedSliceOp::create(
107 rewriter, loc,
reduce, res, startIdx, 1);
115 unsigned maxShuffleBitwidth = 0;
126struct ScalarizeSingleElementReduce final
130 LogicalResult matchAndRewrite(gpu::SubgroupReduceOp op,
131 PatternRewriter &rewriter)
const override {
132 auto vecTy = dyn_cast<VectorType>(op.getType());
133 if (!vecTy || vecTy.getNumElements() != 1)
136 assert(vecTy.getRank() == 1 &&
"Unexpected vector type");
137 assert(!vecTy.isScalable() &&
"Unexpected vector type");
138 Location loc = op.getLoc();
140 vector::ExtractOp::create(rewriter, loc, op.getValue(), 0);
141 Value
reduce = gpu::SubgroupReduceOp::create(
142 rewriter, loc, extracted, op.getOp(), op.getUniform(),
143 op.getClusterSize(), op.getClusterStride());
158 Value input, gpu::AllReduceOperation mode,
164 Value laneVal = input;
168 Value shuffled = gpu::ShuffleOp::create(builder, loc, packFn(laneVal), i,
170 gpu::ShuffleMode::XOR)
174 laneVal, unpackFn(shuffled));
182struct ScalarSubgroupReduceToShuffles final
184 ScalarSubgroupReduceToShuffles(MLIRContext *ctx,
unsigned subgroupSize,
185 unsigned shuffleBitwidth,
bool matchClustered,
186 PatternBenefit benefit)
187 : OpRewritePattern(ctx, benefit), subgroupSize(subgroupSize),
188 shuffleBitwidth(shuffleBitwidth), matchClustered(matchClustered) {}
190 LogicalResult matchAndRewrite(gpu::SubgroupReduceOp op,
191 PatternRewriter &rewriter)
const override {
192 if (op.getClusterSize().has_value() != matchClustered) {
194 op, llvm::formatv(
"op is {0}clustered but pattern is configured to "
195 "only match {1}clustered ops",
196 matchClustered ?
"non-" :
"",
197 matchClustered ?
"" :
"non-"));
204 Type valueTy = op.getType();
205 unsigned elemBitwidth =
207 if (!valueTy.
isIntOrFloat() || elemBitwidth > shuffleBitwidth)
209 op,
"value type is not a compatible scalar");
211 Location loc = op.getLoc();
213 if (elemBitwidth == shuffleBitwidth) {
214 auto identityFn = [](Value v) {
return v; };
215 rewriter.
replaceOp(op, createSubgroupShuffleReduction(
216 rewriter, loc, op.getValue(), op.getOp(), *ci,
217 identityFn, identityFn));
223 auto packFn = [loc, &rewriter, equivIntType,
224 shuffleIntType](Value unpackedVal) -> Value {
226 arith::BitcastOp::create(rewriter, loc, equivIntType, unpackedVal);
227 return arith::ExtUIOp::create(rewriter, loc, shuffleIntType, asInt);
229 auto unpackFn = [loc, &rewriter, equivIntType,
230 valueTy](Value packedVal) -> Value {
232 arith::TruncIOp::create(rewriter, loc, equivIntType, packedVal);
233 return arith::BitcastOp::create(rewriter, loc, valueTy, asInt);
237 op, createSubgroupShuffleReduction(rewriter, loc, op.getValue(),
238 op.getOp(), *ci, packFn, unpackFn));
243 unsigned subgroupSize = 0;
244 unsigned shuffleBitwidth = 0;
245 bool matchClustered =
false;
249struct VectorSubgroupReduceToShuffles final
251 VectorSubgroupReduceToShuffles(MLIRContext *ctx,
unsigned subgroupSize,
252 unsigned shuffleBitwidth,
bool matchClustered,
253 PatternBenefit benefit)
254 : OpRewritePattern(ctx, benefit), subgroupSize(subgroupSize),
255 shuffleBitwidth(shuffleBitwidth), matchClustered(matchClustered) {}
257 LogicalResult matchAndRewrite(gpu::SubgroupReduceOp op,
258 PatternRewriter &rewriter)
const override {
259 if (op.getClusterSize().has_value() != matchClustered) {
261 op, llvm::formatv(
"op is {0}clustered but pattern is configured to "
262 "only match {1}clustered ops",
263 matchClustered ?
"non-" :
"",
264 matchClustered ?
"" :
"non-"));
271 auto vecTy = dyn_cast<VectorType>(op.getType());
275 unsigned vecBitwidth =
276 vecTy.getNumElements() * vecTy.getElementTypeBitWidth();
277 if (vecBitwidth > shuffleBitwidth)
280 llvm::formatv(
"vector type bitwidth too large ({0}), cannot lower "
281 "to shuffles of size {1}",
282 vecBitwidth, shuffleBitwidth));
284 unsigned elementsPerShuffle =
285 shuffleBitwidth / vecTy.getElementTypeBitWidth();
286 if (elementsPerShuffle * vecTy.getElementTypeBitWidth() != shuffleBitwidth)
288 op,
"shuffle bitwidth is not a multiple of the element bitwidth");
290 Location loc = op.getLoc();
294 auto extendedVecTy = VectorType::get(
295 static_cast<int64_t
>(elementsPerShuffle), vecTy.getElementType());
296 Value extendedInput = op.getValue();
297 if (vecBitwidth < shuffleBitwidth) {
298 auto zero = arith::ConstantOp::create(
299 rewriter, loc, rewriter.
getZeroAttr(extendedVecTy));
300 extendedInput = vector::InsertStridedSliceOp::create(
301 rewriter, loc, extendedInput, zero, 0, 1);
305 auto shuffleVecType = VectorType::get(1, shuffleIntType);
307 auto packFn = [loc, &rewriter, shuffleVecType](Value unpackedVal) -> Value {
309 vector::BitCastOp::create(rewriter, loc, shuffleVecType, unpackedVal);
310 return vector::ExtractOp::create(rewriter, loc, asIntVec, 0);
312 auto unpackFn = [loc, &rewriter, shuffleVecType,
313 extendedVecTy](Value packedVal) -> Value {
315 vector::BroadcastOp::create(rewriter, loc, shuffleVecType, packedVal);
316 return vector::BitCastOp::create(rewriter, loc, extendedVecTy, asIntVec);
319 Value res = createSubgroupShuffleReduction(
320 rewriter, loc, extendedInput, op.getOp(), *ci, packFn, unpackFn);
322 if (vecBitwidth < shuffleBitwidth) {
323 res = vector::ExtractStridedSliceOp::create(
324 rewriter, loc, res, 0, vecTy.getNumElements(),
328 rewriter.replaceOp(op, res);
333 unsigned subgroupSize = 0;
334 unsigned shuffleBitwidth = 0;
335 bool matchClustered =
false;
343 maxShuffleBitwidth, benefit);
344 patterns.
add<ScalarizeSingleElementReduce>(patterns.
getContext(), benefit);
350 patterns.
add<ScalarSubgroupReduceToShuffles, VectorSubgroupReduceToShuffles>(
351 patterns.
getContext(), subgroupSize, shuffleBitwidth,
358 patterns.
add<ScalarSubgroupReduceToShuffles, VectorSubgroupReduceToShuffles>(
359 patterns.
getContext(), subgroupSize, shuffleBitwidth,
static Value reduce(OpBuilder &builder, Location loc, Value input, Value output, int64_t dim)
IntegerType getIntegerType(unsigned width)
TypedAttr getZeroAttr(Type type)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class helps build Operations.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
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.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
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 represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
FailureOr< SubgroupReduceClusterInfo > getSubgroupReduceClusterInfo(SubgroupReduceOp op, unsigned subgroupSize)
Returns the cluster layout of op in a subgroup of subgroupSize lanes, which must be a power of two.
vector::CombiningKind convertReductionKind(gpu::AllReduceOperation mode)
Returns the matching vector combining kind.
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.
Include the generated interface declarations.
void populateGpuLowerSubgroupReduceToShufflePatterns(RewritePatternSet &patterns, unsigned subgroupSize, unsigned shuffleBitwidth=32, PatternBenefit benefit=1)
Collect a set of patterns to lower gpu.subgroup_reduce into gpu.shuffle ops over shuffleBitwidth scal...
void populateGpuLowerClusteredSubgroupReduceToShufflePatterns(RewritePatternSet &patterns, unsigned subgroupSize, unsigned shuffleBitwidth=32, PatternBenefit benefit=1)
Disjoint counterpart of populateGpuLowerSubgroupReduceToShufflePatterns that only matches gpu....
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
void populateGpuBreakDownSubgroupReducePatterns(RewritePatternSet &patterns, unsigned maxShuffleBitwidth=32, PatternBenefit benefit=1)
Collect a set of patterns to break down subgroup_reduce ops into smaller ones supported by the target...
llvm::function_ref< Fn > function_ref
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Lane layout of the clusters reduced by a gpu.subgroup_reduce op.