[llvm] [LVI] Handle nonnull attributes at callsite (PR #125377)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 2 06:51:05 PST 2025


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/125377

>From bcc27467398b0fbf16a4f944a48de12fc969c5b7 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 2 Feb 2025 11:08:12 +0800
Subject: [PATCH 1/5] [CVP] Add pre-commit tests. NFC.

---
 .../CorrelatedValuePropagation/non-null.ll    | 71 +++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
index 35d866ed2d92eb..10429ed90d6a22 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
@@ -344,4 +344,75 @@ define i1 @test_store_same_block(ptr %arg) {
   ret i1 %cmp
 }
 
+
+define i1 @test_known_nonnull_at_callsite(ptr %src) {
+; CHECK-LABEL: @test_known_nonnull_at_callsite(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @callee(ptr noundef nonnull [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT:    ret i1 [[NONNULL]]
+;
+entry:
+  call void @callee(ptr noundef nonnull %src)
+  %nonnull = icmp eq ptr %src, null
+  ret i1 %nonnull
+}
+
+define i1 @test_known_nonnull_mixed(ptr %src) {
+; CHECK-LABEL: @test_known_nonnull_mixed(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @callee2(ptr nonnull [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT:    ret i1 [[NONNULL]]
+;
+entry:
+  call void @callee2(ptr nonnull %src)
+  %nonnull = icmp eq ptr %src, null
+  ret i1 %nonnull
+}
+
+define i1 @test_known_nonnull_at_callsite_dereferenceable(ptr %src) {
+; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT:    ret i1 [[NONNULL]]
+;
+entry:
+  call void @callee(ptr dereferenceable(1) %src)
+  %nonnull = icmp eq ptr %src, null
+  ret i1 %nonnull
+}
+
+; Negative tests
+
+define i1 @test_known_nonnull_at_callsite_without_noundef(ptr %src) {
+; CHECK-LABEL: @test_known_nonnull_at_callsite_without_noundef(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @callee(ptr nonnull [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT:    ret i1 [[NONNULL]]
+;
+entry:
+  call void @callee(ptr nonnull %src)
+  %nonnull = icmp eq ptr %src, null
+  ret i1 %nonnull
+}
+
+define i1 @test_known_nonnull_at_callsite_dereferenceable_null_is_defined(ptr %src) #0 {
+; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable_null_is_defined(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT:    ret i1 [[NONNULL]]
+;
+entry:
+  call void @callee(ptr dereferenceable(1) %src)
+  %nonnull = icmp eq ptr %src, null
+  ret i1 %nonnull
+}
+
+declare void @callee(ptr)
+declare void @callee2(ptr noundef)
+
 attributes #0 = { null_pointer_is_valid }

>From c3bacf06324b96fb5d48c781b723a29c0e2cf4ca Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 2 Feb 2025 11:21:10 +0800
Subject: [PATCH 2/5] [LVI] Handle nonnull at callsite

---
 llvm/lib/Analysis/LazyValueInfo.cpp           | 25 ++++++++++++++-----
 .../CorrelatedValuePropagation/non-null.ll    |  9 +++----
 2 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 20f69a0955f51c..14f07da4eefb15 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -780,12 +780,25 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
   }
 
   if (BBLV.isOverdefined()) {
-    // Check whether we're checking at the terminator, and the pointer has
-    // been dereferenced in this block.
-    PointerType *PTy = dyn_cast<PointerType>(Val->getType());
-    if (PTy && BB->getTerminator() == BBI &&
-        isNonNullAtEndOfBlock(Val, BB))
-      BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
+    if (PointerType *PTy = dyn_cast<PointerType>(Val->getType())) {
+      // Check whether we're checking at the terminator, and the pointer has
+      // been dereferenced in this block.
+      if (BB->getTerminator() == BBI && isNonNullAtEndOfBlock(Val, BB))
+        BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
+      else {
+        for (Use &U : Val->uses()) {
+          if (auto *CB = dyn_cast<CallBase>(U.getUser())) {
+            if (CB->isArgOperand(&U) &&
+                CB->paramHasNonNullAttr(CB->getArgOperandNo(&U),
+                                        /*AllowUndefOrPoison=*/false) &&
+                isValidAssumeForContext(CB, BBI)) {
+              BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
+              break;
+            }
+          }
+        }
+      }
+    }
   }
 }
 
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
index 10429ed90d6a22..090826e90ef568 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
@@ -349,8 +349,7 @@ define i1 @test_known_nonnull_at_callsite(ptr %src) {
 ; CHECK-LABEL: @test_known_nonnull_at_callsite(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    call void @callee(ptr noundef nonnull [[SRC:%.*]])
-; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
-; CHECK-NEXT:    ret i1 [[NONNULL]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   call void @callee(ptr noundef nonnull %src)
@@ -362,8 +361,7 @@ define i1 @test_known_nonnull_mixed(ptr %src) {
 ; CHECK-LABEL: @test_known_nonnull_mixed(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    call void @callee2(ptr nonnull [[SRC:%.*]])
-; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
-; CHECK-NEXT:    ret i1 [[NONNULL]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   call void @callee2(ptr nonnull %src)
@@ -375,8 +373,7 @@ define i1 @test_known_nonnull_at_callsite_dereferenceable(ptr %src) {
 ; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
-; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
-; CHECK-NEXT:    ret i1 [[NONNULL]]
+; CHECK-NEXT:    ret i1 false
 ;
 entry:
   call void @callee(ptr dereferenceable(1) %src)

>From 498ac15f6e7fd9a79649c4aecb0ab10fcf4eb00b Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 2 Feb 2025 17:03:11 +0800
Subject: [PATCH 3/5] [LVI] Address review comments.

---
 llvm/lib/Analysis/LazyValueInfo.cpp           | 32 ++++++++-----------
 .../CorrelatedValuePropagation/non-null.ll    |  3 ++
 2 files changed, 16 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 14f07da4eefb15..f547f9a5a01f43 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -644,6 +644,13 @@ static void AddNonNullPointersByInstruction(
     AddNonNullPointer(MI->getRawDest(), PtrSet);
     if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI))
       AddNonNullPointer(MTI->getRawSource(), PtrSet);
+  } else if (auto *CB = dyn_cast<CallBase>(I)) {
+    for (auto &U : CB->args()) {
+      if (U->getType()->isPointerTy() &&
+          CB->paramHasNonNullAttr(CB->getArgOperandNo(&U),
+                                  /*AllowUndefOrPoison=*/false))
+        AddNonNullPointer(U.get(), PtrSet);
+    }
   }
 }
 
@@ -780,25 +787,12 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
   }
 
   if (BBLV.isOverdefined()) {
-    if (PointerType *PTy = dyn_cast<PointerType>(Val->getType())) {
-      // Check whether we're checking at the terminator, and the pointer has
-      // been dereferenced in this block.
-      if (BB->getTerminator() == BBI && isNonNullAtEndOfBlock(Val, BB))
-        BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
-      else {
-        for (Use &U : Val->uses()) {
-          if (auto *CB = dyn_cast<CallBase>(U.getUser())) {
-            if (CB->isArgOperand(&U) &&
-                CB->paramHasNonNullAttr(CB->getArgOperandNo(&U),
-                                        /*AllowUndefOrPoison=*/false) &&
-                isValidAssumeForContext(CB, BBI)) {
-              BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
-              break;
-            }
-          }
-        }
-      }
-    }
+    // Check whether we're checking at the terminator, and the pointer has
+    // been dereferenced in this block.
+    PointerType *PTy = dyn_cast<PointerType>(Val->getType());
+    if (PTy && BB->getTerminator() == BBI &&
+        isNonNullAtEndOfBlock(Val, BB))
+      BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
   }
 }
 
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
index 090826e90ef568..f1acdf373e1ba0 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
@@ -349,6 +349,7 @@ define i1 @test_known_nonnull_at_callsite(ptr %src) {
 ; CHECK-LABEL: @test_known_nonnull_at_callsite(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    call void @callee(ptr noundef nonnull [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
 ; CHECK-NEXT:    ret i1 false
 ;
 entry:
@@ -361,6 +362,7 @@ define i1 @test_known_nonnull_mixed(ptr %src) {
 ; CHECK-LABEL: @test_known_nonnull_mixed(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    call void @callee2(ptr nonnull [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
 ; CHECK-NEXT:    ret i1 false
 ;
 entry:
@@ -373,6 +375,7 @@ define i1 @test_known_nonnull_at_callsite_dereferenceable(ptr %src) {
 ; CHECK-LABEL: @test_known_nonnull_at_callsite_dereferenceable(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    call void @callee(ptr dereferenceable(1) [[SRC:%.*]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
 ; CHECK-NEXT:    ret i1 false
 ;
 entry:

>From 074099d20cc85514d050918b5cbc5e77481ca197 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 2 Feb 2025 22:36:14 +0800
Subject: [PATCH 4/5] [CVP] Add more tests. NFC.

---
 .../CorrelatedValuePropagation/non-null.ll    | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
index f1acdf373e1ba0..aaeba3f4e4d904 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
@@ -384,6 +384,21 @@ entry:
   ret i1 %nonnull
 }
 
+define i1 @test_known_nonnull_at_callsite_gep_inbounds(ptr %src, i64 %x) {
+; CHECK-LABEL: @test_known_nonnull_at_callsite_gep_inbounds(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[SRC:%.*]], i64 [[X:%.*]]
+; CHECK-NEXT:    call void @callee(ptr noundef nonnull [[GEP]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %gep = getelementptr inbounds i8, ptr %src, i64 %x
+  call void @callee(ptr noundef nonnull %gep)
+  %nonnull = icmp eq ptr %src, null
+  ret i1 %nonnull
+}
+
 ; Negative tests
 
 define i1 @test_known_nonnull_at_callsite_without_noundef(ptr %src) {
@@ -412,6 +427,21 @@ entry:
   ret i1 %nonnull
 }
 
+define i1 @test_known_nonnull_at_callsite_gep_without_inbounds(ptr %src, i64 %x) {
+; CHECK-LABEL: @test_known_nonnull_at_callsite_gep_without_inbounds(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[X:%.*]]
+; CHECK-NEXT:    call void @callee(ptr noundef nonnull [[GEP]])
+; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
+; CHECK-NEXT:    ret i1 false
+;
+entry:
+  %gep = getelementptr i8, ptr %src, i64 %x
+  call void @callee(ptr noundef nonnull %gep)
+  %nonnull = icmp eq ptr %src, null
+  ret i1 %nonnull
+}
+
 declare void @callee(ptr)
 declare void @callee2(ptr noundef)
 

>From 54cb33454a17d5bbcf319a3ed104c98d2e4c487f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 2 Feb 2025 22:42:41 +0800
Subject: [PATCH 5/5] [LVI] Fix miscompilation

---
 llvm/lib/Analysis/LazyValueInfo.cpp                       | 8 +++++---
 .../Transforms/CorrelatedValuePropagation/non-null.ll     | 2 +-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index f547f9a5a01f43..8c2d9710e8ea95 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -622,10 +622,12 @@ LazyValueInfoImpl::solveBlockValueImpl(Value *Val, BasicBlock *BB) {
   return getFromRangeMetadata(BBI);
 }
 
-static void AddNonNullPointer(Value *Ptr, NonNullPointerSet &PtrSet) {
+static void AddNonNullPointer(Value *Ptr, NonNullPointerSet &PtrSet,
+                              bool IsDereferenced = true) {
   // TODO: Use NullPointerIsDefined instead.
   if (Ptr->getType()->getPointerAddressSpace() == 0)
-    PtrSet.insert(getUnderlyingObject(Ptr));
+    PtrSet.insert(IsDereferenced ? getUnderlyingObject(Ptr)
+                                 : Ptr->stripInBoundsOffsets());
 }
 
 static void AddNonNullPointersByInstruction(
@@ -649,7 +651,7 @@ static void AddNonNullPointersByInstruction(
       if (U->getType()->isPointerTy() &&
           CB->paramHasNonNullAttr(CB->getArgOperandNo(&U),
                                   /*AllowUndefOrPoison=*/false))
-        AddNonNullPointer(U.get(), PtrSet);
+        AddNonNullPointer(U.get(), PtrSet, /*IsDereferenced=*/false);
     }
   }
 }
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
index aaeba3f4e4d904..53a94e13a1763c 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/non-null.ll
@@ -433,7 +433,7 @@ define i1 @test_known_nonnull_at_callsite_gep_without_inbounds(ptr %src, i64 %x)
 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[SRC:%.*]], i64 [[X:%.*]]
 ; CHECK-NEXT:    call void @callee(ptr noundef nonnull [[GEP]])
 ; CHECK-NEXT:    [[NONNULL:%.*]] = icmp eq ptr [[SRC]], null
-; CHECK-NEXT:    ret i1 false
+; CHECK-NEXT:    ret i1 [[NONNULL]]
 ;
 entry:
   %gep = getelementptr i8, ptr %src, i64 %x



More information about the llvm-commits mailing list