[llvm] [llubi] Global variables with simple initializers and global-address constants (PR #200547)

Zhige Chen via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 2 01:47:28 PDT 2026


https://github.com/nofe1248 updated https://github.com/llvm/llvm-project/pull/200547

>From 6718323b1a69d7748c821fce75a0aadc40d6f540 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhigec_cpp at outlook.com>
Date: Sat, 30 May 2026 15:10:47 +0800
Subject: [PATCH 1/5] [llubi] Global variables with simple initializers &
 address constants

---
 llvm/test/tools/llubi/global.ll               | 25 +++++++
 .../test/tools/llubi/global_constant_store.ll | 14 ++++
 .../llubi/global_constexpr_initializer.ll     | 10 +++
 llvm/tools/llubi/lib/Context.cpp              | 70 ++++++++++++++++++-
 llvm/tools/llubi/lib/Context.h                |  2 +
 llvm/tools/llubi/lib/ExecutorBase.cpp         |  6 ++
 6 files changed, 126 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/tools/llubi/global.ll
 create mode 100644 llvm/test/tools/llubi/global_constant_store.ll
 create mode 100644 llvm/test/tools/llubi/global_constexpr_initializer.ll

diff --git a/llvm/test/tools/llubi/global.ll b/llvm/test/tools/llubi/global.ll
new file mode 100644
index 0000000000000..ddb707f4e5fdc
--- /dev/null
+++ b/llvm/test/tools/llubi/global.ll
@@ -0,0 +1,25 @@
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i32:32:32"
+
+ at value = global i32 41
+ at value_ptr = global ptr @value
+ at aggregate = global { i32, [2 x i8] } { i32 7, [2 x i8] c"hi" }
+
+define void @main() {
+  %initial = load i32, ptr @value
+  store i32 42, ptr @value
+  %ptr = load ptr, ptr @value_ptr
+  %updated = load i32, ptr %ptr
+  %aggregate_value = load { i32, [2 x i8] }, ptr @aggregate
+  ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT:   %initial = load i32, ptr @value, align 4 => i32 41
+; CHECK-NEXT:   store i32 42, ptr @value, align 4
+; CHECK-NEXT:   %ptr = load ptr, ptr @value_ptr, align 8 => ptr 0x8 [value]
+; CHECK-NEXT:   %updated = load i32, ptr %ptr, align 4 => i32 42
+; CHECK-NEXT:   %aggregate_value = load { i32, [2 x i8] }, ptr @aggregate, align 4 => { i32 7, { i8 104, i8 105 } }
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/global_constant_store.ll b/llvm/test/tools/llubi/global_constant_store.ll
new file mode 100644
index 0000000000000..bf5f6322bb014
--- /dev/null
+++ b/llvm/test/tools/llubi/global_constant_store.ll
@@ -0,0 +1,14 @@
+; RUN: not llubi --verbose < %s 2>&1 | FileCheck %s
+
+ at constant = constant i32 1
+
+define void @main() {
+  store i32 2, ptr @constant
+  ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT: Stacktrace:
+; CHECK-NEXT: #0   store i32 2, ptr @constant, align 4 at @main
+; CHECK-NEXT: Immediate UB detected: Try to write to a constant memory object at address 0x8.
+; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/test/tools/llubi/global_constexpr_initializer.ll b/llvm/test/tools/llubi/global_constexpr_initializer.ll
new file mode 100644
index 0000000000000..c4b2ee2e78384
--- /dev/null
+++ b/llvm/test/tools/llubi/global_constexpr_initializer.ll
@@ -0,0 +1,10 @@
+; RUN: not llubi < %s 2>&1 | FileCheck %s
+
+ at value = global i32 0
+ at aggregate = global [1 x ptr] [ptr getelementptr (i32, ptr @value, i64 1)]
+
+define void @main() {
+  ret void
+}
+
+; CHECK: error: Failed to initialize global values
diff --git a/llvm/tools/llubi/lib/Context.cpp b/llvm/tools/llubi/lib/Context.cpp
index fbb952f9ccc75..cf6b5042690f8 100644
--- a/llvm/tools/llubi/lib/Context.cpp
+++ b/llvm/tools/llubi/lib/Context.cpp
@@ -21,6 +21,37 @@ Context::Context(Module &M, const AsmParserContext *ParserContext)
 
 Context::~Context() = default;
 
+bool Context::isSupportedGlobalInitializer(Constant *C) const {
+  if (isa<PoisonValue, ConstantAggregateZero, ConstantPointerNull, ConstantInt,
+          ConstantFP>(C))
+    return true;
+
+  if (auto const *CDS = dyn_cast<ConstantDataSequential>(C)) {
+    for (uint32_t I = 0, E = CDS->getNumElements(); I != E; ++I)
+      if (!isSupportedGlobalInitializer(CDS->getElementAsConstant(I)))
+        return false;
+    return true;
+  }
+
+  if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
+    for (Value *Op : CA->operands())
+      if (!isSupportedGlobalInitializer(cast<Constant>(Op)))
+        return false;
+    return true;
+  }
+
+  if (auto const *BA = dyn_cast<BlockAddress>(C))
+    return BlockAddrMap.contains(BA->getBasicBlock());
+
+  if (auto const *GV = dyn_cast<GlobalVariable>(C))
+    return GlobalAddrMap.contains(GV);
+
+  if (auto const *F = dyn_cast<Function>(C))
+    return FuncAddrMap.contains(F);
+
+  return false;
+}
+
 bool Context::initGlobalValues() {
   // Register all function and block targets that may be used by indirect calls
   // and branches.
@@ -49,7 +80,41 @@ bool Context::initGlobalValues() {
       BlockAddrMap.try_emplace(&BB, deriveFromMemoryObject(BlockObj));
     }
   }
-  // TODO: initialize global variables.
+
+  for (GlobalVariable &GV : M.globals()) {
+    if (!GV.hasInitializer())
+      continue;
+
+    Type *ValueTy = GV.getValueType();
+    uint64_t const Size = getEffectiveTypeAllocSize(ValueTy);
+    Align Alignment = GV.getPointerAlignment(DL);
+    auto const Obj =
+        allocate(Size, Alignment.value(), GV.getName(), GV.getAddressSpace(),
+                 MemInitKind::Zeroed, MemAllocKind::Global);
+
+    if (!Obj)
+      return false;
+
+    Obj->setIsConstant(GV.isConstant());
+    GlobalAddrMap.try_emplace(&GV, deriveFromMemoryObject(Obj));
+  }
+
+  for (GlobalVariable &GV : M.globals()) {
+    if (!GV.hasInitializer())
+      continue;
+
+    MemoryObject *Obj = GlobalAddrMap.at(&GV).getMemoryObject();
+    assert(Obj && "global pointer should have memory object provenance");
+
+    Constant *Init = GV.getInitializer();
+
+    // TODO: Constant expression support
+    if (!isSupportedGlobalInitializer(Init))
+      return false;
+
+    AnyValue InitVal = getConstantValue(Init);
+    store(*Obj, 0, InitVal, GV.getValueType());
+  }
   return true;
 }
 
@@ -96,6 +161,9 @@ AnyValue Context::getConstantValueImpl(Constant *C) {
   if (auto *BA = dyn_cast<BlockAddress>(C))
     return BlockAddrMap.at(BA->getBasicBlock());
 
+  if (auto *GV = dyn_cast<GlobalVariable>(C))
+    return GlobalAddrMap.at(GV);
+
   if (auto *F = dyn_cast<Function>(C))
     return FuncAddrMap.at(F);
 
diff --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index 78d99f2cc5f13..72e0e21ea74fa 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -251,6 +251,8 @@ class Context {
       ValidFuncTargets;
   DenseMap<uint64_t, std::pair<BasicBlock *, IntrusiveRefCntPtr<MemoryObject>>>
       ValidBlockTargets;
+  DenseMap<GlobalVariable *, Pointer> GlobalAddrMap;
+  bool isSupportedGlobalInitializer(Constant *C) const;
   AnyValue getConstantValueImpl(Constant *C);
 
   // Floating-point environment
diff --git a/llvm/tools/llubi/lib/ExecutorBase.cpp b/llvm/tools/llubi/lib/ExecutorBase.cpp
index 3b5a4c6ab0dd5..8ff4d931e191b 100644
--- a/llvm/tools/llubi/lib/ExecutorBase.cpp
+++ b/llvm/tools/llubi/lib/ExecutorBase.cpp
@@ -145,6 +145,12 @@ void ExecutorBase::store(const AnyValue &Ptr, Align Alignment,
         << "Invalid memory access via a pointer with nullary provenance.";
     return;
   }
+  if (MO->isConstant()) {
+    reportImmediateUB()
+        << "Try to write to a constant memory object at address 0x"
+        << Twine::utohexstr(PtrVal.address().getZExtValue()) << ".";
+    return;
+  }
   // TODO: pointer capability check
   if (auto Offset =
           verifyMemAccess(*MO, PtrVal.address(),

>From f221b87bf25bbe4b10f13ea88295b7ca4e4e5f96 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhige_chen at outlook.com>
Date: Sat, 30 May 2026 16:44:10 +0800
Subject: [PATCH 2/5] [llubi] Address comments

---
 llvm/test/tools/llubi/controlflow.ll          |  30 ++---
 llvm/test/tools/llubi/global.ll               |   2 +-
 .../test/tools/llubi/global_constant_store.ll |   2 +-
 llvm/test/tools/llubi/global_external.ll      |  20 +++
 llvm/tools/llubi/lib/Context.cpp              | 115 ++++++++----------
 llvm/tools/llubi/lib/Context.h                |  15 ++-
 llvm/tools/llubi/lib/ExecutorBase.cpp         |   5 +-
 llvm/tools/llubi/lib/Interpreter.cpp          |  10 +-
 llvm/tools/llubi/lib/Value.cpp                |   2 +
 llvm/tools/llubi/lib/Value.h                  |   5 +
 llvm/tools/llubi/llubi.cpp                    |   9 +-
 11 files changed, 125 insertions(+), 90 deletions(-)
 create mode 100644 llvm/test/tools/llubi/global_external.ll

diff --git a/llvm/test/tools/llubi/controlflow.ll b/llvm/test/tools/llubi/controlflow.ll
index 7b14d90b688d9..8a00b30013b16 100644
--- a/llvm/test/tools/llubi/controlflow.ll
+++ b/llvm/test/tools/llubi/controlflow.ll
@@ -243,35 +243,35 @@ exit:
 ; CHECK-NEXT:           to label %next5 unwind label %cleanup jump to %next5
 ; CHECK-NEXT:   indirectbr ptr blockaddress(@main, %exit), [label %exit] jump to %exit
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 5
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => T
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.then
 ; CHECK-NEXT:   %sub1 = sub i32 %n, 1 => i32 4
 ; CHECK-NEXT:   %sub2 = sub i32 %n, 2 => i32 3
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 4
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => T
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.then
 ; CHECK-NEXT:   %sub1 = sub i32 %n, 1 => i32 3
 ; CHECK-NEXT:   %sub2 = sub i32 %n, 2 => i32 2
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 3
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => T
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.then
 ; CHECK-NEXT:   %sub1 = sub i32 %n, 1 => i32 2
 ; CHECK-NEXT:   %sub2 = sub i32 %n, 2 => i32 1
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 2
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => T
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.then
 ; CHECK-NEXT:   %sub1 = sub i32 %n, 1 => i32 1
 ; CHECK-NEXT:   %sub2 = sub i32 %n, 2 => i32 0
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 1
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
@@ -279,7 +279,7 @@ exit:
 ; CHECK-NEXT: Exiting function: fib
 ; CHECK-NEXT:   %res1 = call i32 @fib(ptr %self, i32 %sub1) => i32 1
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 0
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
@@ -291,7 +291,7 @@ exit:
 ; CHECK-NEXT: Exiting function: fib
 ; CHECK-NEXT:   %res1 = call i32 @fib(ptr %self, i32 %sub1) => i32 2
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 1
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
@@ -303,14 +303,14 @@ exit:
 ; CHECK-NEXT: Exiting function: fib
 ; CHECK-NEXT:   %res1 = call i32 @fib(ptr %self, i32 %sub1) => i32 3
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 2
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => T
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.then
 ; CHECK-NEXT:   %sub1 = sub i32 %n, 1 => i32 1
 ; CHECK-NEXT:   %sub2 = sub i32 %n, 2 => i32 0
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 1
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
@@ -318,7 +318,7 @@ exit:
 ; CHECK-NEXT: Exiting function: fib
 ; CHECK-NEXT:   %res1 = call i32 @fib(ptr %self, i32 %sub1) => i32 1
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 0
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
@@ -334,21 +334,21 @@ exit:
 ; CHECK-NEXT: Exiting function: fib
 ; CHECK-NEXT:   %res1 = call i32 @fib(ptr %self, i32 %sub1) => i32 5
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 3
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => T
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.then
 ; CHECK-NEXT:   %sub1 = sub i32 %n, 1 => i32 2
 ; CHECK-NEXT:   %sub2 = sub i32 %n, 2 => i32 1
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 2
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => T
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.then
 ; CHECK-NEXT:   %sub1 = sub i32 %n, 1 => i32 1
 ; CHECK-NEXT:   %sub2 = sub i32 %n, 2 => i32 0
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 1
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
@@ -356,7 +356,7 @@ exit:
 ; CHECK-NEXT: Exiting function: fib
 ; CHECK-NEXT:   %res1 = call i32 @fib(ptr %self, i32 %sub1) => i32 1
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 0
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
@@ -368,7 +368,7 @@ exit:
 ; CHECK-NEXT: Exiting function: fib
 ; CHECK-NEXT:   %res1 = call i32 @fib(ptr %self, i32 %sub1) => i32 2
 ; CHECK-NEXT: Entering function: fib
-; CHECK-NEXT:   ptr %self = ptr 0x8 [fib]
+; CHECK-NEXT:   ptr %self = ptr 0x8 [@fib]
 ; CHECK-NEXT:   i32 %n = i32 1
 ; CHECK-NEXT:   %cond = icmp ugt i32 %n, 1 => F
 ; CHECK-NEXT:   br i1 %cond, label %if.then, label %if.else jump to %if.else
diff --git a/llvm/test/tools/llubi/global.ll b/llvm/test/tools/llubi/global.ll
index ddb707f4e5fdc..3cff71b21769f 100644
--- a/llvm/test/tools/llubi/global.ll
+++ b/llvm/test/tools/llubi/global.ll
@@ -18,7 +18,7 @@ define void @main() {
 ; CHECK: Entering function: main
 ; CHECK-NEXT:   %initial = load i32, ptr @value, align 4 => i32 41
 ; CHECK-NEXT:   store i32 42, ptr @value, align 4
-; CHECK-NEXT:   %ptr = load ptr, ptr @value_ptr, align 8 => ptr 0x8 [value]
+; CHECK-NEXT:   %ptr = load ptr, ptr @value_ptr, align 8 => ptr 0x8 [@value]
 ; CHECK-NEXT:   %updated = load i32, ptr %ptr, align 4 => i32 42
 ; CHECK-NEXT:   %aggregate_value = load { i32, [2 x i8] }, ptr @aggregate, align 4 => { i32 7, { i8 104, i8 105 } }
 ; CHECK-NEXT:   ret void
diff --git a/llvm/test/tools/llubi/global_constant_store.ll b/llvm/test/tools/llubi/global_constant_store.ll
index bf5f6322bb014..6a8c4e48d0885 100644
--- a/llvm/test/tools/llubi/global_constant_store.ll
+++ b/llvm/test/tools/llubi/global_constant_store.ll
@@ -10,5 +10,5 @@ define void @main() {
 ; CHECK: Entering function: main
 ; CHECK-NEXT: Stacktrace:
 ; CHECK-NEXT: #0   store i32 2, ptr @constant, align 4 at @main
-; CHECK-NEXT: Immediate UB detected: Try to write to a constant memory object at address 0x8.
+; CHECK-NEXT: Immediate UB detected: Try to write to a constant memory object: ptr 0x8 [@constant].
 ; CHECK-NEXT: error: Execution of function 'main' failed.
diff --git a/llvm/test/tools/llubi/global_external.ll b/llvm/test/tools/llubi/global_external.ll
new file mode 100644
index 0000000000000..5d26be98a2350
--- /dev/null
+++ b/llvm/test/tools/llubi/global_external.ll
@@ -0,0 +1,20 @@
+; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
+
+target datalayout = "e-p:64:64:64-i32:32:32"
+
+ at external = external global i32
+ at external_ptr = global ptr @external
+
+define void @main() {
+  %ptr = load ptr, ptr @external_ptr
+  store i32 42, ptr @external
+  %loaded = load i32, ptr @external
+  ret void
+}
+
+; CHECK: Entering function: main
+; CHECK-NEXT:   %ptr = load ptr, ptr @external_ptr, align 8 => ptr 0x8 [@external]
+; CHECK-NEXT:   store i32 42, ptr @external, align 4
+; CHECK-NEXT:   %loaded = load i32, ptr @external, align 4 => i32 42
+; CHECK-NEXT:   ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/tools/llubi/lib/Context.cpp b/llvm/tools/llubi/lib/Context.cpp
index cf6b5042690f8..f693c60c49ab8 100644
--- a/llvm/tools/llubi/lib/Context.cpp
+++ b/llvm/tools/llubi/lib/Context.cpp
@@ -21,37 +21,6 @@ Context::Context(Module &M, const AsmParserContext *ParserContext)
 
 Context::~Context() = default;
 
-bool Context::isSupportedGlobalInitializer(Constant *C) const {
-  if (isa<PoisonValue, ConstantAggregateZero, ConstantPointerNull, ConstantInt,
-          ConstantFP>(C))
-    return true;
-
-  if (auto const *CDS = dyn_cast<ConstantDataSequential>(C)) {
-    for (uint32_t I = 0, E = CDS->getNumElements(); I != E; ++I)
-      if (!isSupportedGlobalInitializer(CDS->getElementAsConstant(I)))
-        return false;
-    return true;
-  }
-
-  if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
-    for (Value *Op : CA->operands())
-      if (!isSupportedGlobalInitializer(cast<Constant>(Op)))
-        return false;
-    return true;
-  }
-
-  if (auto const *BA = dyn_cast<BlockAddress>(C))
-    return BlockAddrMap.contains(BA->getBasicBlock());
-
-  if (auto const *GV = dyn_cast<GlobalVariable>(C))
-    return GlobalAddrMap.contains(GV);
-
-  if (auto const *F = dyn_cast<Function>(C))
-    return FuncAddrMap.contains(F);
-
-  return false;
-}
-
 bool Context::initGlobalValues() {
   // Register all function and block targets that may be used by indirect calls
   // and branches.
@@ -60,7 +29,7 @@ bool Context::initGlobalValues() {
       // TODO: Use precise alignment for function pointers if it is necessary.
       auto FuncObj = allocate(0, F.getPointerAlignment(DL).value(), F.getName(),
                               DL.getProgramAddressSpace(), MemInitKind::Zeroed,
-                              MemAllocKind::Global);
+                              MemAllocKind::Global, /*IsGlobalValue=*/true);
       if (!FuncObj)
         return false;
       ValidFuncTargets.try_emplace(FuncObj->getAddress(),
@@ -72,7 +41,7 @@ bool Context::initGlobalValues() {
       if (!BB.hasAddressTaken())
         continue;
       auto BlockObj = allocate(0, 1, BB.getName(), DL.getProgramAddressSpace(),
-                               MemInitKind::Zeroed, MemAllocKind::Global);
+                               MemInitKind::Zeroed, MemAllocKind::BlockAddress);
       if (!BlockObj)
         return false;
       ValidBlockTargets.try_emplace(BlockObj->getAddress(),
@@ -82,15 +51,14 @@ bool Context::initGlobalValues() {
   }
 
   for (GlobalVariable &GV : M.globals()) {
-    if (!GV.hasInitializer())
-      continue;
-
     Type *ValueTy = GV.getValueType();
     uint64_t const Size = getEffectiveTypeAllocSize(ValueTy);
     Align Alignment = GV.getPointerAlignment(DL);
+    auto InitKind =
+        GV.hasInitializer() ? MemInitKind::Zeroed : MemInitKind::Uninitialized;
     auto const Obj =
         allocate(Size, Alignment.value(), GV.getName(), GV.getAddressSpace(),
-                 MemInitKind::Zeroed, MemAllocKind::Global);
+                 InitKind, MemAllocKind::Global, /*IsGlobalValue=*/true);
 
     if (!Obj)
       return false;
@@ -108,17 +76,16 @@ bool Context::initGlobalValues() {
 
     Constant *Init = GV.getInitializer();
 
-    // TODO: Constant expression support
-    if (!isSupportedGlobalInitializer(Init))
+    const AnyValue *InitVal = getConstantValue(Init);
+    if (!InitVal)
       return false;
 
-    AnyValue InitVal = getConstantValue(Init);
-    store(*Obj, 0, InitVal, GV.getValueType());
+    store(*Obj, 0, *InitVal, GV.getValueType());
   }
   return true;
 }
 
-AnyValue Context::getConstantValueImpl(Constant *C) {
+std::optional<AnyValue> Context::getConstantValueImpl(Constant *C) {
   if (isa<PoisonValue>(C))
     return AnyValue::getPoisonValue(*this, C->getType());
 
@@ -145,37 +112,61 @@ AnyValue Context::getConstantValueImpl(Constant *C) {
   if (auto *CDS = dyn_cast<ConstantDataSequential>(C)) {
     std::vector<AnyValue> Elts;
     Elts.reserve(CDS->getNumElements());
-    for (uint32_t I = 0, E = CDS->getNumElements(); I != E; ++I)
-      Elts.push_back(getConstantValue(CDS->getElementAsConstant(I)));
+    for (uint32_t I = 0, E = CDS->getNumElements(); I != E; ++I) {
+      const AnyValue *Elt = getConstantValue(CDS->getElementAsConstant(I));
+      if (!Elt)
+        return std::nullopt;
+      Elts.push_back(*Elt);
+    }
     return std::move(Elts);
   }
 
   if (auto *CA = dyn_cast<ConstantAggregate>(C)) {
     std::vector<AnyValue> Elts;
     Elts.reserve(CA->getNumOperands());
-    for (uint32_t I = 0, E = CA->getNumOperands(); I != E; ++I)
-      Elts.push_back(getConstantValue(CA->getOperand(I)));
+    for (uint32_t I = 0, E = CA->getNumOperands(); I != E; ++I) {
+      const AnyValue *Elt = getConstantValue(CA->getOperand(I));
+      if (!Elt)
+        return std::nullopt;
+      Elts.push_back(*Elt);
+    }
     return std::move(Elts);
   }
 
-  if (auto *BA = dyn_cast<BlockAddress>(C))
-    return BlockAddrMap.at(BA->getBasicBlock());
+  if (auto *BA = dyn_cast<BlockAddress>(C)) {
+    auto It = BlockAddrMap.find(BA->getBasicBlock());
+    if (It == BlockAddrMap.end())
+      return std::nullopt;
+    return It->second;
+  }
 
-  if (auto *GV = dyn_cast<GlobalVariable>(C))
-    return GlobalAddrMap.at(GV);
+  if (auto *GV = dyn_cast<GlobalVariable>(C)) {
+    auto It = GlobalAddrMap.find(GV);
+    if (It == GlobalAddrMap.end())
+      return std::nullopt;
+    return It->second;
+  }
 
-  if (auto *F = dyn_cast<Function>(C))
-    return FuncAddrMap.at(F);
+  if (auto *F = dyn_cast<Function>(C)) {
+    auto It = FuncAddrMap.find(F);
+    if (It == FuncAddrMap.end())
+      return std::nullopt;
+    return It->second;
+  }
 
-  llvm_unreachable("Unrecognized constant");
+  return std::nullopt;
 }
 
-const AnyValue &Context::getConstantValue(Constant *C) {
+const AnyValue *Context::getConstantValue(Constant *C) {
   auto It = ConstCache.find(C);
   if (It != ConstCache.end())
-    return It->second;
+    return &It->second;
+
+  std::optional<AnyValue> Val = getConstantValueImpl(C);
+  if (!Val)
+    return nullptr;
 
-  return ConstCache.emplace(C, getConstantValueImpl(C)).first->second;
+  return &ConstCache.emplace(C, std::move(*Val)).first->second;
 }
 
 APInt Context::getTag(uint32_t BitWidth, Provenance &Prov) {
@@ -569,11 +560,11 @@ void Context::freeze(AnyValue &Val, Type *Ty) {
 MemoryObject::~MemoryObject() = default;
 MemoryObject::MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name,
                            unsigned AS, MemInitKind InitKind,
-                           MemAllocKind AllocKind)
+                           MemAllocKind AllocKind, bool IsGlobalValue)
     : Address(Addr), Size(Size), Name(Name), AS(AS),
       State(InitKind != MemInitKind::Poisoned ? MemoryObjectState::Alive
                                               : MemoryObjectState::Dead),
-      AllocKind(AllocKind) {
+      AllocKind(AllocKind), IsGlobalValue(IsGlobalValue) {
   switch (InitKind) {
   case MemInitKind::Zeroed:
     Bytes.resize(Size, Byte::concrete(0));
@@ -589,15 +580,16 @@ MemoryObject::MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name,
 
 IntrusiveRefCntPtr<MemoryObject>
 Context::allocate(uint64_t Size, uint64_t Align, StringRef Name, unsigned AS,
-                  MemInitKind InitKind, MemAllocKind AllocKind) {
+                  MemInitKind InitKind, MemAllocKind AllocKind,
+                  bool IsGlobalValue) {
   // Even if the memory object is zero-sized, it still occupies a byte to obtain
   // a unique address.
   uint64_t AllocateSize = std::max(Size, (uint64_t)1);
   if (MaxMem != 0 && SaturatingAdd(UsedMem, AllocateSize) >= MaxMem)
     return nullptr;
   uint64_t AlignedAddr = alignTo(AllocationBase, Align);
-  auto MemObj = makeIntrusiveRefCnt<MemoryObject>(AlignedAddr, Size, Name, AS,
-                                                  InitKind, AllocKind);
+  auto MemObj = makeIntrusiveRefCnt<MemoryObject>(
+      AlignedAddr, Size, Name, AS, InitKind, AllocKind, IsGlobalValue);
   MemoryObjects[AlignedAddr] = MemObj;
   AllocationBase = AlignedAddr + AllocateSize;
   UsedMem += AllocateSize;
@@ -713,6 +705,7 @@ bool MemoryObject::isStackAllocated() const {
 bool MemoryObject::isHeapAllocated() const {
   switch (AllocKind) {
   case MemAllocKind::Global:
+  case MemAllocKind::BlockAddress:
   case MemAllocKind::Stack:
     return false;
   case MemAllocKind::Malloc:
diff --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index 72e0e21ea74fa..f4225fbee3eec 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -16,6 +16,7 @@
 #include "llvm/IR/FPEnv.h"
 #include "llvm/IR/Module.h"
 #include <map>
+#include <optional>
 #include <random>
 
 namespace llvm::ubi {
@@ -28,6 +29,7 @@ enum class MemInitKind {
 
 enum class MemAllocKind {
   Global,
+  BlockAddress,
   Stack,
   Malloc,
   New,
@@ -107,6 +109,7 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
   MemoryObjectState State;
   MemAllocKind AllocKind;
   bool IsConstant = false;
+  bool IsGlobalValue = false;
 
   // Tagged provenances related to this memory object.
   // It is used to erasing the tags after the memory object is freed.
@@ -116,7 +119,8 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
 
 public:
   MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name, unsigned AS,
-               MemInitKind InitKind, MemAllocKind AllocKind);
+               MemInitKind InitKind, MemAllocKind AllocKind,
+               bool IsGlobalValue = false);
   MemoryObject(const MemoryObject &) = delete;
   MemoryObject(MemoryObject &&) = delete;
   MemoryObject &operator=(const MemoryObject &) = delete;
@@ -130,6 +134,7 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
   MemoryObjectState getState() const { return State; }
   void setState(MemoryObjectState S) { State = S; }
   MemAllocKind getAllocKind() const { return AllocKind; }
+  bool isGlobalValue() const { return IsGlobalValue; }
   bool isConstant() const { return IsConstant; }
   void setIsConstant(bool C) { IsConstant = C; }
 
@@ -252,8 +257,7 @@ class Context {
   DenseMap<uint64_t, std::pair<BasicBlock *, IntrusiveRefCntPtr<MemoryObject>>>
       ValidBlockTargets;
   DenseMap<GlobalVariable *, Pointer> GlobalAddrMap;
-  bool isSupportedGlobalInitializer(Constant *C) const;
-  AnyValue getConstantValueImpl(Constant *C);
+  std::optional<AnyValue> getConstantValueImpl(Constant *C);
 
   // Floating-point environment
   RoundingMode CurrentRoundingMode = RoundingMode::NearestTiesToEven;
@@ -315,11 +319,12 @@ class Context {
   uint64_t getEffectiveTypeAllocSize(Type *Ty);
   uint64_t getEffectiveTypeStoreSize(Type *Ty);
 
-  const AnyValue &getConstantValue(Constant *C);
+  const AnyValue *getConstantValue(Constant *C);
   IntrusiveRefCntPtr<MemoryObject> allocate(uint64_t Size, uint64_t Align,
                                             StringRef Name, unsigned AS,
                                             MemInitKind InitKind,
-                                            MemAllocKind AllocKind);
+                                            MemAllocKind AllocKind,
+                                            bool IsGlobalValue = false);
   bool free(const MemoryObject &Obj);
   /// Derive a pointer from a memory object with offset 0.
   /// Please use Pointer's interface for further manipulations.
diff --git a/llvm/tools/llubi/lib/ExecutorBase.cpp b/llvm/tools/llubi/lib/ExecutorBase.cpp
index 8ff4d931e191b..1433526f18d3a 100644
--- a/llvm/tools/llubi/lib/ExecutorBase.cpp
+++ b/llvm/tools/llubi/lib/ExecutorBase.cpp
@@ -146,9 +146,8 @@ void ExecutorBase::store(const AnyValue &Ptr, Align Alignment,
     return;
   }
   if (MO->isConstant()) {
-    reportImmediateUB()
-        << "Try to write to a constant memory object at address 0x"
-        << Twine::utohexstr(PtrVal.address().getZExtValue()) << ".";
+    reportImmediateUB() << "Try to write to a constant memory object: "
+                        << PtrVal << ".";
     return;
   }
   // TODO: pointer capability check
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 3c21f8ff175f7..8b9dc8e8c1335 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -150,11 +150,17 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
   const DataLayout &DL;
   std::list<Frame> CallStack;
   AnyValue None;
+  AnyValue UnsupportedConstantValue;
   Library Lib;
 
   const AnyValue &getValue(Value *V) {
-    if (auto *C = dyn_cast<Constant>(V))
-      return Ctx.getConstantValue(C);
+    if (auto *C = dyn_cast<Constant>(V)) {
+      if (const AnyValue *Val = Ctx.getConstantValue(C))
+        return *Val;
+      reportError() << "Unsupported constant: " << *C << ".";
+      UnsupportedConstantValue = AnyValue::getPoisonValue(Ctx, C->getType());
+      return UnsupportedConstantValue;
+    }
     return CurrentFrame->ValueMap.at(V);
   }
 
diff --git a/llvm/tools/llubi/lib/Value.cpp b/llvm/tools/llubi/lib/Value.cpp
index fe8e0f3cff330..f90cd8d9db4a4 100644
--- a/llvm/tools/llubi/lib/Value.cpp
+++ b/llvm/tools/llubi/lib/Value.cpp
@@ -27,6 +27,8 @@ void Pointer::print(raw_ostream &OS) const {
   Address.toStringUnsigned(AddrStr, 16);
   OS << "ptr 0x" << AddrStr << " [";
   if (MemoryObject *Obj = getMemoryObject()) {
+    if (Obj->isGlobalValue())
+      OS << "@";
     OS << Obj->getName();
     if (Address != Obj->getAddress())
       OS << " + " << (Address - Obj->getAddress());
diff --git a/llvm/tools/llubi/lib/Value.h b/llvm/tools/llubi/lib/Value.h
index 60e656342f116..27407251506ce 100644
--- a/llvm/tools/llubi/lib/Value.h
+++ b/llvm/tools/llubi/lib/Value.h
@@ -254,6 +254,11 @@ inline raw_ostream &operator<<(raw_ostream &OS, const AnyValue &V) {
   return OS;
 }
 
+inline raw_ostream &operator<<(raw_ostream &OS, const Pointer &P) {
+  P.print(OS);
+  return OS;
+}
+
 } // namespace llvm::ubi
 
 #endif
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index 5f5e451282714..d96bd2fe9e79b 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -267,8 +267,13 @@ int main(int argc, char **argv) {
   auto *MainFuncTy = FunctionType::get(IntTy, {IntTy, PtrTy}, false);
   SmallVector<ubi::AnyValue> Args;
   if (EntryFn->getFunctionType() == MainFuncTy) {
-    Args.push_back(
-        Ctx.getConstantValue(ConstantInt::get(IntTy, InputArgv.size())));
+    const ubi::AnyValue *Argc =
+        Ctx.getConstantValue(ConstantInt::get(IntTy, InputArgv.size()));
+    if (!Argc) {
+      WithColor::error() << "Failed to initialize argc.\n";
+      return 1;
+    }
+    Args.push_back(*Argc);
 
     uint32_t PtrSize = Ctx.getDataLayout().getPointerSize();
     uint64_t PtrsSize = PtrSize * (InputArgv.size() + 1);

>From 238f9cdb96aeeed65cb9515aca8407f4deee083d Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhige_chen at outlook.com>
Date: Mon, 1 Jun 2026 14:25:17 +0800
Subject: [PATCH 3/5] [llubi] Address comments again

---
 llvm/tools/llubi/lib/Context.cpp     | 28 ++++++++--------------------
 llvm/tools/llubi/lib/Context.h       |  6 +++---
 llvm/tools/llubi/lib/Interpreter.cpp |  7 ++++---
 llvm/tools/llubi/lib/Value.cpp       |  2 +-
 llvm/tools/llubi/llubi.cpp           |  5 +----
 5 files changed, 17 insertions(+), 31 deletions(-)

diff --git a/llvm/tools/llubi/lib/Context.cpp b/llvm/tools/llubi/lib/Context.cpp
index f693c60c49ab8..a6881c91da336 100644
--- a/llvm/tools/llubi/lib/Context.cpp
+++ b/llvm/tools/llubi/lib/Context.cpp
@@ -133,26 +133,14 @@ std::optional<AnyValue> Context::getConstantValueImpl(Constant *C) {
     return std::move(Elts);
   }
 
-  if (auto *BA = dyn_cast<BlockAddress>(C)) {
-    auto It = BlockAddrMap.find(BA->getBasicBlock());
-    if (It == BlockAddrMap.end())
-      return std::nullopt;
-    return It->second;
-  }
+  if (auto *BA = dyn_cast<BlockAddress>(C))
+    return BlockAddrMap.at(BA->getBasicBlock());
 
-  if (auto *GV = dyn_cast<GlobalVariable>(C)) {
-    auto It = GlobalAddrMap.find(GV);
-    if (It == GlobalAddrMap.end())
-      return std::nullopt;
-    return It->second;
-  }
+  if (auto *GV = dyn_cast<GlobalVariable>(C))
+    return GlobalAddrMap.at(GV);
 
-  if (auto *F = dyn_cast<Function>(C)) {
-    auto It = FuncAddrMap.find(F);
-    if (It == FuncAddrMap.end())
-      return std::nullopt;
-    return It->second;
-  }
+  if (auto *F = dyn_cast<Function>(C))
+    return FuncAddrMap.at(F);
 
   return std::nullopt;
 }
@@ -560,11 +548,11 @@ void Context::freeze(AnyValue &Val, Type *Ty) {
 MemoryObject::~MemoryObject() = default;
 MemoryObject::MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name,
                            unsigned AS, MemInitKind InitKind,
-                           MemAllocKind AllocKind, bool IsGlobalValue)
+                           MemAllocKind AllocKind, bool IsIRGlobalValue)
     : Address(Addr), Size(Size), Name(Name), AS(AS),
       State(InitKind != MemInitKind::Poisoned ? MemoryObjectState::Alive
                                               : MemoryObjectState::Dead),
-      AllocKind(AllocKind), IsGlobalValue(IsGlobalValue) {
+      AllocKind(AllocKind), IsIRGlobalValue(IsIRGlobalValue) {
   switch (InitKind) {
   case MemInitKind::Zeroed:
     Bytes.resize(Size, Byte::concrete(0));
diff --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index f4225fbee3eec..5ceb787285f3f 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -109,7 +109,7 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
   MemoryObjectState State;
   MemAllocKind AllocKind;
   bool IsConstant = false;
-  bool IsGlobalValue = false;
+  bool IsIRGlobalValue = false;
 
   // Tagged provenances related to this memory object.
   // It is used to erasing the tags after the memory object is freed.
@@ -120,7 +120,7 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
 public:
   MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name, unsigned AS,
                MemInitKind InitKind, MemAllocKind AllocKind,
-               bool IsGlobalValue = false);
+               bool IsIRGlobalValue = false);
   MemoryObject(const MemoryObject &) = delete;
   MemoryObject(MemoryObject &&) = delete;
   MemoryObject &operator=(const MemoryObject &) = delete;
@@ -134,7 +134,7 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
   MemoryObjectState getState() const { return State; }
   void setState(MemoryObjectState S) { State = S; }
   MemAllocKind getAllocKind() const { return AllocKind; }
-  bool isGlobalValue() const { return IsGlobalValue; }
+  bool isIRGlobalValue() const { return IsIRGlobalValue; }
   bool isConstant() const { return IsConstant; }
   void setIsConstant(bool C) { IsConstant = C; }
 
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index 8b9dc8e8c1335..6f5f74477f48f 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -150,7 +150,7 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
   const DataLayout &DL;
   std::list<Frame> CallStack;
   AnyValue None;
-  AnyValue UnsupportedConstantValue;
+  std::list<AnyValue> UnsupportedConstantValues;
   Library Lib;
 
   const AnyValue &getValue(Value *V) {
@@ -158,8 +158,9 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
       if (const AnyValue *Val = Ctx.getConstantValue(C))
         return *Val;
       reportError() << "Unsupported constant: " << *C << ".";
-      UnsupportedConstantValue = AnyValue::getPoisonValue(Ctx, C->getType());
-      return UnsupportedConstantValue;
+      UnsupportedConstantValues.push_back(
+          AnyValue::getPoisonValue(Ctx, C->getType()));
+      return UnsupportedConstantValues.back();
     }
     return CurrentFrame->ValueMap.at(V);
   }
diff --git a/llvm/tools/llubi/lib/Value.cpp b/llvm/tools/llubi/lib/Value.cpp
index f90cd8d9db4a4..04a1aa803f66c 100644
--- a/llvm/tools/llubi/lib/Value.cpp
+++ b/llvm/tools/llubi/lib/Value.cpp
@@ -27,7 +27,7 @@ void Pointer::print(raw_ostream &OS) const {
   Address.toStringUnsigned(AddrStr, 16);
   OS << "ptr 0x" << AddrStr << " [";
   if (MemoryObject *Obj = getMemoryObject()) {
-    if (Obj->isGlobalValue())
+    if (Obj->isIRGlobalValue())
       OS << "@";
     OS << Obj->getName();
     if (Address != Obj->getAddress())
diff --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index d96bd2fe9e79b..c433e53167743 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -269,10 +269,7 @@ int main(int argc, char **argv) {
   if (EntryFn->getFunctionType() == MainFuncTy) {
     const ubi::AnyValue *Argc =
         Ctx.getConstantValue(ConstantInt::get(IntTy, InputArgv.size()));
-    if (!Argc) {
-      WithColor::error() << "Failed to initialize argc.\n";
-      return 1;
-    }
+    assert(Argc && "failed to initialize argc");
     Args.push_back(*Argc);
 
     uint32_t PtrSize = Ctx.getDataLayout().getPointerSize();

>From 27d6d83e460cb5955ebb18cdd37ecd84da059cd9 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhige_chen at outlook.com>
Date: Mon, 1 Jun 2026 19:29:39 +0800
Subject: [PATCH 4/5] [llubi] Just some nits

---
 llvm/tools/llubi/lib/Context.cpp | 12 ++++++------
 llvm/tools/llubi/lib/Context.h   |  2 +-
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/tools/llubi/lib/Context.cpp b/llvm/tools/llubi/lib/Context.cpp
index a6881c91da336..aa210aa78e36a 100644
--- a/llvm/tools/llubi/lib/Context.cpp
+++ b/llvm/tools/llubi/lib/Context.cpp
@@ -29,7 +29,7 @@ bool Context::initGlobalValues() {
       // TODO: Use precise alignment for function pointers if it is necessary.
       auto FuncObj = allocate(0, F.getPointerAlignment(DL).value(), F.getName(),
                               DL.getProgramAddressSpace(), MemInitKind::Zeroed,
-                              MemAllocKind::Global, /*IsGlobalValue=*/true);
+                              MemAllocKind::Global, /*IsIRGlobalValue=*/true);
       if (!FuncObj)
         return false;
       ValidFuncTargets.try_emplace(FuncObj->getAddress(),
@@ -52,13 +52,13 @@ bool Context::initGlobalValues() {
 
   for (GlobalVariable &GV : M.globals()) {
     Type *ValueTy = GV.getValueType();
-    uint64_t const Size = getEffectiveTypeAllocSize(ValueTy);
+    const uint64_t Size = getEffectiveTypeAllocSize(ValueTy);
     Align Alignment = GV.getPointerAlignment(DL);
     auto InitKind =
         GV.hasInitializer() ? MemInitKind::Zeroed : MemInitKind::Uninitialized;
-    auto const Obj =
+    const auto Obj =
         allocate(Size, Alignment.value(), GV.getName(), GV.getAddressSpace(),
-                 InitKind, MemAllocKind::Global, /*IsGlobalValue=*/true);
+                 InitKind, MemAllocKind::Global, /*IsIRGlobalValue=*/true);
 
     if (!Obj)
       return false;
@@ -569,7 +569,7 @@ MemoryObject::MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name,
 IntrusiveRefCntPtr<MemoryObject>
 Context::allocate(uint64_t Size, uint64_t Align, StringRef Name, unsigned AS,
                   MemInitKind InitKind, MemAllocKind AllocKind,
-                  bool IsGlobalValue) {
+                  bool IsIRGlobalValue) {
   // Even if the memory object is zero-sized, it still occupies a byte to obtain
   // a unique address.
   uint64_t AllocateSize = std::max(Size, (uint64_t)1);
@@ -577,7 +577,7 @@ Context::allocate(uint64_t Size, uint64_t Align, StringRef Name, unsigned AS,
     return nullptr;
   uint64_t AlignedAddr = alignTo(AllocationBase, Align);
   auto MemObj = makeIntrusiveRefCnt<MemoryObject>(
-      AlignedAddr, Size, Name, AS, InitKind, AllocKind, IsGlobalValue);
+      AlignedAddr, Size, Name, AS, InitKind, AllocKind, IsIRGlobalValue);
   MemoryObjects[AlignedAddr] = MemObj;
   AllocationBase = AlignedAddr + AllocateSize;
   UsedMem += AllocateSize;
diff --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index 5ceb787285f3f..5daa9e816f145 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -324,7 +324,7 @@ class Context {
                                             StringRef Name, unsigned AS,
                                             MemInitKind InitKind,
                                             MemAllocKind AllocKind,
-                                            bool IsGlobalValue = false);
+                                            bool IsIRGlobalValue = false);
   bool free(const MemoryObject &Obj);
   /// Derive a pointer from a memory object with offset 0.
   /// Please use Pointer's interface for further manipulations.

>From 7961a7d560a78f5075c02e6dd17e2a958bfb90b7 Mon Sep 17 00:00:00 2001
From: Zhige Chen <zhige_chen at outlook.com>
Date: Tue, 2 Jun 2026 16:03:34 +0800
Subject: [PATCH 5/5] [llubi] Test update

---
 llvm/test/tools/llubi/global_external.ll | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/test/tools/llubi/global_external.ll b/llvm/test/tools/llubi/global_external.ll
index 5d26be98a2350..761f2e82dd691 100644
--- a/llvm/test/tools/llubi/global_external.ll
+++ b/llvm/test/tools/llubi/global_external.ll
@@ -7,14 +7,16 @@ target datalayout = "e-p:64:64:64-i32:32:32"
 
 define void @main() {
   %ptr = load ptr, ptr @external_ptr
+  %load1 = load i32, ptr @external
   store i32 42, ptr @external
-  %loaded = load i32, ptr @external
+  %load2 = load i32, ptr @external
   ret void
 }
 
 ; CHECK: Entering function: main
 ; CHECK-NEXT:   %ptr = load ptr, ptr @external_ptr, align 8 => ptr 0x8 [@external]
+; CHECK-NEXT:   %load1 = load i32, ptr @external, align 4 => i32 -1393641077
 ; CHECK-NEXT:   store i32 42, ptr @external, align 4
-; CHECK-NEXT:   %loaded = load i32, ptr @external, align 4 => i32 42
+; CHECK-NEXT:   %load2 = load i32, ptr @external, align 4 => i32 42
 ; CHECK-NEXT:   ret void
 ; CHECK-NEXT: Exiting function: main



More information about the llvm-commits mailing list