[llvm] 7f09aa9 - [SCEV] Transfer gep nusw and nuw flags
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 20 05:45:09 PDT 2024
Author: Nikita Popov
Date: 2024-06-20T14:45:02+02:00
New Revision: 7f09aa9e3670778217a3d61702a4cf3343e6449d
URL: https://github.com/llvm/llvm-project/commit/7f09aa9e3670778217a3d61702a4cf3343e6449d
DIFF: https://github.com/llvm/llvm-project/commit/7f09aa9e3670778217a3d61702a4cf3343e6449d.diff
LOG: [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.
Added:
Modified:
llvm/lib/Analysis/ScalarEvolution.cpp
llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 7d3e3f4fcd45d..8d90530906bb8 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -3746,21 +3746,23 @@ ScalarEvolution::getGEPExpr(GEPOperator *GEP,
// getSCEV(Base)->getType() has the same address space as Base->getType()
// because SCEV::getType() preserves the address space.
Type *IntIdxTy = getEffectiveSCEVType(BaseExpr->getType());
- const bool AssumeInBoundsFlags = [&]() {
- if (!GEP->isInBounds())
- return false;
-
+ GEPNoWrapFlags NW = GEP->getNoWrapFlags();
+ if (NW != GEPNoWrapFlags::none()) {
// We'd like to propagate flags from the IR to the corresponding SCEV nodes,
// but to do that, we have to ensure that said flag is valid in the entire
// defined scope of the SCEV.
- auto *GEPI = dyn_cast<Instruction>(GEP);
// TODO: non-instructions have global scope. We might be able to prove
// some global scope cases
- return GEPI && isSCEVExprNeverPoison(GEPI);
- }();
+ auto *GEPI = dyn_cast<Instruction>(GEP);
+ if (!GEPI || !isSCEVExprNeverPoison(GEPI))
+ NW = GEPNoWrapFlags::none();
+ }
- SCEV::NoWrapFlags OffsetWrap =
- AssumeInBoundsFlags ? SCEV::FlagNSW : SCEV::FlagAnyWrap;
+ SCEV::NoWrapFlags OffsetWrap = SCEV::FlagAnyWrap;
+ if (NW.hasNoUnsignedSignedWrap())
+ OffsetWrap = setFlags(OffsetWrap, SCEV::FlagNSW);
+ if (NW.hasNoUnsignedWrap())
+ OffsetWrap = setFlags(OffsetWrap, SCEV::FlagNUW);
Type *CurTy = GEP->getType();
bool FirstIter = true;
@@ -3806,8 +3808,9 @@ ScalarEvolution::getGEPExpr(GEPOperator *GEP,
// Add the base address and the offset. We cannot use the nsw flag, as the
// base address is unsigned. However, if we know that the offset is
// non-negative, we can use nuw.
- SCEV::NoWrapFlags BaseWrap = AssumeInBoundsFlags && isKnownNonNegative(Offset)
- ? SCEV::FlagNUW : SCEV::FlagAnyWrap;
+ bool NUW = NW.hasNoUnsignedWrap() ||
+ (NW.hasNoUnsignedSignedWrap() && isKnownNonNegative(Offset));
+ SCEV::NoWrapFlags BaseWrap = NUW ? SCEV::FlagNUW : SCEV::FlagAnyWrap;
auto *GEPExpr = getAddExpr(BaseExpr, Offset, BaseWrap);
assert(BaseExpr->getType() == GEPExpr->getType() &&
"GEP should not change type mid-flight.");
diff --git a/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll b/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll
index a8531a8f57799..a52352655cb92 100644
--- a/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll
+++ b/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll
@@ -1956,3 +1956,86 @@ define noundef i32 @add-recurse-inline() {
%res = add nuw i32 %x, %y
ret i32 %res
}
+
+define noundef ptr @gep_inbounds(ptr %p, i64 %index) {
+; CHECK-LABEL: 'gep_inbounds'
+; CHECK-NEXT: Classifying expressions for: @gep_inbounds
+; CHECK-NEXT: %gep = getelementptr inbounds i32, ptr %p, i64 %index
+; CHECK-NEXT: --> ((4 * %index)<nsw> + %p) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @gep_inbounds
+;
+ %gep = getelementptr inbounds i32, ptr %p, i64 %index
+ ret ptr %gep
+}
+
+define noundef ptr @gep_inbounds_nneg(ptr %p, i32 %index) {
+; CHECK-LABEL: 'gep_inbounds_nneg'
+; CHECK-NEXT: Classifying expressions for: @gep_inbounds_nneg
+; CHECK-NEXT: %index.ext = zext i32 %index to i64
+; CHECK-NEXT: --> (zext i32 %index to i64) U: [0,4294967296) S: [0,4294967296)
+; CHECK-NEXT: %gep = getelementptr inbounds i32, ptr %p, i64 %index.ext
+; CHECK-NEXT: --> ((4 * (zext i32 %index to i64))<nuw><nsw> + %p)<nuw> U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @gep_inbounds_nneg
+;
+ %index.ext = zext i32 %index to i64
+ %gep = getelementptr inbounds i32, ptr %p, i64 %index.ext
+ ret ptr %gep
+}
+
+define noundef ptr @gep_nusw(ptr %p, i64 %index) {
+; CHECK-LABEL: 'gep_nusw'
+; CHECK-NEXT: Classifying expressions for: @gep_nusw
+; CHECK-NEXT: %gep = getelementptr nusw i32, ptr %p, i64 %index
+; CHECK-NEXT: --> ((4 * %index)<nsw> + %p) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @gep_nusw
+;
+ %gep = getelementptr nusw i32, ptr %p, i64 %index
+ ret ptr %gep
+}
+
+define noundef ptr @gep_nusw_nneg(ptr %p, i32 %index) {
+; CHECK-LABEL: 'gep_nusw_nneg'
+; CHECK-NEXT: Classifying expressions for: @gep_nusw_nneg
+; CHECK-NEXT: %index.ext = zext i32 %index to i64
+; CHECK-NEXT: --> (zext i32 %index to i64) U: [0,4294967296) S: [0,4294967296)
+; CHECK-NEXT: %gep = getelementptr nusw i32, ptr %p, i64 %index.ext
+; CHECK-NEXT: --> ((4 * (zext i32 %index to i64))<nuw><nsw> + %p)<nuw> U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @gep_nusw_nneg
+;
+ %index.ext = zext i32 %index to i64
+ %gep = getelementptr nusw i32, ptr %p, i64 %index.ext
+ ret ptr %gep
+}
+
+define noundef ptr @gep_nuw(ptr %p, i64 %index) {
+; CHECK-LABEL: 'gep_nuw'
+; CHECK-NEXT: Classifying expressions for: @gep_nuw
+; CHECK-NEXT: %gep = getelementptr nuw i32, ptr %p, i64 %index
+; CHECK-NEXT: --> ((4 * %index)<nuw> + %p)<nuw> U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @gep_nuw
+;
+ %gep = getelementptr nuw i32, ptr %p, i64 %index
+ ret ptr %gep
+}
+
+define noundef ptr @gep_nusw_nuw(ptr %p, i64 %index) {
+; CHECK-LABEL: 'gep_nusw_nuw'
+; CHECK-NEXT: Classifying expressions for: @gep_nusw_nuw
+; CHECK-NEXT: %gep = getelementptr nusw nuw i32, ptr %p, i64 %index
+; CHECK-NEXT: --> ((4 * %index)<nuw><nsw> + %p)<nuw> U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @gep_nusw_nuw
+;
+ %gep = getelementptr nusw nuw i32, ptr %p, i64 %index
+ ret ptr %gep
+}
+
+define ptr @gep_nusw_nuw_missing_noundef(ptr %p, i64 %index) {
+; CHECK-LABEL: 'gep_nusw_nuw_missing_noundef'
+; CHECK-NEXT: Classifying expressions for: @gep_nusw_nuw_missing_noundef
+; CHECK-NEXT: %gep = getelementptr nusw nuw i32, ptr %p, i64 %index
+; CHECK-NEXT: --> ((4 * %index) + %p) U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @gep_nusw_nuw_missing_noundef
+;
+ %gep = getelementptr nusw nuw i32, ptr %p, i64 %index
+ ret ptr %gep
+}
More information about the llvm-commits
mailing list