Skip to content

Commit 0bdd99f

Browse files
committed
wip
1 parent 90d1d23 commit 0bdd99f

21 files changed

+163
-146
lines changed

llvm/include/llvm/Analysis/ScalarEvolution.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,10 +1776,11 @@ class ScalarEvolution {
17761776
/// operands iteratively first.
17771777
const ConstantRange &getRangeRefIter(const SCEV *S, RangeSignHint Hint);
17781778

1779-
/// Determines the range for the affine SCEVAddRecExpr {\p Start,+,\p Step}.
1780-
/// Helper for \c getRange.
1781-
ConstantRange getRangeForAffineAR(const SCEV *Start, const SCEV *Step,
1782-
const APInt &MaxBECount);
1779+
/// Determines the range for the affine SCEVAddRecExpr {\p Start,+,\p Step},
1780+
/// and whether it may wrap. Helper for \c getRange.
1781+
std::pair<ConstantRange, SCEV::NoWrapFlags>
1782+
getRangeForAffineAR(const SCEV *Start, const SCEV *Step,
1783+
const APInt &MaxBECount);
17831784

17841785
/// Determines the range for the affine non-self-wrapping SCEVAddRecExpr {\p
17851786
/// Start,+,\p Step}<nw>.

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6799,10 +6799,11 @@ const ConstantRange &ScalarEvolution::getRangeRef(
67996799
MaxBECount = MaxBECount.zext(BitWidth);
68006800

68016801
if (MaxBECount.getBitWidth() == BitWidth) {
6802-
auto RangeFromAffine = getRangeForAffineAR(
6802+
auto [RangeFromAffine, Flags] = getRangeForAffineAR(
68036803
AddRec->getStart(), AddRec->getStepRecurrence(*this), MaxBECount);
68046804
ConservativeResult =
68056805
ConservativeResult.intersectWith(RangeFromAffine, RangeType);
6806+
const_cast<SCEVAddRecExpr *>(AddRec)->setNoWrapFlags(Flags);
68066807

68076808
auto RangeFromFactoring = getRangeViaFactoring(
68086809
AddRec->getStart(), AddRec->getStepRecurrence(*this), MaxBECount);
@@ -6978,24 +6979,24 @@ const ConstantRange &ScalarEvolution::getRangeRef(
69786979
// Given a StartRange, Step and MaxBECount for an expression compute a range of
69796980
// values that the expression can take. Initially, the expression has a value
69806981
// from StartRange and then is changed by Step up to MaxBECount times. Signed
6981-
// argument defines if we treat Step as signed or unsigned.
6982-
static ConstantRange getRangeForAffineARHelper(APInt Step,
6983-
const ConstantRange &StartRange,
6984-
const APInt &MaxBECount,
6985-
bool Signed) {
6982+
// argument defines if we treat Step as signed or unsigned. The second return
6983+
// value indicates that no wrapping occurred.
6984+
static std::pair<ConstantRange, bool>
6985+
getRangeForAffineARHelper(APInt Step, const ConstantRange &StartRange,
6986+
const APInt &MaxBECount, bool Signed) {
69866987
unsigned BitWidth = Step.getBitWidth();
69876988
assert(BitWidth == StartRange.getBitWidth() &&
69886989
BitWidth == MaxBECount.getBitWidth() && "mismatched bit widths");
69896990
// If either Step or MaxBECount is 0, then the expression won't change, and we
69906991
// just need to return the initial range.
69916992
if (Step == 0 || MaxBECount == 0)
6992-
return StartRange;
6993+
return {StartRange, true};
69936994

69946995
// If we don't know anything about the initial value (i.e. StartRange is
69956996
// FullRange), then we don't know anything about the final range either.
69966997
// Return FullRange.
69976998
if (StartRange.isFullSet())
6998-
return ConstantRange::getFull(BitWidth);
6999+
return {ConstantRange::getFull(BitWidth), false};
69997000

70007001
// If Step is signed and negative, then we use its absolute value, but we also
70017002
// note that we're moving in the opposite direction.
@@ -7011,7 +7012,7 @@ static ConstantRange getRangeForAffineARHelper(APInt Step,
70117012
// Check if Offset is more than full span of BitWidth. If it is, the
70127013
// expression is guaranteed to overflow.
70137014
if (APInt::getMaxValue(StartRange.getBitWidth()).udiv(Step).ult(MaxBECount))
7014-
return ConstantRange::getFull(BitWidth);
7015+
return {ConstantRange::getFull(BitWidth), false};
70157016

70167017
// Offset is by how much the expression can change. Checks above guarantee no
70177018
// overflow here.
@@ -7023,14 +7024,21 @@ static ConstantRange getRangeForAffineARHelper(APInt Step,
70237024
// if the expression is decreasing and will be increased by Offset otherwise.
70247025
APInt StartLower = StartRange.getLower();
70257026
APInt StartUpper = StartRange.getUpper() - 1;
7026-
APInt MovedBoundary = Descending ? (StartLower - std::move(Offset))
7027-
: (StartUpper + std::move(Offset));
7027+
bool Overflow;
7028+
APInt MovedBoundary;
7029+
if (Signed) {
7030+
MovedBoundary = Descending ? StartLower.ssub_ov(Offset, Overflow)
7031+
: StartUpper.sadd_ov(Offset, Overflow);
7032+
Overflow |= Offset.isNegative();
7033+
} else {
7034+
MovedBoundary = StartUpper.uadd_ov(std::move(Offset), Overflow);
7035+
}
70287036

70297037
// It's possible that the new minimum/maximum value will fall into the initial
70307038
// range (due to wrap around). This means that the expression can take any
70317039
// value in this bitwidth, and we have to return full range.
70327040
if (StartRange.contains(MovedBoundary))
7033-
return ConstantRange::getFull(BitWidth);
7041+
return {ConstantRange::getFull(BitWidth), false};
70347042

70357043
APInt NewLower =
70367044
Descending ? std::move(MovedBoundary) : std::move(StartLower);
@@ -7039,12 +7047,13 @@ static ConstantRange getRangeForAffineARHelper(APInt Step,
70397047
NewUpper += 1;
70407048

70417049
// No overflow detected, return [StartLower, StartUpper + Offset + 1) range.
7042-
return ConstantRange::getNonEmpty(std::move(NewLower), std::move(NewUpper));
7050+
return {ConstantRange::getNonEmpty(std::move(NewLower), std::move(NewUpper)),
7051+
!Overflow};
70437052
}
70447053

7045-
ConstantRange ScalarEvolution::getRangeForAffineAR(const SCEV *Start,
7046-
const SCEV *Step,
7047-
const APInt &MaxBECount) {
7054+
std::pair<ConstantRange, SCEV::NoWrapFlags>
7055+
ScalarEvolution::getRangeForAffineAR(const SCEV *Start, const SCEV *Step,
7056+
const APInt &MaxBECount) {
70487057
assert(getTypeSizeInBits(Start->getType()) ==
70497058
getTypeSizeInBits(Step->getType()) &&
70507059
getTypeSizeInBits(Start->getType()) == MaxBECount.getBitWidth() &&
@@ -7056,19 +7065,26 @@ ConstantRange ScalarEvolution::getRangeForAffineAR(const SCEV *Start,
70567065

70577066
// If Step can be both positive and negative, we need to find ranges for the
70587067
// maximum absolute step values in both directions and union them.
7059-
ConstantRange SR = getRangeForAffineARHelper(
7060-
StepSRange.getSignedMin(), StartSRange, MaxBECount, /* Signed = */ true);
7061-
SR = SR.unionWith(getRangeForAffineARHelper(StepSRange.getSignedMax(),
7062-
StartSRange, MaxBECount,
7063-
/* Signed = */ true));
7068+
auto [SR1, NSW1] = getRangeForAffineARHelper(
7069+
StepSRange.getSignedMin(), StartSRange, MaxBECount, /*Signed=*/true);
7070+
auto [SR2, NSW2] = getRangeForAffineARHelper(StepSRange.getSignedMax(),
7071+
StartSRange, MaxBECount,
7072+
/*Signed=*/true);
7073+
ConstantRange SR = SR1.unionWith(SR2);
70647074

70657075
// Next, consider step unsigned.
7066-
ConstantRange UR = getRangeForAffineARHelper(
7076+
auto [UR, NUW] = getRangeForAffineARHelper(
70677077
getUnsignedRangeMax(Step), getUnsignedRange(Start), MaxBECount,
7068-
/* Signed = */ false);
7078+
/*Signed=*/false);
7079+
7080+
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
7081+
if (NUW)
7082+
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
7083+
if (NSW1 && NSW2)
7084+
Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
70697085

70707086
// Finally, intersect signed and unsigned ranges.
7071-
return SR.intersectWith(UR, ConstantRange::Smallest);
7087+
return {SR.intersectWith(UR, ConstantRange::Smallest), Flags};
70727088
}
70737089

70747090
ConstantRange ScalarEvolution::getRangeForAffineNoSelfWrappingAR(
@@ -7246,9 +7262,9 @@ ConstantRange ScalarEvolution::getRangeViaFactoring(const SCEV *Start,
72467262
const SCEV *FalseStep = this->getConstant(StepPattern.FalseValue);
72477263

72487264
ConstantRange TrueRange =
7249-
this->getRangeForAffineAR(TrueStart, TrueStep, MaxBECount);
7265+
this->getRangeForAffineAR(TrueStart, TrueStep, MaxBECount).first;
72507266
ConstantRange FalseRange =
7251-
this->getRangeForAffineAR(FalseStart, FalseStep, MaxBECount);
7267+
this->getRangeForAffineAR(FalseStart, FalseStep, MaxBECount).first;
72527268

72537269
return TrueRange.unionWith(FalseRange);
72547270
}

llvm/test/Analysis/ScalarEvolution/addrec-computed-during-addrec-calculation.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ define void @test(ptr %p) {
2020
; CHECK-NEXT: %iv2.ext = sext i32 %iv2 to i64
2121
; CHECK-NEXT: --> (sext i32 {%iv,+,1}<%loop2> to i64) U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: <<Unknown>> LoopDispositions: { %loop.header: Variant, %loop2: Computable, %loop3: Invariant }
2222
; CHECK-NEXT: %iv3 = phi i64 [ %iv2.ext, %loop2.end ], [ %iv3.next, %loop3 ]
23-
; CHECK-NEXT: --> {(sext i32 {%iv,+,1}<%loop2> to i64),+,1}<nsw><%loop3> U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: (sext i32 {%iv,+,1}<%loop2> to i64) LoopDispositions: { %loop3: Computable, %loop.header: Variant }
23+
; CHECK-NEXT: --> {(sext i32 {%iv,+,1}<%loop2> to i64),+,1}<nuw><nsw><%loop3> U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: (sext i32 {%iv,+,1}<%loop2> to i64) LoopDispositions: { %loop3: Computable, %loop.header: Variant }
2424
; CHECK-NEXT: %iv3.next = add nsw i64 %iv3, 1
2525
; CHECK-NEXT: --> {(1 + (sext i32 {%iv,+,1}<%loop2> to i64))<nsw>,+,1}<nsw><%loop3> U: [-2147483647,2147483649) S: [-2147483647,2147483649) Exits: (1 + (sext i32 {%iv,+,1}<%loop2> to i64))<nsw> LoopDispositions: { %loop3: Computable, %loop.header: Variant }
2626
; CHECK-NEXT: %iv.next = trunc i64 %iv3 to i32
27-
; CHECK-NEXT: --> {{\{\{}}%iv,+,1}<%loop2>,+,1}<%loop3> U: full-set S: full-set --> {%iv,+,1}<%loop2> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop.header: Variant, %loop2: Variant, %loop3: Computable }
27+
; CHECK-NEXT: --> {{\{\{}}%iv,+,1}<%loop2>,+,1}<nuw><nsw><%loop3> U: full-set S: full-set --> {%iv,+,1}<%loop2> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop.header: Variant, %loop2: Variant, %loop3: Computable }
2828
; CHECK-NEXT: Determining loop execution counts for: @test
2929
; CHECK-NEXT: Loop %loop2: Unpredictable backedge-taken count.
3030
; CHECK-NEXT: Loop %loop2: constant max backedge-taken count is i32 -1

llvm/test/Analysis/ScalarEvolution/backedge-taken-count-guard-info.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ define void @rewrite_preserve_add_nsw(i32 %a) {
7777
; CHECK-NEXT: %add = add nsw i32 %a, 4
7878
; CHECK-NEXT: --> (4 + %a)<nsw> U: [-2147483644,-2147483648) S: [-2147483644,-2147483648)
7979
; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
80-
; CHECK-NEXT: --> {0,+,1}<nuw><%loop> U: [0,-2147483648) S: [0,-2147483648) Exits: (4 + %a)<nsw> LoopDispositions: { %loop: Computable }
80+
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,-2147483648) S: [0,-2147483648) Exits: (4 + %a)<nsw> LoopDispositions: { %loop: Computable }
8181
; CHECK-NEXT: %iv.next = add i32 %iv, 1
8282
; CHECK-NEXT: --> {1,+,1}<nuw><%loop> U: [1,-2147483647) S: [1,-2147483647) Exits: (5 + %a) LoopDispositions: { %loop: Computable }
8383
; CHECK-NEXT: Determining loop execution counts for: @rewrite_preserve_add_nsw

llvm/test/Analysis/ScalarEvolution/becount-invalidation.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ define void @test(ptr %arg) {
1313
; CHECK-NEXT: %ptr2 = phi ptr [ %ptr2.next, %loop.latch ], [ null, %entry ]
1414
; CHECK-NEXT: --> %ptr2 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop.header: Variant, %loop2.header: Invariant }
1515
; CHECK-NEXT: %ptr1.next = phi ptr [ %ptr2, %loop.header ], [ %ptr1.next.next, %loop2.latch ]
16-
; CHECK-NEXT: --> {%ptr2,+,8}<nuw><%loop2.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop2.header: Computable, %loop.header: Variant }
16+
; CHECK-NEXT: --> {%ptr2,+,8}<nuw><nsw><%loop2.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop2.header: Computable, %loop.header: Variant }
1717
; CHECK-NEXT: %iv = phi i64 [ 0, %loop.header ], [ %iv.next, %loop2.latch ]
1818
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop2.header> U: [0,1) S: [0,1) Exits: <<Unknown>> LoopDispositions: { %loop2.header: Computable, %loop.header: Variant }
1919
; CHECK-NEXT: %ptr1.dummy = getelementptr inbounds i64, ptr %ptr1.next, i64 0
20-
; CHECK-NEXT: --> {%ptr2,+,8}<nuw><%loop2.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop2.header: Computable, %loop.header: Variant }
20+
; CHECK-NEXT: --> {%ptr2,+,8}<nuw><nsw><%loop2.header> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop2.header: Computable, %loop.header: Variant }
2121
; CHECK-NEXT: %val = load i64, ptr %ptr1.dummy, align 8
2222
; CHECK-NEXT: --> %val U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop2.header: Variant, %loop.header: Variant }
2323
; CHECK-NEXT: %ptr1.next.next = getelementptr inbounds i64, ptr %ptr1.next, i64 1

0 commit comments

Comments
 (0)