[llvm] [ConstantFolding] Fix dropped bits in non-integer-ratio bitcast with undef lane (PR #202282)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 01:05:44 PDT 2026


https://github.com/lijinpei-amd created https://github.com/llvm/llvm-project/pull/202282

When constant-folding a vector bitcast(e.g. <4 x i24> -> <3 x i32>), an undef source element inserted a DstBitSize-wide zero placeholder into the bit buffer. This could clobber defined source element, producing a wrong result on big-endian targets.

Fix by inserting SrcBitSize-wide zero instead.

Alive2 proof:
  before (unsound): https://alive2.llvm.org/ce/z/R_ZQ75
  after  (verified): https://alive2.llvm.org/ce/z/VuV3mz

>From de3c6528567f7b1de94c04bb55a6e57c95da27f8 Mon Sep 17 00:00:00 2001
From: Li Jinpei <jinpli at amd.com>
Date: Sat, 6 Jun 2026 21:45:47 +0800
Subject: [PATCH] [ConstantFolding] Fix dropped bits in non-integer-ratio
 bitcast with undef lane

When constant-folding a vector bitcast(e.g. <4 x i24> -> <3 x i32>), an undef source element inserted a
DstBitSize-wide zero placeholder into the bit buffer. This could clobber defined source element, producing a wrong result on
big-endian targets.

Fix by inserting SrcBitSize-wide zero instead.

Alive2 proof:
  before (unsound): https://alive2.llvm.org/ce/z/R_ZQ75
  after  (verified): https://alive2.llvm.org/ce/z/VuV3mz
---
 llvm/lib/Analysis/ConstantFolding.cpp                    | 6 +++++-
 llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll | 2 +-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 959b46f8eff46..4bb8bd8d7b583 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -359,7 +359,11 @@ Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {
         UndefMask.setBits(BitPosition, BitPosition + SrcBitSize);
         if (isa<PoisonValue>(Element))
           PoisonMask.setBits(BitPosition, BitPosition + SrcBitSize);
-        SrcValue = APInt::getZero(DstBitSize);
+        // The placeholder value must be exactly SrcBitSize wide. Using a wider
+        // value here would clear DstBitSize bits via insertBits and clobber
+        // bits belonging to a previously loaded (defined) source element,
+        // producing an incorrect result for non-integer element ratios.
+        SrcValue = APInt::getZero(SrcBitSize);
       } else {
         auto *Src = dyn_cast<ConstantInt>(Element);
         if (!Src)
diff --git a/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll b/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll
index 88f34cabc6188..14789847911a5 100644
--- a/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll
+++ b/llvm/test/Transforms/InstSimplify/bitcast-vector-fold.ll
@@ -412,7 +412,7 @@ define <3 x i32> @bitcast_constexpr_3i32_4i24_n1255uu() {
 ; LE-NEXT:    ret <3 x i32> <i32 -1, i32 0, i32 undef>
 ;
 ; BE-LABEL: @bitcast_constexpr_3i32_4i24_n1255uu(
-; BE-NEXT:    ret <3 x i32> <i32 -256, i32 0, i32 undef>
+; BE-NEXT:    ret <3 x i32> <i32 -256, i32 16711680, i32 undef>
 ;
   %cast = bitcast <4 x i24><i24 -1, i24 255, i24 undef, i24 undef> to <3 x i32>
   ret <3 x i32> %cast



More information about the llvm-commits mailing list