[llvm] 2c8c39a - Revert "[llubi] Add support for load/store/lifetime markers" (#185101)

via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 6 13:03:19 PST 2026


Author: Yingwei Zheng
Date: 2026-03-06T21:03:14Z
New Revision: 2c8c39a70837c03f550d83272e01d019ba28965c

URL: https://github.com/llvm/llvm-project/commit/2c8c39a70837c03f550d83272e01d019ba28965c
DIFF: https://github.com/llvm/llvm-project/commit/2c8c39a70837c03f550d83272e01d019ba28965c.diff

LOG: Revert "[llubi] Add support for load/store/lifetime markers" (#185101)

Reverts llvm/llvm-project#182532 to unblock CI.
The original patch causes some test failures related to undef bits, as
it incorrectly assumes `std::uniform_int_distribution` returns the same
result with different C++ stdlib vendors.

Added: 
    

Modified: 
    llvm/docs/CommandGuide/llubi.rst
    llvm/tools/llubi/lib/Context.cpp
    llvm/tools/llubi/lib/Context.h
    llvm/tools/llubi/lib/Interpreter.cpp
    llvm/tools/llubi/lib/Value.h
    llvm/tools/llubi/llubi.cpp

Removed: 
    llvm/test/tools/llubi/loadstore_be.ll
    llvm/test/tools/llubi/loadstore_le.ll
    llvm/test/tools/llubi/loadstore_misaligned.ll
    llvm/test/tools/llubi/loadstore_null.ll
    llvm/test/tools/llubi/loadstore_oob1.ll
    llvm/test/tools/llubi/loadstore_overaligned.ll
    llvm/test/tools/llubi/loadstore_poison.ll
    llvm/test/tools/llubi/loadstore_uaf.ll
    llvm/test/tools/llubi/store_dead.ll


################################################################################
diff  --git a/llvm/docs/CommandGuide/llubi.rst b/llvm/docs/CommandGuide/llubi.rst
index 55528373cffef..f652af83d810a 100644
--- a/llvm/docs/CommandGuide/llubi.rst
+++ b/llvm/docs/CommandGuide/llubi.rst
@@ -70,18 +70,6 @@ INTERPRETER OPTIONS
 
   Set the value of `llvm.vscale` to N. The default value is 4.
 
-.. option:: -seed=N
-
-  Set the seed for random number generator to N. By default, the seed is 0.
-
-.. option:: -undef-behavior=mode
-
-  Set the behavior for undefined values (e.g., load from uninitialized memory or freeze a poison value).
-  The options for `mode` are:
-
-  * `nondet`: Each load from the same uninitialized byte yields a freshly random value. This is the default behavior.
-  * `zero`: Uninitialized values are treated as zero.
-
 EXIT STATUS
 -----------
 

diff  --git a/llvm/test/tools/llubi/loadstore_be.ll b/llvm/test/tools/llubi/loadstore_be.ll
deleted file mode 100644
index 2e03939db7859..0000000000000
--- a/llvm/test/tools/llubi/loadstore_be.ll
+++ /dev/null
@@ -1,190 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
-; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
-
-target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64"
-
-%struct = type { [2 x i16], i64 }
-%struct.packed = type <{ [2 x i16], i64 }>
-%struct.vscale = type { <vscale x 1 x i32>, <vscale x 1 x i32> }
-
-define void @main() {
-  %alloc = alloca i32
-  store i32 u0x00010203, ptr %alloc
-  %val1 = load i32, ptr %alloc
-  %val2 = load i32, ptr %alloc, align 2
-  %gep = getelementptr i8, ptr %alloc, i64 1
-  %val3 = load i8, ptr %gep
-  %val4 = load <4 x i8>, ptr %alloc
-
-  store i16 u0x0405, ptr %gep, align 1
-  %val5 = load <4 x i8>, ptr %alloc
-  store <2 x i16> <i16 u0x0607, i16 u0x0809>, ptr %alloc
-  %val6 = load <4 x i8>, ptr %alloc
-  %val7 = load <8 x i4>, ptr %alloc
-  store <3 x i3> <i3 1, i3 2, i3 3>, ptr %alloc
-  ; padding bits are undefined.
-  %val8 = load <16 x i1>, ptr %alloc
-  %val9 = load <16 x i1>, ptr %alloc
-  store <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 4, i3 5, i3 6, i3 7>, ptr %alloc
-  %val_bitcast = load <3 x i8>, ptr %alloc
-
-  ; For non-byte-sized types, the padding bits must be zero.
-  store i25 -1, ptr %alloc
-  %val10 = load <4 x i8>, ptr %alloc
-  store i8 -1, ptr %alloc
-  ; If the padding bits were not zero, load yields poison value.
-  %val11 = load i25, ptr %alloc
-
-  call void @llvm.lifetime.start.p0(ptr poison)
-  call void @llvm.lifetime.end.p0(ptr poison)
-  %alloc_lifetime = alloca i32
-  ; Load of an dead object yields poison value.
-  %val12 = load i32, ptr %alloc_lifetime
-  call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-  ; After lifetime.start, the object is alive but uninitialized.
-  %val13 = load i32, ptr %alloc_lifetime
-  %val14 = load i32, ptr %alloc_lifetime
-  store i32 77, ptr %alloc_lifetime
-  %val15 = load i32, ptr %alloc_lifetime
-  ; Calling lifetime.start on an alive object makes the contents uninitialized again.
-  call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-  %val_undef1 = load i32, ptr %alloc_lifetime
-  %val_undef2 = load i32, ptr %alloc_lifetime
-  call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-  ; Calling lifetime.end on an already dead object is a no-op.
-  call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-  ; Load of an dead object yields poison value.
-  %val16 = load i32, ptr %alloc_lifetime
-
-  store i32 u0xFFF80000, ptr %alloc
-  %val17 = load float, ptr %alloc
-
-  %alloc_vscale = alloca <vscale x 2 x i32>
-  %insert = insertelement <vscale x 1 x i32> poison, i32 1, i32 0
-  %ones = shufflevector <vscale x 1 x i32> %insert, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer
-  %twos = add <vscale x 1 x i32> %ones, %ones
-  store <vscale x 1 x i32> %ones, ptr %alloc_vscale
-  %gep3 = getelementptr <vscale x 1 x i32>, ptr %alloc_vscale, i64 1
-  store <vscale x 1 x i32> %twos, ptr %gep3
-  %val18 = load <vscale x 2 x i32>, ptr %alloc_vscale
-
-  %alloc_struct = alloca %struct
-  store %struct { [2 x i16] [i16 1, i16 2], i64 3 }, ptr %alloc_struct
-  %val19 = load %struct, ptr %alloc_struct
-  ; Padding bytes of struct are undefined.
-  %val20 = load i64, ptr %alloc_struct
-  %val21 = load i64, ptr %alloc_struct
-
-  %alloc_struct_packed = alloca %struct.packed
-  store %struct.packed <{ [2 x i16] [i16 1, i16 2], i64 3 }>, ptr %alloc_struct_packed
-  %val22 = load %struct.packed, ptr %alloc_struct_packed
-  ; No padding bytes.
-  %val23 = load i64, ptr %alloc_struct_packed
-  %val24 = load i64, ptr %alloc_struct_packed
-
-  %alloc_struct_vscale = alloca %struct.vscale
-  store %struct.vscale zeroinitializer, ptr %alloc_struct_vscale
-  %gep4 = getelementptr <vscale x 1 x i32>, ptr %alloc_struct_vscale, i32 1
-  store <vscale x 1 x i32> %ones, ptr %gep4
-  %val25 = load %struct.vscale, ptr %alloc_struct_vscale
-
-  %alloc_array = alloca [2 x i32]
-  store [2 x i32] [i32 1, i32 2], ptr %alloc_array
-  %val26 = load [2 x i32], ptr %alloc_array
-
-  %alloc_i1_vec = alloca <4 x i1>
-  store <4 x i1> <i1 1, i1 0, i1 poison, i1 0>, ptr %alloc_i1_vec
-  %val27 = load <4 x i1>, ptr %alloc_i1_vec
-  %val28 = load i8, ptr %alloc_i1_vec
-
-  %alloc_padding = alloca i31
-  store i32 0, ptr %alloc_padding
-
-  %alloc_padding_vec = alloca i64
-  store { <6 x i5>, i32 } { <6 x i5> zeroinitializer, i32 -1}, ptr %alloc_padding_vec
-  %load_agg = load { <6 x i5>, i32 }, ptr %alloc_padding_vec
-  %load_vec = load <6 x i5>, ptr %alloc_padding_vec
-  %load_int_non_zero_padding = load i33, ptr %alloc_padding_vec
-  %load_vec_non_zero_padding = load <3 x i11>, ptr %alloc_padding_vec
-
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT:   %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
-; CHECK-NEXT:   store i32 66051, ptr %alloc, align 4
-; CHECK-NEXT:   %val1 = load i32, ptr %alloc, align 4 => i32 66051
-; CHECK-NEXT:   %val2 = load i32, ptr %alloc, align 2 => i32 66051
-; CHECK-NEXT:   %gep = getelementptr i8, ptr %alloc, i64 1 => ptr 0x9 [alloc + 1]
-; CHECK-NEXT:   %val3 = load i8, ptr %gep, align 1 => i8 1
-; CHECK-NEXT:   %val4 = load <4 x i8>, ptr %alloc, align 4 => { i8 3, i8 2, i8 1, i8 0 }
-; CHECK-NEXT:   store i16 1029, ptr %gep, align 1
-; CHECK-NEXT:   %val5 = load <4 x i8>, ptr %alloc, align 4 => { i8 3, i8 5, i8 4, i8 0 }
-; CHECK-NEXT:   store <2 x i16> <i16 1543, i16 2057>, ptr %alloc, align 4
-; CHECK-NEXT:   %val6 = load <4 x i8>, ptr %alloc, align 4 => { i8 7, i8 6, i8 9, i8 8 }
-; CHECK-NEXT:   %val7 = load <8 x i4>, ptr %alloc, align 4 => { i4 0, i4 7, i4 0, i4 6, i4 0, i4 -7, i4 0, i4 -8 }
-; CHECK-NEXT:   store <3 x i3> <i3 1, i3 2, i3 3>, ptr %alloc, align 2
-; CHECK-NEXT:   %val8 = load <16 x i1>, ptr %alloc, align 2 => { F, F, F, F, F, F, F, F, F, T, F, T, F, F, T, T }
-; CHECK-NEXT:   %val9 = load <16 x i1>, ptr %alloc, align 2 => { F, F, F, F, F, F, F, F, F, T, F, T, F, F, T, T }
-; CHECK-NEXT:   store <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 -4, i3 -3, i3 -2, i3 -1>, ptr %alloc, align 4
-; CHECK-NEXT:   %val_bitcast = load <3 x i8>, ptr %alloc, align 4 => { i8 5, i8 57, i8 119 }
-; CHECK-NEXT:   store i25 -1, ptr %alloc, align 4
-; CHECK-NEXT:   %val10 = load <4 x i8>, ptr %alloc, align 4 => { i8 -1, i8 -1, i8 -1, i8 1 }
-; CHECK-NEXT:   store i8 -1, ptr %alloc, align 1
-; CHECK-NEXT:   %val11 = load i25, ptr %alloc, align 4 => poison
-; CHECK-NEXT:   call void @llvm.lifetime.start.p0(ptr poison)
-; CHECK-NEXT:   call void @llvm.lifetime.end.p0(ptr poison)
-; CHECK-NEXT:   %alloc_lifetime = alloca i32, align 4 => ptr 0xC [alloc_lifetime]
-; CHECK-NEXT:   %val12 = load i32, ptr %alloc_lifetime, align 4 => poison
-; CHECK-NEXT:   call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   %val13 = load i32, ptr %alloc_lifetime, align 4 => i32 -1744110296
-; CHECK-NEXT:   %val14 = load i32, ptr %alloc_lifetime, align 4 => i32 1822494346
-; CHECK-NEXT:   store i32 77, ptr %alloc_lifetime, align 4
-; CHECK-NEXT:   %val15 = load i32, ptr %alloc_lifetime, align 4 => i32 77
-; CHECK-NEXT:   call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   %val_undef1 = load i32, ptr %alloc_lifetime, align 4 => i32 -1486034729
-; CHECK-NEXT:   %val_undef2 = load i32, ptr %alloc_lifetime, align 4 => i32 1900108014
-; CHECK-NEXT:   call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   %val16 = load i32, ptr %alloc_lifetime, align 4 => poison
-; CHECK-NEXT:   store i32 -524288, ptr %alloc, align 4
-; CHECK-NEXT:   %val17 = load float, ptr %alloc, align 4 => NaN
-; CHECK-NEXT:   %alloc_vscale = alloca <vscale x 2 x i32>, align 8 => ptr 0x10 [alloc_vscale]
-; CHECK-NEXT:   %insert = insertelement <vscale x 1 x i32> poison, i32 1, i32 0 => { i32 1, poison, poison, poison }
-; CHECK-NEXT:   %ones = shufflevector <vscale x 1 x i32> %insert, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer => { i32 1, i32 1, i32 1, i32 1 }
-; CHECK-NEXT:   %twos = add <vscale x 1 x i32> %ones, %ones => { i32 2, i32 2, i32 2, i32 2 }
-; CHECK-NEXT:   store <vscale x 1 x i32> %ones, ptr %alloc_vscale, align 4
-; CHECK-NEXT:   %gep3 = getelementptr <vscale x 1 x i32>, ptr %alloc_vscale, i64 1 => ptr 0x20 [alloc_vscale + 16]
-; CHECK-NEXT:   store <vscale x 1 x i32> %twos, ptr %gep3, align 4
-; CHECK-NEXT:   %val18 = load <vscale x 2 x i32>, ptr %alloc_vscale, align 8 => { i32 2, i32 2, i32 2, i32 2, i32 1, i32 1, i32 1, i32 1 }
-; CHECK-NEXT:   %alloc_struct = alloca %struct, align 8 => ptr 0x30 [alloc_struct]
-; CHECK-NEXT:   store %struct { [2 x i16] [i16 1, i16 2], i64 3 }, ptr %alloc_struct, align 8
-; CHECK-NEXT:   %val19 = load %struct, ptr %alloc_struct, align 8 => { { i16 1, i16 2 }, i64 3 }
-; CHECK-NEXT:   %val20 = load i64, ptr %alloc_struct, align 8 => i64 281484800733898
-; CHECK-NEXT:   %val21 = load i64, ptr %alloc_struct, align 8 => i64 281484196877349
-; CHECK-NEXT:   %alloc_struct_packed = alloca %struct.packed, align 8 => ptr 0x40 [alloc_struct_packed]
-; CHECK-NEXT:   store %struct.packed <{ [2 x i16] [i16 1, i16 2], i64 3 }>, ptr %alloc_struct_packed, align 1
-; CHECK-NEXT:   %val22 = load %struct.packed, ptr %alloc_struct_packed, align 1 => { { i16 1, i16 2 }, i64 3 }
-; CHECK-NEXT:   %val23 = load i64, ptr %alloc_struct_packed, align 8 => i64 281483566645248
-; CHECK-NEXT:   %val24 = load i64, ptr %alloc_struct_packed, align 8 => i64 281483566645248
-; CHECK-NEXT:   %alloc_struct_vscale = alloca %struct.vscale, align 8 => ptr 0x50 [alloc_struct_vscale]
-; CHECK-NEXT:   store %struct.vscale zeroinitializer, ptr %alloc_struct_vscale, align 4
-; CHECK-NEXT:   %gep4 = getelementptr <vscale x 1 x i32>, ptr %alloc_struct_vscale, i32 1 => ptr 0x60 [alloc_struct_vscale + 16]
-; CHECK-NEXT:   store <vscale x 1 x i32> %ones, ptr %gep4, align 4
-; CHECK-NEXT:   %val25 = load %struct.vscale, ptr %alloc_struct_vscale, align 4 => { { i32 0, i32 0, i32 0, i32 0 }, { i32 1, i32 1, i32 1, i32 1 } }
-; CHECK-NEXT:   %alloc_array = alloca [2 x i32], align 4 => ptr 0x70 [alloc_array]
-; CHECK-NEXT:   store [2 x i32] [i32 1, i32 2], ptr %alloc_array, align 4
-; CHECK-NEXT:   %val26 = load [2 x i32], ptr %alloc_array, align 4 => { i32 1, i32 2 }
-; CHECK-NEXT:   %alloc_i1_vec = alloca <4 x i1>, align 1 => ptr 0x78 [alloc_i1_vec]
-; CHECK-NEXT:   store <4 x i1> <i1 true, i1 false, i1 poison, i1 false>, ptr %alloc_i1_vec, align 1
-; CHECK-NEXT:   %val27 = load <4 x i1>, ptr %alloc_i1_vec, align 1 => { F, F, F, F }
-; CHECK-NEXT:   %val28 = load i8, ptr %alloc_i1_vec, align 1 => poison
-; CHECK-NEXT:   %alloc_padding = alloca i31, align 4 => ptr 0x7C [alloc_padding]
-; CHECK-NEXT:   store i32 0, ptr %alloc_padding, align 4
-; CHECK-NEXT:   %alloc_padding_vec = alloca i64, align 8 => ptr 0x80 [alloc_padding_vec]
-; CHECK-NEXT:   store { <6 x i5>, i32 } { <6 x i5> zeroinitializer, i32 -1 }, ptr %alloc_padding_vec, align 4
-; CHECK-NEXT:   %load_agg = load { <6 x i5>, i32 }, ptr %alloc_padding_vec, align 4 => { { i5 0, i5 0, i5 0, i5 0, i5 0, i5 0 }, i32 -1 }
-; CHECK-NEXT:   %load_vec = load <6 x i5>, ptr %alloc_padding_vec, align 4 => { i5 0, i5 0, i5 0, i5 0, i5 0, i5 0 }
-; CHECK-NEXT:   %load_int_non_zero_padding = load i33, ptr %alloc_padding_vec, align 8 => i33 255
-; CHECK-NEXT:   %load_vec_non_zero_padding = load <3 x i11>, ptr %alloc_padding_vec, align 8 => { i11 255, i11 0, i11 0 }
-; CHECK-NEXT:   ret void
-; CHECK-NEXT: Exiting function: main

diff  --git a/llvm/test/tools/llubi/loadstore_le.ll b/llvm/test/tools/llubi/loadstore_le.ll
deleted file mode 100644
index e1170fb3854a2..0000000000000
--- a/llvm/test/tools/llubi/loadstore_le.ll
+++ /dev/null
@@ -1,192 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
-; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
-
-target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64"
-
-%struct = type { [2 x i16], i64 }
-%struct.packed = type <{ [2 x i16], i64 }>
-%struct.vscale = type { <vscale x 1 x i32>, <vscale x 1 x i32> }
-
-define void @main() {
-  %alloc = alloca i32
-  store i32 u0x00010203, ptr %alloc
-  %val1 = load i32, ptr %alloc
-  %val2 = load i32, ptr %alloc, align 2
-  %gep = getelementptr i8, ptr %alloc, i64 1
-  %val3 = load i8, ptr %gep
-  %val4 = load <4 x i8>, ptr %alloc
-
-  store i16 u0x0405, ptr %gep, align 1
-  %val5 = load <4 x i8>, ptr %alloc
-  store <2 x i16> <i16 u0x0607, i16 u0x0809>, ptr %alloc
-  %val6 = load <4 x i8>, ptr %alloc
-  %val7 = load <8 x i4>, ptr %alloc
-  store <3 x i3> <i3 1, i3 2, i3 3>, ptr %alloc
-  ; padding bits are undefined.
-  %val8 = load <16 x i1>, ptr %alloc
-  %val9 = load <16 x i1>, ptr %alloc
-  store <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 4, i3 5, i3 6, i3 7>, ptr %alloc
-  %val_bitcast = load <3 x i8>, ptr %alloc
-
-  ; For non-byte-sized types, the padding bits must be zero.
-  store i25 -1, ptr %alloc
-  %val10 = load <4 x i8>, ptr %alloc
-  %gep2 = getelementptr i8, ptr %alloc, i64 3
-  store i8 -1, ptr %gep2
-  ; If the padding bits were not zero, load yields poison value.
-  %val11 = load i25, ptr %alloc
-
-  call void @llvm.lifetime.start.p0(ptr poison)
-  call void @llvm.lifetime.end.p0(ptr poison)
-  %alloc_lifetime = alloca i32
-  ; Load of an dead object yields poison value.
-  %val12 = load i32, ptr %alloc_lifetime
-  call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-  ; After lifetime.start, the object is alive but uninitialized.
-  %val13 = load i32, ptr %alloc_lifetime
-  %val14 = load i32, ptr %alloc_lifetime
-  store i32 77, ptr %alloc_lifetime
-  %val15 = load i32, ptr %alloc_lifetime
-  ; Calling lifetime.start on an alive object makes the contents uninitialized again.
-  call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-  %val_undef1 = load i32, ptr %alloc_lifetime
-  %val_undef2 = load i32, ptr %alloc_lifetime
-  call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-  ; Calling lifetime.end on an already dead object is a no-op.
-  call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-  ; Load of an dead object yields poison value.
-  %val16 = load i32, ptr %alloc_lifetime
-
-  store i32 u0xFFF80000, ptr %alloc
-  %val17 = load float, ptr %alloc
-
-  %alloc_vscale = alloca <vscale x 2 x i32>
-  %insert = insertelement <vscale x 1 x i32> poison, i32 1, i32 0
-  %ones = shufflevector <vscale x 1 x i32> %insert, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer
-  %twos = add <vscale x 1 x i32> %ones, %ones
-  store <vscale x 1 x i32> %ones, ptr %alloc_vscale
-  %gep3 = getelementptr <vscale x 1 x i32>, ptr %alloc_vscale, i64 1
-  store <vscale x 1 x i32> %twos, ptr %gep3
-  %val18 = load <vscale x 2 x i32>, ptr %alloc_vscale
-
-  %alloc_struct = alloca %struct
-  store %struct { [2 x i16] [i16 1, i16 2], i64 3 }, ptr %alloc_struct
-  %val19 = load %struct, ptr %alloc_struct
-  ; Padding bytes of struct are undefined.
-  %val20 = load i64, ptr %alloc_struct
-  %val21 = load i64, ptr %alloc_struct
-
-  %alloc_struct_packed = alloca %struct.packed
-  store %struct.packed <{ [2 x i16] [i16 1, i16 2], i64 3 }>, ptr %alloc_struct_packed
-  %val22 = load %struct.packed, ptr %alloc_struct_packed
-  ; No padding bytes.
-  %val23 = load i64, ptr %alloc_struct_packed
-  %val24 = load i64, ptr %alloc_struct_packed
-
-  %alloc_struct_vscale = alloca %struct.vscale
-  store %struct.vscale zeroinitializer, ptr %alloc_struct_vscale
-  %gep4 = getelementptr <vscale x 1 x i32>, ptr %alloc_struct_vscale, i32 1
-  store <vscale x 1 x i32> %ones, ptr %gep4
-  %val25 = load %struct.vscale, ptr %alloc_struct_vscale
-
-  %alloc_array = alloca [2 x i32]
-  store [2 x i32] [i32 1, i32 2], ptr %alloc_array
-  %val26 = load [2 x i32], ptr %alloc_array
-
-  %alloc_i1_vec = alloca <4 x i1>
-  store <4 x i1> <i1 1, i1 0, i1 poison, i1 0>, ptr %alloc_i1_vec
-  %val27 = load <4 x i1>, ptr %alloc_i1_vec
-  %val28 = load i8, ptr %alloc_i1_vec
-
-  %alloc_padding = alloca i31
-  store i32 0, ptr %alloc_padding
-
-  %alloc_padding_vec = alloca i64
-  store { <6 x i5>, i32 } { <6 x i5> zeroinitializer, i32 -1}, ptr %alloc_padding_vec
-  %load_agg = load { <6 x i5>, i32 }, ptr %alloc_padding_vec
-  %load_vec = load <6 x i5>, ptr %alloc_padding_vec
-  %load_int_non_zero_padding = load i33, ptr %alloc_padding_vec
-  %load_vec_non_zero_padding = load <3 x i11>, ptr %alloc_padding_vec
-
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT:   %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
-; CHECK-NEXT:   store i32 66051, ptr %alloc, align 4
-; CHECK-NEXT:   %val1 = load i32, ptr %alloc, align 4 => i32 66051
-; CHECK-NEXT:   %val2 = load i32, ptr %alloc, align 2 => i32 66051
-; CHECK-NEXT:   %gep = getelementptr i8, ptr %alloc, i64 1 => ptr 0x9 [alloc + 1]
-; CHECK-NEXT:   %val3 = load i8, ptr %gep, align 1 => i8 2
-; CHECK-NEXT:   %val4 = load <4 x i8>, ptr %alloc, align 4 => { i8 3, i8 2, i8 1, i8 0 }
-; CHECK-NEXT:   store i16 1029, ptr %gep, align 1
-; CHECK-NEXT:   %val5 = load <4 x i8>, ptr %alloc, align 4 => { i8 3, i8 5, i8 4, i8 0 }
-; CHECK-NEXT:   store <2 x i16> <i16 1543, i16 2057>, ptr %alloc, align 4
-; CHECK-NEXT:   %val6 = load <4 x i8>, ptr %alloc, align 4 => { i8 7, i8 6, i8 9, i8 8 }
-; CHECK-NEXT:   %val7 = load <8 x i4>, ptr %alloc, align 4 => { i4 7, i4 0, i4 6, i4 0, i4 -7, i4 0, i4 -8, i4 0 }
-; CHECK-NEXT:   store <3 x i3> <i3 1, i3 2, i3 3>, ptr %alloc, align 2
-; CHECK-NEXT:   %val8 = load <16 x i1>, ptr %alloc, align 2 => { T, F, F, F, T, F, T, T, F, F, F, F, F, F, F, F }
-; CHECK-NEXT:   %val9 = load <16 x i1>, ptr %alloc, align 2 => { T, F, F, F, T, F, T, T, F, F, F, F, F, F, F, F }
-; CHECK-NEXT:   store <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 -4, i3 -3, i3 -2, i3 -1>, ptr %alloc, align 4
-; CHECK-NEXT:   %val_bitcast = load <3 x i8>, ptr %alloc, align 4 => { i8 -120, i8 -58, i8 -6 }
-; CHECK-NEXT:   store i25 -1, ptr %alloc, align 4
-; CHECK-NEXT:   %val10 = load <4 x i8>, ptr %alloc, align 4 => { i8 -1, i8 -1, i8 -1, i8 1 }
-; CHECK-NEXT:   %gep2 = getelementptr i8, ptr %alloc, i64 3 => ptr 0xB [alloc + 3]
-; CHECK-NEXT:   store i8 -1, ptr %gep2, align 1
-; CHECK-NEXT:   %val11 = load i25, ptr %alloc, align 4 => poison
-; CHECK-NEXT:   call void @llvm.lifetime.start.p0(ptr poison)
-; CHECK-NEXT:   call void @llvm.lifetime.end.p0(ptr poison)
-; CHECK-NEXT:   %alloc_lifetime = alloca i32, align 4 => ptr 0xC [alloc_lifetime]
-; CHECK-NEXT:   %val12 = load i32, ptr %alloc_lifetime, align 4 => poison
-; CHECK-NEXT:   call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   %val13 = load i32, ptr %alloc_lifetime, align 4 => i32 -1744110296
-; CHECK-NEXT:   %val14 = load i32, ptr %alloc_lifetime, align 4 => i32 1822494346
-; CHECK-NEXT:   store i32 77, ptr %alloc_lifetime, align 4
-; CHECK-NEXT:   %val15 = load i32, ptr %alloc_lifetime, align 4 => i32 77
-; CHECK-NEXT:   call void @llvm.lifetime.start.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   %val_undef1 = load i32, ptr %alloc_lifetime, align 4 => i32 -1486034729
-; CHECK-NEXT:   %val_undef2 = load i32, ptr %alloc_lifetime, align 4 => i32 1900108014
-; CHECK-NEXT:   call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   call void @llvm.lifetime.end.p0(ptr %alloc_lifetime)
-; CHECK-NEXT:   %val16 = load i32, ptr %alloc_lifetime, align 4 => poison
-; CHECK-NEXT:   store i32 -524288, ptr %alloc, align 4
-; CHECK-NEXT:   %val17 = load float, ptr %alloc, align 4 => NaN
-; CHECK-NEXT:   %alloc_vscale = alloca <vscale x 2 x i32>, align 8 => ptr 0x10 [alloc_vscale]
-; CHECK-NEXT:   %insert = insertelement <vscale x 1 x i32> poison, i32 1, i32 0 => { i32 1, poison, poison, poison }
-; CHECK-NEXT:   %ones = shufflevector <vscale x 1 x i32> %insert, <vscale x 1 x i32> poison, <vscale x 1 x i32> zeroinitializer => { i32 1, i32 1, i32 1, i32 1 }
-; CHECK-NEXT:   %twos = add <vscale x 1 x i32> %ones, %ones => { i32 2, i32 2, i32 2, i32 2 }
-; CHECK-NEXT:   store <vscale x 1 x i32> %ones, ptr %alloc_vscale, align 4
-; CHECK-NEXT:   %gep3 = getelementptr <vscale x 1 x i32>, ptr %alloc_vscale, i64 1 => ptr 0x20 [alloc_vscale + 16]
-; CHECK-NEXT:   store <vscale x 1 x i32> %twos, ptr %gep3, align 4
-; CHECK-NEXT:   %val18 = load <vscale x 2 x i32>, ptr %alloc_vscale, align 8 => { i32 1, i32 1, i32 1, i32 1, i32 2, i32 2, i32 2, i32 2 }
-; CHECK-NEXT:   %alloc_struct = alloca %struct, align 8 => ptr 0x30 [alloc_struct]
-; CHECK-NEXT:   store %struct { [2 x i16] [i16 1, i16 2], i64 3 }, ptr %alloc_struct, align 8
-; CHECK-NEXT:   %val19 = load %struct, ptr %alloc_struct, align 8 => { { i16 1, i16 2 }, i64 3 }
-; CHECK-NEXT:   %val20 = load i64, ptr %alloc_struct, align 8 => i64 5300370392114921473
-; CHECK-NEXT:   %val21 = load i64, ptr %alloc_struct, align 8 => i64 2706826262684499969
-; CHECK-NEXT:   %alloc_struct_packed = alloca %struct.packed, align 8 => ptr 0x40 [alloc_struct_packed]
-; CHECK-NEXT:   store %struct.packed <{ [2 x i16] [i16 1, i16 2], i64 3 }>, ptr %alloc_struct_packed, align 1
-; CHECK-NEXT:   %val22 = load %struct.packed, ptr %alloc_struct_packed, align 1 => { { i16 1, i16 2 }, i64 3 }
-; CHECK-NEXT:   %val23 = load i64, ptr %alloc_struct_packed, align 8 => i64 12885032961
-; CHECK-NEXT:   %val24 = load i64, ptr %alloc_struct_packed, align 8 => i64 12885032961
-; CHECK-NEXT:   %alloc_struct_vscale = alloca %struct.vscale, align 8 => ptr 0x50 [alloc_struct_vscale]
-; CHECK-NEXT:   store %struct.vscale zeroinitializer, ptr %alloc_struct_vscale, align 4
-; CHECK-NEXT:   %gep4 = getelementptr <vscale x 1 x i32>, ptr %alloc_struct_vscale, i32 1 => ptr 0x60 [alloc_struct_vscale + 16]
-; CHECK-NEXT:   store <vscale x 1 x i32> %ones, ptr %gep4, align 4
-; CHECK-NEXT:   %val25 = load %struct.vscale, ptr %alloc_struct_vscale, align 4 => { { i32 0, i32 0, i32 0, i32 0 }, { i32 1, i32 1, i32 1, i32 1 } }
-; CHECK-NEXT:   %alloc_array = alloca [2 x i32], align 4 => ptr 0x70 [alloc_array]
-; CHECK-NEXT:   store [2 x i32] [i32 1, i32 2], ptr %alloc_array, align 4
-; CHECK-NEXT:   %val26 = load [2 x i32], ptr %alloc_array, align 4 => { i32 1, i32 2 }
-; CHECK-NEXT:   %alloc_i1_vec = alloca <4 x i1>, align 1 => ptr 0x78 [alloc_i1_vec]
-; CHECK-NEXT:   store <4 x i1> <i1 true, i1 false, i1 poison, i1 false>, ptr %alloc_i1_vec, align 1
-; CHECK-NEXT:   %val27 = load <4 x i1>, ptr %alloc_i1_vec, align 1 => { T, F, poison, F }
-; CHECK-NEXT:   %val28 = load i8, ptr %alloc_i1_vec, align 1 => poison
-; CHECK-NEXT:   %alloc_padding = alloca i31, align 4 => ptr 0x7C [alloc_padding]
-; CHECK-NEXT:   store i32 0, ptr %alloc_padding, align 4
-; CHECK-NEXT:   %alloc_padding_vec = alloca i64, align 8 => ptr 0x80 [alloc_padding_vec]
-; CHECK-NEXT:   store { <6 x i5>, i32 } { <6 x i5> zeroinitializer, i32 -1 }, ptr %alloc_padding_vec, align 4
-; CHECK-NEXT:   %load_agg = load { <6 x i5>, i32 }, ptr %alloc_padding_vec, align 4 => { { i5 0, i5 0, i5 0, i5 0, i5 0, i5 0 }, i32 -1 }
-; CHECK-NEXT:   %load_vec = load <6 x i5>, ptr %alloc_padding_vec, align 4 => { i5 0, i5 0, i5 0, i5 0, i5 0, i5 0 }
-; CHECK-NEXT:   %load_int_non_zero_padding = load i33, ptr %alloc_padding_vec, align 8 => poison
-; CHECK-NEXT:   %load_vec_non_zero_padding = load <3 x i11>, ptr %alloc_padding_vec, align 8 => { poison, poison, poison }
-; CHECK-NEXT:   ret void
-; CHECK-NEXT: Exiting function: main

diff  --git a/llvm/test/tools/llubi/loadstore_misaligned.ll b/llvm/test/tools/llubi/loadstore_misaligned.ll
deleted file mode 100644
index cc80639d773bd..0000000000000
--- a/llvm/test/tools/llubi/loadstore_misaligned.ll
+++ /dev/null
@@ -1,14 +0,0 @@
-; RUN: sed 's/OP1/store i32 0/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-; RUN: sed 's/OP1/%res = load i32/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-
-define void @main() {
-  %alloc = alloca [2 x i32], align 8
-  %gep = getelementptr inbounds [2 x i32], ptr %alloc, i64 0, i64 1
-  OP1, ptr %gep, align 8
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT: %alloc = alloca [2 x i32], align 8 => ptr 0x8 [alloc]
-; CHECK-NEXT: %gep = getelementptr inbounds [2 x i32], ptr %alloc, i64 0, i64 1 => ptr 0xC [alloc + 4]
-; CHECK-NEXT: Immediate UB detected: Misaligned memory access.
-; CHECK-NEXT: error: Execution of function 'main' failed.

diff  --git a/llvm/test/tools/llubi/loadstore_null.ll b/llvm/test/tools/llubi/loadstore_null.ll
deleted file mode 100644
index 7a243784e6bd6..0000000000000
--- a/llvm/test/tools/llubi/loadstore_null.ll
+++ /dev/null
@@ -1,10 +0,0 @@
-; RUN: sed 's/OP1/store i32 0/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-; RUN: sed 's/OP1/%res = load i32/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-
-define void @main() {
-  OP1, ptr null
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT: Immediate UB detected: Invalid memory access via a pointer with nullary provenance.
-; CHECK-NEXT: error: Execution of function 'main' failed.

diff  --git a/llvm/test/tools/llubi/loadstore_oob1.ll b/llvm/test/tools/llubi/loadstore_oob1.ll
deleted file mode 100644
index 0618faa96bfde..0000000000000
--- a/llvm/test/tools/llubi/loadstore_oob1.ll
+++ /dev/null
@@ -1,14 +0,0 @@
-; RUN: sed 's/OP1/store i32 0/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-; RUN: sed 's/OP1/%res = load i32/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-
-define void @main() {
-  %alloc = alloca [2 x i32]
-  %gep = getelementptr inbounds [2 x i32], ptr %alloc, i64 0, i64 2
-  OP1, ptr %gep
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT: %alloc = alloca [2 x i32], align 4 => ptr 0x8 [alloc]
-; CHECK-NEXT: %gep = getelementptr inbounds [2 x i32], ptr %alloc, i64 0, i64 2 => ptr 0x10 [alloc + 8]
-; CHECK-NEXT: Immediate UB detected: Memory access is out of bounds.
-; CHECK-NEXT: error: Execution of function 'main' failed.

diff  --git a/llvm/test/tools/llubi/loadstore_overaligned.ll b/llvm/test/tools/llubi/loadstore_overaligned.ll
deleted file mode 100644
index 91a4eb63d9d2a..0000000000000
--- a/llvm/test/tools/llubi/loadstore_overaligned.ll
+++ /dev/null
@@ -1,30 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llubi_test_checks.py UTC_ARGS: --version 6
-; RUN: llubi --verbose < %s 2>&1 | FileCheck %s
-
-; For over-aligned arrays, the padding bytes between elements should be filled with undef.
-
-target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:64:64-i64:64:64"
-
-define void @main() {
-  %alloca = alloca [2 x i32]
-  store <4 x i32> zeroinitializer, ptr %alloca, align 8
-  store [2 x i32] [i32 1, i32 1], ptr %alloca, align 8
-  ; The padding bytes in the middle are filled with undef,
-  ; while the tail padding bytes are still zero-initialized.
-  %load1 = load <4 x i32>, ptr %alloca, align 8
-  %load2 = load <4 x i32>, ptr %alloca, align 8
-  %load3 = load <4 x i32>, ptr %alloca, align 8
-  %load_arr = load [2 x i32], ptr %alloca, align 8
-  ret void
-}
-
-; CHECK: Entering function: main
-; CHECK-NEXT:   %alloca = alloca [2 x i32], align 8 => ptr 0x8 [alloca]
-; CHECK-NEXT:   store <4 x i32> zeroinitializer, ptr %alloca, align 8
-; CHECK-NEXT:   store [2 x i32] [i32 1, i32 1], ptr %alloca, align 8
-; CHECK-NEXT:   %load1 = load <4 x i32>, ptr %alloca, align 8 => { i32 1, i32 -1744110296, i32 1, i32 0 }
-; CHECK-NEXT:   %load2 = load <4 x i32>, ptr %alloca, align 8 => { i32 1, i32 1822494346, i32 1, i32 0 }
-; CHECK-NEXT:   %load3 = load <4 x i32>, ptr %alloca, align 8 => { i32 1, i32 -1486034729, i32 1, i32 0 }
-; CHECK-NEXT:   %load_arr = load [2 x i32], ptr %alloca, align 8 => { i32 1, i32 1 }
-; CHECK-NEXT:   ret void
-; CHECK-NEXT: Exiting function: main

diff  --git a/llvm/test/tools/llubi/loadstore_poison.ll b/llvm/test/tools/llubi/loadstore_poison.ll
deleted file mode 100644
index 44c72aa803709..0000000000000
--- a/llvm/test/tools/llubi/loadstore_poison.ll
+++ /dev/null
@@ -1,10 +0,0 @@
-; RUN: sed 's/OP1/store i32 0/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-; RUN: sed 's/OP1/%res = load i32/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-
-define void @main() {
-  OP1, ptr poison
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT: Immediate UB detected: Invalid memory access with a poison pointer.
-; CHECK-NEXT: error: Execution of function 'main' failed.

diff  --git a/llvm/test/tools/llubi/loadstore_uaf.ll b/llvm/test/tools/llubi/loadstore_uaf.ll
deleted file mode 100644
index 21b86552275b6..0000000000000
--- a/llvm/test/tools/llubi/loadstore_uaf.ll
+++ /dev/null
@@ -1,21 +0,0 @@
-; RUN: sed 's/OP1/store i32 0/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-; RUN: sed 's/OP1/%res = load i32/g' %s | not llubi --verbose 2>&1 | FileCheck %s
-
-define ptr @stack_object() {
-  %alloc = alloca i32
-  ret ptr %alloc
-}
-
-define void @main() {
-  %alloc = call ptr @stack_object()
-  OP1, ptr %alloc
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT: Entering function: stack_object
-; CHECK-NEXT:   %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
-; CHECK-NEXT:   ret ptr %alloc
-; CHECK-NEXT: Exiting function: stack_object
-; CHECK-NEXT:   %alloc = call ptr @stack_object() => ptr 0x8 [dangling]
-; CHECK-NEXT: Immediate UB detected: Try to access a dead memory object.
-; CHECK-NEXT: error: Execution of function 'main' failed.

diff  --git a/llvm/test/tools/llubi/store_dead.ll b/llvm/test/tools/llubi/store_dead.ll
deleted file mode 100644
index 8bd15beefb8d3..0000000000000
--- a/llvm/test/tools/llubi/store_dead.ll
+++ /dev/null
@@ -1,18 +0,0 @@
-; 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.lifetime.start.p0(ptr %alloc)
-  store i32 0, ptr %alloc
-  call void @llvm.lifetime.end.p0(ptr %alloc)
-  store i32 0, ptr %alloc
-  ret void
-}
-; CHECK: Entering function: main
-; CHECK-NEXT:   %alloc = alloca i32, align 4 => ptr 0x8 [alloc]
-; CHECK-NEXT:   call void @llvm.lifetime.start.p0(ptr %alloc)
-; CHECK-NEXT:   store i32 0, ptr %alloc, align 4
-; CHECK-NEXT:   call void @llvm.lifetime.end.p0(ptr %alloc)
-; CHECK-NEXT: Immediate UB detected: Try to access a dead memory object.
-; CHECK-NEXT: error: Execution of function 'main' failed.

diff  --git a/llvm/tools/llubi/lib/Context.cpp b/llvm/tools/llubi/lib/Context.cpp
index fe95eef57c2ab..adedfbcc3886b 100644
--- a/llvm/tools/llubi/lib/Context.cpp
+++ b/llvm/tools/llubi/lib/Context.cpp
@@ -103,298 +103,6 @@ const AnyValue &Context::getConstantValue(Constant *C) {
   return ConstCache.emplace(C, getConstantValueImpl(C)).first->second;
 }
 
-AnyValue Context::fromBytes(ArrayRef<Byte> Bytes, Type *Ty,
-                            uint32_t &OffsetInBits, bool CheckPaddingBits) {
-  if (Ty->isIntegerTy() || Ty->isFloatingPointTy() || Ty->isPointerTy()) {
-    uint32_t NumBits = DL.getTypeSizeInBits(Ty).getFixedValue();
-    uint32_t NewOffsetInBits = OffsetInBits + NumBits;
-    if (CheckPaddingBits)
-      NewOffsetInBits = alignTo(NewOffsetInBits, 8);
-    bool NeedsPadding = NewOffsetInBits != OffsetInBits + NumBits;
-    uint32_t NumBitsToExtract = NewOffsetInBits - OffsetInBits;
-    SmallVector<uint64_t> RawBits(alignTo(NumBitsToExtract, 8));
-    for (uint32_t I = 0; I < NumBitsToExtract; I += 8) {
-      // Try to form a 'logical' byte that represents the bits in the range
-      // [BitsStart, BitsEnd].
-      uint32_t NumBitsInByte = std::min(8U, NumBitsToExtract - I);
-      uint32_t BitsStart =
-          OffsetInBits +
-          (DL.isLittleEndian() ? I : (NumBitsToExtract - NumBitsInByte - I));
-      uint32_t BitsEnd = BitsStart + NumBitsInByte - 1;
-      Byte LogicalByte;
-      // Check whether it is a cross-byte access.
-      if (((BitsStart ^ BitsEnd) & ~7) == 0)
-        LogicalByte = Bytes[BitsStart / 8].lshr(BitsStart % 8);
-      else
-        LogicalByte =
-            Byte::fshr(Bytes[BitsStart / 8], Bytes[BitsEnd / 8], BitsStart % 8);
-
-      uint32_t Mask = (1U << NumBitsInByte) - 1;
-      // If any of the bits in the byte is poison, the whole value is poison.
-      if (~LogicalByte.ConcreteMask & ~LogicalByte.Value & Mask) {
-        OffsetInBits = NewOffsetInBits;
-        return AnyValue::poison();
-      }
-      uint8_t RandomBits = 0;
-      if (UndefBehavior == UndefValueBehavior::NonDeterministic &&
-          (~LogicalByte.ConcreteMask & Mask)) {
-        // This byte contains undef bits.
-        std::uniform_int_distribution<uint32_t> Distrib(0, 255);
-        RandomBits = static_cast<uint8_t>(Distrib(Rng));
-      }
-      uint8_t ActualBits = ((LogicalByte.Value & LogicalByte.ConcreteMask) |
-                            (RandomBits & ~LogicalByte.ConcreteMask)) &
-                           Mask;
-      RawBits[I / 64] |= static_cast<APInt::WordType>(ActualBits) << (I % 64);
-    }
-    OffsetInBits = NewOffsetInBits;
-
-    APInt Bits(NumBitsToExtract, RawBits);
-
-    // Padding bits for non-byte-sized scalar types must be zero.
-    if (NeedsPadding) {
-      if (!Bits.isIntN(NumBits))
-        return AnyValue::poison();
-      Bits = Bits.trunc(NumBits);
-    }
-
-    if (Ty->isIntegerTy())
-      return Bits;
-    if (Ty->isFloatingPointTy())
-      return APFloat(Ty->getFltSemantics(), Bits);
-    assert(Ty->isPointerTy() && "Expect a pointer type");
-    // TODO: recover provenance
-    return Pointer(Bits);
-  }
-
-  assert(OffsetInBits % 8 == 0 && "Missing padding bits.");
-  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
-    Type *ElemTy = VecTy->getElementType();
-    uint32_t ElemBits = DL.getTypeSizeInBits(ElemTy).getFixedValue();
-    uint32_t NumElements = getEVL(VecTy->getElementCount());
-    // Check padding bits. <N x iM> acts as if an integer type with N * M bits.
-    uint32_t NewOffsetInBits = OffsetInBits + ElemBits * NumElements;
-    uint32_t AlignedNewOffsetInBits = alignTo(NewOffsetInBits, 8);
-    if (NewOffsetInBits != AlignedNewOffsetInBits) {
-      assert(NewOffsetInBits % 8 != 0 &&
-             AlignedNewOffsetInBits - NewOffsetInBits < 8 &&
-             "Unexpected offset.");
-      // The padding bits are located in the last byte on little-endian systems.
-      // On big-endian systems, the padding bits are located in the first byte.
-      const Byte &PaddingByte =
-          Bytes[(DL.isBigEndian() ? OffsetInBits : NewOffsetInBits) / 8];
-      uint32_t Mask = (~0U << (NewOffsetInBits % 8)) & 255U;
-      // Make sure all high padding bits are zero.
-      if ((PaddingByte.ConcreteMask & ~PaddingByte.Value & Mask) != Mask) {
-        OffsetInBits = AlignedNewOffsetInBits;
-        return AnyValue::getPoisonValue(*this, Ty);
-      }
-      if (DL.isBigEndian())
-        OffsetInBits += AlignedNewOffsetInBits - NewOffsetInBits;
-    }
-
-    std::vector<AnyValue> ValVec;
-    ValVec.reserve(NumElements);
-    for (uint32_t I = 0; I != NumElements; ++I)
-      ValVec.push_back(
-          fromBytes(Bytes, ElemTy, OffsetInBits, /*CheckPaddingBits=*/false));
-    if (DL.isBigEndian())
-      std::reverse(ValVec.begin(), ValVec.end());
-    OffsetInBits = AlignedNewOffsetInBits;
-    return AnyValue(std::move(ValVec));
-  }
-  if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
-    Type *ElemTy = ArrTy->getElementType();
-    uint32_t StrideInBits = getEffectiveTypeAllocSize(ElemTy) * 8;
-    std::vector<AnyValue> ValVec;
-    uint32_t NumElements = ArrTy->getNumElements();
-    ValVec.reserve(NumElements);
-    uint32_t BaseOffsetInBits = OffsetInBits;
-    for (uint32_t I = 0; I != NumElements; ++I) {
-      OffsetInBits = BaseOffsetInBits + I * StrideInBits;
-      ValVec.push_back(
-          fromBytes(Bytes, ElemTy, OffsetInBits, /*CheckPaddingBits=*/true));
-    }
-    return AnyValue(std::move(ValVec));
-  }
-  if (auto *StructTy = dyn_cast<StructType>(Ty)) {
-    auto *Layout = DL.getStructLayout(StructTy);
-    uint32_t BaseOffsetInBits = OffsetInBits;
-    std::vector<AnyValue> ValVec;
-    uint32_t NumElements = StructTy->getNumElements();
-    ValVec.reserve(NumElements);
-    for (uint32_t I = 0; I != NumElements; ++I) {
-      Type *ElemTy = StructTy->getElementType(I);
-      TypeSize ElemOffset = Layout->getElementOffset(I);
-      OffsetInBits = BaseOffsetInBits + getEffectiveTypeSize(ElemOffset) * 8;
-      ValVec.push_back(
-          fromBytes(Bytes, ElemTy, OffsetInBits, /*CheckPaddingBits=*/true));
-    }
-    OffsetInBits =
-        BaseOffsetInBits +
-        static_cast<uint32_t>(getEffectiveTypeStoreSize(StructTy)) * 8;
-    return AnyValue(std::move(ValVec));
-  }
-  llvm_unreachable("Unsupported first class type.");
-}
-
-void Context::toBytes(const AnyValue &Val, Type *Ty, uint32_t &OffsetInBits,
-                      MutableArrayRef<Byte> Bytes, bool PaddingBits) {
-  if (Val.isPoison() || Ty->isIntegerTy() || Ty->isFloatingPointTy() ||
-      Ty->isPointerTy()) {
-    uint32_t NumBits = DL.getTypeSizeInBits(Ty).getFixedValue();
-    uint32_t NewOffsetInBits = OffsetInBits + NumBits;
-    if (PaddingBits)
-      NewOffsetInBits = alignTo(NewOffsetInBits, 8);
-    bool NeedsPadding = NewOffsetInBits != OffsetInBits + NumBits;
-    auto WriteBits = [&](const APInt &Bits) {
-      for (uint32_t I = 0, E = Bits.getBitWidth(); I < E; I += 8) {
-        uint32_t NumBitsInByte = std::min(8U, E - I);
-        uint32_t BitsStart =
-            OffsetInBits + (DL.isLittleEndian() ? I : (E - NumBitsInByte - I));
-        uint32_t BitsEnd = BitsStart + NumBitsInByte - 1;
-        uint8_t BitsVal =
-            static_cast<uint8_t>(Bits.extractBitsAsZExtValue(NumBitsInByte, I));
-
-        Bytes[BitsStart / 8].writeBits(
-            static_cast<uint8_t>(((1U << NumBitsInByte) - 1)
-                                 << (BitsStart % 8)),
-            static_cast<uint8_t>(BitsVal << (BitsStart % 8)));
-        // If it is a cross-byte access, write the remaining bits to the next
-        // byte.
-        if (((BitsStart ^ BitsEnd) & ~7) != 0)
-          Bytes[BitsEnd / 8].writeBits(
-              static_cast<uint8_t>((1U << (BitsEnd % 8 + 1)) - 1),
-              static_cast<uint8_t>(BitsVal >> (8 - (BitsStart % 8))));
-      }
-    };
-    if (Val.isPoison()) {
-      for (uint32_t I = 0, E = NewOffsetInBits - OffsetInBits; I < E;) {
-        uint32_t NumBitsInByte = std::min(8 - (OffsetInBits + I) % 8, E - I);
-        assert(((OffsetInBits ^ (OffsetInBits + NumBitsInByte - 1)) & ~7) ==
-                   0 &&
-               "Across byte boundary.");
-        Bytes[(OffsetInBits + I) / 8].poisonBits(static_cast<uint8_t>(
-            ((1U << NumBitsInByte) - 1) << ((OffsetInBits + I) % 8)));
-        I += NumBitsInByte;
-      }
-    } else if (Ty->isIntegerTy()) {
-      auto &Bits = Val.asInteger();
-      WriteBits(NeedsPadding ? Bits.zext(NewOffsetInBits - OffsetInBits)
-                             : Bits);
-    } else if (Ty->isFloatingPointTy()) {
-      auto Bits = Val.asFloat().bitcastToAPInt();
-      WriteBits(NeedsPadding ? Bits.zext(NewOffsetInBits - OffsetInBits)
-                             : Bits);
-    } else if (Ty->isPointerTy()) {
-      auto &Bits = Val.asPointer().address();
-      WriteBits(NeedsPadding ? Bits.zext(NewOffsetInBits - OffsetInBits)
-                             : Bits);
-      // TODO: save metadata of the pointer.
-    } else {
-      llvm_unreachable("Unsupported scalar type.");
-    }
-    OffsetInBits = NewOffsetInBits;
-    return;
-  }
-
-  assert(OffsetInBits % 8 == 0 && "Missing padding bits.");
-  if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
-    Type *ElemTy = VecTy->getElementType();
-    auto &ValVec = Val.asAggregate();
-    uint32_t NewOffsetInBits =
-        alignTo(OffsetInBits + DL.getTypeSizeInBits(ElemTy).getFixedValue() *
-                                   ValVec.size(),
-                8);
-    if (DL.isLittleEndian()) {
-      for (const auto &SubVal : ValVec)
-        toBytes(SubVal, ElemTy, OffsetInBits, Bytes,
-                /*PaddingBits=*/false);
-    } else {
-      for (const auto &SubVal : reverse(ValVec))
-        toBytes(SubVal, ElemTy, OffsetInBits, Bytes,
-                /*PaddingBits=*/false);
-    }
-    if (NewOffsetInBits != OffsetInBits) {
-      assert(OffsetInBits % 8 != 0 && NewOffsetInBits - OffsetInBits < 8 &&
-             "Unexpected offset.");
-      // Fill remaining bits with zero.
-      Bytes[OffsetInBits / 8].zeroBits(
-          static_cast<uint8_t>(~0U << (OffsetInBits % 8)));
-    }
-    OffsetInBits = NewOffsetInBits;
-    return;
-  }
-  auto FillUndefBytes = [&](uint32_t NewOffsetInBits) {
-    if (OffsetInBits == NewOffsetInBits)
-      return;
-    // Fill padding bits due to alignment requirement.
-    assert(NewOffsetInBits > OffsetInBits &&
-           "Unexpected negative padding bits!");
-    fill(Bytes.slice(OffsetInBits / 8, (NewOffsetInBits - OffsetInBits) / 8),
-         Byte::undef());
-    OffsetInBits = NewOffsetInBits;
-  };
-  if (auto *ArrTy = dyn_cast<ArrayType>(Ty)) {
-    Type *ElemTy = ArrTy->getElementType();
-    uint32_t CurrentOffsetInBits = OffsetInBits;
-    uint32_t StrideInBits = getEffectiveTypeAllocSize(ElemTy) * 8;
-    for (const auto &SubVal : Val.asAggregate()) {
-      FillUndefBytes(CurrentOffsetInBits);
-      toBytes(SubVal, ElemTy, OffsetInBits, Bytes, /*PaddingBits=*/true);
-      CurrentOffsetInBits += StrideInBits;
-    }
-    return;
-  }
-  if (auto *StructTy = dyn_cast<StructType>(Ty)) {
-    auto *Layout = DL.getStructLayout(StructTy);
-    uint32_t BaseOffsetInBits = OffsetInBits;
-    for (uint32_t I = 0, E = Val.asAggregate().size(); I != E; ++I) {
-      Type *ElemTy = StructTy->getElementType(I);
-      TypeSize ElemOffset = Layout->getElementOffset(I);
-      uint32_t NewOffsetInBits =
-          BaseOffsetInBits + getEffectiveTypeSize(ElemOffset) * 8;
-      FillUndefBytes(NewOffsetInBits);
-      toBytes(Val.asAggregate()[I], ElemTy, OffsetInBits, Bytes,
-              /*PaddingBits=*/true);
-    }
-    uint32_t NewOffsetInBits =
-        BaseOffsetInBits + getEffectiveTypeStoreSize(StructTy) * 8;
-    FillUndefBytes(NewOffsetInBits);
-    return;
-  }
-
-  llvm_unreachable("Unsupported first class type.");
-}
-
-AnyValue Context::fromBytes(ArrayRef<Byte> Bytes, Type *Ty) {
-  uint32_t OffsetInBits = 0;
-  return fromBytes(Bytes, Ty, OffsetInBits, /*CheckPaddingBits=*/true);
-}
-
-void Context::toBytes(const AnyValue &Val, Type *Ty,
-                      MutableArrayRef<Byte> Bytes) {
-  uint32_t OffsetInBits = 0;
-  toBytes(Val, Ty, OffsetInBits, Bytes, /*PaddingBits=*/true);
-}
-
-AnyValue Context::load(MemoryObject &MO, uint64_t Offset, Type *ValTy) {
-  return fromBytes(
-      MO.getBytes().slice(Offset, getEffectiveTypeStoreSize(ValTy)), ValTy);
-}
-
-void Context::store(MemoryObject &MO, uint64_t Offset, const AnyValue &Val,
-                    Type *ValTy) {
-  toBytes(Val, ValTy,
-          MO.getBytes().slice(Offset, getEffectiveTypeStoreSize(ValTy)));
-}
-
-void Context::storeRawBytes(MemoryObject &MO, uint64_t Offset, const void *Data,
-                            uint64_t Size) {
-  for (uint64_t I = 0; I != Size; ++I)
-    MO[Offset + I] = Byte::concrete(static_cast<const uint8_t *>(Data)[I]);
-}
-
 MemoryObject::~MemoryObject() = default;
 MemoryObject::MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name,
                            unsigned AS, MemInitKind InitKind)
@@ -403,13 +111,13 @@ MemoryObject::MemoryObject(uint64_t Addr, uint64_t Size, StringRef Name,
                                               : MemoryObjectState::Dead) {
   switch (InitKind) {
   case MemInitKind::Zeroed:
-    Bytes.resize(Size, Byte::concrete(0));
+    Bytes.resize(Size, Byte{0, ByteKind::Concrete});
     break;
   case MemInitKind::Uninitialized:
-    Bytes.resize(Size, Byte::undef());
+    Bytes.resize(Size, Byte{0, ByteKind::Undef});
     break;
   case MemInitKind::Poisoned:
-    Bytes.resize(Size, Byte::poison());
+    Bytes.resize(Size, Byte{0, ByteKind::Poison});
     break;
   }
 }
@@ -467,17 +175,38 @@ BasicBlock *Context::getTargetBlock(const Pointer &Ptr) {
   return It->second.first;
 }
 
-uint64_t Context::getEffectiveTypeAllocSize(Type *Ty) {
-  // FIXME: It is incorrect for overaligned scalable vector types.
-  return getEffectiveTypeSize(DL.getTypeAllocSize(Ty));
-}
-uint64_t Context::getEffectiveTypeStoreSize(Type *Ty) {
-  return getEffectiveTypeSize(DL.getTypeStoreSize(Ty));
-}
-
 void MemoryObject::markAsFreed() {
   State = MemoryObjectState::Freed;
   Bytes.clear();
 }
 
+void MemoryObject::writeRawBytes(uint64_t Offset, const void *Data,
+                                 uint64_t Length) {
+  assert(SaturatingAdd(Offset, Length) <= Size && "Write out of bounds");
+  const uint8_t *ByteData = static_cast<const uint8_t *>(Data);
+  for (uint64_t I = 0; I < Length; ++I)
+    Bytes[Offset + I].set(ByteData[I]);
+}
+
+void MemoryObject::writeInteger(uint64_t Offset, const APInt &Int,
+                                const DataLayout &DL) {
+  uint64_t BitWidth = Int.getBitWidth();
+  uint64_t IntSize = divideCeil(BitWidth, 8);
+  assert(SaturatingAdd(Offset, IntSize) <= Size && "Write out of bounds");
+  for (uint64_t I = 0; I < IntSize; ++I) {
+    uint64_t ByteIndex = DL.isLittleEndian() ? I : (IntSize - 1 - I);
+    uint64_t Bits = std::min(BitWidth - ByteIndex * 8, uint64_t(8));
+    Bytes[Offset + I].set(Int.extractBitsAsZExtValue(Bits, ByteIndex * 8));
+  }
+}
+void MemoryObject::writeFloat(uint64_t Offset, const APFloat &Float,
+                              const DataLayout &DL) {
+  writeInteger(Offset, Float.bitcastToAPInt(), DL);
+}
+void MemoryObject::writePointer(uint64_t Offset, const Pointer &Ptr,
+                                const DataLayout &DL) {
+  writeInteger(Offset, Ptr.address(), DL);
+  // TODO: provenance
+}
+
 } // namespace llvm::ubi

diff  --git a/llvm/tools/llubi/lib/Context.h b/llvm/tools/llubi/lib/Context.h
index a250004b3cb54..25ba940323ebf 100644
--- a/llvm/tools/llubi/lib/Context.h
+++ b/llvm/tools/llubi/lib/Context.h
@@ -14,7 +14,6 @@
 #include "llvm/Analysis/TargetLibraryInfo.h"
 #include "llvm/IR/Module.h"
 #include <map>
-#include <random>
 
 namespace llvm::ubi {
 
@@ -42,11 +41,6 @@ enum class MemoryObjectState {
   Freed,
 };
 
-enum class UndefValueBehavior {
-  NonDeterministic, // Each use of the undef value can yield 
diff erent results.
-  Zero,             // All uses of the undef value yield zero.
-};
-
 class MemoryObject : public RefCountedBase<MemoryObject> {
   uint64_t Address;
   uint64_t Size;
@@ -71,7 +65,6 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
   StringRef getName() const { return Name; }
   unsigned getAddressSpace() const { return AS; }
   MemoryObjectState getState() const { return State; }
-  void setState(MemoryObjectState S) { State = S; }
   bool isConstant() const { return IsConstant; }
   void setIsConstant(bool C) { IsConstant = C; }
 
@@ -83,8 +76,10 @@ class MemoryObject : public RefCountedBase<MemoryObject> {
     assert(Offset < Size && "Offset out of bounds");
     return Bytes[Offset];
   }
-  ArrayRef<Byte> getBytes() const { return Bytes; }
-  MutableArrayRef<Byte> getBytes() { return Bytes; }
+  void writeRawBytes(uint64_t Offset, const void *Data, uint64_t Length);
+  void writeInteger(uint64_t Offset, const APInt &Int, const DataLayout &DL);
+  void writeFloat(uint64_t Offset, const APFloat &Float, const DataLayout &DL);
+  void writePointer(uint64_t Offset, const Pointer &Ptr, const DataLayout &DL);
 
   void markAsFreed();
 };
@@ -131,9 +126,6 @@ class Context {
   uint32_t VScale = 4;
   uint32_t MaxSteps = 0;
   uint32_t MaxStackDepth = 256;
-  UndefValueBehavior UndefBehavior = UndefValueBehavior::NonDeterministic;
-
-  std::mt19937_64 Rng;
 
   // Memory
   uint64_t UsedMem = 0;
@@ -149,10 +141,6 @@ class Context {
   // precisely after we make ptrtoint have the implicit side-effect of exposing
   // the provenance.
   std::map<uint64_t, IntrusiveRefCntPtr<MemoryObject>> MemoryObjects;
-  AnyValue fromBytes(ArrayRef<Byte> Bytes, Type *Ty, uint32_t &OffsetInBits,
-                     bool CheckPaddingBits);
-  void toBytes(const AnyValue &Val, Type *Ty, uint32_t &OffsetInBits,
-               MutableArrayRef<Byte> Bytes, bool PaddingBits);
 
   // Constants
   // Use std::map to avoid iterator/reference invalidation.
@@ -183,29 +171,15 @@ class Context {
   uint32_t getVScale() const { return VScale; }
   uint32_t getMaxSteps() const { return MaxSteps; }
   uint32_t getMaxStackDepth() const { return MaxStackDepth; }
-  void setUndefValueBehavior(UndefValueBehavior UB) { UndefBehavior = UB; }
-  void reseed(uint32_t Seed) { Rng.seed(Seed); }
 
   LLVMContext &getContext() const { return Ctx; }
   const DataLayout &getDataLayout() const { return DL; }
   const TargetLibraryInfoImpl &getTLIImpl() const { return TLIImpl; }
-  /// Get the effective vector length for a vector type.
   uint32_t getEVL(ElementCount EC) const {
     if (EC.isScalable())
       return VScale * EC.getKnownMinValue();
     return EC.getFixedValue();
   }
-  /// The result is multiplied by VScale for scalable type sizes.
-  uint64_t getEffectiveTypeSize(TypeSize Size) const {
-    if (Size.isScalable())
-      return VScale * Size.getKnownMinValue();
-    return Size.getFixedValue();
-  }
-  /// Returns DL.getTypeAllocSize/getTypeStoreSize for the given type.
-  /// An exception to this is that for scalable vector types, the size is
-  /// computed as if the vector has getEVL(ElementCount) elements.
-  uint64_t getEffectiveTypeAllocSize(Type *Ty);
-  uint64_t getEffectiveTypeStoreSize(Type *Ty);
 
   const AnyValue &getConstantValue(Constant *C);
   IntrusiveRefCntPtr<MemoryObject> allocate(uint64_t Size, uint64_t Align,
@@ -215,18 +189,6 @@ class Context {
   /// Derive a pointer from a memory object with offset 0.
   /// Please use Pointer's interface for further manipulations.
   Pointer deriveFromMemoryObject(IntrusiveRefCntPtr<MemoryObject> Obj);
-  /// Convert byte sequence to a value of the given type. Uninitialized bits are
-  /// flushed according to the options.
-  AnyValue fromBytes(ArrayRef<Byte> Bytes, Type *Ty);
-  /// Convert a value to byte sequence. Padding bits are set to zero.
-  void toBytes(const AnyValue &Val, Type *Ty, MutableArrayRef<Byte> Bytes);
-  /// Direct memory load without checks.
-  AnyValue load(MemoryObject &MO, uint64_t Offset, Type *ValTy);
-  /// Direct memory store without checks.
-  void store(MemoryObject &MO, uint64_t Offset, const AnyValue &Val,
-             Type *ValTy);
-  void storeRawBytes(MemoryObject &MO, uint64_t Offset, const void *Data,
-                     uint64_t Size);
 
   Function *getTargetFunction(const Pointer &Ptr);
   BasicBlock *getTargetBlock(const Pointer &Ptr);

diff  --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index dd5530a355538..7961f7551cf48 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -16,13 +16,10 @@
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/InstVisitor.h"
 #include "llvm/IR/Operator.h"
-#include "llvm/IR/PatternMatch.h"
 #include "llvm/Support/Allocator.h"
 
 namespace llvm::ubi {
 
-using namespace PatternMatch;
-
 enum class FrameState {
   // It is about to enter the function.
   // Valid transition:
@@ -251,88 +248,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void> {
     return false;
   }
 
-  /// Check if the upcoming memory access is valid. Returns the offset relative
-  /// to the underlying object if it is valid.
-  std::optional<uint64_t> verifyMemAccess(const MemoryObject &MO,
-                                          const APInt &Address,
-                                          uint64_t AccessSize, Align Alignment,
-                                          bool IsStore) {
-    // Loading from a stack object outside its lifetime is not undefined
-    // behavior and returns a poison value instead. Storing to it is still
-    // undefined behavior.
-    if (IsStore ? MO.getState() != MemoryObjectState::Alive
-                : MO.getState() == MemoryObjectState::Freed) {
-      reportImmediateUB("Try to access a dead memory object.");
-      return std::nullopt;
-    }
-
-    if (Address.countr_zero() < Log2(Alignment)) {
-      reportImmediateUB("Misaligned memory access.");
-      return std::nullopt;
-    }
-
-    if (AccessSize > MO.getSize() || Address.ult(MO.getAddress())) {
-      reportImmediateUB("Memory access is out of bounds.");
-      return std::nullopt;
-    }
-
-    APInt Offset = Address - MO.getAddress();
-
-    if (Offset.ugt(MO.getSize() - AccessSize)) {
-      reportImmediateUB("Memory access is out of bounds.");
-      return std::nullopt;
-    }
-
-    return Offset.getZExtValue();
-  }
-
-  AnyValue load(const AnyValue &Ptr, Align Alignment, Type *ValTy) {
-    if (Ptr.isPoison()) {
-      reportImmediateUB("Invalid memory access with a poison pointer.");
-      return AnyValue::getPoisonValue(Ctx, ValTy);
-    }
-    auto &PtrVal = Ptr.asPointer();
-    auto *MO = PtrVal.getMemoryObject();
-    if (!MO) {
-      reportImmediateUB(
-          "Invalid memory access via a pointer with nullary provenance.");
-      return AnyValue::getPoisonValue(Ctx, ValTy);
-    }
-    // TODO: pointer capability check
-    if (auto Offset =
-            verifyMemAccess(*MO, PtrVal.address(),
-                            Ctx.getEffectiveTypeStoreSize(ValTy), Alignment,
-                            /*IsStore=*/false)) {
-      // Load from a dead stack object yields poison value.
-      if (MO->getState() == MemoryObjectState::Dead)
-        return AnyValue::getPoisonValue(Ctx, ValTy);
-
-      return Ctx.load(*MO, *Offset, ValTy);
-    }
-    return AnyValue::getPoisonValue(Ctx, ValTy);
-  }
-
-  void store(const AnyValue &Ptr, Align Alignment, const AnyValue &Val,
-             Type *ValTy) {
-    if (Ptr.isPoison()) {
-      reportImmediateUB("Invalid memory access with a poison pointer.");
-      return;
-    }
-    auto &PtrVal = Ptr.asPointer();
-    auto *MO = PtrVal.getMemoryObject();
-    if (!MO) {
-      reportImmediateUB(
-          "Invalid memory access via a pointer with nullary provenance.");
-      return;
-    }
-    // TODO: pointer capability check
-    if (auto Offset =
-            verifyMemAccess(*MO, PtrVal.address(),
-                            Ctx.getEffectiveTypeStoreSize(ValTy), Alignment,
-                            /*IsStore=*/true))
-      Ctx.store(*MO, *Offset, Val, ValTy);
-  }
-
   AnyValue computePtrAdd(const Pointer &Ptr, const APInt &Offset,
                          GEPNoWrapFlags Flags, AnyValue &AccumulatedOffset) {
     if (Offset.isZero())
@@ -523,22 +438,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void> {
       }
       // TODO: handle llvm.assume with operand bundles
       return AnyValue();
-    case Intrinsic::lifetime_start:
-    case Intrinsic::lifetime_end: {
-      auto *Ptr = CB.getArgOperand(0);
-      if (isa<PoisonValue>(Ptr))
-        return AnyValue();
-      auto *MO = getValue(Ptr).asPointer().getMemoryObject();
-      assert(MO && "Memory object accessed by lifetime intrinsic should be "
-                   "always valid.");
-      if (IID == Intrinsic::lifetime_start) {
-        MO->setState(MemoryObjectState::Alive);
-        fill(MO->getBytes(), Byte::undef());
-      } else {
-        MO->setState(MemoryObjectState::Dead);
-      }
-      return AnyValue();
-    }
     default:
       Handler.onUnrecognizedInstruction(CB);
       Status = false;
@@ -900,7 +799,8 @@ class InstExecutor : public InstVisitor<InstExecutor, void> {
   }
 
   void visitAllocaInst(AllocaInst &AI) {
-    uint64_t AllocSize = Ctx.getEffectiveTypeAllocSize(AI.getAllocatedType());
+    uint64_t AllocSize =
+        DL.getTypeAllocSize(AI.getAllocatedType()).getFixedValue();
     if (AI.isArrayAllocation()) {
       auto &Size = getValue(AI.getArraySize());
       if (Size.isPoison()) {
@@ -921,14 +821,10 @@ class InstExecutor : public InstVisitor<InstExecutor, void> {
         return;
       }
     }
-    // If it is used by llvm.lifetime.start, it should be initially dead.
-    bool IsInitiallyDead = any_of(AI.users(), [](User *U) {
-      return match(U, m_Intrinsic<Intrinsic::lifetime_start>());
-    });
+    // FIXME: If it is used by llvm.lifetime.start, it should be initially dead.
     auto Obj = Ctx.allocate(AllocSize, AI.getPointerAlignment(DL).value(),
                             AI.getName(), AI.getAddressSpace(),
-                            IsInitiallyDead ? MemInitKind::Poisoned
-                                            : MemInitKind::Uninitialized);
+                            MemInitKind::Uninitialized);
     if (!Obj) {
       reportError("Insufficient stack space.");
       return;
@@ -1001,7 +897,10 @@ class InstExecutor : public InstVisitor<InstExecutor, void> {
       // TODO: Should be documented in LangRef: GEPs with nowrap flags should
       // return poison when the type size exceeds index space.
       TypeSize Offset = GTI.getSequentialElementStride(DL);
-      APInt Scale(IndexBitWidth, Ctx.getEffectiveTypeSize(Offset),
+      APInt Scale(IndexBitWidth,
+                  Offset.isScalable()
+                      ? Offset.getKnownMinValue() * Ctx.getVScale()
+                      : Offset.getFixedValue(),
                   /*isSigned=*/false, /*implicitTrunc=*/true);
       if (!Scale.isZero())
         ApplyScaledOffset(getValue(V), Scale);
@@ -1021,24 +920,6 @@ class InstExecutor : public InstVisitor<InstExecutor, void> {
     });
   }
 
-  void visitLoadInst(LoadInst &LI) {
-    auto RetVal =
-        load(getValue(LI.getPointerOperand()), LI.getAlign(), LI.getType());
-    // TODO: track volatile loads
-    // TODO: handle metadata
-    setResult(LI, std::move(RetVal));
-  }
-
-  void visitStoreInst(StoreInst &SI) {
-    auto &Ptr = getValue(SI.getPointerOperand());
-    auto &Val = getValue(SI.getValueOperand());
-    // TODO: track volatile stores
-    // TODO: handle metadata
-    store(Ptr, SI.getAlign(), Val, SI.getValueOperand()->getType());
-    if (Status)
-      Status &= Handler.onInstructionExecuted(SI, AnyValue());
-  }
-
   void visitInstruction(Instruction &I) {
     Handler.onUnrecognizedInstruction(I);
     Status = false;

diff  --git a/llvm/tools/llubi/lib/Value.h b/llvm/tools/llubi/lib/Value.h
index b4686160ea8b8..6add6e7f06304 100644
--- a/llvm/tools/llubi/lib/Value.h
+++ b/llvm/tools/llubi/lib/Value.h
@@ -21,55 +21,26 @@ class MemoryObject;
 class Context;
 class AnyValue;
 
-/// Representation of a byte in memory.
-/// How to interpret the byte per bit:
-/// - If the concrete mask bit is 0, the bit is either undef or poison. The
-/// value bit indicates whether it is undef.
-/// - If the concrete mask bit is 1, the bit is a concrete value. The value bit
-/// stores the concrete bit value.
+enum class ByteKind : uint8_t {
+  // A concrete byte with a known value.
+  Concrete,
+  // A uninitialized byte. Each load from an uninitialized byte yields
+  // a nondeterministic value.
+  Undef,
+  // A poisoned byte. It occurs when the program stores a poison value to
+  // memory,
+  // or when a memory object is dead.
+  Poison,
+};
+
 struct Byte {
-  uint8_t ConcreteMask;
   uint8_t Value;
-  // TODO: captured capabilities of pointers.
-
-  static Byte poison() { return Byte{0, 0}; }
-  static Byte undef() { return Byte{0, 255}; }
-  static Byte concrete(uint8_t Val) { return Byte{255, Val}; }
-
-  void zeroBits(uint8_t Mask) {
-    ConcreteMask |= Mask;
-    Value &= ~Mask;
-  }
-
-  void poisonBits(uint8_t Mask) {
-    ConcreteMask &= ~Mask;
-    Value &= ~Mask;
-  }
-
-  void undefBits(uint8_t Mask) {
-    ConcreteMask &= ~Mask;
-    Value |= Mask;
-  }
-
-  void writeBits(uint8_t Mask, uint8_t Val) {
-    ConcreteMask |= Mask;
-    Value = (Value & ~Mask) | (Val & Mask);
-  }
-
-  /// Returns a logical byte that is part of two adjacent bytes.
-  /// Example with ShAmt = 5:
-  ///     |       Low       |      High       |
-  /// LSB | 0 1 0 1 0 1 0 1 | 0 0 0 0 1 1 1 1 | MSB
-  ///     Result =  | 1 0 1   0 0 0 0 1 |
-  static Byte fshr(const Byte &Low, const Byte &High, uint32_t ShAmt) {
-    return Byte{static_cast<uint8_t>(
-                    (Low.ConcreteMask | (High.ConcreteMask << 8)) >> ShAmt),
-                static_cast<uint8_t>((Low.Value | (High.Value << 8)) >> ShAmt)};
-  }
+  ByteKind Kind : 2;
+  // TODO: provenance
 
-  Byte lshr(uint8_t Shift) const {
-    return Byte{static_cast<uint8_t>(ConcreteMask >> Shift),
-                static_cast<uint8_t>(Value >> Shift)};
+  void set(uint8_t V) {
+    Value = V;
+    Kind = ByteKind::Concrete;
   }
 };
 

diff  --git a/llvm/tools/llubi/llubi.cpp b/llvm/tools/llubi/llubi.cpp
index de76a7e64c27b..1d2d4dc050b5d 100644
--- a/llvm/tools/llubi/llubi.cpp
+++ b/llvm/tools/llubi/llubi.cpp
@@ -74,19 +74,6 @@ static cl::opt<unsigned>
     VScale("vscale", cl::desc("The value of llvm.vscale (default = 4)"),
            cl::value_desc("N"), cl::init(4), cl::cat(InterpreterCategory));
 
-static cl::opt<unsigned>
-    Seed("seed",
-         cl::desc("Random seed for non-deterministic behavior (default = 0)"),
-         cl::value_desc("N"), cl::init(0), cl::cat(InterpreterCategory));
-
-cl::opt<ubi::UndefValueBehavior> UndefBehavior(
-    "", cl::desc("Choose undef value behavior:"),
-    cl::values(clEnumVal(ubi::UndefValueBehavior::NonDeterministic,
-                         "Each load of an uninitialized byte yields a freshly "
-                         "random value."),
-               clEnumVal(ubi::UndefValueBehavior::Zero,
-                         "All uses of an uninitialized byte yield zero.")));
-
 class VerboseEventHandler : public ubi::EventHandler {
 public:
   bool onInstructionExecuted(Instruction &I,
@@ -177,8 +164,6 @@ int main(int argc, char **argv) {
   Ctx.setVScale(VScale);
   Ctx.setMaxSteps(MaxSteps);
   Ctx.setMaxStackDepth(MaxStackDepth);
-  Ctx.setUndefValueBehavior(UndefBehavior);
-  Ctx.reseed(Seed);
 
   if (!Ctx.initGlobalValues()) {
     WithColor::error() << "Failed to initialize global values (e.g., the "
@@ -197,8 +182,8 @@ int main(int argc, char **argv) {
   }
   TargetLibraryInfo TLI(Ctx.getTLIImpl());
   Type *IntTy = IntegerType::get(Ctx.getContext(), TLI.getIntSize());
-  Type *PtrTy = PointerType::getUnqual(Ctx.getContext());
-  auto *MainFuncTy = FunctionType::get(IntTy, {IntTy, PtrTy}, false);
+  auto *MainFuncTy = FunctionType::get(
+      IntTy, {IntTy, PointerType::getUnqual(Ctx.getContext())}, false);
   SmallVector<ubi::AnyValue> Args;
   if (EntryFn->getFunctionType() == MainFuncTy) {
     Args.push_back(
@@ -221,8 +206,8 @@ int main(int argc, char **argv) {
         return 1;
       }
       ubi::Pointer ArgPtr = Ctx.deriveFromMemoryObject(ArgvStrMem);
-      Ctx.storeRawBytes(*ArgvStrMem, 0, Arg.c_str(), Arg.length());
-      Ctx.store(*ArgvPtrsMem, Idx * PtrSize, ArgPtr, PtrTy);
+      ArgvStrMem->writeRawBytes(0, Arg.c_str(), Arg.length());
+      ArgvPtrsMem->writePointer(Idx * PtrSize, ArgPtr, Ctx.getDataLayout());
     }
     Args.push_back(Ctx.deriveFromMemoryObject(ArgvPtrsMem));
   } else if (!EntryFn->arg_empty()) {


        


More information about the llvm-commits mailing list