@@ -43,20 +43,22 @@ class SCFLoop {
43
43
mlir::Value getLowerBound () { return lowerBound; }
44
44
mlir::Value getUpperBound () { return upperBound; }
45
45
46
- int64_t findStepAndIV (mlir::Value &addr);
46
+ // Returns true if successfully finds both step and induction variable.
47
+ bool findStepAndIV ();
47
48
cir::CmpOp findCmpOp ();
48
49
mlir::Value findIVInitValue ();
49
50
void analysis ();
50
51
51
- mlir::Value plusConstant (mlir::Value V , mlir::Location loc, int addend);
52
+ mlir::Value plusConstant (mlir::Value v , mlir::Location loc, int addend);
52
53
void transferToSCFForOp ();
53
54
54
55
private:
55
56
cir::ForOp forOp;
56
57
cir::CmpOp cmpOp;
57
- mlir::Value IVAddr , lowerBound = nullptr , upperBound = nullptr ;
58
+ mlir::Value ivAddr , lowerBound = nullptr , upperBound = nullptr ;
58
59
mlir::ConversionPatternRewriter *rewriter;
59
60
int64_t step = 0 ;
61
+ bool canonical = true ;
60
62
};
61
63
62
64
class SCFWhileLoop {
@@ -86,47 +88,96 @@ class SCFDoLoop {
86
88
};
87
89
88
90
static int64_t getConstant (cir::ConstantOp op) {
89
- auto attr = op-> getAttrs (). front () .getValue ();
90
- const auto IntAttr = mlir::dyn_cast <cir::IntAttr>(attr);
91
- return IntAttr .getValue ().getSExtValue ();
91
+ auto attr = op.getValue ();
92
+ const auto intAttr = mlir::cast <cir::IntAttr>(attr);
93
+ return intAttr .getValue ().getSExtValue ();
92
94
}
93
95
94
- int64_t SCFLoop::findStepAndIV (mlir::Value &addr ) {
96
+ bool SCFLoop::findStepAndIV () {
95
97
auto *stepBlock =
96
98
(forOp.maybeGetStep () ? &forOp.maybeGetStep ()->front () : nullptr );
97
99
assert (stepBlock && " Can not find step block" );
98
100
99
- int64_t step = 0 ;
100
- mlir::Value IV = nullptr ;
101
- // Try to match "IV load addr; ++IV; store IV, addr" to find step.
102
- for (mlir::Operation &op : *stepBlock)
103
- if (auto loadOp = dyn_cast<cir::LoadOp>(op)) {
104
- addr = loadOp.getAddr ();
105
- IV = loadOp.getResult ();
106
- } else if (auto cop = dyn_cast<cir::ConstantOp>(op)) {
107
- if (step)
108
- llvm_unreachable (
109
- " Not support multiple constant in step calculation yet" );
110
- step = getConstant (cop);
111
- } else if (auto bop = dyn_cast<cir::BinOp>(op)) {
112
- if (bop.getLhs () != IV)
113
- llvm_unreachable (" Find BinOp not operate on IV" );
114
- if (bop.getKind () != cir::BinOpKind::Add)
115
- llvm_unreachable (
116
- " Not support BinOp other than Add in step calculation yet" );
117
- } else if (auto uop = dyn_cast<cir::UnaryOp>(op)) {
118
- if (uop.getInput () != IV)
119
- llvm_unreachable (" Find UnaryOp not operate on IV" );
120
- if (uop.getKind () == cir::UnaryOpKind::Inc)
121
- step = 1 ;
122
- else if (uop.getKind () == cir::UnaryOpKind::Dec)
123
- llvm_unreachable (" Not support decrement step yet" );
124
- } else if (auto storeOp = dyn_cast<cir::StoreOp>(op)) {
125
- assert (storeOp.getAddr () == addr && " Can't find IV when lowering ForOp" );
126
- }
127
- assert (step && " Can't find step when lowering ForOp" );
128
101
129
- return step;
102
+ // Try to match "iv = load addr; ++iv; store iv, addr; yield" to find step.
103
+ // We should match the exact pattern, in case there's something unexpected:
104
+ // we must rule out cases like `for (int i = 0; i < n; i++, printf("\n"))`.
105
+ auto &oplist = stepBlock->getOperations ();
106
+
107
+ auto iterator = oplist.begin ();
108
+
109
+ // We might find constants at beginning. Skip them.
110
+ // We could have hoisted them outside the for loop in previous passes, but
111
+ // it hasn't been done yet.
112
+ while (iterator != oplist.end () && isa<ConstantOp>(*iterator))
113
+ ++iterator;
114
+
115
+ if (iterator == oplist.end ())
116
+ return false ;
117
+
118
+ auto load = dyn_cast<LoadOp>(*iterator);
119
+ if (!load)
120
+ return false ;
121
+
122
+ // We assume this is the address of induction variable (IV). The operations that come
123
+ // next will check if that's true.
124
+ mlir::Value addr = load.getAddr ();
125
+ mlir::Value iv = load.getResult ();
126
+
127
+ // Then we try to match either "++IV" or "IV += n". Same for reversed loops.
128
+ if (++iterator == oplist.end ())
129
+ return false ;
130
+
131
+ mlir::Operation &arith = *iterator;
132
+
133
+ if (auto unary = dyn_cast<UnaryOp>(arith)) {
134
+ // Not operating on induction variable. Fail.
135
+ if (unary.getInput () != iv)
136
+ return false ;
137
+
138
+ if (unary.getKind () == UnaryOpKind::Inc)
139
+ step = 1 ;
140
+ else if (unary.getKind () == UnaryOpKind::Dec)
141
+ step = -1 ;
142
+ else
143
+ return false ;
144
+ }
145
+
146
+ if (auto binary = dyn_cast<BinOp>(arith)) {
147
+ if (binary.getLhs () != iv)
148
+ return false ;
149
+
150
+ mlir::Value value = binary.getRhs ();
151
+ if (auto constValue = dyn_cast<ConstantOp>(value.getDefiningOp ()); isa<IntAttr>(constValue.getValue ()))
152
+ step = getConstant (constValue);
153
+
154
+ if (binary.getKind () == BinOpKind::Add)
155
+ ; // Nothing to do. Step has been calculated above.
156
+ else if (binary.getKind () == BinOpKind::Sub)
157
+ step = -step;
158
+ else
159
+ return false ;
160
+ }
161
+
162
+ // Check whether we immediately store this value into the appropriate place.
163
+ if (++iterator == oplist.end ())
164
+ return false ;
165
+
166
+ auto store = dyn_cast<StoreOp>(*iterator);
167
+ if (!store || store.getAddr () != addr || store.getValue () != arith.getResult (0 ))
168
+ return false ;
169
+
170
+ if (++iterator == oplist.end ())
171
+ return false ;
172
+
173
+ // Finally, this should precede a yield with nothing in between.
174
+ bool success = isa<YieldOp>(*iterator);
175
+
176
+ // Remember to update analysis information.
177
+ if (success)
178
+ ivAddr = addr;
179
+
180
+ return success;
130
181
}
131
182
132
183
static bool isIVLoad (mlir::Operation *op, mlir::Value IVAddr) {
@@ -143,7 +194,7 @@ static bool isIVLoad(mlir::Operation *op, mlir::Value IVAddr) {
143
194
144
195
cir::CmpOp SCFLoop::findCmpOp () {
145
196
cmpOp = nullptr ;
146
- for (auto *user : IVAddr .getUsers ()) {
197
+ for (auto *user : ivAddr .getUsers ()) {
147
198
if (user->getParentRegion () != &forOp.getCond ())
148
199
continue ;
149
200
if (auto loadOp = dyn_cast<cir::LoadOp>(*user)) {
@@ -162,10 +213,10 @@ cir::CmpOp SCFLoop::findCmpOp() {
162
213
if (!mlir::isa<cir::IntType>(type))
163
214
llvm_unreachable (" Non-integer type IV is not supported" );
164
215
165
- auto lhsDefOp = cmpOp.getLhs ().getDefiningOp ();
216
+ auto * lhsDefOp = cmpOp.getLhs ().getDefiningOp ();
166
217
if (!lhsDefOp)
167
218
llvm_unreachable (" Can't find IV load" );
168
- if (!isIVLoad (lhsDefOp, IVAddr ))
219
+ if (!isIVLoad (lhsDefOp, ivAddr ))
169
220
llvm_unreachable (" cmpOp LHS is not IV" );
170
221
171
222
if (cmpOp.getKind () != cir::CmpOpKind::le &&
@@ -187,7 +238,7 @@ mlir::Value SCFLoop::plusConstant(mlir::Value V, mlir::Location loc,
187
238
// The operations before the loop have been transferred to MLIR.
188
239
// So we need to go through getRemappedValue to find the value.
189
240
mlir::Value SCFLoop::findIVInitValue () {
190
- auto remapAddr = rewriter->getRemappedValue (IVAddr );
241
+ auto remapAddr = rewriter->getRemappedValue (ivAddr );
191
242
if (!remapAddr)
192
243
return nullptr ;
193
244
if (!remapAddr.hasOneUse ())
@@ -199,7 +250,10 @@ mlir::Value SCFLoop::findIVInitValue() {
199
250
}
200
251
201
252
void SCFLoop::analysis () {
202
- step = findStepAndIV (IVAddr);
253
+ canonical = findStepAndIV ();
254
+ if (!canonical)
255
+ llvm_unreachable (" Non-canonical for loops are not yet handled" );
256
+
203
257
cmpOp = findCmpOp ();
204
258
auto IVInit = findIVInitValue ();
205
259
// The loop end value should be hoisted out of loop by -cir-mlir-scf-prepare.
@@ -237,7 +291,7 @@ void SCFLoop::transferToSCFForOp() {
237
291
llvm_unreachable (
238
292
" Not support lowering loop with break, continue or if yet" );
239
293
// Replace the IV usage to scf loop induction variable.
240
- if (isIVLoad (op, IVAddr )) {
294
+ if (isIVLoad (op, ivAddr )) {
241
295
// Replace CIR IV load with arith.addi scf.IV, 0.
242
296
// The replacement makes the SCF IV can be automatically propogated
243
297
// by OpAdaptor for individual IV user lowering.
0 commit comments