Skip to content

Commit fc6e2c8

Browse files
committed
[SCEV] Add option to request use-specific SCEV for a GEP expr (WIP).
Use SCEVUse from #91961 to return a SCEVUse with use-specific no-wrap flags for GEP expr, when demanded. Clients need to opt-in, as the use-specific flags may not be valid in some contexts (e.g. backedge taken counts).
1 parent bcc33a2 commit fc6e2c8

File tree

8 files changed

+41
-33
lines changed

8 files changed

+41
-33
lines changed

llvm/include/llvm/Analysis/ScalarEvolution.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ class ScalarEvolution {
667667

668668
/// Return a SCEV expression for the full generality of the specified
669669
/// expression.
670-
SCEVUse getSCEV(Value *V);
670+
SCEVUse getSCEV(Value *V, bool UseCtx = false);
671671

672672
/// Return an existing SCEV for V if there is one, otherwise return nullptr.
673673
SCEVUse getExistingSCEV(Value *V);
@@ -749,9 +749,11 @@ class ScalarEvolution {
749749
/// \p GEP The GEP. The indices contained in the GEP itself are ignored,
750750
/// instead we use IndexExprs.
751751
/// \p IndexExprs The expressions for the indices.
752-
SCEVUse getGEPExpr(GEPOperator *GEP, ArrayRef<const SCEV *> IndexExprs);
752+
SCEVUse getGEPExpr(GEPOperator *GEP, ArrayRef<const SCEV *> IndexExprs,
753+
bool UseCtx = false);
753754
SCEVUse getGEPExpr(GEPOperator *GEP,
754-
const SmallVectorImpl<SCEVUse> &IndexExprs);
755+
const SmallVectorImpl<SCEVUse> &IndexExprs,
756+
bool UseCtx = false);
755757
SCEVUse getAbsExpr(SCEVUse Op, bool IsNSW);
756758
SCEVUse getMinMaxExpr(SCEVTypes Kind, ArrayRef<const SCEV *> Operands);
757759
SCEVUse getMinMaxExpr(SCEVTypes Kind, SmallVectorImpl<SCEVUse> &Operands);
@@ -1866,11 +1868,11 @@ class ScalarEvolution {
18661868

18671869
/// We know that there is no SCEV for the specified value. Analyze the
18681870
/// expression recursively.
1869-
SCEVUse createSCEV(Value *V);
1871+
SCEVUse createSCEV(Value *V, bool UseCtx = false);
18701872

18711873
/// We know that there is no SCEV for the specified value. Create a new SCEV
18721874
/// for \p V iteratively.
1873-
SCEVUse createSCEVIter(Value *V);
1875+
SCEVUse createSCEVIter(Value *V, bool UseCtx = false);
18741876
/// Collect operands of \p V for which SCEV expressions should be constructed
18751877
/// first. Returns a SCEV directly if it can be constructed trivially for \p
18761878
/// V.
@@ -1909,7 +1911,7 @@ class ScalarEvolution {
19091911
Value *FalseVal);
19101912

19111913
/// Provide the special handling we need to analyze GEP SCEVs.
1912-
SCEVUse createNodeForGEP(GEPOperator *GEP);
1914+
SCEVUse createNodeForGEP(GEPOperator *GEP, bool UseCtx = false);
19131915

19141916
/// Implementation code for getSCEVAtScope; called at most once for each
19151917
/// SCEV+Loop pair.

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,6 +2803,8 @@ SCEVUse ScalarEvolution::getAddExpr(SmallVectorImpl<SCEVUse> &Ops,
28032803
break;
28042804
// If we have an add, expand the add operands onto the end of the operands
28052805
// list.
2806+
// CommonFlags = maskFlags(CommonFlags, setFlags(Add->getNoWrapFlags(),
2807+
// static_cast<SCEV::NoWrapFlags>(Ops[Idx].getInt())));
28062808
Ops.erase(Ops.begin()+Idx);
28072809
append_range(Ops, Add->operands());
28082810
DeletedAdd = true;
@@ -3822,13 +3824,14 @@ SCEVUse ScalarEvolution::getAddRecExpr(SmallVectorImpl<SCEVUse> &Operands,
38223824
}
38233825

38243826
SCEVUse ScalarEvolution::getGEPExpr(GEPOperator *GEP,
3825-
ArrayRef<const SCEV *> IndexExprs) {
3826-
return getGEPExpr(GEP, SmallVector<SCEVUse>(IndexExprs));
3827+
ArrayRef<const SCEV *> IndexExprs,
3828+
bool UseCtx) {
3829+
return getGEPExpr(GEP, SmallVector<SCEVUse>(IndexExprs), UseCtx);
38273830
}
38283831

3829-
SCEVUse
3830-
ScalarEvolution::getGEPExpr(GEPOperator *GEP,
3831-
const SmallVectorImpl<SCEVUse> &IndexExprs) {
3832+
SCEVUse ScalarEvolution::getGEPExpr(GEPOperator *GEP,
3833+
const SmallVectorImpl<SCEVUse> &IndexExprs,
3834+
bool UseCtx) {
38323835
SCEVUse BaseExpr = getSCEV(GEP->getPointerOperand());
38333836
// getSCEV(Base)->getType() has the same address space as Base->getType()
38343837
// because SCEV::getType() preserves the address space.
@@ -3901,6 +3904,9 @@ ScalarEvolution::getGEPExpr(GEPOperator *GEP,
39013904
auto GEPExpr = getAddExpr(BaseExpr, Offset, BaseWrap);
39023905
assert(BaseExpr->getType() == GEPExpr->getType() &&
39033906
"GEP should not change type mid-flight.");
3907+
if (UseCtx && BaseWrap != SCEV::FlagNUW && GEP->isInBounds() &&
3908+
isKnownNonNegative(Offset))
3909+
GEPExpr = SCEVUse(&*GEPExpr, 2);
39043910
return GEPExpr;
39053911
}
39063912

@@ -4636,12 +4642,12 @@ void ScalarEvolution::insertValueToMap(Value *V, SCEVUse S) {
46364642

46374643
/// Return an existing SCEV if it exists, otherwise analyze the expression and
46384644
/// create a new one.
4639-
SCEVUse ScalarEvolution::getSCEV(Value *V) {
4645+
SCEVUse ScalarEvolution::getSCEV(Value *V, bool UseCtx) {
46404646
assert(isSCEVable(V->getType()) && "Value is not SCEVable!");
46414647

46424648
if (SCEVUse S = getExistingSCEV(V))
46434649
return S;
4644-
return createSCEVIter(V);
4650+
return createSCEVIter(V, UseCtx);
46454651
}
46464652

46474653
SCEVUse ScalarEvolution::getExistingSCEV(Value *V) {
@@ -6334,14 +6340,14 @@ SCEVUse ScalarEvolution::createNodeForSelectOrPHI(Value *V, Value *Cond,
63346340

63356341
/// Expand GEP instructions into add and multiply operations. This allows them
63366342
/// to be analyzed by regular SCEV code.
6337-
SCEVUse ScalarEvolution::createNodeForGEP(GEPOperator *GEP) {
6343+
SCEVUse ScalarEvolution::createNodeForGEP(GEPOperator *GEP, bool UseCtx) {
63386344
assert(GEP->getSourceElementType()->isSized() &&
63396345
"GEP source element type must be sized");
63406346

63416347
SmallVector<SCEVUse, 4> IndexExprs;
63426348
for (Value *Index : GEP->indices())
63436349
IndexExprs.push_back(getSCEV(Index));
6344-
return getGEPExpr(GEP, IndexExprs);
6350+
return getGEPExpr(GEP, IndexExprs, UseCtx);
63456351
}
63466352

63476353
APInt ScalarEvolution::getConstantMultipleImpl(SCEVUse S) {
@@ -7489,7 +7495,7 @@ bool ScalarEvolution::loopIsFiniteByAssumption(const Loop *L) {
74897495
return isFinite(L) || (isMustProgress(L) && loopHasNoSideEffects(L));
74907496
}
74917497

7492-
SCEVUse ScalarEvolution::createSCEVIter(Value *V) {
7498+
SCEVUse ScalarEvolution::createSCEVIter(Value *V, bool UseCtx) {
74937499
// Worklist item with a Value and a bool indicating whether all operands have
74947500
// been visited already.
74957501
using PointerTy = PointerIntPair<Value *, 1, bool>;
@@ -7508,7 +7514,7 @@ SCEVUse ScalarEvolution::createSCEVIter(Value *V) {
75087514
SCEVUse CreatedSCEV = nullptr;
75097515
// If all operands have been visited already, create the SCEV.
75107516
if (E.getInt()) {
7511-
CreatedSCEV = createSCEV(CurV);
7517+
CreatedSCEV = createSCEV(CurV, UseCtx);
75127518
} else {
75137519
// Otherwise get the operands we need to create SCEV's for before creating
75147520
// the SCEV for CurV. If the SCEV for CurV can be constructed trivially,
@@ -7717,7 +7723,7 @@ SCEVUse ScalarEvolution::getOperandsToCreate(Value *V,
77177723
return nullptr;
77187724
}
77197725

7720-
SCEVUse ScalarEvolution::createSCEV(Value *V) {
7726+
SCEVUse ScalarEvolution::createSCEV(Value *V, bool UseCtx) {
77217727
if (!isSCEVable(V->getType()))
77227728
return getUnknown(V);
77237729

@@ -8126,7 +8132,7 @@ SCEVUse ScalarEvolution::createSCEV(Value *V) {
81268132
break;
81278133

81288134
case Instruction::GetElementPtr:
8129-
return createNodeForGEP(cast<GEPOperator>(U));
8135+
return createNodeForGEP(cast<GEPOperator>(U), UseCtx);
81308136

81318137
case Instruction::PHI:
81328138
return createNodeForPHI(cast<PHINode>(U));
@@ -13952,8 +13958,8 @@ void ScalarEvolution::print(raw_ostream &OS) const {
1395213958
if (isSCEVable(I.getType()) && !isa<CmpInst>(I)) {
1395313959
OS << I << '\n';
1395413960
OS << " --> ";
13955-
SCEVUse SV = SE.getSCEV(&I);
13956-
SV->print(OS);
13961+
SCEVUse SV = SE.getSCEV(&I, /*UseCtx=*/true);
13962+
SV.print(OS);
1395713963
if (!isa<SCEVCouldNotCompute>(SV)) {
1395813964
OS << " U: ";
1395913965
SE.getUnsignedRange(SV).print(OS);

llvm/test/Analysis/ScalarEvolution/min-max-exprs.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ define void @f(ptr %A, i32 %N) {
4242
; CHECK-NEXT: %tmp19 = select i1 %tmp14, i64 0, i64 %tmp17
4343
; CHECK-NEXT: --> (-3 + (3 smax {0,+,1}<nuw><nsw><%bb1>))<nsw> U: [0,2147483645) S: [0,2147483645) Exits: (-3 + (3 smax (zext i32 (0 smax %N) to i64)))<nsw> LoopDispositions: { %bb1: Computable }
4444
; CHECK-NEXT: %tmp21 = getelementptr inbounds i32, ptr %A, i64 %tmp19
45-
; CHECK-NEXT: --> (-12 + (4 * (3 smax {0,+,1}<nuw><nsw><%bb1>))<nuw><nsw> + %A) U: full-set S: full-set Exits: (-12 + (4 * (3 smax (zext i32 (0 smax %N) to i64)))<nuw><nsw> + %A) LoopDispositions: { %bb1: Computable }
45+
; CHECK-NEXT: --> (-12 + (4 * (3 smax {0,+,1}<nuw><nsw><%bb1>))<nuw><nsw> + %A)(u nuw) U: full-set S: full-set Exits: (-12 + (4 * (3 smax (zext i32 (0 smax %N) to i64)))<nuw><nsw> + %A) LoopDispositions: { %bb1: Computable }
4646
; CHECK-NEXT: %tmp23 = add nuw nsw i32 %i.0, 1
4747
; CHECK-NEXT: --> {1,+,1}<nuw><%bb1> U: [1,-2147483647) S: [1,-2147483647) Exits: (1 + (0 smax %N))<nuw> LoopDispositions: { %bb1: Computable }
4848
; CHECK-NEXT: Determining loop execution counts for: @f

llvm/test/Analysis/ScalarEvolution/no-wrap-add-exprs.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,11 @@ define void @f3(ptr %x_addr, ptr %y_addr, ptr %tmp_addr) {
209209
; CHECK-NEXT: %sunkaddr3 = mul i64 %add4.zext, 4
210210
; CHECK-NEXT: --> (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> U: [0,17179869169) S: [0,17179869181)
211211
; CHECK-NEXT: %sunkaddr4 = getelementptr inbounds i8, ptr @tmp_addr, i64 %sunkaddr3
212-
; CHECK-NEXT: --> ((4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
212+
; CHECK-NEXT: --> ((4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr)(u nuw) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
213213
; CHECK-NEXT: %sunkaddr5 = getelementptr inbounds i8, ptr %sunkaddr4, i64 4096
214-
; CHECK-NEXT: --> (4096 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
214+
; CHECK-NEXT: --> (4096 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr)(u nuw) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
215215
; CHECK-NEXT: %addr4.cast = bitcast ptr %sunkaddr5 to ptr
216-
; CHECK-NEXT: --> (4096 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
216+
; CHECK-NEXT: --> (4096 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr)(u nuw) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
217217
; CHECK-NEXT: %addr4.incr = getelementptr i32, ptr %addr4.cast, i64 1
218218
; CHECK-NEXT: --> (4100 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
219219
; CHECK-NEXT: %add5 = add i32 %mul, 5
@@ -223,11 +223,11 @@ define void @f3(ptr %x_addr, ptr %y_addr, ptr %tmp_addr) {
223223
; CHECK-NEXT: %sunkaddr0 = mul i64 %add5.zext, 4
224224
; CHECK-NEXT: --> (4 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw>)<nuw><nsw> U: [4,17179869173) S: [4,17179869185)
225225
; CHECK-NEXT: %sunkaddr1 = getelementptr inbounds i8, ptr @tmp_addr, i64 %sunkaddr0
226-
; CHECK-NEXT: --> (4 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
226+
; CHECK-NEXT: --> (4 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr)(u nuw) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
227227
; CHECK-NEXT: %sunkaddr2 = getelementptr inbounds i8, ptr %sunkaddr1, i64 4096
228-
; CHECK-NEXT: --> (4100 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
228+
; CHECK-NEXT: --> (4100 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr)(u nuw) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
229229
; CHECK-NEXT: %addr5.cast = bitcast ptr %sunkaddr2 to ptr
230-
; CHECK-NEXT: --> (4100 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
230+
; CHECK-NEXT: --> (4100 + (4 * (zext i32 (4 + (4 * (%tmp /u 4))<nuw>) to i64))<nuw><nsw> + @tmp_addr)(u nuw) U: [0,-3) S: [-9223372036854775808,9223372036854775805)
231231
; CHECK-NEXT: Determining loop execution counts for: @f3
232232
;
233233
entry:

llvm/test/Analysis/ScalarEvolution/no-wrap-symbolic-becount.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ define void @pointer_iv_nowrap(ptr %startptr, ptr %endptr) local_unnamed_addr {
9696
; CHECK-LABEL: 'pointer_iv_nowrap'
9797
; CHECK-NEXT: Classifying expressions for: @pointer_iv_nowrap
9898
; CHECK-NEXT: %init = getelementptr inbounds i8, ptr %startptr, i64 2000
99-
; CHECK-NEXT: --> (2000 + %startptr) U: full-set S: full-set
99+
; CHECK-NEXT: --> (2000 + %startptr)(u nuw) U: full-set S: full-set
100100
; CHECK-NEXT: %iv = phi ptr [ %init, %entry ], [ %iv.next, %loop ]
101101
; CHECK-NEXT: --> {(2000 + %startptr),+,1}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
102102
; CHECK-NEXT: %iv.next = getelementptr inbounds i8, ptr %iv, i64 1

llvm/test/Analysis/ScalarEvolution/ptrtoint.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ define void @ptrtoint_of_gep(ptr %in, ptr %out0) {
192192
; X64-LABEL: 'ptrtoint_of_gep'
193193
; X64-NEXT: Classifying expressions for: @ptrtoint_of_gep
194194
; X64-NEXT: %in_adj = getelementptr inbounds i8, ptr %in, i64 42
195-
; X64-NEXT: --> (42 + %in) U: full-set S: full-set
195+
; X64-NEXT: --> (42 + %in)(u nuw) U: full-set S: full-set
196196
; X64-NEXT: %p0 = ptrtoint ptr %in_adj to i64
197197
; X64-NEXT: --> (42 + (ptrtoint ptr %in to i64)) U: full-set S: full-set
198198
; X64-NEXT: Determining loop execution counts for: @ptrtoint_of_gep
199199
;
200200
; X32-LABEL: 'ptrtoint_of_gep'
201201
; X32-NEXT: Classifying expressions for: @ptrtoint_of_gep
202202
; X32-NEXT: %in_adj = getelementptr inbounds i8, ptr %in, i64 42
203-
; X32-NEXT: --> (42 + %in) U: full-set S: full-set
203+
; X32-NEXT: --> (42 + %in)(u nuw) U: full-set S: full-set
204204
; X32-NEXT: %p0 = ptrtoint ptr %in_adj to i64
205205
; X32-NEXT: --> (zext i32 (42 + (ptrtoint ptr %in to i32)) to i64) U: [0,4294967296) S: [0,4294967296)
206206
; X32-NEXT: Determining loop execution counts for: @ptrtoint_of_gep

llvm/test/Analysis/ScalarEvolution/sdiv.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ define dso_local void @_Z4loopi(i32 %width) local_unnamed_addr #0 {
1818
; CHECK-NEXT: %idxprom = sext i32 %rem to i64
1919
; CHECK-NEXT: --> ({0,+,1}<nuw><nsw><%for.cond> /u 2) U: [0,2147483648) S: [0,2147483648) Exits: ((zext i32 %width to i64) /u 2) LoopDispositions: { %for.cond: Computable }
2020
; CHECK-NEXT: %arrayidx = getelementptr inbounds [2 x i32], ptr %storage, i64 0, i64 %idxprom
21-
; CHECK-NEXT: --> ((4 * ({0,+,1}<nuw><nsw><%for.cond> /u 2))<nuw><nsw> + %storage) U: [0,-3) S: [-9223372036854775808,9223372036854775805) Exits: ((4 * ((zext i32 %width to i64) /u 2))<nuw><nsw> + %storage) LoopDispositions: { %for.cond: Computable }
21+
; CHECK-NEXT: --> ((4 * ({0,+,1}<nuw><nsw><%for.cond> /u 2))<nuw><nsw> + %storage)(u nuw) U: [0,-3) S: [-9223372036854775808,9223372036854775805) Exits: ((4 * ((zext i32 %width to i64) /u 2))<nuw><nsw> + %storage) LoopDispositions: { %for.cond: Computable }
2222
; CHECK-NEXT: %1 = load i32, ptr %arrayidx, align 4
2323
; CHECK-NEXT: --> %1 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %for.cond: Variant }
2424
; CHECK-NEXT: %call = call i32 @_Z3adji(i32 %1)

llvm/test/Analysis/ScalarEvolution/srem.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ define dso_local void @_Z4loopi(i32 %width) local_unnamed_addr #0 {
1818
; CHECK-NEXT: %idxprom = sext i32 %rem to i64
1919
; CHECK-NEXT: --> (zext i1 {false,+,true}<%for.cond> to i64) U: [0,2) S: [0,2) Exits: (zext i1 (trunc i32 %width to i1) to i64) LoopDispositions: { %for.cond: Computable }
2020
; CHECK-NEXT: %arrayidx = getelementptr inbounds [2 x i32], ptr %storage, i64 0, i64 %idxprom
21-
; CHECK-NEXT: --> ((4 * (zext i1 {false,+,true}<%for.cond> to i64))<nuw><nsw> + %storage) U: [4,-7) S: [-9223372036854775808,9223372036854775805) Exits: ((4 * (zext i1 (trunc i32 %width to i1) to i64))<nuw><nsw> + %storage) LoopDispositions: { %for.cond: Computable }
21+
; CHECK-NEXT: --> ((4 * (zext i1 {false,+,true}<%for.cond> to i64))<nuw><nsw> + %storage)(u nuw) U: [4,-7) S: [-9223372036854775808,9223372036854775805) Exits: ((4 * (zext i1 (trunc i32 %width to i1) to i64))<nuw><nsw> + %storage) LoopDispositions: { %for.cond: Computable }
2222
; CHECK-NEXT: %1 = load i32, ptr %arrayidx, align 4
2323
; CHECK-NEXT: --> %1 U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %for.cond: Variant }
2424
; CHECK-NEXT: %call = call i32 @_Z3adji(i32 %1)

0 commit comments

Comments
 (0)