@@ -110,47 +110,25 @@ AffineExpr ValueBoundsConstraintSet::getExpr(Value value,
110
110
assertValidValueDim (value, dim);
111
111
#endif // NDEBUG
112
112
113
- // Check if the value/dim is statically known. In that case, an affine
114
- // constant expression should be returned. This allows us to support
115
- // multiplications with constants. (Multiplications of two columns in the
116
- // constraint set is not supported.)
117
- std::optional<int64_t > constSize = std::nullopt;
118
113
auto shapedType = dyn_cast<ShapedType>(value.getType ());
119
114
if (shapedType) {
115
+ // Static dimension: return constant directly.
120
116
if (shapedType.hasRank () && !shapedType.isDynamicDim (*dim))
121
- constSize = shapedType.getDimSize (*dim);
122
- } else if (auto constInt = ::getConstantIntValue (value)) {
123
- constSize = *constInt;
117
+ return builder.getAffineConstantExpr (shapedType.getDimSize (*dim));
118
+ } else {
119
+ // Constant index value: return directly.
120
+ if (auto constInt = ::getConstantIntValue (value))
121
+ return builder.getAffineConstantExpr (*constInt);
124
122
}
125
123
126
- // If the value/dim is already mapped, return the corresponding expression
127
- // directly.
124
+ // Dynamic value: add to constraint set.
128
125
ValueDim valueDim = std::make_pair (value, dim.value_or (kIndexValue ));
129
- if (valueDimToPosition.contains (valueDim)) {
130
- // If it is a constant, return an affine constant expression. Otherwise,
131
- // return an affine expression that represents the respective column in the
132
- // constraint set.
133
- if (constSize)
134
- return builder.getAffineConstantExpr (*constSize);
135
- return getPosExpr (getPos (value, dim));
136
- }
137
-
138
- if (constSize) {
139
- // Constant index value/dim: add column to the constraint set, add EQ bound
140
- // and return an affine constant expression without pushing the newly added
141
- // column to the worklist.
142
- (void )insert (value, dim, /* isSymbol=*/ true , /* addToWorklist=*/ false );
143
- if (shapedType)
144
- bound (value)[*dim] == *constSize;
145
- else
146
- bound (value) == *constSize;
147
- return builder.getAffineConstantExpr (*constSize);
148
- }
149
-
150
- // Dynamic value/dim: insert column to the constraint set and put it on the
151
- // worklist. Return an affine expression that represents the newly inserted
152
- // column in the constraint set.
153
- return getPosExpr (insert (value, dim, /* isSymbol=*/ true ));
126
+ if (!valueDimToPosition.contains (valueDim))
127
+ (void )insert (value, dim);
128
+ int64_t pos = getPos (value, dim);
129
+ return pos < cstr.getNumDimVars ()
130
+ ? builder.getAffineDimExpr (pos)
131
+ : builder.getAffineSymbolExpr (pos - cstr.getNumDimVars ());
154
132
}
155
133
156
134
AffineExpr ValueBoundsConstraintSet::getExpr (OpFoldResult ofr) {
@@ -167,7 +145,7 @@ AffineExpr ValueBoundsConstraintSet::getExpr(int64_t constant) {
167
145
168
146
int64_t ValueBoundsConstraintSet::insert (Value value,
169
147
std::optional<int64_t > dim,
170
- bool isSymbol, bool addToWorklist ) {
148
+ bool isSymbol) {
171
149
#ifndef NDEBUG
172
150
assertValidValueDim (value, dim);
173
151
#endif // NDEBUG
@@ -182,12 +160,7 @@ int64_t ValueBoundsConstraintSet::insert(Value value,
182
160
if (positionToValueDim[i].has_value ())
183
161
valueDimToPosition[*positionToValueDim[i]] = i;
184
162
185
- if (addToWorklist) {
186
- LLVM_DEBUG (llvm::dbgs () << " Push to worklist: " << value
187
- << " (dim: " << dim.value_or (kIndexValue ) << " )\n " );
188
- worklist.push (pos);
189
- }
190
-
163
+ worklist.push (pos);
191
164
return pos;
192
165
}
193
166
@@ -217,13 +190,6 @@ int64_t ValueBoundsConstraintSet::getPos(Value value,
217
190
return it->second ;
218
191
}
219
192
220
- AffineExpr ValueBoundsConstraintSet::getPosExpr (int64_t pos) {
221
- assert (pos >= 0 && pos < cstr.getNumDimAndSymbolVars () && " invalid position" );
222
- return pos < cstr.getNumDimVars ()
223
- ? builder.getAffineDimExpr (pos)
224
- : builder.getAffineSymbolExpr (pos - cstr.getNumDimVars ());
225
- }
226
-
227
193
static Operation *getOwnerOfValue (Value value) {
228
194
if (auto bbArg = dyn_cast<BlockArgument>(value))
229
195
return bbArg.getOwner ()->getParentOp ();
@@ -526,16 +492,15 @@ FailureOr<int64_t> ValueBoundsConstraintSet::computeConstantBound(
526
492
527
493
// Default stop condition if none was specified: Keep adding constraints until
528
494
// a bound could be computed.
529
- int64_t pos = 0 ;
495
+ int64_t pos;
530
496
auto defaultStopCondition = [&](Value v, std::optional<int64_t > dim,
531
497
ValueBoundsConstraintSet &cstr) {
532
498
return cstr.cstr .getConstantBound64 (type, pos).has_value ();
533
499
};
534
500
535
501
ValueBoundsConstraintSet cstr (
536
502
map.getContext (), stopCondition ? stopCondition : defaultStopCondition);
537
- pos = cstr.populateConstraints (map, operands);
538
- assert (pos == 0 && " expected `map` is the first column" );
503
+ cstr.populateConstraintsSet (map, operands, &pos);
539
504
540
505
// Compute constant bound for `valueDim`.
541
506
int64_t ubAdjustment = closedUB ? 0 : 1 ;
@@ -544,28 +509,29 @@ FailureOr<int64_t> ValueBoundsConstraintSet::computeConstantBound(
544
509
return failure ();
545
510
}
546
511
547
- void ValueBoundsConstraintSet::populateConstraints (Value value,
548
- std::optional<int64_t > dim) {
512
+ int64_t
513
+ ValueBoundsConstraintSet::populateConstraintsSet (Value value,
514
+ std::optional<int64_t > dim) {
549
515
#ifndef NDEBUG
550
516
assertValidValueDim (value, dim);
551
517
#endif // NDEBUG
552
518
553
- // `getExpr` pushes the value/dim onto the worklist (unless it was already
554
- // analyzed).
555
- (void )getExpr (value, dim);
556
- // Process all values/dims on the worklist. This may traverse and analyze
557
- // additional IR, depending the current stop function.
558
- processWorklist ();
519
+ AffineMap map =
520
+ AffineMap::get (/* dimCount=*/ 1 , /* symbolCount=*/ 0 ,
521
+ Builder (value.getContext ()).getAffineDimExpr (0 ));
522
+ return populateConstraintsSet (map, {{value, dim}});
559
523
}
560
524
561
- int64_t ValueBoundsConstraintSet::populateConstraints (AffineMap map,
562
- ValueDimList operands) {
525
+ int64_t ValueBoundsConstraintSet::populateConstraintsSet (AffineMap map,
526
+ ValueDimList operands,
527
+ int64_t *posOut) {
563
528
assert (map.getNumResults () == 1 && " expected affine map with one result" );
564
529
int64_t pos = insert (/* isSymbol=*/ false );
530
+ if (posOut)
531
+ *posOut = pos;
565
532
566
533
// Add map and operands to the constraint set. Dimensions are converted to
567
- // symbols. All operands are added to the worklist (unless they were already
568
- // processed).
534
+ // symbols. All operands are added to the worklist.
569
535
auto mapper = [&](std::pair<Value, std::optional<int64_t >> v) {
570
536
return getExpr (v.first , v.second );
571
537
};
@@ -600,55 +566,6 @@ ValueBoundsConstraintSet::computeConstantDelta(Value value1, Value value2,
600
566
{{value1, dim1}, {value2, dim2}});
601
567
}
602
568
603
- bool ValueBoundsConstraintSet::compare (Value lhs, std::optional<int64_t > lhsDim,
604
- ComparisonOperator cmp, Value rhs,
605
- std::optional<int64_t > rhsDim) {
606
- // This function returns "true" if "lhs CMP rhs" is proven to hold.
607
- //
608
- // Example for ComparisonOperator::LE and index-typed values: We would like to
609
- // prove that lhs <= rhs. Proof by contradiction: add the inverse
610
- // relation (lhs > rhs) to the constraint set and check if the resulting
611
- // constraint set is "empty" (i.e. has no solution). In that case,
612
- // lhs > rhs must be incorrect and we can deduce that lhs <= rhs holds.
613
-
614
- // We cannot prove anything if the constraint set is already empty.
615
- if (cstr.isEmpty ()) {
616
- LLVM_DEBUG (
617
- llvm::dbgs ()
618
- << " cannot compare value/dims: constraint system is already empty" );
619
- return false ;
620
- }
621
-
622
- // EQ can be expressed as LE and GE.
623
- if (cmp == EQ)
624
- return compare (lhs, lhsDim, ComparisonOperator::LE, rhs, rhsDim) &&
625
- compare (lhs, lhsDim, ComparisonOperator::GE, rhs, rhsDim);
626
-
627
- // Construct inequality. For the above example: lhs > rhs.
628
- // `IntegerRelation` inequalities are expressed in the "flattened" form and
629
- // with ">= 0". I.e., lhs - rhs - 1 >= 0.
630
- SmallVector<int64_t > eq (cstr.getNumDimAndSymbolVars () + 1 , 0 );
631
- if (cmp == LT || cmp == LE) {
632
- ++eq[getPos (lhs, lhsDim)];
633
- --eq[getPos (rhs, rhsDim)];
634
- } else if (cmp == GT || cmp == GE) {
635
- --eq[getPos (lhs, lhsDim)];
636
- ++eq[getPos (rhs, rhsDim)];
637
- } else {
638
- llvm_unreachable (" unsupported comparison operator" );
639
- }
640
- if (cmp == LE || cmp == GE)
641
- eq[cstr.getNumDimAndSymbolVars ()] -= 1 ;
642
-
643
- // Add inequality to the constraint set and check if it made the constraint
644
- // set empty.
645
- int64_t ineqPos = cstr.getNumInequalities ();
646
- cstr.addInequality (eq);
647
- bool isEmpty = cstr.isEmpty ();
648
- cstr.removeInequality (ineqPos);
649
- return isEmpty;
650
- }
651
-
652
569
FailureOr<bool >
653
570
ValueBoundsConstraintSet::areEqual (Value value1, Value value2,
654
571
std::optional<int64_t > dim1,
0 commit comments