Skip to content

Commit f8d1f53

Browse files
authored
[mlir][scf] Add value bound for computed upper bound of forall loop (#171158)
Add additional bound for the induction variable of the scf.forall such that: %iv <= %lower_bound + (%trip_count - 1) * step Same as #126426 but for scf.forall loop
1 parent 4f5071f commit f8d1f53

File tree

2 files changed

+43
-29
lines changed

2 files changed

+43
-29
lines changed

mlir/lib/Dialect/SCF/IR/ValueBoundsOpInterfaceImpl.cpp

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,36 @@ namespace mlir {
1717
namespace scf {
1818
namespace {
1919

20+
static AffineExpr getTripCountExpr(OpFoldResult lb, OpFoldResult ub,
21+
OpFoldResult step,
22+
ValueBoundsConstraintSet &cstr) {
23+
AffineExpr lbExpr = cstr.getExpr(lb);
24+
AffineExpr ubExpr = cstr.getExpr(ub);
25+
AffineExpr stepExpr = cstr.getExpr(step);
26+
AffineExpr tripCountExpr =
27+
AffineExpr(ubExpr - lbExpr).ceilDiv(stepExpr); // (ub - lb) / step
28+
return tripCountExpr;
29+
}
30+
31+
static void populateIVBounds(OpFoldResult lb, OpFoldResult ub,
32+
OpFoldResult step, Value iv,
33+
ValueBoundsConstraintSet &cstr) {
34+
cstr.bound(iv) >= cstr.getExpr(lb);
35+
cstr.bound(iv) < cstr.getExpr(ub);
36+
// iv <= lb + ((ub-lb)/step - 1) * step
37+
// This bound does not replace the `iv < ub` constraint mentioned above,
38+
// since constraints involving the multiplication of two constraint set
39+
// dimensions are not supported.
40+
AffineExpr tripCountMinusOne =
41+
getTripCountExpr(lb, ub, step, cstr) - cstr.getExpr(1);
42+
AffineExpr computedUpperBound =
43+
cstr.getExpr(lb) + AffineExpr(tripCountMinusOne * cstr.getExpr(step));
44+
cstr.bound(iv) <= computedUpperBound;
45+
}
46+
2047
struct ForOpInterface
2148
: public ValueBoundsOpInterface::ExternalModel<ForOpInterface, ForOp> {
2249

23-
static AffineExpr getTripCountExpr(scf::ForOp forOp,
24-
ValueBoundsConstraintSet &cstr) {
25-
AffineExpr lbExpr = cstr.getExpr(forOp.getLowerBound());
26-
AffineExpr ubExpr = cstr.getExpr(forOp.getUpperBound());
27-
AffineExpr stepExpr = cstr.getExpr(forOp.getStep());
28-
AffineExpr tripCountExpr =
29-
AffineExpr(ubExpr - lbExpr).ceilDiv(stepExpr); // (ub - lb) / step
30-
return tripCountExpr;
31-
}
32-
3350
/// Populate bounds of values/dimensions for iter_args/OpResults. If the
3451
/// value/dimension size does not change in an iteration, we can deduce that
3552
/// it the same as the initial value/dimension.
@@ -87,7 +104,8 @@ struct ForOpInterface
87104
// `value` is result of `forOp`, we can prove that:
88105
// %result == %init_arg + trip_count * (%yielded_value - %iter_arg).
89106
// Where trip_count is (ub - lb) / step.
90-
AffineExpr tripCountExpr = getTripCountExpr(forOp, cstr);
107+
AffineExpr tripCountExpr = getTripCountExpr(
108+
forOp.getLowerBound(), forOp.getUpperBound(), forOp.getStep(), cstr);
91109
AffineExpr oneIterAdvanceExpr =
92110
cstr.getExpr(yieldedValue) - cstr.getExpr(iterArg);
93111
cstr.bound(value) ==
@@ -99,19 +117,8 @@ struct ForOpInterface
99117
auto forOp = cast<ForOp>(op);
100118

101119
if (value == forOp.getInductionVar()) {
102-
cstr.bound(value) >= forOp.getLowerBound();
103-
cstr.bound(value) < forOp.getUpperBound();
104-
// iv <= lb + ((ub-lb)/step - 1) * step
105-
// This bound does not replace the `iv < ub` constraint mentioned above,
106-
// since constraints involving the multiplication of two constraint set
107-
// dimensions are not supported.
108-
AffineExpr tripCountMinusOne =
109-
getTripCountExpr(forOp, cstr) - cstr.getExpr(1);
110-
AffineExpr computedUpperBound =
111-
cstr.getExpr(forOp.getLowerBound()) +
112-
AffineExpr(tripCountMinusOne * cstr.getExpr(forOp.getStep()));
113-
cstr.bound(value) <= computedUpperBound;
114-
return;
120+
return populateIVBounds(forOp.getLowerBound(), forOp.getUpperBound(),
121+
forOp.getStep(), value, cstr);
115122
}
116123

117124
// Handle iter_args and OpResults.
@@ -141,11 +148,9 @@ struct ForallOpInterface
141148
assert(blockArg.getArgNumber() < forallOp.getInductionVars().size() &&
142149
"expected index value to be an induction var");
143150
int64_t idx = blockArg.getArgNumber();
144-
// TODO: Take into account step size.
145-
AffineExpr lb = cstr.getExpr(forallOp.getMixedLowerBound()[idx]);
146-
AffineExpr ub = cstr.getExpr(forallOp.getMixedUpperBound()[idx]);
147-
cstr.bound(value) >= lb;
148-
cstr.bound(value) < ub;
151+
return populateIVBounds(forallOp.getMixedLowerBound()[idx],
152+
forallOp.getMixedUpperBound()[idx],
153+
forallOp.getMixedStep()[idx], value, cstr);
149154
}
150155

151156
void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,

mlir/test/Dialect/SCF/value-bounds-op-interface-impl.mlir

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,12 @@ func.func @scf_for_result_infer_dynamic_init_big_step(%i : index) {
379379
"test.compare"(%0, %7) {cmp = "LE"} : (index, index) -> ()
380380
return
381381
}
382+
383+
func.func @scf_forall_computed_upper_bound(%x: index) {
384+
%c6 = arith.constant 6 : index
385+
scf.forall (%iv) = (0) to (8) step (3) {
386+
// expected-remark @below{{true}}
387+
"test.compare"(%iv, %c6) {cmp = "LE"} : (index, index) -> ()
388+
}
389+
return
390+
}

0 commit comments

Comments
 (0)