[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