Skip to content

[LVI] Extract information from assume operand bundles#176734

Merged
philnik777 merged 2 commits intollvm:mainfrom
philnik777:lvi_handle_assume_operand_bundles
Jan 19, 2026
Merged

[LVI] Extract information from assume operand bundles#176734
philnik777 merged 2 commits intollvm:mainfrom
philnik777:lvi_handle_assume_operand_bundles

Conversation

@philnik777
Copy link
Copy Markdown
Contributor

This patch teaches LVI to extract information from assume operand bundles. Specifically, it now uses nonnull and dereferenceable information to remove comparisons to null pointers.

@philnik777 philnik777 requested a review from nikic as a code owner January 19, 2026 11:36
@llvmbot llvmbot added llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Jan 19, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Jan 19, 2026

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: Nikolas Klauser (philnik777)

Changes

This patch teaches LVI to extract information from assume operand bundles. Specifically, it now uses nonnull and dereferenceable information to remove comparisons to null pointers.


Full diff: https://github.com/llvm/llvm-project/pull/176734.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/LazyValueInfo.cpp (+31-4)
  • (added) llvm/test/Transforms/JumpThreading/assume-operand-bundles.ll (+60)
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index df75999eb6080..35bfab115c521 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -14,6 +14,7 @@
 #include "llvm/Analysis/LazyValueInfo.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Analysis/AssumeBundleQueries.h"
 #include "llvm/Analysis/AssumptionCache.h"
 #include "llvm/Analysis/ConstantFolding.h"
 #include "llvm/Analysis/InstructionSimplify.h"
@@ -833,13 +834,39 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
     // Only check assumes in the block of the context instruction. Other
     // assumes will have already been taken into account when the value was
     // propagated from predecessor blocks.
-    auto *I = cast<CallInst>(AssumeVH);
+    auto *I = cast<AssumeInst>(AssumeVH);
+
     if (I->getParent() != BB || !isValidAssumeForContext(I, BBI))
       continue;
 
-    BBLV = BBLV.intersect(*getValueFromCondition(Val, I->getArgOperand(0),
-                                                 /*IsTrueDest*/ true,
-                                                 /*UseBlockValue*/ false));
+    if (I->hasOperandBundles()) {
+      for (auto Info : I->bundle_op_infos()) {
+        if (RetainedKnowledge RK = getKnowledgeFromBundle(*I, Info)) {
+          if (RK.WasOn != Val)
+            continue;
+          switch (RK.AttrKind) {
+          case Attribute::NonNull:
+            BBLV = BBLV.intersect(ValueLatticeElement::getNot(
+                Constant::getNullValue(RK.WasOn->getType())));
+            break;
+
+          case Attribute::Dereferenceable:
+            if (auto *CI = dyn_cast<ConstantInt>(RK.IRArgValue);
+                CI && !CI->isZero())
+              BBLV = BBLV.intersect(ValueLatticeElement::getNot(
+                  Constant::getNullValue(RK.IRArgValue->getType())));
+            break;
+
+          default:
+            break;
+          }
+        }
+      }
+    } else {
+      BBLV = BBLV.intersect(*getValueFromCondition(Val, I->getArgOperand(0),
+                                                   /*IsTrueDest*/ true,
+                                                   /*UseBlockValue*/ false));
+    }
   }
 
   // If guards are not used in the module, don't spend time looking for them
diff --git a/llvm/test/Transforms/JumpThreading/assume-operand-bundles.ll b/llvm/test/Transforms/JumpThreading/assume-operand-bundles.ll
new file mode 100644
index 0000000000000..822b08f676a04
--- /dev/null
+++ b/llvm/test/Transforms/JumpThreading/assume-operand-bundles.ll
@@ -0,0 +1,60 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=jump-threading,dce %s | FileCheck %s
+
+define i32 @nonull(ptr %ptr) {
+; CHECK-LABEL: define i32 @nonull(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[TRUE:.*:]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[PTR]]) ]
+; CHECK-NEXT:    ret i32 1
+;
+  call void @llvm.assume(i1 true) [ "nonnull"(ptr %ptr) ]
+  %is_nonnull = icmp ne ptr %ptr, null
+  br i1 %is_nonnull, label %true, label %false
+
+true:
+  ret i32 1
+
+false:
+  ret i32 2
+}
+
+define i32 @nonull_on_other_ptr(ptr %ptr, ptr %other_ptr) {
+; CHECK-LABEL: define i32 @nonull_on_other_ptr(
+; CHECK-SAME: ptr [[PTR:%.*]], ptr [[OTHER_PTR:%.*]]) {
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(ptr [[OTHER_PTR]]) ]
+; CHECK-NEXT:    [[IS_NONNULL:%.*]] = icmp ne ptr [[PTR]], null
+; CHECK-NEXT:    br i1 [[IS_NONNULL]], label %[[TRUE:.*]], label %[[FALSE:.*]]
+; CHECK:       [[TRUE]]:
+; CHECK-NEXT:    ret i32 1
+; CHECK:       [[FALSE]]:
+; CHECK-NEXT:    ret i32 2
+;
+  call void @llvm.assume(i1 true) [ "nonnull"(ptr %other_ptr) ]
+  %is_nonnull = icmp ne ptr %ptr, null
+  br i1 %is_nonnull, label %true, label %false
+
+true:
+  ret i32 1
+
+false:
+  ret i32 2
+}
+
+define i32 @dereferenceable(ptr %ptr) {
+; CHECK-LABEL: define i32 @dereferenceable(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT:  [[TRUE:.*:]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i32 1) ]
+; CHECK-NEXT:    ret i32 1
+;
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %ptr, i32 1) ]
+  %is_nonnull = icmp ne ptr %ptr, null
+  br i1 %is_nonnull, label %true, label %false
+
+true:
+  ret i32 1
+
+false:
+  ret i32 2
+}

Copy link
Copy Markdown
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@philnik777 philnik777 merged commit d45ea8f into llvm:main Jan 19, 2026
11 checks passed
@philnik777 philnik777 deleted the lvi_handle_assume_operand_bundles branch January 19, 2026 16:14
BStott6 pushed a commit to BStott6/llvm-project that referenced this pull request Jan 22, 2026
This patch teaches LVI to extract information from assume operand
bundles. Specifically, it now uses nonnull and dereferenceable
information to remove comparisons to null pointers.
@pcc
Copy link
Copy Markdown
Contributor

pcc commented Jan 23, 2026

There are several UBSan failures relating to null pointers after this change landed, e.g. https://lab.llvm.org/buildbot/#/builders/25/builds/14949

This change looks like the most likely culprit. Can you please take a look?

@philnik777
Copy link
Copy Markdown
Contributor Author

@pcc #177562 should have fixed this. It looks like there are still UBSan issues, but they seem unrelated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants