[llvm] [llubi] Add support for bitcast (PR #185205)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sat Mar 7 09:04:56 PST 2026
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/185205
Bitcasting pointers to pointers is not fully implemented for now. We haven't encoded provenance information in the memory.
>From 8d9afbb3d1532ecb119f9568db826229753a357f Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 8 Mar 2026 01:02:02 +0800
Subject: [PATCH] [llubi] Add support for bitcast
---
llvm/test/tools/llubi/bitcast_be.ll | 49 ++++++++++++++++++++++++++++
llvm/test/tools/llubi/bitcast_le.ll | 49 ++++++++++++++++++++++++++++
llvm/tools/llubi/lib/Context.cpp | 7 ++++
llvm/tools/llubi/lib/Interpreter.cpp | 11 +++++++
4 files changed, 116 insertions(+)
create mode 100644 llvm/test/tools/llubi/bitcast_be.ll
create mode 100644 llvm/test/tools/llubi/bitcast_le.ll
diff --git a/llvm/test/tools/llubi/bitcast_be.ll b/llvm/test/tools/llubi/bitcast_be.ll
new file mode 100644
index 0000000000000..cdc650bf25196
--- /dev/null
+++ b/llvm/test/tools/llubi/bitcast_be.ll
@@ -0,0 +1,49 @@
+; 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"
+
+define void @main() {
+entry:
+ %bitcast_int2int = bitcast i32 1 to i32
+ %bitcast_int2int_poison = bitcast i32 poison to i32
+ %bitcast_int2float = bitcast i32 0 to float
+ %bitcast_float2float = bitcast float 2.0 to float
+ %bitcast_float2int = bitcast float 2.0 to i32
+ %bitcast_half2bf16 = bitcast half 1.0 to bfloat
+ %ptr = alloca i32
+ ; FIXME: The provenance is lost.
+ %bitcast_ptr2ptr = bitcast ptr %ptr to ptr
+
+ %bitcast_vec2scalar = bitcast <2 x i32> <i32 0, i32 1> to i64
+ %bitcast_scalar2vec = bitcast i64 1 to <2 x i32>
+ %bitcast_vec2scalar_partial_poison = bitcast <2 x i32> <i32 poison, i32 0> to i64
+ %bitcast_scalar2vec_poison = bitcast i64 poison to <2 x i32>
+
+ %bitcast_vec2vec_up = bitcast <2 x i32> <i32 1, i32 poison> to <4 x i16>
+ %bitcast_vec2vec_down = bitcast <4 x i16> <i16 0, i16 poison, i16 2, i16 3> to <2 x i32>
+ %bitcast_vec2vec_weird = bitcast <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 4, i3 5, i3 6, i3 7> to <3 x i8>
+
+ %bitcast_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half>
+ %bitcast_floatvec2int = bitcast <4 x half> <half 1.0, half 2.0, half 3.0, half 4.0> to i64
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %bitcast_int2int = bitcast i32 1 to i32 => i32 1
+; CHECK-NEXT: %bitcast_int2int_poison = bitcast i32 poison to i32 => poison
+; CHECK-NEXT: %bitcast_int2float = bitcast i32 0 to float => 0
+; CHECK-NEXT: %bitcast_float2float = bitcast float 2.000000e+00 to float => 2
+; CHECK-NEXT: %bitcast_float2int = bitcast float 2.000000e+00 to i32 => i32 1073741824
+; CHECK-NEXT: %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => 0.007813
+; CHECK-NEXT: %ptr = alloca i32, align 4 => ptr 0x8 [ptr]
+; CHECK-NEXT: %bitcast_ptr2ptr = bitcast ptr %ptr to ptr => ptr 0x8 [dangling]
+; CHECK-NEXT: %bitcast_vec2scalar = bitcast <2 x i32> <i32 0, i32 1> to i64 => i64 4294967296
+; CHECK-NEXT: %bitcast_scalar2vec = bitcast i64 1 to <2 x i32> => { i32 1, i32 0 }
+; CHECK-NEXT: %bitcast_vec2scalar_partial_poison = bitcast <2 x i32> <i32 poison, i32 0> to i64 => poison
+; CHECK-NEXT: %bitcast_scalar2vec_poison = bitcast i64 poison to <2 x i32> => { poison, poison }
+; CHECK-NEXT: %bitcast_vec2vec_up = bitcast <2 x i32> <i32 1, i32 poison> to <4 x i16> => { i16 1, i16 0, poison, poison }
+; CHECK-NEXT: %bitcast_vec2vec_down = bitcast <4 x i16> <i16 0, i16 poison, i16 2, i16 3> to <2 x i32> => { poison, i32 196610 }
+; CHECK-NEXT: %bitcast_vec2vec_weird = bitcast <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 -4, i3 -3, i3 -2, i3 -1> to <3 x i8> => { i8 5, i8 57, i8 119 }
+; CHECK-NEXT: %bitcast_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half> => { 5.9605E-8, 0, 1.1921E-7, 0 }
+; CHECK-NEXT: %bitcast_floatvec2int = bitcast <4 x half> <half 0xH3C00, half 0xH4000, half 0xH4200, half 0xH4400> to i64 => i64 4899988963420290048
+; CHECK-NEXT: ret void
+; CHECK-NEXT: Exiting function: main
diff --git a/llvm/test/tools/llubi/bitcast_le.ll b/llvm/test/tools/llubi/bitcast_le.ll
new file mode 100644
index 0000000000000..21173a625e6c2
--- /dev/null
+++ b/llvm/test/tools/llubi/bitcast_le.ll
@@ -0,0 +1,49 @@
+; 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"
+
+define void @main() {
+entry:
+ %bitcast_int2int = bitcast i32 1 to i32
+ %bitcast_int2int_poison = bitcast i32 poison to i32
+ %bitcast_int2float = bitcast i32 0 to float
+ %bitcast_float2float = bitcast float 2.0 to float
+ %bitcast_float2int = bitcast float 2.0 to i32
+ %bitcast_half2bf16 = bitcast half 1.0 to bfloat
+ %ptr = alloca i32
+ ; FIXME: The provenance is lost.
+ %bitcast_ptr2ptr = bitcast ptr %ptr to ptr
+
+ %bitcast_vec2scalar = bitcast <2 x i32> <i32 0, i32 1> to i64
+ %bitcast_scalar2vec = bitcast i64 1 to <2 x i32>
+ %bitcast_vec2scalar_partial_poison = bitcast <2 x i32> <i32 poison, i32 0> to i64
+ %bitcast_scalar2vec_poison = bitcast i64 poison to <2 x i32>
+
+ %bitcast_vec2vec_up = bitcast <2 x i32> <i32 1, i32 poison> to <4 x i16>
+ %bitcast_vec2vec_down = bitcast <4 x i16> <i16 0, i16 poison, i16 2, i16 3> to <2 x i32>
+ %bitcast_vec2vec_weird = bitcast <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 4, i3 5, i3 6, i3 7> to <3 x i8>
+
+ %bitcast_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half>
+ %bitcast_floatvec2int = bitcast <4 x half> <half 1.0, half 2.0, half 3.0, half 4.0> to i64
+ ret void
+}
+; CHECK: Entering function: main
+; CHECK-NEXT: %bitcast_int2int = bitcast i32 1 to i32 => i32 1
+; CHECK-NEXT: %bitcast_int2int_poison = bitcast i32 poison to i32 => poison
+; CHECK-NEXT: %bitcast_int2float = bitcast i32 0 to float => 0
+; CHECK-NEXT: %bitcast_float2float = bitcast float 2.000000e+00 to float => 2
+; CHECK-NEXT: %bitcast_float2int = bitcast float 2.000000e+00 to i32 => i32 1073741824
+; CHECK-NEXT: %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => 0.007813
+; CHECK-NEXT: %ptr = alloca i32, align 4 => ptr 0x8 [ptr]
+; CHECK-NEXT: %bitcast_ptr2ptr = bitcast ptr %ptr to ptr => ptr 0x8 [dangling]
+; CHECK-NEXT: %bitcast_vec2scalar = bitcast <2 x i32> <i32 0, i32 1> to i64 => i64 4294967296
+; CHECK-NEXT: %bitcast_scalar2vec = bitcast i64 1 to <2 x i32> => { i32 1, i32 0 }
+; CHECK-NEXT: %bitcast_vec2scalar_partial_poison = bitcast <2 x i32> <i32 poison, i32 0> to i64 => poison
+; CHECK-NEXT: %bitcast_scalar2vec_poison = bitcast i64 poison to <2 x i32> => { poison, poison }
+; CHECK-NEXT: %bitcast_vec2vec_up = bitcast <2 x i32> <i32 1, i32 poison> to <4 x i16> => { i16 1, i16 0, poison, poison }
+; CHECK-NEXT: %bitcast_vec2vec_down = bitcast <4 x i16> <i16 0, i16 poison, i16 2, i16 3> to <2 x i32> => { poison, i32 196610 }
+; CHECK-NEXT: %bitcast_vec2vec_weird = bitcast <8 x i3> <i3 0, i3 1, i3 2, i3 3, i3 -4, i3 -3, i3 -2, i3 -1> to <3 x i8> => { i8 -120, i8 -58, i8 -6 }
+; CHECK-NEXT: %bitcast_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half> => { 5.9605E-8, 0, 1.1921E-7, 0 }
+; CHECK-NEXT: %bitcast_floatvec2int = bitcast <4 x half> <half 0xH3C00, half 0xH4000, half 0xH4200, half 0xH4400> to i64 => i64 4899988963420290048
+; 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 0ff685c05643c..e84047b839bfa 100644
--- a/llvm/tools/llubi/lib/Context.cpp
+++ b/llvm/tools/llubi/lib/Context.cpp
@@ -70,6 +70,13 @@ AnyValue Context::getConstantValueImpl(Constant *C) {
return CI->getValue();
}
+ if (auto *CFP = dyn_cast<ConstantFP>(C)) {
+ if (auto *VecTy = dyn_cast<VectorType>(CFP->getType()))
+ return std::vector<AnyValue>(getEVL(VecTy->getElementCount()),
+ AnyValue(CFP->getValue()));
+ return CFP->getValue();
+ }
+
if (auto *CDS = dyn_cast<ConstantDataSequential>(C)) {
std::vector<AnyValue> Elts;
Elts.reserve(CDS->getNumElements());
diff --git a/llvm/tools/llubi/lib/Interpreter.cpp b/llvm/tools/llubi/lib/Interpreter.cpp
index dd5530a355538..948fb3334423a 100644
--- a/llvm/tools/llubi/lib/Interpreter.cpp
+++ b/llvm/tools/llubi/lib/Interpreter.cpp
@@ -1108,6 +1108,17 @@ class InstExecutor : public InstVisitor<InstExecutor, void> {
setResult(SVI, std::move(Res));
}
+ void visitBitCastInst(BitCastInst &BCI) {
+ // The conversion is done as if the value had been stored to memory and read
+ // back as the target type.
+ SmallVector<Byte> Bytes;
+ Bytes.resize(Ctx.getEffectiveTypeStoreSize(BCI.getType()),
+ Byte::concrete(0));
+ Ctx.toBytes(getValue(BCI.getOperand(0)), BCI.getOperand(0)->getType(),
+ Bytes);
+ setResult(BCI, Ctx.fromBytes(Bytes, BCI.getType()));
+ }
+
/// This function implements the main interpreter loop.
/// It handles function calls in a non-recursive manner to avoid stack
/// overflows.
More information about the llvm-commits
mailing list