[llvm] [VectorCombine] Relax vector type constraint on bitop(bitcast, constant) (PR #157246)

Hongyu Chen via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 7 06:30:47 PDT 2025


https://github.com/XChy updated https://github.com/llvm/llvm-project/pull/157246

>From 280d9f7d12cc44c267c9ba77ec24d65d8bd82d28 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sat, 6 Sep 2025 17:06:46 +0800
Subject: [PATCH 1/4] Precommit tests

---
 .../VectorCombine/X86/bitop-of-castops.ll     | 60 +++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll b/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
index ca707ca08f169..fe62f91480cd2 100644
--- a/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
@@ -420,3 +420,63 @@ define <4 x i32> @or_zext_nneg_multiconstant(<4 x i8> %a) {
   %or = or <4 x i32> %z1, <i32 240, i32 1, i32 242, i32 3>
   ret <4 x i32> %or
 }
+
+; Negative test: bitcast from scalar float to vector int (optimization should not apply)
+define <2 x i16> @and_bitcast_f32_to_v2i16_constant(float %a) {
+; CHECK-LABEL: @and_bitcast_f32_to_v2i16_constant(
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast float [[B:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i16> <i16 0, i16 1>, [[BC2]]
+; CHECK-NEXT:    ret <2 x i16> [[AND]]
+;
+  %bc = bitcast float %a to <2 x i16>
+  %and = and <2 x i16> <i16 0, i16 1>, %bc
+  ret <2 x i16> %and
+}
+
+; Negative test: bitcast from vector float to scalar int (optimization should not apply)
+define i64 @and_bitcast_v2f32_to_i64_constant(<2 x float> %a) {
+; CHECK-LABEL: @and_bitcast_v2f32_to_i64_constant(
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast <2 x float> [[B:%.*]] to i64
+; CHECK-NEXT:    [[AND:%.*]] = and i64 123, [[BC2]]
+; CHECK-NEXT:    ret i64 [[AND]]
+;
+  %bc = bitcast <2 x float> %a to i64
+  %and = and i64 123, %bc
+  ret i64 %and
+}
+
+; Test no-op bitcast
+define i16 @xor_bitcast_i16_to_i16_constant(i16 %a) {
+; CHECK-LABEL: @xor_bitcast_i16_to_i16_constant(
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast i16 [[B:%.*]] to i16
+; CHECK-NEXT:    [[OR:%.*]] = xor i16 123, [[BC2]]
+; CHECK-NEXT:    ret i16 [[OR]]
+;
+  %bc = bitcast i16 %a to i16
+  %or = xor i16 123, %bc
+  ret i16 %or
+}
+
+; Test bitwise operations with integer vector to integer bitcast
+define <16 x i1> @xor_bitcast_i16_to_v16i1_constant(i16 %a) {
+; CHECK-LABEL: @xor_bitcast_i16_to_v16i1_constant(
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast i16 [[B:%.*]] to <16 x i1>
+; CHECK-NEXT:    [[OR:%.*]] = xor <16 x i1> [[BC2]], splat (i1 true)
+; CHECK-NEXT:    ret <16 x i1> [[OR]]
+;
+  %bc = bitcast i16 %a to <16 x i1>
+  %or = xor <16 x i1> %bc, splat (i1 true)
+  ret <16 x i1> %or
+}
+
+; Test bitwise operations with integer vector to integer bitcast
+define i16 @or_bitcast_v16i1_to_i16_constant(<16 x i1> %a) {
+; CHECK-LABEL: @or_bitcast_v16i1_to_i16_constant(
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast <16 x i1> [[B:%.*]] to i16
+; CHECK-NEXT:    [[OR:%.*]] = or i16 [[BC2]], 3
+; CHECK-NEXT:    ret i16 [[OR]]
+;
+  %bc = bitcast <16 x i1> %a to i16
+  %or = or i16 %bc, 3
+  ret i16 %or
+}

>From 3caa1e152b591ecddabe433f66abc1d8b43110b0 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sat, 6 Sep 2025 17:14:56 +0800
Subject: [PATCH 2/4] [VectorCombine] Relax vector type constraint in
 foldBitOpOfCastConstant

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 27 +++++++++----------
 .../VectorCombine/X86/bitop-of-castops.ll     |  6 ++---
 2 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 6e46547b15b2b..cea818350103a 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1013,19 +1013,20 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {
 
   Value *LHSSrc = LHSCast->getOperand(0);
 
-  // Only handle vector types with integer elements
-  auto *SrcVecTy = dyn_cast<FixedVectorType>(LHSSrc->getType());
-  auto *DstVecTy = dyn_cast<FixedVectorType>(I.getType());
-  if (!SrcVecTy || !DstVecTy)
+  // Only handle vector types with integer elements if the cast is not bitcast
+  auto *SrcTy = LHSSrc->getType();
+  auto *DstTy = I.getType();
+  if (CastOpcode != Instruction::BitCast &&
+      (!isa<FixedVectorType>(SrcTy) || !!isa<FixedVectorType>(DstTy)))
     return false;
 
-  if (!SrcVecTy->getScalarType()->isIntegerTy() ||
-      !DstVecTy->getScalarType()->isIntegerTy())
+  if (!SrcTy->getScalarType()->isIntegerTy() ||
+      !DstTy->getScalarType()->isIntegerTy())
     return false;
 
   // Find the constant InvC, such that castop(InvC) equals to C.
   PreservedCastFlags RHSFlags;
-  Constant *InvC = getLosslessInvCast(C, SrcVecTy, CastOpcode, *DL, RHSFlags);
+  Constant *InvC = getLosslessInvCast(C, SrcTy, CastOpcode, *DL, RHSFlags);
   if (!InvC)
     return false;
 
@@ -1034,20 +1035,18 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {
   // NewCost = bitlogic + cast
 
   // Calculate specific costs for each cast with instruction context
-  InstructionCost LHSCastCost =
-      TTI.getCastInstrCost(CastOpcode, DstVecTy, SrcVecTy,
-                           TTI::CastContextHint::None, CostKind, LHSCast);
+  InstructionCost LHSCastCost = TTI.getCastInstrCost(
+      CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind, LHSCast);
 
   InstructionCost OldCost =
-      TTI.getArithmeticInstrCost(I.getOpcode(), DstVecTy, CostKind) +
-      LHSCastCost;
+      TTI.getArithmeticInstrCost(I.getOpcode(), DstTy, CostKind) + LHSCastCost;
 
   // For new cost, we can't provide an instruction (it doesn't exist yet)
   InstructionCost GenericCastCost = TTI.getCastInstrCost(
-      CastOpcode, DstVecTy, SrcVecTy, TTI::CastContextHint::None, CostKind);
+      CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind);
 
   InstructionCost NewCost =
-      TTI.getArithmeticInstrCost(I.getOpcode(), SrcVecTy, CostKind) +
+      TTI.getArithmeticInstrCost(I.getOpcode(), SrcTy, CostKind) +
       GenericCastCost;
 
   // Account for multi-use casts using specific costs
diff --git a/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll b/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
index fe62f91480cd2..c6253a7b858ad 100644
--- a/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
@@ -460,9 +460,9 @@ define i16 @xor_bitcast_i16_to_i16_constant(i16 %a) {
 ; Test bitwise operations with integer vector to integer bitcast
 define <16 x i1> @xor_bitcast_i16_to_v16i1_constant(i16 %a) {
 ; CHECK-LABEL: @xor_bitcast_i16_to_v16i1_constant(
-; CHECK-NEXT:    [[BC2:%.*]] = bitcast i16 [[B:%.*]] to <16 x i1>
-; CHECK-NEXT:    [[OR:%.*]] = xor <16 x i1> [[BC2]], splat (i1 true)
-; CHECK-NEXT:    ret <16 x i1> [[OR]]
+; CHECK-NEXT:    [[B:%.*]] = xor i16 [[A:%.*]], -1
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast i16 [[B]] to <16 x i1>
+; CHECK-NEXT:    ret <16 x i1> [[BC2]]
 ;
   %bc = bitcast i16 %a to <16 x i1>
   %or = xor <16 x i1> %bc, splat (i1 true)

>From 67e3093fd603ea88a8d7fb4fb6427b52795429b1 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sun, 7 Sep 2025 21:24:16 +0800
Subject: [PATCH 3/4] update comment

---
 llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index cea818350103a..296416c03a9e5 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1013,17 +1013,20 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {
 
   Value *LHSSrc = LHSCast->getOperand(0);
 
-  // Only handle vector types with integer elements if the cast is not bitcast
   auto *SrcTy = LHSSrc->getType();
   auto *DstTy = I.getType();
+  // Bitcasts can handle scalar/vector mixes, such as i16 -> <16 x i1>.
+  // Other casts only handle vector types with integer elements.
   if (CastOpcode != Instruction::BitCast &&
-      (!isa<FixedVectorType>(SrcTy) || !!isa<FixedVectorType>(DstTy)))
+      (!isa<FixedVectorType>(SrcTy) || !isa<FixedVectorType>(DstTy)))
     return false;
 
+  // Only integer scalar/vector values are legal for bitwise logic operations.
   if (!SrcTy->getScalarType()->isIntegerTy() ||
       !DstTy->getScalarType()->isIntegerTy())
     return false;
 
+
   // Find the constant InvC, such that castop(InvC) equals to C.
   PreservedCastFlags RHSFlags;
   Constant *InvC = getLosslessInvCast(C, SrcTy, CastOpcode, *DL, RHSFlags);

>From 11f3332dedcf1693e79e948dbb718660830ec9c3 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sun, 7 Sep 2025 21:30:30 +0800
Subject: [PATCH 4/4] format

---
 llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 296416c03a9e5..b1c7a2682785b 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1026,7 +1026,6 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {
       !DstTy->getScalarType()->isIntegerTy())
     return false;
 
-
   // Find the constant InvC, such that castop(InvC) equals to C.
   PreservedCastFlags RHSFlags;
   Constant *InvC = getLosslessInvCast(C, SrcTy, CastOpcode, *DL, RHSFlags);



More information about the llvm-commits mailing list