MLIR 23.0.0git
LowerVectorBroadcast.cpp
Go to the documentation of this file.
1//===- LowerVectorBroadcast.cpp - Lower 'vector.broadcast' operation ------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements target-independent rewrites and utilities to lower the
10// 'vector.broadcast' operation.
11//
12//===----------------------------------------------------------------------===//
13
21#include "mlir/IR/Location.h"
24
25#define DEBUG_TYPE "vector-broadcast-lowering"
26
27using namespace mlir;
28using namespace mlir::vector;
29
30namespace {
31
32/// Convert a vector.broadcast with a vector operand to a lower rank
33/// vector.broadcast. vector.broadcast with a scalar operand is expected to be
34/// convertible to the lower level target dialect (LLVM, SPIR-V, etc.) directly.
35class BroadcastOpLowering : public OpRewritePattern<vector::BroadcastOp> {
36public:
37 using Base::Base;
38
39 LogicalResult matchAndRewrite(vector::BroadcastOp op,
40 PatternRewriter &rewriter) const override {
41 auto loc = op.getLoc();
42 VectorType dstType = op.getResultVectorType();
43 VectorType srcType = dyn_cast<VectorType>(op.getSourceType());
44 Type eltType = dstType.getElementType();
45
46 // A broadcast from a scalar is considered to be in the lowered form.
47 if (!srcType)
48 return rewriter.notifyMatchFailure(
49 op, "broadcast from scalar already in lowered form");
50
51 // Determine rank of source and destination.
52 int64_t srcRank = srcType.getRank();
53 int64_t dstRank = dstType.getRank();
54
55 // Single-element fixed-size source: extract the scalar and broadcast it.
56 if (srcType.getNumElements() == 1 && !srcType.isScalable()) {
57 SmallVector<int64_t> fullRankPosition(srcRank, 0);
58 Value ext = vector::ExtractOp::create(rewriter, loc, op.getSource(),
59 fullRankPosition);
60 assert(!isa<VectorType>(ext.getType()) && "expected scalar");
61 rewriter.replaceOpWithNewOp<vector::BroadcastOp>(op, dstType, ext);
62 return success();
63 }
64
65 // Duplicate this rank.
66 // For example:
67 // %x = broadcast %y : k-D to n-D, k < n
68 // becomes:
69 // %b = broadcast %y : k-D to (n-1)-D
70 // %x = [%b,%b,%b,%b] : n-D
71 // becomes:
72 // %b = [%y,%y] : (n-1)-D
73 // %x = [%b,%b,%b,%b] : n-D
74 if (srcRank < dstRank) {
75 // Duplication.
76 VectorType resType = VectorType::Builder(dstType).dropDim(0);
77 Value bcst =
78 vector::BroadcastOp::create(rewriter, loc, resType, op.getSource());
79 Value result = ub::PoisonOp::create(rewriter, loc, dstType);
80 for (int64_t d = 0, dim = dstType.getDimSize(0); d < dim; ++d)
81 result = vector::InsertOp::create(rewriter, loc, bcst, result, d);
82 rewriter.replaceOp(op, result);
83 return success();
84 }
85
86 // Find non-matching dimension, if any.
87 assert(srcRank == dstRank);
88 int64_t m = -1;
89 for (int64_t r = 0; r < dstRank; r++)
90 if (srcType.getDimSize(r) != dstType.getDimSize(r)) {
91 m = r;
92 break;
93 }
94
95 // All trailing dimensions are the same. Simply pass through.
96 if (m == -1) {
97 rewriter.replaceOp(op, op.getSource());
98 return success();
99 }
100
101 // Any non-matching dimension forces a stretch along this rank.
102 // For example:
103 // %x = broadcast %y : vector<4x1x2xf32> to vector<4x2x2xf32>
104 // becomes:
105 // %a = broadcast %y[0] : vector<1x2xf32> to vector<2x2xf32>
106 // %b = broadcast %y[1] : vector<1x2xf32> to vector<2x2xf32>
107 // %c = broadcast %y[2] : vector<1x2xf32> to vector<2x2xf32>
108 // %d = broadcast %y[3] : vector<1x2xf32> to vector<2x2xf32>
109 // %x = [%a,%b,%c,%d]
110 // becomes:
111 // %u = broadcast %y[0][0] : vector<2xf32> to vector <2x2xf32>
112 // %v = broadcast %y[1][0] : vector<2xf32> to vector <2x2xf32>
113 // %a = [%u, %v]
114 // ..
115 // %x = [%a,%b,%c,%d]
116 VectorType resType =
117 VectorType::get(dstType.getShape().drop_front(), eltType,
118 dstType.getScalableDims().drop_front());
119
120 // For "stretch not at start" with a scalable outer dimension we would need
121 // to emit an scf.for loop, which is not yet supported. Check before
122 // creating any IR so that returning failure() does not violate the pattern
123 // API contract.
124 if (m != 0 && dstType.getScalableDims()[0]) {
125 // TODO: For scalable vectors we should emit an scf.for loop.
126 return failure();
127 }
128
129 Value result = ub::PoisonOp::create(rewriter, loc, dstType);
130 if (m == 0) {
131 // Stetch at start.
132 Value ext = vector::ExtractOp::create(rewriter, loc, op.getSource(), 0);
133 Value bcst = vector::BroadcastOp::create(rewriter, loc, resType, ext);
134 for (int64_t d = 0, dim = dstType.getDimSize(0); d < dim; ++d)
135 result = vector::InsertOp::create(rewriter, loc, bcst, result, d);
136 } else {
137 // Stetch not at start.
138 for (int64_t d = 0, dim = dstType.getDimSize(0); d < dim; ++d) {
139 Value ext = vector::ExtractOp::create(rewriter, loc, op.getSource(), d);
140 Value bcst = vector::BroadcastOp::create(rewriter, loc, resType, ext);
141 result = vector::InsertOp::create(rewriter, loc, bcst, result, d);
142 }
143 }
144 rewriter.replaceOp(op, result);
145 return success();
146 }
147};
148} // namespace
149
151 RewritePatternSet &patterns, PatternBenefit benefit) {
152 patterns.add<BroadcastOpLowering>(patterns.getContext(), benefit);
153}
return success()
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...
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...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
This is a builder type that keeps local references to arguments.
Builder & dropDim(unsigned pos)
Erase a dim from shape @pos.
void populateVectorBroadcastLoweringPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
Include the generated interface declarations.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...