[llvm] [llubi] Update the implementation of assume align operand bundle (PR #203775)

Zhige Chen via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 14 08:59:22 PDT 2026


https://github.com/nofe1248 created https://github.com/llvm/llvm-project/pull/203775

This PR updates the implementation for the `"align"(ptr %p, i64 %align, i64 %offset)` operand bundle of `@llvm.assume`: The old implementation reduced align/offset to the largest shared power of two. But LangRef requires checking %alloc - %offset in this case.

>From 4b3520b36b64e2ff8a340763c2cd595bdb19b3d6 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Sun, 14 Jun 2026 23:55:35 +0800
Subject: [PATCH] [llubi] Update the implementation of assume align operand
 bundle

---
 llvm/test/tools/llubi/assume_align_offset.ll    | 16 ++++++++++++++++
 llvm/test/tools/llubi/assume_operand_bundles.ll |  4 ++--
 llvm/tools/llubi/lib/Interpreter.cpp            | 16 ++++++----------
 3 files changed, 24 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/tools/llubi/assume_align_offset.ll

diff --git a/llvm/test/tools/llubi/assume_align_offset.ll b/llvm/test/tools/llubi/assume_align_offset.ll
new file mode 100644
index 0000000000000..4c13b6f959db3
--- /dev/null
+++ b/llvm/test/tools/llubi/assume_align_offset.ll
@@ -0,0 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
+; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
+
+define void @main() {
+  %alloc = alloca i32
+  call void @llvm.assume(i1 true) ["align"(ptr %alloc, i32 17, i32 8)]
+  call void @llvm.assume(i1 true) ["align"(ptr %alloc, i32 17, i32 4)]
+  ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT:   %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
+; CHECK-NEXT:   call void @llvm.assume(i1 true) [ "align"(ptr %alloc, i32 17, i32 8) ]
+; CHECK-NEXT: Stacktrace:
+; CHECK-NEXT: #0   call void @llvm.assume(i1 true) [ "align"(ptr %alloc, i32 17, i32 4) ] at @main <stdin>:10
+; CHECK-NEXT: Immediate UB detected: Assume on pointer ptr 0x8 [alloc] with a nonzero adjusted address and a non-power-of-two alignment 17.
+; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/test/tools/llubi/assume_operand_bundles.ll b/llvm/test/tools/llubi/assume_operand_bundles.ll
index e9abb574e0a1b..0c13993b08cf6 100644
--- a/llvm/test/tools/llubi/assume_operand_bundles.ll
+++ b/llvm/test/tools/llubi/assume_operand_bundles.ll
@@ -4,7 +4,7 @@
 define void @assume_align_dynamic(ptr %p, i32 %align) {
   call void @llvm.assume(i1 true) ["align"(ptr %p, i32 4)]
   call void @llvm.assume(i1 true) ["align"(ptr %p, i32 %align)]
-  call void @llvm.assume(i1 true) ["align"(ptr %p, i32 %align, i32 20)]
+  call void @llvm.assume(i1 true) ["align"(ptr %p, i32 %align, i32 0)]
   ret void
 }
 
@@ -31,7 +31,7 @@ define void @main() {
 ; CHECK-NEXT:   i32 %align = i32 8
 ; CHECK-NEXT:   call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 4) ]
 ; CHECK-NEXT:   call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 %align) ]
-; CHECK-NEXT:   call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 %align, i32 20) ]
+; CHECK-NEXT:   call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 %align, i32 0) ]
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: Exiting function: assume_align_dynamic
 ; CHECK-NEXT:   call void @assume_align_dynamic(ptr %alloc, i32 8)
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 5769d0a4a9c4d..a1460f20e6c58 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -830,25 +830,21 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
           switch (Kind) {
           case Attribute::Alignment: {
             // Alignment assumptions should have 2 or 3 arguments.
-            // If there are two integer arguments, use the largest power of 2
-            // that divides them as the alignment.
             APInt Alignment = getIntNonPoison(getValue(GetBundleArg(1)));
+            APInt CheckedAddr = WasOnPtr.address();
             if (OBU.Inputs.size() == 3) {
               APInt Offset = getIntNonPoison(getValue(GetBundleArg(2)));
-              if (!Alignment.isZero() || !Offset.isZero())
-                Alignment = APInt::getOneBitSet(
-                    std::max(Alignment.getBitWidth(), Offset.getBitWidth()),
-                    std::min(Alignment.countr_zero(), Offset.countr_zero()));
+              CheckedAddr -= Offset.zextOrTrunc(CheckedAddr.getBitWidth());
             }
             if (!Alignment.isPowerOf2()) {
-              if (!WasOnPtr.address().isZero())
-                reportImmediateUB() << "Assume on nonzero pointer " << WasOn
-                                    << " with a "
+              if (!CheckedAddr.isZero())
+                reportImmediateUB() << "Assume on pointer " << WasOn
+                                    << " with a nonzero adjusted address and a "
                                        "non-power-of-two alignment "
                                     << Alignment << '.';
               break;
             }
-            if (WasOnPtr.address().countr_zero() < Alignment.logBase2())
+            if (CheckedAddr.countr_zero() < Alignment.logBase2())
               reportImmediateUB()
                   << "The pointer " << WasOn << " violates align(" << Alignment
                   << ") assumption.";



More information about the llvm-commits mailing list