[llvm] InstCombine: Fold bitcast of vector with constant to scalar (PR #179042)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Sat Jan 31 06:51:42 PST 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/179042

Fold bitcast (select cond, val, const) ->
  select cond, (bitcast val), (bitcast const)

Rocm device libs has an unfortunate amount of code that does bithacking
on the sign bit of double values by casting to <2 x i32> and operation
on the high element. This breaks value tracking optimizations on the
fp value.

The existing transform would only do this if the input to the select was
also a bitcast with a single use, and if it didn't convert between vector
and scalar.

>From f162306b8b80346572d3427ef0533553134e0adb Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Sat, 31 Jan 2026 15:30:25 +0100
Subject: [PATCH] InstCombine: Fold bitcast of vector with constant to scalar

Fold bitcast (select cond, val, const) ->
  select cond, (bitcast val), (bitcast const)

Rocm device libs has an unfortunate amount of code that does bithacking
on the sign bit of double values by casting to <2 x i32> and operation
on the high element. This breaks value tracking optimizations on the
fp value.

The existing transform would only do this if the input to the select was
also a bitcast with a single use, and if it didn't convert between vector
and scalar.
---
 .../InstCombine/InstCombineCasts.cpp          |  9 ++-
 .../bitcast-select-const-vector.ll            | 58 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/copysign.ll  |  7 +--
 .../InstCombine/fold-bin-operand.ll           |  6 +-
 4 files changed, 72 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/Transforms/InstCombine/bitcast-select-const-vector.ll

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 0cd2c09726a2d..0ba6eb582af02 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -2851,6 +2851,14 @@ static Instruction *foldBitCastSelect(BitCastInst &BitCast,
             cast<VectorType>(DestTy)->getElementCount())
       return nullptr;
 
+  auto *Sel = cast<Instruction>(BitCast.getOperand(0));
+
+  if (isa<Constant>(TVal) || isa<Constant>(FVal)) {
+    Value *CastedTVal = Builder.CreateBitCast(TVal, DestTy);
+    Value *CastedFVal = Builder.CreateBitCast(FVal, DestTy);
+    return SelectInst::Create(Cond, CastedTVal, CastedFVal, "", nullptr, Sel);
+  }
+
   // FIXME: This transform is restricted from changing the select between
   // scalars and vectors to avoid backend problems caused by creating
   // potentially illegal operations. If a fix-up is added to handle that
@@ -2858,7 +2866,6 @@ static Instruction *foldBitCastSelect(BitCastInst &BitCast,
   if (DestTy->isVectorTy() != TVal->getType()->isVectorTy())
     return nullptr;
 
-  auto *Sel = cast<Instruction>(BitCast.getOperand(0));
   Value *X;
   if (match(TVal, m_OneUse(m_BitCast(m_Value(X)))) && X->getType() == DestTy &&
       !isa<Constant>(X)) {
diff --git a/llvm/test/Transforms/InstCombine/bitcast-select-const-vector.ll b/llvm/test/Transforms/InstCombine/bitcast-select-const-vector.ll
new file mode 100644
index 0000000000000..878518b6f4194
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/bitcast-select-const-vector.ll
@@ -0,0 +1,58 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+define double @bitcast_v2i32_select_to_double_const_rhs(double %i, <2 x i32> %i41) {
+; CHECK-LABEL: define double @bitcast_v2i32_select_to_double_const_rhs(
+; CHECK-SAME: double [[I:%.*]], <2 x i32> [[I41:%.*]]) {
+; CHECK-NEXT:    [[I42:%.*]] = fcmp one double [[I]], 0x7FF0000000000000
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[I41]] to double
+; CHECK-NEXT:    [[ASTYPE13_I_I:%.*]] = select i1 [[I42]], double [[TMP1]], double 0x7FF8000000000000
+; CHECK-NEXT:    ret double [[ASTYPE13_I_I]]
+;
+  %i42 = fcmp one double %i, 0x7FF0000000000000
+  %s.0.i.i = select i1 %i42, <2 x i32> %i41, <2 x i32> <i32 0, i32 2146959360>
+  %astype13.i.i = bitcast <2 x i32> %s.0.i.i to double
+  ret double %astype13.i.i
+}
+
+define double @bitcast_v2i32_select_to_double_const_lhs(double %i, <2 x i32> %i41) {
+; CHECK-LABEL: define double @bitcast_v2i32_select_to_double_const_lhs(
+; CHECK-SAME: double [[I:%.*]], <2 x i32> [[I41:%.*]]) {
+; CHECK-NEXT:    [[I42:%.*]] = fcmp one double [[I]], 0x7FF0000000000000
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[I41]] to double
+; CHECK-NEXT:    [[ASTYPE13_I_I:%.*]] = select i1 [[I42]], double 0x7FF8000000000000, double [[TMP1]]
+; CHECK-NEXT:    ret double [[ASTYPE13_I_I]]
+;
+  %i42 = fcmp one double %i, 0x7FF0000000000000
+  %s.0.i.i = select i1 %i42, <2 x i32> <i32 0, i32 2146959360>, <2 x i32> %i41
+  %astype13.i.i = bitcast <2 x i32> %s.0.i.i to double
+  ret double %astype13.i.i
+}
+
+define <2 x i32> @bitcast_select_double_to_v2i32_const_rhs(i64 %i, double %i41) {
+; CHECK-LABEL: define <2 x i32> @bitcast_select_double_to_v2i32_const_rhs(
+; CHECK-SAME: i64 [[I:%.*]], double [[I41:%.*]]) {
+; CHECK-NEXT:    [[I42_NOT:%.*]] = icmp eq i64 [[I]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast double [[I41]] to <2 x i32>
+; CHECK-NEXT:    [[ASTYPE13_I_I:%.*]] = select i1 [[I42_NOT]], <2 x i32> <i32 0, i32 1072693248>, <2 x i32> [[TMP1]]
+; CHECK-NEXT:    ret <2 x i32> [[ASTYPE13_I_I]]
+;
+  %i42 = icmp ne i64 %i, 0
+  %s.0.i.i = select nnan i1 %i42, double %i41, double 1.0
+  %astype13.i.i = bitcast double %s.0.i.i to <2 x i32>
+  ret <2 x i32> %astype13.i.i
+}
+
+define <2 x i32> @bitcast_select_double_to_v2i32_const_lhs(i64 %i, double %i41) {
+; CHECK-LABEL: define <2 x i32> @bitcast_select_double_to_v2i32_const_lhs(
+; CHECK-SAME: i64 [[I:%.*]], double [[I41:%.*]]) {
+; CHECK-NEXT:    [[I42_NOT:%.*]] = icmp eq i64 [[I]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast double [[I41]] to <2 x i32>
+; CHECK-NEXT:    [[ASTYPE13_I_I:%.*]] = select i1 [[I42_NOT]], <2 x i32> [[TMP1]], <2 x i32> <i32 0, i32 1072693248>
+; CHECK-NEXT:    ret <2 x i32> [[ASTYPE13_I_I]]
+;
+  %i42 = icmp ne i64 %i, 0
+  %s.0.i.i = select nnan i1 %i42, double 1.0, double %i41
+  %astype13.i.i = bitcast double %s.0.i.i to <2 x i32>
+  ret <2 x i32> %astype13.i.i
+}
diff --git a/llvm/test/Transforms/InstCombine/copysign.ll b/llvm/test/Transforms/InstCombine/copysign.ll
index b89ddec1459aa..59b13e6834961 100644
--- a/llvm/test/Transforms/InstCombine/copysign.ll
+++ b/llvm/test/Transforms/InstCombine/copysign.ll
@@ -194,12 +194,11 @@ define i32 @issue178245(i32 %i.0.i.i) {
 ; CHECK-LABEL: @issue178245(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[TOBOOL104_I_I_NOT:%.*]] = icmp eq i32 [[I_0_I_I:%.*]], -1177359834
-; CHECK-NEXT:    [[CONV111_I_I:%.*]] = select i1 [[TOBOOL104_I_I_NOT]], i32 0, i32 -5
-; CHECK-NEXT:    [[CAST_SIGN:%.*]] = bitcast i32 [[CONV111_I_I]] to float
+; CHECK-NEXT:    [[CAST_SIGN:%.*]] = select i1 [[TOBOOL104_I_I_NOT]], float 0.000000e+00, float 0xFFFFFFFF60000000
 ; CHECK-NEXT:    [[FCMP:%.*]] = fcmp uno float [[CAST_SIGN]], 0.000000e+00
 ; CHECK-NEXT:    [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[CAST_SIGN]])
-; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[FCMP]], float 0.000000e+00, float [[COPYSIGN]]
-; CHECK-NEXT:    [[RESULT:%.*]] = bitcast float [[SELECT]] to i32
+; CHECK-NEXT:    [[TMP0:%.*]] = bitcast float [[COPYSIGN]] to i32
+; CHECK-NEXT:    [[RESULT:%.*]] = select i1 [[FCMP]], i32 0, i32 [[TMP0]]
 ; CHECK-NEXT:    ret i32 [[RESULT]]
 ;
 entry:
diff --git a/llvm/test/Transforms/InstCombine/fold-bin-operand.ll b/llvm/test/Transforms/InstCombine/fold-bin-operand.ll
index 79671215dba61..55b8b79f1485a 100644
--- a/llvm/test/Transforms/InstCombine/fold-bin-operand.ll
+++ b/llvm/test/Transforms/InstCombine/fold-bin-operand.ll
@@ -292,9 +292,9 @@ EntryBlock:
 define <vscale x 2 x i64> @h3(i1 %A, <vscale x 4 x i32> %B) {
 ; CHECK-LABEL: @h3(
 ; CHECK-NEXT:  EntryBlock:
-; CHECK-NEXT:    [[CF:%.*]] = select i1 [[A:%.*]], <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> [[B:%.*]]
-; CHECK-NEXT:    [[BC:%.*]] = bitcast <vscale x 4 x i32> [[CF]] to <vscale x 2 x i64>
-; CHECK-NEXT:    ret <vscale x 2 x i64> [[BC]]
+; CHECK-NEXT:    [[BC:%.*]] = bitcast <vscale x 4 x i32> [[CF:%.*]] to <vscale x 2 x i64>
+; CHECK-NEXT:    [[BC1:%.*]] = select i1 [[A:%.*]], <vscale x 2 x i64> zeroinitializer, <vscale x 2 x i64> [[BC]]
+; CHECK-NEXT:    ret <vscale x 2 x i64> [[BC1]]
 ;
 EntryBlock:
   %cf = select i1 %A, <vscale x 4 x i32> zeroinitializer, <vscale x 4 x i32> %B



More information about the llvm-commits mailing list