Skip to content

Commit ad1b2ac

Browse files
[mlir][Interfaces][NFC] ValueBoundsConstraintSet: Pass stop condition in the constructor
This commit changes the API of `ValueBoundsConstraintSet`: the stop condition is now passed to the constructor instead of `processWorklist`. That makes it easier to add items to the worklist multiple times and process them in a consistent manner. The current `ValueBoundsConstraintSet` is passed as a reference to the stop function, so that the stop function can be defined before the the `ValueBoundsConstraintSet` is constructed. This change is in preparation of adding support for branches.
1 parent f944279 commit ad1b2ac

File tree

9 files changed

+90
-63
lines changed

9 files changed

+90
-63
lines changed

mlir/include/mlir/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ struct ValueBoundsConstraintSet : protected ::mlir::ValueBoundsConstraintSet {
2929
struct ScalableValueBoundsConstraintSet
3030
: public llvm::RTTIExtends<ScalableValueBoundsConstraintSet,
3131
detail::ValueBoundsConstraintSet> {
32-
ScalableValueBoundsConstraintSet(MLIRContext *context, unsigned vscaleMin,
33-
unsigned vscaleMax)
34-
: RTTIExtends(context), vscaleMin(vscaleMin), vscaleMax(vscaleMax){};
32+
ScalableValueBoundsConstraintSet(
33+
MLIRContext *context,
34+
ValueBoundsConstraintSet::StopConditionFn stopCondition,
35+
unsigned vscaleMin, unsigned vscaleMax)
36+
: RTTIExtends(context, stopCondition), vscaleMin(vscaleMin),
37+
vscaleMax(vscaleMax) {};
3538

3639
using RTTIExtends::bound;
3740
using RTTIExtends::StopConditionFn;

mlir/include/mlir/Interfaces/ValueBoundsOpInterface.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,9 @@ class ValueBoundsConstraintSet
117117
///
118118
/// The first parameter of the function is the shaped value/index-typed
119119
/// value. The second parameter is the dimension in case of a shaped value.
120-
using StopConditionFn =
121-
function_ref<bool(Value, std::optional<int64_t> /*dim*/)>;
120+
/// The third parameter is this constraint set.
121+
using StopConditionFn = std::function<bool(
122+
Value, std::optional<int64_t> /*dim*/, ValueBoundsConstraintSet &cstr)>;
122123

123124
/// Compute a bound for the given index-typed value or shape dimension size.
124125
/// The computed bound is stored in `resultMap`. The operands of the bound are
@@ -267,22 +268,20 @@ class ValueBoundsConstraintSet
267268
/// An index-typed value or the dimension of a shaped-type value.
268269
using ValueDim = std::pair<Value, int64_t>;
269270

270-
ValueBoundsConstraintSet(MLIRContext *ctx);
271+
ValueBoundsConstraintSet(MLIRContext *ctx, StopConditionFn stopCondition);
271272

272273
/// Populates the constraint set for a value/map without actually computing
273274
/// the bound. Returns the position for the value/map (via the return value
274275
/// and `posOut` output parameter).
275276
int64_t populateConstraintsSet(Value value,
276-
std::optional<int64_t> dim = std::nullopt,
277-
StopConditionFn stopCondition = nullptr);
277+
std::optional<int64_t> dim = std::nullopt);
278278
int64_t populateConstraintsSet(AffineMap map, ValueDimList mapOperands,
279-
StopConditionFn stopCondition = nullptr,
280279
int64_t *posOut = nullptr);
281280

282281
/// Iteratively process all elements on the worklist until an index-typed
283282
/// value or shaped value meets `stopCondition`. Such values are not processed
284283
/// any further.
285-
void processWorklist(StopConditionFn stopCondition);
284+
void processWorklist();
286285

287286
/// Bound the given column in the underlying constraint set by the given
288287
/// expression.
@@ -330,6 +329,9 @@ class ValueBoundsConstraintSet
330329

331330
/// Builder for constructing affine expressions.
332331
Builder builder;
332+
333+
/// The current stop condition function.
334+
StopConditionFn stopCondition = nullptr;
333335
};
334336

335337
} // namespace mlir

mlir/lib/Dialect/Affine/Transforms/ReifyValueBounds.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ FailureOr<OpFoldResult> mlir::affine::reifyShapedValueDimBound(
8484
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
8585
int64_t dim, ValueBoundsConstraintSet::StopConditionFn stopCondition,
8686
bool closedUB) {
87-
auto reifyToOperands = [&](Value v, std::optional<int64_t> d) {
87+
auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
88+
ValueBoundsConstraintSet &cstr) {
8889
// We are trying to reify a bound for `value` in terms of the owning op's
8990
// operands. Construct a stop condition that evaluates to "true" for any SSA
9091
// value except for `value`. I.e., the bound will be computed in terms of
@@ -100,7 +101,8 @@ FailureOr<OpFoldResult> mlir::affine::reifyShapedValueDimBound(
100101
FailureOr<OpFoldResult> mlir::affine::reifyIndexValueBound(
101102
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
102103
ValueBoundsConstraintSet::StopConditionFn stopCondition, bool closedUB) {
103-
auto reifyToOperands = [&](Value v, std::optional<int64_t> d) {
104+
auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
105+
ValueBoundsConstraintSet &cstr) {
104106
return v != value;
105107
};
106108
return reifyValueBound(b, loc, type, value, /*dim=*/std::nullopt,

mlir/lib/Dialect/Arith/Transforms/ReifyValueBounds.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ FailureOr<OpFoldResult> mlir::arith::reifyShapedValueDimBound(
119119
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
120120
int64_t dim, ValueBoundsConstraintSet::StopConditionFn stopCondition,
121121
bool closedUB) {
122-
auto reifyToOperands = [&](Value v, std::optional<int64_t> d) {
122+
auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
123+
ValueBoundsConstraintSet &cstr) {
123124
// We are trying to reify a bound for `value` in terms of the owning op's
124125
// operands. Construct a stop condition that evaluates to "true" for any SSA
125126
// value expect for `value`. I.e., the bound will be computed in terms of
@@ -135,7 +136,8 @@ FailureOr<OpFoldResult> mlir::arith::reifyShapedValueDimBound(
135136
FailureOr<OpFoldResult> mlir::arith::reifyIndexValueBound(
136137
OpBuilder &b, Location loc, presburger::BoundType type, Value value,
137138
ValueBoundsConstraintSet::StopConditionFn stopCondition, bool closedUB) {
138-
auto reifyToOperands = [&](Value v, std::optional<int64_t> d) {
139+
auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
140+
ValueBoundsConstraintSet &cstr) {
139141
return v != value;
140142
};
141143
return reifyValueBound(b, loc, type, value, /*dim=*/std::nullopt,

mlir/lib/Dialect/Linalg/Transforms/HoistPadding.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ HoistPaddingAnalysis::getHoistedPackedTensorSizes(RewriterBase &rewriter,
468468
FailureOr<OpFoldResult> loopUb = affine::reifyIndexValueBound(
469469
rewriter, loc, presburger::BoundType::UB, forOp.getUpperBound(),
470470
/*stopCondition=*/
471-
[&](Value v, std::optional<int64_t> d) {
471+
[&](Value v, std::optional<int64_t> d, ValueBoundsConstraintSet &cstr) {
472472
if (v == forOp.getUpperBound())
473473
return false;
474474
// Compute a bound that is independent of any affine op results.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct ForOpInterface
5858
ValueDimList boundOperands;
5959
LogicalResult status = ValueBoundsConstraintSet::computeBound(
6060
bound, boundOperands, BoundType::EQ, yieldedValue, dim,
61-
[&](Value v, std::optional<int64_t> d) {
61+
[&](Value v, std::optional<int64_t> d, ValueBoundsConstraintSet &cstr) {
6262
// Stop when reaching a block argument of the loop body.
6363
if (auto bbArg = llvm::dyn_cast<BlockArgument>(v))
6464
return bbArg.getOwner()->getParentOp() == forOp;

mlir/lib/Dialect/Vector/IR/ScalableValueBoundsConstraintSet.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,26 @@ ScalableValueBoundsConstraintSet::computeScalableBound(
4747
unsigned vscaleMax, presburger::BoundType boundType, bool closedUB,
4848
StopConditionFn stopCondition) {
4949
using namespace presburger;
50-
5150
assert(vscaleMin <= vscaleMax);
52-
ScalableValueBoundsConstraintSet scalableCstr(value.getContext(), vscaleMin,
53-
vscaleMax);
5451

55-
int64_t pos = scalableCstr.populateConstraintsSet(value, dim, stopCondition);
52+
// No stop condition specified: Keep adding constraints until the worklist
53+
// is empty.
54+
auto defaultStopCondition = [&](Value v, std::optional<int64_t> dim,
55+
mlir::ValueBoundsConstraintSet &cstr) {
56+
return false;
57+
};
58+
59+
ScalableValueBoundsConstraintSet scalableCstr(
60+
value.getContext(), stopCondition ? stopCondition : defaultStopCondition,
61+
vscaleMin, vscaleMax);
62+
int64_t pos = scalableCstr.populateConstraintsSet(value, dim);
5663

5764
// Project out all variables apart from vscale.
5865
// This should result in constraints in terms of vscale only.
59-
scalableCstr.projectOut(
60-
[&](ValueDim p) { return p.first != scalableCstr.getVscaleValue(); });
66+
auto projectOutFn = [&](ValueDim p) {
67+
return p.first != scalableCstr.getVscaleValue();
68+
};
69+
scalableCstr.projectOut(projectOutFn);
6170

6271
assert(scalableCstr.cstr.getNumDimAndSymbolVars() ==
6372
scalableCstr.positionToValueDim.size() &&

mlir/lib/Interfaces/ValueBoundsOpInterface.cpp

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ static std::optional<int64_t> getConstantIntValue(OpFoldResult ofr) {
6767
return std::nullopt;
6868
}
6969

70-
ValueBoundsConstraintSet::ValueBoundsConstraintSet(MLIRContext *ctx)
71-
: builder(ctx) {}
70+
ValueBoundsConstraintSet::ValueBoundsConstraintSet(
71+
MLIRContext *ctx, StopConditionFn stopCondition)
72+
: builder(ctx), stopCondition(stopCondition) {
73+
assert(stopCondition && "expected non-null stop condition");
74+
}
7275

7376
char ValueBoundsConstraintSet::ID = 0;
7477

@@ -230,7 +233,8 @@ static Operation *getOwnerOfValue(Value value) {
230233
return value.getDefiningOp();
231234
}
232235

233-
void ValueBoundsConstraintSet::processWorklist(StopConditionFn stopCondition) {
236+
void ValueBoundsConstraintSet::processWorklist() {
237+
LLVM_DEBUG(llvm::dbgs() << "Processing value bounds worklist...\n");
234238
while (!worklist.empty()) {
235239
int64_t pos = worklist.front();
236240
worklist.pop();
@@ -251,13 +255,19 @@ void ValueBoundsConstraintSet::processWorklist(StopConditionFn stopCondition) {
251255

252256
// Do not process any further if the stop condition is met.
253257
auto maybeDim = dim == kIndexValue ? std::nullopt : std::make_optional(dim);
254-
if (stopCondition(value, maybeDim))
258+
if (stopCondition(value, maybeDim, *this)) {
259+
LLVM_DEBUG(llvm::dbgs() << "Stop condition met for: " << value
260+
<< " (dim: " << maybeDim << ")\n");
255261
continue;
262+
}
256263

257264
// Query `ValueBoundsOpInterface` for constraints. New items may be added to
258265
// the worklist.
259266
auto valueBoundsOp =
260267
dyn_cast<ValueBoundsOpInterface>(getOwnerOfValue(value));
268+
LLVM_DEBUG(llvm::dbgs()
269+
<< "Query value bounds for: " << value
270+
<< " (owner: " << getOwnerOfValue(value)->getName() << ")\n");
261271
if (valueBoundsOp) {
262272
if (dim == kIndexValue) {
263273
valueBoundsOp.populateBoundsForIndexValue(value, *this);
@@ -266,6 +276,7 @@ void ValueBoundsConstraintSet::processWorklist(StopConditionFn stopCondition) {
266276
}
267277
continue;
268278
}
279+
LLVM_DEBUG(llvm::dbgs() << "--> ValueBoundsOpInterface not implemented\n");
269280

270281
// If the op does not implement `ValueBoundsOpInterface`, check if it
271282
// implements the `DestinationStyleOpInterface`. OpResults of such ops are
@@ -315,8 +326,6 @@ LogicalResult ValueBoundsConstraintSet::computeBound(
315326
bool closedUB) {
316327
#ifndef NDEBUG
317328
assertValidValueDim(value, dim);
318-
assert(!stopCondition(value, dim) &&
319-
"stop condition should not be satisfied for starting point");
320329
#endif // NDEBUG
321330

322331
int64_t ubAdjustment = closedUB ? 0 : 1;
@@ -326,9 +335,11 @@ LogicalResult ValueBoundsConstraintSet::computeBound(
326335
// Process the backward slice of `value` (i.e., reverse use-def chain) until
327336
// `stopCondition` is met.
328337
ValueDim valueDim = std::make_pair(value, dim.value_or(kIndexValue));
329-
ValueBoundsConstraintSet cstr(value.getContext());
338+
ValueBoundsConstraintSet cstr(value.getContext(), stopCondition);
339+
assert(!stopCondition(value, dim, cstr) &&
340+
"stop condition should not be satisfied for starting point");
330341
int64_t pos = cstr.insert(value, dim, /*isSymbol=*/false);
331-
cstr.processWorklist(stopCondition);
342+
cstr.processWorklist();
332343

333344
// Project out all variables (apart from `valueDim`) that do not match the
334345
// stop condition.
@@ -338,7 +349,7 @@ LogicalResult ValueBoundsConstraintSet::computeBound(
338349
return false;
339350
auto maybeDim =
340351
p.second == kIndexValue ? std::nullopt : std::make_optional(p.second);
341-
return !stopCondition(p.first, maybeDim);
352+
return !stopCondition(p.first, maybeDim, cstr);
342353
});
343354

344355
// Compute lower and upper bounds for `valueDim`.
@@ -444,7 +455,7 @@ LogicalResult ValueBoundsConstraintSet::computeDependentBound(
444455
bool closedUB) {
445456
return computeBound(
446457
resultMap, mapOperands, type, value, dim,
447-
[&](Value v, std::optional<int64_t> d) {
458+
[&](Value v, std::optional<int64_t> d, ValueBoundsConstraintSet &cstr) {
448459
return llvm::is_contained(dependencies, std::make_pair(v, d));
449460
},
450461
closedUB);
@@ -480,7 +491,9 @@ LogicalResult ValueBoundsConstraintSet::computeIndependentBound(
480491
// Reify bounds in terms of any independent values.
481492
return computeBound(
482493
resultMap, mapOperands, type, value, dim,
483-
[&](Value v, std::optional<int64_t> d) { return isIndependent(v); },
494+
[&](Value v, std::optional<int64_t> d, ValueBoundsConstraintSet &cstr) {
495+
return isIndependent(v);
496+
},
484497
closedUB);
485498
}
486499

@@ -513,43 +526,42 @@ FailureOr<int64_t> ValueBoundsConstraintSet::computeConstantBound(
513526
presburger::BoundType type, AffineMap map, ValueDimList operands,
514527
StopConditionFn stopCondition, bool closedUB) {
515528
assert(map.getNumResults() == 1 && "expected affine map with one result");
516-
ValueBoundsConstraintSet cstr(map.getContext());
517529

518-
int64_t pos = 0;
519-
if (stopCondition) {
520-
cstr.populateConstraintsSet(map, operands, stopCondition, &pos);
521-
} else {
522-
// No stop condition specified: Keep adding constraints until a bound could
523-
// be computed.
524-
cstr.populateConstraintsSet(
525-
map, operands,
526-
[&](Value v, std::optional<int64_t> dim) {
527-
return cstr.cstr.getConstantBound64(type, pos).has_value();
528-
},
529-
&pos);
530-
}
530+
// Default stop condition if none was specified: Keep adding constraints until
531+
// a bound could be computed.
532+
int64_t pos;
533+
auto defaultStopCondition = [&](Value v, std::optional<int64_t> dim,
534+
ValueBoundsConstraintSet &cstr) {
535+
return cstr.cstr.getConstantBound64(type, pos).has_value();
536+
};
537+
538+
ValueBoundsConstraintSet cstr(
539+
map.getContext(), stopCondition ? stopCondition : defaultStopCondition);
540+
cstr.populateConstraintsSet(map, operands, &pos);
541+
531542
// Compute constant bound for `valueDim`.
532543
int64_t ubAdjustment = closedUB ? 0 : 1;
533544
if (auto bound = cstr.cstr.getConstantBound64(type, pos))
534545
return type == BoundType::UB ? *bound + ubAdjustment : *bound;
535546
return failure();
536547
}
537548

538-
int64_t ValueBoundsConstraintSet::populateConstraintsSet(
539-
Value value, std::optional<int64_t> dim, StopConditionFn stopCondition) {
549+
int64_t
550+
ValueBoundsConstraintSet::populateConstraintsSet(Value value,
551+
std::optional<int64_t> dim) {
540552
#ifndef NDEBUG
541553
assertValidValueDim(value, dim);
542554
#endif // NDEBUG
543555

544556
AffineMap map =
545557
AffineMap::get(/*dimCount=*/1, /*symbolCount=*/0,
546558
Builder(value.getContext()).getAffineDimExpr(0));
547-
return populateConstraintsSet(map, {{value, dim}}, stopCondition);
559+
return populateConstraintsSet(map, {{value, dim}});
548560
}
549561

550-
int64_t ValueBoundsConstraintSet::populateConstraintsSet(
551-
AffineMap map, ValueDimList operands, StopConditionFn stopCondition,
552-
int64_t *posOut) {
562+
int64_t ValueBoundsConstraintSet::populateConstraintsSet(AffineMap map,
563+
ValueDimList operands,
564+
int64_t *posOut) {
553565
assert(map.getNumResults() == 1 && "expected affine map with one result");
554566
int64_t pos = insert(/*isSymbol=*/false);
555567
if (posOut)
@@ -570,13 +582,7 @@ int64_t ValueBoundsConstraintSet::populateConstraintsSet(
570582

571583
// Process the backward slice of `operands` (i.e., reverse use-def chain)
572584
// until `stopCondition` is met.
573-
if (stopCondition) {
574-
processWorklist(stopCondition);
575-
} else {
576-
// No stop condition specified: Keep adding constraints until the worklist
577-
// is empty.
578-
processWorklist([](Value v, std::optional<int64_t> dim) { return false; });
579-
}
585+
processWorklist();
580586

581587
return pos;
582588
}

mlir/test/lib/Dialect/Affine/TestReifyValueBounds.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,17 @@ static LogicalResult testReifyValueBounds(func::FuncOp funcOp,
117117

118118
// Prepare stop condition. By default, reify in terms of the op's
119119
// operands. No stop condition is used when a constant was requested.
120-
std::function<bool(Value, std::optional<int64_t>)> stopCondition =
121-
[&](Value v, std::optional<int64_t> d) {
120+
std::function<bool(Value, std::optional<int64_t>,
121+
ValueBoundsConstraintSet & cstr)>
122+
stopCondition = [&](Value v, std::optional<int64_t> d,
123+
ValueBoundsConstraintSet &cstr) {
122124
// Reify in terms of SSA values that are different from `value`.
123125
return v != value;
124126
};
125127
if (reifyToFuncArgs) {
126128
// Reify in terms of function block arguments.
127-
stopCondition = stopCondition = [](Value v, std::optional<int64_t> d) {
129+
stopCondition = [](Value v, std::optional<int64_t> d,
130+
ValueBoundsConstraintSet &cstr) {
128131
auto bbArg = dyn_cast<BlockArgument>(v);
129132
if (!bbArg)
130133
return false;

0 commit comments

Comments
 (0)