[llvm] edeffec - [llubi] Global variables with simple initializers and global-address constants (#200547)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 2 02:17:10 PDT 2026
Author: Zhige Chen
Date: 2026-06-02T09:17:05Z
New Revision: edeffec62d462e0d162c6bcb41050c9afe192815
URL: https://github.com/llvm/llvm-project/commit/edeffec62d462e0d162c6bcb41050c9afe192815
DIFF: https://github.com/llvm/llvm-project/commit/edeffec62d462e0d162c6bcb41050c9afe192815.diff
LOG: [llubi] Global variables with simple initializers and global-address constants (#200547)
This PR implements global variables with simple initializers and
global-address constants. Support for constant expressions, alias, etc.,
are left for future PRs.
Added:
llvm/test/tools/llubi/global.ll
llvm/test/tools/llubi/global_constant_store.ll
llvm/test/tools/llubi/global_constexpr_initializer.ll
llvm/test/tools/llubi/global_external.ll
Modified:
llvm/test/tools/llubi/controlflow.ll
llvm/tools/llubi/lib/Context.cpp
llvm/tools/llubi/lib/Context.h
llvm/tools/llubi/lib/ExecutorBase.cpp
llvm/tools/llubi/lib/Interpreter.cpp
llvm/tools/llubi/lib/Value.cpp
llvm/tools/llubi/lib/Value.h
llvm/tools/llubi/llubi.cpp
Removed:
################################################################################
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
new file mode 100644
index 0000000000000..3cff71b21769f
--- /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..6a8c4e48d0885
--- /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: ptr 0x8 [@constant].
+; 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/test/tools/llubi/global_external.ll b/llvm/test/tools/llubi/global_external.ll
new file mode 100644
index 0000000000000..761f2e82dd691
--- /dev/null
+++ b/llvm/test/tools/llubi/global_external.ll
@@ -0,0 +1,22 @@
+; 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
+ %load1 = load i32, ptr @external
+ store i32 42, 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: %load2 = 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 69cc52545adc6..dc503a788754a 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);
+ MemAllocKind::Global, /*IsIRGlobalValue=*/true);
if (!FuncObj)
return false;
ValidFuncTargets.try_emplace(FuncObj->getAddress(),
@@ -41,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(),
@@ -49,11 +49,43 @@ bool Context::initGlobalValues() {
BlockAddrMap.try_emplace(&BB, deriveFromMemoryObject(BlockObj));
}
}
- // TODO: initialize global variables.
+
+ for (GlobalVariable &GV : M.globals()) {
+ Type *ValueTy = GV.getValueType();
+ const uint64_t Size = getEffectiveTypeAllocSize(ValueTy);
+ Align Alignment = GV.getPointerAlignment(DL);
+ auto InitKind =
+ GV.hasInitializer() ? MemInitKind::Zeroed : MemInitKind::Uninitialized;
+ const auto Obj =
+ allocate(Size, Alignment.value(), GV.getName(), GV.getAddressSpace(),
+ InitKind, MemAllocKind::Global, /*IsIRGlobalValue=*/true);
+
+ 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();
+
+ const AnyValue *InitVal = getConstantValue(Init);
+ if (!InitVal)
+ return false;
+
+ 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());
@@ -80,34 +112,49 @@ 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 *GV = dyn_cast<GlobalVariable>(C))
+ return GlobalAddrMap.at(GV);
+
if (auto *F = dyn_cast<Function>(C))
return FuncAddrMap.at(F);
- 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) {
@@ -503,11 +550,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 IsIRGlobalValue)
: Address(Addr), Size(Size), Name(Name), AS(AS),
State(InitKind != MemInitKind::Poisoned ? MemoryObjectState::Alive
: MemoryObjectState::Dead),
- AllocKind(AllocKind) {
+ AllocKind(AllocKind), IsIRGlobalValue(IsIRGlobalValue) {
switch (InitKind) {
case MemInitKind::Zeroed:
Bytes.resize(Size, Byte::concrete(0));
@@ -523,15 +570,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 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);
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, IsIRGlobalValue);
MemoryObjects[AlignedAddr] = MemObj;
AllocationBase = AlignedAddr + AllocateSize;
UsedMem += AllocateSize;
@@ -647,6 +695,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 78d99f2cc5f13..5daa9e816f145 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 IsIRGlobalValue = 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 IsIRGlobalValue = 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 isIRGlobalValue() const { return IsIRGlobalValue; }
bool isConstant() const { return IsConstant; }
void setIsConstant(bool C) { IsConstant = C; }
@@ -251,7 +256,8 @@ class Context {
ValidFuncTargets;
DenseMap<uint64_t, std::pair<BasicBlock *, IntrusiveRefCntPtr<MemoryObject>>>
ValidBlockTargets;
- AnyValue getConstantValueImpl(Constant *C);
+ DenseMap<GlobalVariable *, Pointer> GlobalAddrMap;
+ std::optional<AnyValue> getConstantValueImpl(Constant *C);
// Floating-point environment
RoundingMode CurrentRoundingMode = RoundingMode::NearestTiesToEven;
@@ -313,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 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.
diff --git a/llvm/tools/llubi/lib/ExecutorBase.cpp b/llvm/tools/llubi/lib/ExecutorBase.cpp
index 3b5a4c6ab0dd5..1433526f18d3a 100644
--- a/llvm/tools/llubi/lib/ExecutorBase.cpp
+++ b/llvm/tools/llubi/lib/ExecutorBase.cpp
@@ -145,6 +145,11 @@ 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: "
+ << PtrVal << ".";
+ return;
+ }
// TODO: pointer capability check
if (auto Offset =
verifyMemAccess(*MO, PtrVal.address(),
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index c98622e4bb83e..81cc968535a2f 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -150,11 +150,18 @@ class InstExecutor : public InstVisitor<InstExecutor, void>,
const DataLayout &DL;
std::list<Frame> CallStack;
AnyValue None;
+ std::list<AnyValue> UnsupportedConstantValues;
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 << ".";
+ 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 fe8e0f3cff330..04a1aa803f66c 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->isIRGlobalValue())
+ 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 089245ce8e417..71ee212b4299e 100644
--- a/llvm/tools/llubi/lib/Value.h
+++ b/llvm/tools/llubi/lib/Value.h
@@ -273,6 +273,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..c433e53167743 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -267,8 +267,10 @@ 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()));
+ assert(Argc && "failed to initialize argc");
+ Args.push_back(*Argc);
uint32_t PtrSize = Ctx.getDataLayout().getPointerSize();
uint64_t PtrsSize = PtrSize * (InputArgv.size() + 1);
More information about the llvm-commits
mailing list