Skip to content

Commit 1cea5c2

Browse files
authored
[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).
1 parent 0ef8e71 commit 1cea5c2

File tree

2 files changed

+40
-15
lines changed

2 files changed

+40
-15
lines changed

llvm/lib/Transforms/Utils/SCCPSolver.cpp

+33-1
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,12 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
446446
return markConstant(ValueState[V], V, C);
447447
}
448448

449+
bool markNotConstant(ValueLatticeElement &IV, Value *V, Constant *C);
450+
451+
bool markNotNull(ValueLatticeElement &IV, Value *V) {
452+
return markNotConstant(IV, V, Constant::getNullValue(V->getType()));
453+
}
454+
449455
/// markConstantRange - Mark the object as constant range with \p CR. If the
450456
/// object is not a constant range with the range \p CR, add it to the
451457
/// instruction work list so that the users of the instruction are updated
@@ -820,7 +826,11 @@ class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
820826
return;
821827
}
822828
}
823-
// Assume nothing about the incoming arguments without range.
829+
if (A->hasNonNullAttr()) {
830+
markNotNull(ValueState[A], A);
831+
return;
832+
}
833+
// Assume nothing about the incoming arguments without attributes.
824834
markOverdefined(A);
825835
}
826836

@@ -905,6 +915,15 @@ bool SCCPInstVisitor::markConstant(ValueLatticeElement &IV, Value *V,
905915
return true;
906916
}
907917

918+
bool SCCPInstVisitor::markNotConstant(ValueLatticeElement &IV, Value *V,
919+
Constant *C) {
920+
if (!IV.markNotConstant(C))
921+
return false;
922+
LLVM_DEBUG(dbgs() << "markNotConstant: " << *C << ": " << *V << '\n');
923+
pushToWorkList(IV, V);
924+
return true;
925+
}
926+
908927
bool SCCPInstVisitor::markConstantRange(ValueLatticeElement &IV, Value *V,
909928
const ConstantRange &CR) {
910929
if (!IV.markConstantRange(CR))
@@ -1574,6 +1593,19 @@ void SCCPInstVisitor::visitGetElementPtrInst(GetElementPtrInst &I) {
15741593
if (ValueState[&I].isOverdefined())
15751594
return (void)markOverdefined(&I);
15761595

1596+
const ValueLatticeElement &PtrState = getValueState(I.getPointerOperand());
1597+
if (PtrState.isUnknownOrUndef())
1598+
return;
1599+
1600+
// gep inbounds/nuw of non-null is non-null.
1601+
if (PtrState.isNotConstant() && PtrState.getNotConstant()->isNullValue()) {
1602+
if (I.hasNoUnsignedWrap() ||
1603+
(I.isInBounds() &&
1604+
!NullPointerIsDefined(I.getFunction(), I.getAddressSpace())))
1605+
return (void)markNotNull(ValueState[&I], &I);
1606+
return (void)markOverdefined(&I);
1607+
}
1608+
15771609
SmallVector<Constant *, 8> Operands;
15781610
Operands.reserve(I.getNumOperands());
15791611

llvm/test/Transforms/SCCP/pointer-nonnull.ll

+7-14
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ define i1 @test_no_attr(ptr %p) {
1414
define i1 @test_nonnull(ptr nonnull %p) {
1515
; CHECK-LABEL: define i1 @test_nonnull(
1616
; CHECK-SAME: ptr nonnull [[P:%.*]]) {
17-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[P]], null
18-
; CHECK-NEXT: ret i1 [[CMP]]
17+
; CHECK-NEXT: ret i1 true
1918
;
2019
%cmp = icmp ne ptr %p, null
2120
ret i1 %cmp
@@ -24,8 +23,7 @@ define i1 @test_nonnull(ptr nonnull %p) {
2423
define i1 @test_nonnull_eq(ptr nonnull %p) {
2524
; CHECK-LABEL: define i1 @test_nonnull_eq(
2625
; CHECK-SAME: ptr nonnull [[P:%.*]]) {
27-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[P]], null
28-
; CHECK-NEXT: ret i1 [[CMP]]
26+
; CHECK-NEXT: ret i1 false
2927
;
3028
%cmp = icmp eq ptr %p, null
3129
ret i1 %cmp
@@ -34,8 +32,7 @@ define i1 @test_nonnull_eq(ptr nonnull %p) {
3432
define i1 @test_dereferenceable(ptr dereferenceable(4) %p) {
3533
; CHECK-LABEL: define i1 @test_dereferenceable(
3634
; CHECK-SAME: ptr dereferenceable(4) [[P:%.*]]) {
37-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[P]], null
38-
; CHECK-NEXT: ret i1 [[CMP]]
35+
; CHECK-NEXT: ret i1 true
3936
;
4037
%cmp = icmp ne ptr %p, null
4138
ret i1 %cmp
@@ -57,8 +54,7 @@ define i1 @test_gep_nuw(ptr nonnull %p, i64 %x) {
5754
; CHECK-LABEL: define i1 @test_gep_nuw(
5855
; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
5956
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]]
60-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[GEP]], null
61-
; CHECK-NEXT: ret i1 [[CMP]]
57+
; CHECK-NEXT: ret i1 true
6258
;
6359
%gep = getelementptr nuw i8, ptr %p, i64 %x
6460
%cmp = icmp ne ptr %gep, null
@@ -69,8 +65,7 @@ define i1 @test_gep_inbounds(ptr nonnull %p, i64 %x) {
6965
; CHECK-LABEL: define i1 @test_gep_inbounds(
7066
; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
7167
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[X]]
72-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[GEP]], null
73-
; CHECK-NEXT: ret i1 [[CMP]]
68+
; CHECK-NEXT: ret i1 true
7469
;
7570
%gep = getelementptr inbounds i8, ptr %p, i64 %x
7671
%cmp = icmp ne ptr %gep, null
@@ -94,8 +89,7 @@ define i1 @test_select(i1 %c, ptr nonnull %p, i64 %x) {
9489
; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
9590
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]]
9691
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], ptr [[P]], ptr [[GEP]]
97-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[SEL]], null
98-
; CHECK-NEXT: ret i1 [[CMP]]
92+
; CHECK-NEXT: ret i1 true
9993
;
10094
%gep = getelementptr nuw i8, ptr %p, i64 %x
10195
%sel = select i1 %c, ptr %p, ptr %gep
@@ -127,8 +121,7 @@ define i1 @test_phi(i1 %c, ptr nonnull %p, i64 %x) {
127121
; CHECK-NEXT: br label %[[JOIN]]
128122
; CHECK: [[JOIN]]:
129123
; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[GEP]], %[[IF]] ]
130-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[PHI]], null
131-
; CHECK-NEXT: ret i1 [[CMP]]
124+
; CHECK-NEXT: ret i1 true
132125
;
133126
entry:
134127
br i1 %c, label %if, label %join

0 commit comments

Comments
 (0)