Skip to content

Commit 7f09aa9

Browse files
committed
[SCEV] Transfer gep nusw and nuw flags
nusw implies nsw offset and nuw base+offset arithmetic if offset is non-negative. nuw implies nuw offset and base+offset arithmetic. As usual, we can only transfer is poison implies UB.
1 parent 3808ba7 commit 7f09aa9

File tree

2 files changed

+97
-11
lines changed

2 files changed

+97
-11
lines changed

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3746,21 +3746,23 @@ ScalarEvolution::getGEPExpr(GEPOperator *GEP,
37463746
// getSCEV(Base)->getType() has the same address space as Base->getType()
37473747
// because SCEV::getType() preserves the address space.
37483748
Type *IntIdxTy = getEffectiveSCEVType(BaseExpr->getType());
3749-
const bool AssumeInBoundsFlags = [&]() {
3750-
if (!GEP->isInBounds())
3751-
return false;
3752-
3749+
GEPNoWrapFlags NW = GEP->getNoWrapFlags();
3750+
if (NW != GEPNoWrapFlags::none()) {
37533751
// We'd like to propagate flags from the IR to the corresponding SCEV nodes,
37543752
// but to do that, we have to ensure that said flag is valid in the entire
37553753
// defined scope of the SCEV.
3756-
auto *GEPI = dyn_cast<Instruction>(GEP);
37573754
// TODO: non-instructions have global scope. We might be able to prove
37583755
// some global scope cases
3759-
return GEPI && isSCEVExprNeverPoison(GEPI);
3760-
}();
3756+
auto *GEPI = dyn_cast<Instruction>(GEP);
3757+
if (!GEPI || !isSCEVExprNeverPoison(GEPI))
3758+
NW = GEPNoWrapFlags::none();
3759+
}
37613760

3762-
SCEV::NoWrapFlags OffsetWrap =
3763-
AssumeInBoundsFlags ? SCEV::FlagNSW : SCEV::FlagAnyWrap;
3761+
SCEV::NoWrapFlags OffsetWrap = SCEV::FlagAnyWrap;
3762+
if (NW.hasNoUnsignedSignedWrap())
3763+
OffsetWrap = setFlags(OffsetWrap, SCEV::FlagNSW);
3764+
if (NW.hasNoUnsignedWrap())
3765+
OffsetWrap = setFlags(OffsetWrap, SCEV::FlagNUW);
37643766

37653767
Type *CurTy = GEP->getType();
37663768
bool FirstIter = true;
@@ -3806,8 +3808,9 @@ ScalarEvolution::getGEPExpr(GEPOperator *GEP,
38063808
// Add the base address and the offset. We cannot use the nsw flag, as the
38073809
// base address is unsigned. However, if we know that the offset is
38083810
// non-negative, we can use nuw.
3809-
SCEV::NoWrapFlags BaseWrap = AssumeInBoundsFlags && isKnownNonNegative(Offset)
3810-
? SCEV::FlagNUW : SCEV::FlagAnyWrap;
3811+
bool NUW = NW.hasNoUnsignedWrap() ||
3812+
(NW.hasNoUnsignedSignedWrap() && isKnownNonNegative(Offset));
3813+
SCEV::NoWrapFlags BaseWrap = NUW ? SCEV::FlagNUW : SCEV::FlagAnyWrap;
38113814
auto *GEPExpr = getAddExpr(BaseExpr, Offset, BaseWrap);
38123815
assert(BaseExpr->getType() == GEPExpr->getType() &&
38133816
"GEP should not change type mid-flight.");

llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,3 +1956,86 @@ define noundef i32 @add-recurse-inline() {
19561956
%res = add nuw i32 %x, %y
19571957
ret i32 %res
19581958
}
1959+
1960+
define noundef ptr @gep_inbounds(ptr %p, i64 %index) {
1961+
; CHECK-LABEL: 'gep_inbounds'
1962+
; CHECK-NEXT: Classifying expressions for: @gep_inbounds
1963+
; CHECK-NEXT: %gep = getelementptr inbounds i32, ptr %p, i64 %index
1964+
; CHECK-NEXT: --> ((4 * %index)<nsw> + %p) U: full-set S: full-set
1965+
; CHECK-NEXT: Determining loop execution counts for: @gep_inbounds
1966+
;
1967+
%gep = getelementptr inbounds i32, ptr %p, i64 %index
1968+
ret ptr %gep
1969+
}
1970+
1971+
define noundef ptr @gep_inbounds_nneg(ptr %p, i32 %index) {
1972+
; CHECK-LABEL: 'gep_inbounds_nneg'
1973+
; CHECK-NEXT: Classifying expressions for: @gep_inbounds_nneg
1974+
; CHECK-NEXT: %index.ext = zext i32 %index to i64
1975+
; CHECK-NEXT: --> (zext i32 %index to i64) U: [0,4294967296) S: [0,4294967296)
1976+
; CHECK-NEXT: %gep = getelementptr inbounds i32, ptr %p, i64 %index.ext
1977+
; CHECK-NEXT: --> ((4 * (zext i32 %index to i64))<nuw><nsw> + %p)<nuw> U: full-set S: full-set
1978+
; CHECK-NEXT: Determining loop execution counts for: @gep_inbounds_nneg
1979+
;
1980+
%index.ext = zext i32 %index to i64
1981+
%gep = getelementptr inbounds i32, ptr %p, i64 %index.ext
1982+
ret ptr %gep
1983+
}
1984+
1985+
define noundef ptr @gep_nusw(ptr %p, i64 %index) {
1986+
; CHECK-LABEL: 'gep_nusw'
1987+
; CHECK-NEXT: Classifying expressions for: @gep_nusw
1988+
; CHECK-NEXT: %gep = getelementptr nusw i32, ptr %p, i64 %index
1989+
; CHECK-NEXT: --> ((4 * %index)<nsw> + %p) U: full-set S: full-set
1990+
; CHECK-NEXT: Determining loop execution counts for: @gep_nusw
1991+
;
1992+
%gep = getelementptr nusw i32, ptr %p, i64 %index
1993+
ret ptr %gep
1994+
}
1995+
1996+
define noundef ptr @gep_nusw_nneg(ptr %p, i32 %index) {
1997+
; CHECK-LABEL: 'gep_nusw_nneg'
1998+
; CHECK-NEXT: Classifying expressions for: @gep_nusw_nneg
1999+
; CHECK-NEXT: %index.ext = zext i32 %index to i64
2000+
; CHECK-NEXT: --> (zext i32 %index to i64) U: [0,4294967296) S: [0,4294967296)
2001+
; CHECK-NEXT: %gep = getelementptr nusw i32, ptr %p, i64 %index.ext
2002+
; CHECK-NEXT: --> ((4 * (zext i32 %index to i64))<nuw><nsw> + %p)<nuw> U: full-set S: full-set
2003+
; CHECK-NEXT: Determining loop execution counts for: @gep_nusw_nneg
2004+
;
2005+
%index.ext = zext i32 %index to i64
2006+
%gep = getelementptr nusw i32, ptr %p, i64 %index.ext
2007+
ret ptr %gep
2008+
}
2009+
2010+
define noundef ptr @gep_nuw(ptr %p, i64 %index) {
2011+
; CHECK-LABEL: 'gep_nuw'
2012+
; CHECK-NEXT: Classifying expressions for: @gep_nuw
2013+
; CHECK-NEXT: %gep = getelementptr nuw i32, ptr %p, i64 %index
2014+
; CHECK-NEXT: --> ((4 * %index)<nuw> + %p)<nuw> U: full-set S: full-set
2015+
; CHECK-NEXT: Determining loop execution counts for: @gep_nuw
2016+
;
2017+
%gep = getelementptr nuw i32, ptr %p, i64 %index
2018+
ret ptr %gep
2019+
}
2020+
2021+
define noundef ptr @gep_nusw_nuw(ptr %p, i64 %index) {
2022+
; CHECK-LABEL: 'gep_nusw_nuw'
2023+
; CHECK-NEXT: Classifying expressions for: @gep_nusw_nuw
2024+
; CHECK-NEXT: %gep = getelementptr nusw nuw i32, ptr %p, i64 %index
2025+
; CHECK-NEXT: --> ((4 * %index)<nuw><nsw> + %p)<nuw> U: full-set S: full-set
2026+
; CHECK-NEXT: Determining loop execution counts for: @gep_nusw_nuw
2027+
;
2028+
%gep = getelementptr nusw nuw i32, ptr %p, i64 %index
2029+
ret ptr %gep
2030+
}
2031+
2032+
define ptr @gep_nusw_nuw_missing_noundef(ptr %p, i64 %index) {
2033+
; CHECK-LABEL: 'gep_nusw_nuw_missing_noundef'
2034+
; CHECK-NEXT: Classifying expressions for: @gep_nusw_nuw_missing_noundef
2035+
; CHECK-NEXT: %gep = getelementptr nusw nuw i32, ptr %p, i64 %index
2036+
; CHECK-NEXT: --> ((4 * %index) + %p) U: full-set S: full-set
2037+
; CHECK-NEXT: Determining loop execution counts for: @gep_nusw_nuw_missing_noundef
2038+
;
2039+
%gep = getelementptr nusw nuw i32, ptr %p, i64 %index
2040+
ret ptr %gep
2041+
}

0 commit comments

Comments
 (0)