24#define GEN_PASS_DEF_LOWERVECTORMULTIREDUCTION
25#include "mlir/Dialect/Vector/Transforms/Passes.h.inc"
29#define DEBUG_TYPE "vector-multi-reduction"
39class InnerOuterDimReductionConversion
44 explicit InnerOuterDimReductionConversion(
48 useInnerDimsForReduction(
49 options == vector::VectorMultiReductionLowering::InnerReduction) {}
51 LogicalResult matchAndRewrite(vector::MultiDimReductionOp multiReductionOp,
56 cast<vector::MaskableOpInterface>(multiReductionOp.getOperation());
58 if (maskableOp.isMasked()) {
60 rootOp = maskableOp.getMaskingOp();
62 rootOp = multiReductionOp;
65 auto src = multiReductionOp.getSource();
66 auto loc = multiReductionOp.
getLoc();
67 auto srcRank = multiReductionOp.getSourceVectorType().getRank();
71 llvm::SmallDenseSet<int64_t> reductionDimsSet(reductionDims.begin(),
73 int64_t reductionSize = reductionDims.size();
75 for (
int64_t i = 0; i < srcRank; ++i)
76 if (!reductionDimsSet.contains(i))
77 parallelDims.push_back(i);
81 if (parallelDims.empty())
83 if (useInnerDimsForReduction &&
85 llvm::to_vector<4>(llvm::seq<int64_t>(0, parallelDims.size()))))
88 if (!useInnerDimsForReduction &&
89 (parallelDims == llvm::to_vector<4>(llvm::seq<int64_t>(
91 parallelDims.size() + reductionDims.size()))))
95 if (useInnerDimsForReduction) {
96 indices.append(parallelDims.begin(), parallelDims.end());
97 indices.append(reductionDims.begin(), reductionDims.end());
99 indices.append(reductionDims.begin(), reductionDims.end());
100 indices.append(parallelDims.begin(), parallelDims.end());
104 Value transposedMask;
105 if (maskableOp.isMasked()) {
106 transposedMask = vector::TransposeOp::create(
107 rewriter, loc, maskableOp.getMaskingOp().getMask(),
indices);
111 auto transposeOp = vector::TransposeOp::create(rewriter, loc, src,
indices);
113 for (
int i = 0; i < reductionSize; ++i) {
114 if (useInnerDimsForReduction)
115 reductionMask[srcRank - i - 1] =
true;
117 reductionMask[i] =
true;
120 Operation *newMultiRedOp = vector::MultiDimReductionOp::create(
121 rewriter, multiReductionOp.getLoc(), transposeOp.getResult(),
122 multiReductionOp.getAcc(), reductionMask, multiReductionOp.getKind(),
123 multiReductionOp.getFastmath());
132 const bool useInnerDimsForReduction;
148class FlattenMultiReduction
153 explicit FlattenMultiReduction(
MLIRContext *context,
154 vector::VectorMultiReductionLowering
options,
157 useInnerDimsForReduction(
158 options == vector::VectorMultiReductionLowering::InnerReduction) {}
160 LogicalResult matchAndRewrite(vector::MultiDimReductionOp multiReductionOp,
165 cast<vector::MaskableOpInterface>(multiReductionOp.getOperation());
167 if (maskableOp.isMasked()) {
169 rootOp = maskableOp.getMaskingOp();
171 rootOp = multiReductionOp;
174 auto srcRank = multiReductionOp.getSourceVectorType().getRank();
175 auto srcShape = multiReductionOp.getSourceVectorType().getShape();
176 auto srcScalableDims =
177 multiReductionOp.getSourceVectorType().getScalableDims();
178 auto loc = multiReductionOp.
getLoc();
186 if (llvm::count(srcScalableDims,
true) > 1)
191 if (srcRank == 2 && reductionMask.front() != reductionMask.back())
198 bool isReductionDimScalable =
false;
199 for (
const auto &it : llvm::enumerate(reductionMask)) {
201 bool isReduction = it.value();
203 reductionDims.push_back(i);
204 reductionShapes.push_back(srcShape[i]);
205 isReductionDimScalable |= srcScalableDims[i];
207 parallelDims.push_back(i);
208 parallelShapes.push_back(srcShape[i]);
209 parallelScalableDims.push_back(srcScalableDims[i]);
214 int flattenedParallelDim = 0;
215 int flattenedReductionDim = 0;
216 if (!parallelShapes.empty()) {
217 flattenedParallelDim = 1;
218 for (
auto d : parallelShapes)
219 flattenedParallelDim *= d;
221 if (!reductionShapes.empty()) {
222 flattenedReductionDim = 1;
223 for (
auto d : reductionShapes)
224 flattenedReductionDim *= d;
227 assert((flattenedParallelDim || flattenedReductionDim) &&
228 "expected at least one parallel or reduction dim");
233 if (useInnerDimsForReduction &&
234 llvm::any_of(parallelDims, [&](
int64_t i) {
return i != counter++; }))
237 counter = reductionDims.size();
238 if (!useInnerDimsForReduction &&
239 llvm::any_of(parallelDims, [&](
int64_t i) {
return i != counter++; }))
247 bool isParallelDimScalable = llvm::is_contained(parallelScalableDims,
true);
248 if (flattenedParallelDim) {
249 mask.push_back(
false);
251 scalableDims.push_back(isParallelDimScalable);
253 if (flattenedReductionDim) {
254 mask.push_back(
true);
256 scalableDims.push_back(isReductionDimScalable);
258 if (!useInnerDimsForReduction &&
vectorShape.size() == 2) {
259 std::swap(mask.front(), mask.back());
261 std::swap(scalableDims.front(), scalableDims.back());
265 if (maskableOp.isMasked()) {
266 Value vectorMask = maskableOp.getMaskingOp().getMask();
267 auto maskCastedType = VectorType::get(
269 llvm::cast<VectorType>(vectorMask.
getType()).getElementType());
270 newVectorMask = vector::ShapeCastOp::create(rewriter, loc, maskCastedType,
274 auto castedType = VectorType::get(
275 vectorShape, multiReductionOp.getSourceVectorType().getElementType(),
277 Value cast = vector::ShapeCastOp::create(rewriter, loc, castedType,
278 multiReductionOp.getSource());
280 Value acc = multiReductionOp.getAcc();
281 if (flattenedParallelDim) {
282 auto accType = VectorType::get(
283 {flattenedParallelDim},
285 {isParallelDimScalable});
286 acc = vector::ShapeCastOp::create(rewriter, loc, accType, acc);
290 Operation *newMultiDimRedOp = vector::MultiDimReductionOp::create(
291 rewriter, loc, cast, acc, mask, multiReductionOp.getKind(),
292 multiReductionOp.getFastmath());
298 if (parallelShapes.empty()) {
305 VectorType outputCastedType = VectorType::get(
306 parallelShapes, multiReductionOp.getSourceVectorType().getElementType(),
307 parallelScalableDims);
309 rootOp, outputCastedType, newMultiDimRedOp->
getResult(0));
314 const bool useInnerDimsForReduction;
343struct TwoDimMultiReductionToElementWise
345 using MaskableOpRewritePattern::MaskableOpRewritePattern;
348 matchAndRewriteMaskableOp(vector::MultiDimReductionOp multiReductionOp,
349 vector::MaskingOpInterface maskingOp,
350 PatternRewriter &rewriter)
const override {
351 auto srcRank = multiReductionOp.getSourceVectorType().getRank();
356 if (multiReductionOp.isReducedDim(1) || !multiReductionOp.isReducedDim(0))
359 Value mask = maskingOp ? maskingOp.getMask() : Value();
361 auto loc = multiReductionOp.getLoc();
362 Value source = multiReductionOp.getSource();
363 ArrayRef<int64_t> srcShape =
364 multiReductionOp.getSourceVectorType().getShape();
365 int outerDim = srcShape[0];
367 Value
result = multiReductionOp.getAcc();
368 for (int64_t i = 0; i < outerDim; i++) {
369 auto v = vector::ExtractOp::create(rewriter, loc, source, i);
370 Value m = mask ? Value(vector::ExtractOp::create(rewriter, loc, mask, i))
374 result, multiReductionOp.getFastmathAttr(), m);
401struct TwoDimMultiReductionToReduction
403 using MaskableOpRewritePattern::MaskableOpRewritePattern;
406 matchAndRewriteMaskableOp(vector::MultiDimReductionOp multiReductionOp,
407 vector::MaskingOpInterface maskingOp,
408 PatternRewriter &rewriter)
const override {
409 auto srcRank = multiReductionOp.getSourceVectorType().getRank();
414 if (multiReductionOp.isReducedDim(0) || !multiReductionOp.isReducedDim(1))
417 Value mask = maskingOp ? maskingOp.getMask() :
nullptr;
419 auto loc = multiReductionOp.
getLoc();
420 Value source = multiReductionOp.getSource();
421 Value acc = multiReductionOp.getAcc();
422 int outerDim = multiReductionOp.getSourceVectorType().getShape()[0];
424 Value
result = arith::ConstantOp::create(
425 rewriter, loc, multiReductionOp.getDestType(),
426 rewriter.
getZeroAttr(multiReductionOp.getDestType()));
428 SmallVector<Value> vectors(outerDim);
429 for (int64_t i = 0; i < outerDim; ++i) {
430 Value v = vector::ExtractOp::create(rewriter, loc, source, i);
431 Value a = vector::ExtractOp::create(rewriter, loc, acc, i);
433 Operation *reductionOp =
434 vector::ReductionOp::create(rewriter, loc, multiReductionOp.getKind(),
435 v, a, multiReductionOp.getFastmath());
438 Value m = vector::ExtractOp::create(rewriter, loc, mask, i);
442 result = vector::InsertOp::create(rewriter, loc,
460struct OneDimMultiReductionToReduction
462 using MaskableOpRewritePattern::MaskableOpRewritePattern;
465 matchAndRewriteMaskableOp(vector::MultiDimReductionOp multiReductionOp,
466 vector::MaskingOpInterface maskingOp,
467 PatternRewriter &rewriter)
const override {
468 auto srcRank = multiReductionOp.getSourceVectorType().getRank();
472 if (!multiReductionOp.isReducedDim(0))
475 auto loc = multiReductionOp.getLoc();
476 Value mask = maskingOp ? maskingOp.getMask() : Value();
478 Operation *reductionOp = vector::ReductionOp::create(
479 rewriter, loc, multiReductionOp.getKind(), multiReductionOp.getSource(),
480 multiReductionOp.getAcc(), multiReductionOp.getFastmath());
489struct LowerVectorMultiReductionPass
491 LowerVectorMultiReductionPass> {
492 LowerVectorMultiReductionPass(vector::VectorMultiReductionLowering option) {
493 this->loweringStrategy = option;
496 void runOnOperation()
override {
497 Operation *op = getOperation();
500 RewritePatternSet patterns(context);
502 patterns, this->loweringStrategy);
506 RewritePatternSet flatteningPatterns(context);
508 flatteningPatterns, this->loweringStrategy);
512 RewritePatternSet unrollingPatterns(context);
514 unrollingPatterns, this->loweringStrategy);
519 void getDependentDialects(DialectRegistry ®istry)
const override {
520 registry.
insert<vector::VectorDialect>();
542 patterns.
add<OneDimMultiReductionToReduction>(patterns.
getContext(), benefit);
543 if (
options == VectorMultiReductionLowering ::InnerReduction)
544 patterns.
add<TwoDimMultiReductionToReduction>(patterns.
getContext(),
547 patterns.
add<TwoDimMultiReductionToElementWise>(patterns.
getContext(),
552 vector::VectorMultiReductionLowering option) {
553 return std::make_unique<LowerVectorMultiReductionPass>(option);
static llvm::ManagedStatic< PassManagerOptions > options
static std::optional< VectorShape > vectorShape(Type type)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
TypedAttr getZeroAttr(Type type)
MLIRContext is the top-level object for a collection of MLIR operations.
RAII guard to reset the insertion point of the builder when destroyed.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
Operation is the basic unit of execution within MLIR.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
MLIRContext * getContext()
Return the context this operation is associated with.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
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.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
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.
Location getLoc() const
Return the location of this value.
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.
Operation * maskOperation(OpBuilder &builder, Operation *maskableOp, Value mask, Value passthru=Value())
Creates a vector.mask operation around a maskable operation.
std::unique_ptr< Pass > createLowerVectorMultiReductionPass(VectorMultiReductionLowering option=VectorMultiReductionLowering::InnerParallel)
Creates an instance of the vector.multi_reduction lowering pass.
void populateVectorMultiReductionUnrollingPatterns(RewritePatternSet &patterns, VectorMultiReductionLowering options, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
void populateVectorMultiReductionFlatteningPatterns(RewritePatternSet &patterns, VectorMultiReductionLowering options, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
void populateVectorMultiReductionReorderPatterns(RewritePatternSet &patterns, VectorMultiReductionLowering options, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
Include the generated interface declarations.
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
A pattern for ops that implement MaskableOpInterface and that might be masked (i.e.