[llvm] [llubi] Add support for bitcast (PR #185205)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 7 10:41:41 PST 2026


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/185205

>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 1/3] [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.

>From 2683cf248f8edfc3faf1100ceac5ce36cbfb20b9 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 8 Mar 2026 02:22:12 +0800
Subject: [PATCH 2/3] [llubi] Update format of APFloat

---
 llvm/test/tools/llubi/bitcast_be.ll   | 16 ++++++++++------
 llvm/test/tools/llubi/bitcast_le.ll   | 16 ++++++++++------
 llvm/test/tools/llubi/loadstore_be.ll |  2 +-
 llvm/test/tools/llubi/loadstore_le.ll |  2 +-
 llvm/tools/llubi/lib/Value.cpp        | 23 +++++++++++++++++++++--
 5 files changed, 43 insertions(+), 16 deletions(-)

diff --git a/llvm/test/tools/llubi/bitcast_be.ll b/llvm/test/tools/llubi/bitcast_be.ll
index cdc650bf25196..8d59d43d23c23 100644
--- a/llvm/test/tools/llubi/bitcast_be.ll
+++ b/llvm/test/tools/llubi/bitcast_be.ll
@@ -6,8 +6,10 @@ 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_int2float1 = bitcast i32 0 to float
+  %bitcast_int2float2 = bitcast i32 5033160 to float
+  %bitcast_float2float1 = bitcast float 2.0 to float
+  %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float
   %bitcast_float2int = bitcast float 2.0 to i32
   %bitcast_half2bf16 = bitcast half 1.0 to bfloat
   %ptr = alloca i32
@@ -30,10 +32,12 @@ entry:
 ; 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_int2float1 = bitcast i32 0 to float => 0.000000e+00
+; CHECK-NEXT:   %bitcast_int2float2 = bitcast i32 5033160 to float => 0x004CCCC8
+; CHECK-NEXT:   %bitcast_float2float1 = bitcast float 2.000000e+00 to float => 2.000000e+00
+; CHECK-NEXT:   %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float => 0x3D4CCCC8
 ; 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:   %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => 7.812500e-03
 ; 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
@@ -43,7 +47,7 @@ entry:
 ; 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_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half> => { 5.960460e-08, 0.000000e+00, 1.192090e-07, 0.000000e+00 }
 ; 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
index 21173a625e6c2..c747f9db8c7cd 100644
--- a/llvm/test/tools/llubi/bitcast_le.ll
+++ b/llvm/test/tools/llubi/bitcast_le.ll
@@ -6,8 +6,10 @@ 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_int2float1 = bitcast i32 0 to float
+  %bitcast_int2float2 = bitcast i32 5033160 to float
+  %bitcast_float2float1 = bitcast float 2.0 to float
+  %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float
   %bitcast_float2int = bitcast float 2.0 to i32
   %bitcast_half2bf16 = bitcast half 1.0 to bfloat
   %ptr = alloca i32
@@ -30,10 +32,12 @@ entry:
 ; 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_int2float1 = bitcast i32 0 to float => 0.000000e+00
+; CHECK-NEXT:   %bitcast_int2float2 = bitcast i32 5033160 to float => 0x004CCCC8
+; CHECK-NEXT:   %bitcast_float2float1 = bitcast float 2.000000e+00 to float => 2.000000e+00
+; CHECK-NEXT:   %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float => 0x3D4CCCC8
 ; 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:   %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => 7.812500e-03
 ; 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
@@ -43,7 +47,7 @@ entry:
 ; 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_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half> => { 5.960460e-08, 0.000000e+00, 1.192090e-07, 0.000000e+00 }
 ; 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/loadstore_be.ll b/llvm/test/tools/llubi/loadstore_be.ll
index 3dc03de73f303..60c722c57df26 100644
--- a/llvm/test/tools/llubi/loadstore_be.ll
+++ b/llvm/test/tools/llubi/loadstore_be.ll
@@ -147,7 +147,7 @@ define void @main() {
 ; 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:   %val17 = load float, ptr %alloc, align 4 => 0xFFF80000
 ; 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 }
diff --git a/llvm/test/tools/llubi/loadstore_le.ll b/llvm/test/tools/llubi/loadstore_le.ll
index 35e1cd425e72c..e6ac89502ee5d 100644
--- a/llvm/test/tools/llubi/loadstore_le.ll
+++ b/llvm/test/tools/llubi/loadstore_le.ll
@@ -149,7 +149,7 @@ define void @main() {
 ; 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:   %val17 = load float, ptr %alloc, align 4 => 0xFFF80000
 ; 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 }
diff --git a/llvm/tools/llubi/lib/Value.cpp b/llvm/tools/llubi/lib/Value.cpp
index 172e810bcb77e..aec3a3542bd1e 100644
--- a/llvm/tools/llubi/lib/Value.cpp
+++ b/llvm/tools/llubi/lib/Value.cpp
@@ -44,9 +44,28 @@ void AnyValue::print(raw_ostream &OS) const {
     }
     OS << "i" << IntVal.getBitWidth() << ' ' << IntVal;
     break;
-  case StorageKind::Float:
-    OS << FloatVal;
+  case StorageKind::Float: {
+    // We cannot reuse Value::print due to lack of LLVMContext here.
+    // Similar to writeAPFloatInternal, output the FP constant value in
+    // exponential notation if it is lossless, otherwise output it in
+    // hexadecimal notation.
+    SmallString<16> StrVal;
+    FloatVal.toString(StrVal, /*FormatPrecision=*/6, /*FormatMaxPadding=*/0,
+                      /*TruncateZero=*/false);
+    if (APFloat(FloatVal.getSemantics(), StrVal).bitwiseIsEqual(FloatVal)) {
+      OS << StrVal;
+    } else {
+      StrVal.clear();
+      APInt Bits = FloatVal.bitcastToAPInt();
+      Bits.toStringUnsigned(StrVal, 16);
+      size_t MaxDigits = divideCeil(Bits.getBitWidth(), 4);
+      OS << "0x";
+      for (size_t Digits = StrVal.size(); Digits != MaxDigits; ++Digits)
+        OS << '0';
+      OS << StrVal;
+    }
     break;
+  }
   case StorageKind::Pointer:
     PtrVal.print(OS);
     break;

>From 481c8eeba4e118579d22618d44047b73919cac9a Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 8 Mar 2026 02:41:22 +0800
Subject: [PATCH 3/3] [llubi] Add type prefix for float values

---
 llvm/test/tools/llubi/bitcast_be.ll   | 12 ++++++------
 llvm/test/tools/llubi/bitcast_le.ll   | 12 ++++++------
 llvm/test/tools/llubi/loadstore_be.ll |  2 +-
 llvm/test/tools/llubi/loadstore_le.ll |  2 +-
 llvm/tools/llubi/lib/Value.cpp        | 25 +++++++++++++++++++++++++
 5 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/llvm/test/tools/llubi/bitcast_be.ll b/llvm/test/tools/llubi/bitcast_be.ll
index 8d59d43d23c23..9e73411095b17 100644
--- a/llvm/test/tools/llubi/bitcast_be.ll
+++ b/llvm/test/tools/llubi/bitcast_be.ll
@@ -32,12 +32,12 @@ entry:
 ; 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_int2float1 = bitcast i32 0 to float => 0.000000e+00
-; CHECK-NEXT:   %bitcast_int2float2 = bitcast i32 5033160 to float => 0x004CCCC8
-; CHECK-NEXT:   %bitcast_float2float1 = bitcast float 2.000000e+00 to float => 2.000000e+00
-; CHECK-NEXT:   %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float => 0x3D4CCCC8
+; CHECK-NEXT:   %bitcast_int2float1 = bitcast i32 0 to float => float 0.000000e+00
+; CHECK-NEXT:   %bitcast_int2float2 = bitcast i32 5033160 to float => float 0x004CCCC8
+; CHECK-NEXT:   %bitcast_float2float1 = bitcast float 2.000000e+00 to float => float 2.000000e+00
+; CHECK-NEXT:   %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float => float 0x3D4CCCC8
 ; CHECK-NEXT:   %bitcast_float2int = bitcast float 2.000000e+00 to i32 => i32 1073741824
-; CHECK-NEXT:   %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => 7.812500e-03
+; CHECK-NEXT:   %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => bfloat 7.812500e-03
 ; 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
@@ -47,7 +47,7 @@ entry:
 ; 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.960460e-08, 0.000000e+00, 1.192090e-07, 0.000000e+00 }
+; CHECK-NEXT:   %bitcast_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half> => { half 5.960460e-08, half 0.000000e+00, half 1.192090e-07, half 0.000000e+00 }
 ; 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
index c747f9db8c7cd..19e595074a4d5 100644
--- a/llvm/test/tools/llubi/bitcast_le.ll
+++ b/llvm/test/tools/llubi/bitcast_le.ll
@@ -32,12 +32,12 @@ entry:
 ; 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_int2float1 = bitcast i32 0 to float => 0.000000e+00
-; CHECK-NEXT:   %bitcast_int2float2 = bitcast i32 5033160 to float => 0x004CCCC8
-; CHECK-NEXT:   %bitcast_float2float1 = bitcast float 2.000000e+00 to float => 2.000000e+00
-; CHECK-NEXT:   %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float => 0x3D4CCCC8
+; CHECK-NEXT:   %bitcast_int2float1 = bitcast i32 0 to float => float 0.000000e+00
+; CHECK-NEXT:   %bitcast_int2float2 = bitcast i32 5033160 to float => float 0x004CCCC8
+; CHECK-NEXT:   %bitcast_float2float1 = bitcast float 2.000000e+00 to float => float 2.000000e+00
+; CHECK-NEXT:   %bitcast_float2float2 = bitcast float 0x3FA9999900000000 to float => float 0x3D4CCCC8
 ; CHECK-NEXT:   %bitcast_float2int = bitcast float 2.000000e+00 to i32 => i32 1073741824
-; CHECK-NEXT:   %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => 7.812500e-03
+; CHECK-NEXT:   %bitcast_half2bf16 = bitcast half 0xH3C00 to bfloat => bfloat 7.812500e-03
 ; 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
@@ -47,7 +47,7 @@ entry:
 ; 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.960460e-08, 0.000000e+00, 1.192090e-07, 0.000000e+00 }
+; CHECK-NEXT:   %bitcast_intvec2floatvec = bitcast <2 x i32> <i32 1, i32 2> to <4 x half> => { half 5.960460e-08, half 0.000000e+00, half 1.192090e-07, half 0.000000e+00 }
 ; 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/loadstore_be.ll b/llvm/test/tools/llubi/loadstore_be.ll
index 60c722c57df26..237d22253108a 100644
--- a/llvm/test/tools/llubi/loadstore_be.ll
+++ b/llvm/test/tools/llubi/loadstore_be.ll
@@ -147,7 +147,7 @@ define void @main() {
 ; 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 => 0xFFF80000
+; CHECK-NEXT:   %val17 = load float, ptr %alloc, align 4 => float 0xFFF80000
 ; 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 }
diff --git a/llvm/test/tools/llubi/loadstore_le.ll b/llvm/test/tools/llubi/loadstore_le.ll
index e6ac89502ee5d..bdd82ddabbfec 100644
--- a/llvm/test/tools/llubi/loadstore_le.ll
+++ b/llvm/test/tools/llubi/loadstore_le.ll
@@ -149,7 +149,7 @@ define void @main() {
 ; 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 => 0xFFF80000
+; CHECK-NEXT:   %val17 = load float, ptr %alloc, align 4 => float 0xFFF80000
 ; 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 }
diff --git a/llvm/tools/llubi/lib/Value.cpp b/llvm/tools/llubi/lib/Value.cpp
index aec3a3542bd1e..f685e86efee20 100644
--- a/llvm/tools/llubi/lib/Value.cpp
+++ b/llvm/tools/llubi/lib/Value.cpp
@@ -45,6 +45,31 @@ void AnyValue::print(raw_ostream &OS) const {
     OS << "i" << IntVal.getBitWidth() << ' ' << IntVal;
     break;
   case StorageKind::Float: {
+    switch (APFloat::SemanticsToEnum(FloatVal.getSemantics())) {
+    default:
+      llvm_unreachable("invalid fltSemantics");
+    case APFloatBase::S_IEEEhalf:
+      OS << "half ";
+      break;
+    case APFloatBase::S_BFloat:
+      OS << "bfloat ";
+      break;
+    case APFloatBase::S_IEEEsingle:
+      OS << "float ";
+      break;
+    case APFloatBase::S_IEEEdouble:
+      OS << "double ";
+      break;
+    case APFloatBase::S_x87DoubleExtended:
+      OS << "x86_fp80 ";
+      break;
+    case APFloatBase::S_IEEEquad:
+      OS << "fp128 ";
+      break;
+    case APFloatBase::S_PPCDoubleDouble:
+      OS << "ppc_fp128 ";
+      break;
+    }
     // We cannot reuse Value::print due to lack of LLVMContext here.
     // Similar to writeAPFloatInternal, output the FP constant value in
     // exponential notation if it is lossless, otherwise output it in



More information about the llvm-commits mailing list