[llvm] 1cea5c2 - [SCCP] Propagate non-null pointers (#106090)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 27 00:13:45 PDT 2024
Author: Nikita Popov
Date: 2024-08-27T09:13:41+02:00
New Revision: 1cea5c2138bef3d8fec75508df6dbb858e6e3560
URL: https://github.com/llvm/llvm-project/commit/1cea5c2138bef3d8fec75508df6dbb858e6e3560
DIFF: https://github.com/llvm/llvm-project/commit/1cea5c2138bef3d8fec75508df6dbb858e6e3560.diff
LOG: [SCCP] Propagate non-null pointers (#106090)
Add NotConstant(Null) roots for nonnull arguments and then propagate
them through nuw/inbounds GEPs.
Having this functionality in SCCP is useful because it allows reliably
eliminating null comparisons, independently of how deeply nested they
are in selects/phis. This handles cases that would hit a cutoff in
ValueTracking otherwise.
The implementation is something of a MVP, there are a number of obvious
extensions (e.g. allocas are also non-null).
Added:
Modified:
llvm/lib/Transforms/Utils/SCCPSolver.cpp
llvm/test/Transforms/SCCP/pointer-nonnull.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index c6f355a07d9c7f..c21b4c0b3a1c87 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -446,6 +446,12 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
return markConstant(ValueState[V], V, C);
}
+ bool markNotConstant(ValueLatticeElement &IV, Value *V, Constant *C);
+
+ bool markNotNull(ValueLatticeElement &IV, Value *V) {
+ return markNotConstant(IV, V, Constant::getNullValue(V->getType()));
+ }
+
/// markConstantRange - Mark the object as constant range with \p CR. If the
/// object is not a constant range with the range \p CR, add it to the
/// instruction work list so that the users of the instruction are updated
@@ -820,7 +826,11 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
return;
}
}
- // Assume nothing about the incoming arguments without range.
+ if (A->hasNonNullAttr()) {
+ markNotNull(ValueState[A], A);
+ return;
+ }
+ // Assume nothing about the incoming arguments without attributes.
markOverdefined(A);
}
@@ -905,6 +915,15 @@ bool SCCPInstVisitor::markConstant(ValueLatticeElement &IV, Value *V,
return true;
}
+bool SCCPInstVisitor::markNotConstant(ValueLatticeElement &IV, Value *V,
+ Constant *C) {
+ if (!IV.markNotConstant(C))
+ return false;
+ LLVM_DEBUG(dbgs() << "markNotConstant: " << *C << ": " << *V << '\n');
+ pushToWorkList(IV, V);
+ return true;
+}
+
bool SCCPInstVisitor::markConstantRange(ValueLatticeElement &IV, Value *V,
const ConstantRange &CR) {
if (!IV.markConstantRange(CR))
@@ -1574,6 +1593,19 @@ void SCCPInstVisitor::visitGetElementPtrInst(GetElementPtrInst &I) {
if (ValueState[&I].isOverdefined())
return (void)markOverdefined(&I);
+ const ValueLatticeElement &PtrState = getValueState(I.getPointerOperand());
+ if (PtrState.isUnknownOrUndef())
+ return;
+
+ // gep inbounds/nuw of non-null is non-null.
+ if (PtrState.isNotConstant() && PtrState.getNotConstant()->isNullValue()) {
+ if (I.hasNoUnsignedWrap() ||
+ (I.isInBounds() &&
+ !NullPointerIsDefined(I.getFunction(), I.getAddressSpace())))
+ return (void)markNotNull(ValueState[&I], &I);
+ return (void)markOverdefined(&I);
+ }
+
SmallVector<Constant *, 8> Operands;
Operands.reserve(I.getNumOperands());
diff --git a/llvm/test/Transforms/SCCP/pointer-nonnull.ll b/llvm/test/Transforms/SCCP/pointer-nonnull.ll
index 85367d8a56765e..a88f08ab25fe1d 100644
--- a/llvm/test/Transforms/SCCP/pointer-nonnull.ll
+++ b/llvm/test/Transforms/SCCP/pointer-nonnull.ll
@@ -14,8 +14,7 @@ define i1 @test_no_attr(ptr %p) {
define i1 @test_nonnull(ptr nonnull %p) {
; CHECK-LABEL: define i1 @test_nonnull(
; CHECK-SAME: ptr nonnull [[P:%.*]]) {
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[P]], null
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%cmp = icmp ne ptr %p, null
ret i1 %cmp
@@ -24,8 +23,7 @@ define i1 @test_nonnull(ptr nonnull %p) {
define i1 @test_nonnull_eq(ptr nonnull %p) {
; CHECK-LABEL: define i1 @test_nonnull_eq(
; CHECK-SAME: ptr nonnull [[P:%.*]]) {
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P]], null
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%cmp = icmp eq ptr %p, null
ret i1 %cmp
@@ -34,8 +32,7 @@ define i1 @test_nonnull_eq(ptr nonnull %p) {
define i1 @test_dereferenceable(ptr dereferenceable(4) %p) {
; CHECK-LABEL: define i1 @test_dereferenceable(
; CHECK-SAME: ptr dereferenceable(4) [[P:%.*]]) {
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[P]], null
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%cmp = icmp ne ptr %p, null
ret i1 %cmp
@@ -57,8 +54,7 @@ define i1 @test_gep_nuw(ptr nonnull %p, i64 %x) {
; CHECK-LABEL: define i1 @test_gep_nuw(
; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[GEP]], null
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%gep = getelementptr nuw i8, ptr %p, i64 %x
%cmp = icmp ne ptr %gep, null
@@ -69,8 +65,7 @@ define i1 @test_gep_inbounds(ptr nonnull %p, i64 %x) {
; CHECK-LABEL: define i1 @test_gep_inbounds(
; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[X]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[GEP]], null
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%gep = getelementptr inbounds i8, ptr %p, i64 %x
%cmp = icmp ne ptr %gep, null
@@ -94,8 +89,7 @@ define i1 @test_select(i1 %c, ptr nonnull %p, i64 %x) {
; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]]
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], ptr [[P]], ptr [[GEP]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[SEL]], null
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%gep = getelementptr nuw i8, ptr %p, i64 %x
%sel = select i1 %c, ptr %p, ptr %gep
@@ -127,8 +121,7 @@ define i1 @test_phi(i1 %c, ptr nonnull %p, i64 %x) {
; CHECK-NEXT: br label %[[JOIN]]
; CHECK: [[JOIN]]:
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[GEP]], %[[IF]] ]
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[PHI]], null
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
entry:
br i1 %c, label %if, label %join
More information about the llvm-commits
mailing list