@@ -220,6 +220,11 @@ static cl::opt<unsigned>
220
220
cl::desc("Size of the expression which is considered huge"),
221
221
cl::init(4096));
222
222
223
+ static cl::opt<unsigned> RangeIterThreshold(
224
+ "scev-range-iter-threshold", cl::Hidden,
225
+ cl::desc("Threshold for switching to iteratively computing SCEV ranges"),
226
+ cl::init(32));
227
+
223
228
static cl::opt<bool>
224
229
ClassifyExpressions("scalar-evolution-classify-expressions",
225
230
cl::Hidden, cl::init(true),
@@ -6425,18 +6430,78 @@ getRangeForUnknownRecurrence(const SCEVUnknown *U) {
6425
6430
return FullSet;
6426
6431
}
6427
6432
6433
+ const ConstantRange &
6434
+ ScalarEvolution::getRangeRefIter(const SCEV *S,
6435
+ ScalarEvolution::RangeSignHint SignHint) {
6436
+ DenseMap<const SCEV *, ConstantRange> &Cache =
6437
+ SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED ? UnsignedRanges
6438
+ : SignedRanges;
6439
+ SmallVector<const SCEV *> WorkList;
6440
+ SmallPtrSet<const SCEV *, 8> Seen;
6441
+
6442
+ // Add Expr to the worklist, if Expr is either an N-ary expression or a
6443
+ // SCEVUnknown PHI node.
6444
+ auto AddToWorklist = [&WorkList, &Seen, &Cache](const SCEV *Expr) {
6445
+ if (!Seen.insert(Expr).second)
6446
+ return;
6447
+ if (Cache.find(Expr) != Cache.end())
6448
+ return;
6449
+ if (isa<SCEVNAryExpr>(Expr) || isa<SCEVUDivExpr>(Expr))
6450
+ WorkList.push_back(Expr);
6451
+ else if (auto *UnknownS = dyn_cast<SCEVUnknown>(Expr))
6452
+ if (isa<PHINode>(UnknownS->getValue()))
6453
+ WorkList.push_back(Expr);
6454
+ };
6455
+ AddToWorklist(S);
6456
+
6457
+ // Build worklist by queuing operands of N-ary expressions and phi nodes.
6458
+ for (unsigned I = 0; I != WorkList.size(); ++I) {
6459
+ const SCEV *P = WorkList[I];
6460
+ if (auto *NaryS = dyn_cast<SCEVNAryExpr>(P)) {
6461
+ for (const SCEV *Op : NaryS->operands())
6462
+ AddToWorklist(Op);
6463
+ } else if (auto *UDiv = dyn_cast<SCEVUDivExpr>(P)) {
6464
+ AddToWorklist(UDiv->getLHS());
6465
+ AddToWorklist(UDiv->getRHS());
6466
+ } else {
6467
+ auto *UnknownS = cast<SCEVUnknown>(P);
6468
+ if (const PHINode *P = dyn_cast<PHINode>(UnknownS->getValue())) {
6469
+ if (!PendingPhiRangesIter.insert(P).second)
6470
+ continue;
6471
+ for (auto &Op : reverse(P->operands()))
6472
+ AddToWorklist(getSCEV(Op));
6473
+ }
6474
+ }
6475
+ }
6476
+
6477
+ if (!WorkList.empty()) {
6478
+ // Use getRangeRef to compute ranges for items in the worklist in reverse
6479
+ // order. This will force ranges for earlier operands to be computed before
6480
+ // their users in most cases.
6481
+ for (const SCEV *P :
6482
+ reverse(make_range(WorkList.begin() + 1, WorkList.end()))) {
6483
+ getRangeRef(P, SignHint);
6484
+
6485
+ if (auto *UnknownS = dyn_cast<SCEVUnknown>(P))
6486
+ if (const PHINode *P = dyn_cast<PHINode>(UnknownS->getValue()))
6487
+ PendingPhiRangesIter.erase(P);
6488
+ }
6489
+ }
6490
+
6491
+ return getRangeRef(S, SignHint, 0);
6492
+ }
6493
+
6428
6494
/// Determine the range for a particular SCEV. If SignHint is
6429
6495
/// HINT_RANGE_UNSIGNED (resp. HINT_RANGE_SIGNED) then getRange prefers ranges
6430
6496
/// with a "cleaner" unsigned (resp. signed) representation.
6431
- const ConstantRange &
6432
- ScalarEvolution::getRangeRef(const SCEV *S,
6433
- ScalarEvolution::RangeSignHint SignHint) {
6497
+ const ConstantRange &ScalarEvolution::getRangeRef(
6498
+ const SCEV *S, ScalarEvolution::RangeSignHint SignHint, unsigned Depth) {
6434
6499
DenseMap<const SCEV *, ConstantRange> &Cache =
6435
6500
SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED ? UnsignedRanges
6436
6501
: SignedRanges;
6437
6502
ConstantRange::PreferredRangeType RangeType =
6438
- SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED
6439
- ? ConstantRange::Unsigned : ConstantRange::Signed;
6503
+ SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED ? ConstantRange::Unsigned
6504
+ : ConstantRange::Signed;
6440
6505
6441
6506
// See if we've computed this range already.
6442
6507
DenseMap<const SCEV *, ConstantRange>::iterator I = Cache.find(S);
@@ -6446,6 +6511,11 @@ ScalarEvolution::getRangeRef(const SCEV *S,
6446
6511
if (const SCEVConstant *C = dyn_cast<SCEVConstant>(S))
6447
6512
return setRange(C, SignHint, ConstantRange(C->getAPInt()));
6448
6513
6514
+ // Switch to iteratively computing the range for S, if it is part of a deeply
6515
+ // nested expression.
6516
+ if (Depth > RangeIterThreshold)
6517
+ return getRangeRefIter(S, SignHint);
6518
+
6449
6519
unsigned BitWidth = getTypeSizeInBits(S->getType());
6450
6520
ConstantRange ConservativeResult(BitWidth, /*isFullSet=*/true);
6451
6521
using OBO = OverflowingBinaryOperator;
@@ -6465,23 +6535,23 @@ ScalarEvolution::getRangeRef(const SCEV *S,
6465
6535
}
6466
6536
6467
6537
if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(S)) {
6468
- ConstantRange X = getRangeRef(Add->getOperand(0), SignHint);
6538
+ ConstantRange X = getRangeRef(Add->getOperand(0), SignHint, Depth + 1 );
6469
6539
unsigned WrapType = OBO::AnyWrap;
6470
6540
if (Add->hasNoSignedWrap())
6471
6541
WrapType |= OBO::NoSignedWrap;
6472
6542
if (Add->hasNoUnsignedWrap())
6473
6543
WrapType |= OBO::NoUnsignedWrap;
6474
6544
for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i)
6475
- X = X.addWithNoWrap(getRangeRef(Add->getOperand(i), SignHint),
6545
+ X = X.addWithNoWrap(getRangeRef(Add->getOperand(i), SignHint, Depth + 1 ),
6476
6546
WrapType, RangeType);
6477
6547
return setRange(Add, SignHint,
6478
6548
ConservativeResult.intersectWith(X, RangeType));
6479
6549
}
6480
6550
6481
6551
if (const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(S)) {
6482
- ConstantRange X = getRangeRef(Mul->getOperand(0), SignHint);
6552
+ ConstantRange X = getRangeRef(Mul->getOperand(0), SignHint, Depth + 1 );
6483
6553
for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i)
6484
- X = X.multiply(getRangeRef(Mul->getOperand(i), SignHint));
6554
+ X = X.multiply(getRangeRef(Mul->getOperand(i), SignHint, Depth + 1 ));
6485
6555
return setRange(Mul, SignHint,
6486
6556
ConservativeResult.intersectWith(X, RangeType));
6487
6557
}
@@ -6507,41 +6577,42 @@ ScalarEvolution::getRangeRef(const SCEV *S,
6507
6577
}
6508
6578
6509
6579
const auto *NAry = cast<SCEVNAryExpr>(S);
6510
- ConstantRange X = getRangeRef(NAry->getOperand(0), SignHint);
6580
+ ConstantRange X = getRangeRef(NAry->getOperand(0), SignHint, Depth + 1 );
6511
6581
for (unsigned i = 1, e = NAry->getNumOperands(); i != e; ++i)
6512
- X = X.intrinsic(ID, {X, getRangeRef(NAry->getOperand(i), SignHint)});
6582
+ X = X.intrinsic(
6583
+ ID, {X, getRangeRef(NAry->getOperand(i), SignHint, Depth + 1)});
6513
6584
return setRange(S, SignHint,
6514
6585
ConservativeResult.intersectWith(X, RangeType));
6515
6586
}
6516
6587
6517
6588
if (const SCEVUDivExpr *UDiv = dyn_cast<SCEVUDivExpr>(S)) {
6518
- ConstantRange X = getRangeRef(UDiv->getLHS(), SignHint);
6519
- ConstantRange Y = getRangeRef(UDiv->getRHS(), SignHint);
6589
+ ConstantRange X = getRangeRef(UDiv->getLHS(), SignHint, Depth + 1 );
6590
+ ConstantRange Y = getRangeRef(UDiv->getRHS(), SignHint, Depth + 1 );
6520
6591
return setRange(UDiv, SignHint,
6521
6592
ConservativeResult.intersectWith(X.udiv(Y), RangeType));
6522
6593
}
6523
6594
6524
6595
if (const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(S)) {
6525
- ConstantRange X = getRangeRef(ZExt->getOperand(), SignHint);
6596
+ ConstantRange X = getRangeRef(ZExt->getOperand(), SignHint, Depth + 1 );
6526
6597
return setRange(ZExt, SignHint,
6527
6598
ConservativeResult.intersectWith(X.zeroExtend(BitWidth),
6528
6599
RangeType));
6529
6600
}
6530
6601
6531
6602
if (const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(S)) {
6532
- ConstantRange X = getRangeRef(SExt->getOperand(), SignHint);
6603
+ ConstantRange X = getRangeRef(SExt->getOperand(), SignHint, Depth + 1 );
6533
6604
return setRange(SExt, SignHint,
6534
6605
ConservativeResult.intersectWith(X.signExtend(BitWidth),
6535
6606
RangeType));
6536
6607
}
6537
6608
6538
6609
if (const SCEVPtrToIntExpr *PtrToInt = dyn_cast<SCEVPtrToIntExpr>(S)) {
6539
- ConstantRange X = getRangeRef(PtrToInt->getOperand(), SignHint);
6610
+ ConstantRange X = getRangeRef(PtrToInt->getOperand(), SignHint, Depth + 1 );
6540
6611
return setRange(PtrToInt, SignHint, X);
6541
6612
}
6542
6613
6543
6614
if (const SCEVTruncateExpr *Trunc = dyn_cast<SCEVTruncateExpr>(S)) {
6544
- ConstantRange X = getRangeRef(Trunc->getOperand(), SignHint);
6615
+ ConstantRange X = getRangeRef(Trunc->getOperand(), SignHint, Depth + 1 );
6545
6616
return setRange(Trunc, SignHint,
6546
6617
ConservativeResult.intersectWith(X.truncate(BitWidth),
6547
6618
RangeType));
@@ -6671,12 +6742,13 @@ ScalarEvolution::getRangeRef(const SCEV *S,
6671
6742
RangeType);
6672
6743
6673
6744
// A range of Phi is a subset of union of all ranges of its input.
6674
- if (const PHINode *Phi = dyn_cast<PHINode>(U->getValue())) {
6745
+ if (PHINode *Phi = dyn_cast<PHINode>(U->getValue())) {
6675
6746
// Make sure that we do not run over cycled Phis.
6676
6747
if (PendingPhiRanges.insert(Phi).second) {
6677
6748
ConstantRange RangeFromOps(BitWidth, /*isFullSet=*/false);
6749
+
6678
6750
for (const auto &Op : Phi->operands()) {
6679
- auto OpRange = getRangeRef(getSCEV(Op), SignHint);
6751
+ auto OpRange = getRangeRef(getSCEV(Op), SignHint, Depth + 1 );
6680
6752
RangeFromOps = RangeFromOps.unionWith(OpRange);
6681
6753
// No point to continue if we already have a full set.
6682
6754
if (RangeFromOps.isFullSet())
0 commit comments