[llvm] 3bdd397 - [VectorCombine] Relax vector type constraint on bitop(bitcast, bitcast) (#157245)

via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 7 23:58:13 PDT 2025


Author: Hongyu Chen
Date: 2025-09-08T06:58:09Z
New Revision: 3bdd39715a6e8591378d18fc9b74e807705bdb18

URL: https://github.com/llvm/llvm-project/commit/3bdd39715a6e8591378d18fc9b74e807705bdb18
DIFF: https://github.com/llvm/llvm-project/commit/3bdd39715a6e8591378d18fc9b74e807705bdb18.diff

LOG: [VectorCombine] Relax vector type constraint on bitop(bitcast, bitcast) (#157245)

Inspired by https://github.com/llvm/llvm-project/issues/157131.
This patch allows `bitop(bitcast, bitcast) -> bitcast(bitop)` for scalar
integer types.

Added: 
    

Modified: 
    llvm/lib/Transforms/Vectorize/VectorCombine.cpp
    llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index b1c7a2682785b..7a0b7ad57a493 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -870,14 +870,17 @@ bool VectorCombine::foldBitOpOfCastops(Instruction &I) {
   if (LHSSrc->getType() != RHSSrc->getType())
     return false;
 
-  // Only handle vector types with integer elements
-  auto *SrcVecTy = dyn_cast<FixedVectorType>(LHSSrc->getType());
-  auto *DstVecTy = dyn_cast<FixedVectorType>(I.getType());
-  if (!SrcVecTy || !DstVecTy)
+  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)))
     return false;
 
-  if (!SrcVecTy->getScalarType()->isIntegerTy() ||
-      !DstVecTy->getScalarType()->isIntegerTy())
+  // Only integer scalar/vector values are legal for bitwise logic operations.
+  if (!SrcTy->getScalarType()->isIntegerTy() ||
+      !DstTy->getScalarType()->isIntegerTy())
     return false;
 
   // Cost Check :
@@ -885,23 +888,21 @@ bool VectorCombine::foldBitOpOfCastops(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 RHSCastCost =
-      TTI.getCastInstrCost(CastOpcode, DstVecTy, SrcVecTy,
-                           TTI::CastContextHint::None, CostKind, RHSCast);
+  InstructionCost LHSCastCost = TTI.getCastInstrCost(
+      CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind, LHSCast);
+  InstructionCost RHSCastCost = TTI.getCastInstrCost(
+      CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind, RHSCast);
 
   InstructionCost OldCost =
-      TTI.getArithmeticInstrCost(BinOp->getOpcode(), DstVecTy, CostKind) +
+      TTI.getArithmeticInstrCost(BinOp->getOpcode(), DstTy, CostKind) +
       LHSCastCost + RHSCastCost;
 
   // 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(BinOp->getOpcode(), SrcVecTy, CostKind) +
+      TTI.getArithmeticInstrCost(BinOp->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 c6253a7b858ad..f6c9dce542ef4 100644
--- a/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll
@@ -433,6 +433,19 @@ define <2 x i16> @and_bitcast_f32_to_v2i16_constant(float %a) {
   ret <2 x i16> %and
 }
 
+define <2 x i16> @and_bitcast_f32_to_v2i16(float %a, float %b) {
+; CHECK-LABEL: @and_bitcast_f32_to_v2i16(
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast float [[A:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast float [[B:%.*]] to <2 x i16>
+; CHECK-NEXT:    [[AND:%.*]] = and <2 x i16> [[BC1]], [[BC2]]
+; CHECK-NEXT:    ret <2 x i16> [[AND]]
+;
+  %bc1 = bitcast float %a to <2 x i16>
+  %bc2 = bitcast float %b to <2 x i16>
+  %and = and <2 x i16> %bc1, %bc2
+  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(
@@ -445,6 +458,19 @@ define i64 @and_bitcast_v2f32_to_i64_constant(<2 x float> %a) {
   ret i64 %and
 }
 
+define i64 @and_bitcast_v2f32_to_i64(<2 x float> %a, <2 x float> %b) {
+; CHECK-LABEL: @and_bitcast_v2f32_to_i64(
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <2 x float> [[A:%.*]] to i64
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast <2 x float> [[B:%.*]] to i64
+; CHECK-NEXT:    [[AND:%.*]] = and i64 [[BC1]], [[BC2]]
+; CHECK-NEXT:    ret i64 [[AND]]
+;
+  %bc1 = bitcast <2 x float> %a to i64
+  %bc2 = bitcast <2 x float> %b to i64
+  %and = and i64 %bc1, %bc2
+  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(
@@ -457,6 +483,19 @@ define i16 @xor_bitcast_i16_to_i16_constant(i16 %a) {
   ret i16 %or
 }
 
+define i16 @xor_bitcast_i16_to_i16(i16 %a, i16 %b) {
+; CHECK-LABEL: @xor_bitcast_i16_to_i16(
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast i16 [[A:%.*]] to i16
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast i16 [[B:%.*]] to i16
+; CHECK-NEXT:    [[OR:%.*]] = xor i16 [[BC1]], [[BC2]]
+; CHECK-NEXT:    ret i16 [[OR]]
+;
+  %bc1 = bitcast i16 %a to i16
+  %bc2 = bitcast i16 %b to i16
+  %or = xor i16 %bc1, %bc2
+  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(
@@ -469,6 +508,18 @@ define <16 x i1> @xor_bitcast_i16_to_v16i1_constant(i16 %a) {
   ret <16 x i1> %or
 }
 
+define <16 x i1> @xor_bitcast_i16_to_v16i1(i16 %a, i16 %b) {
+; CHECK-LABEL: @xor_bitcast_i16_to_v16i1(
+; CHECK-NEXT:    [[B1:%.*]] = xor i16 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[BC3:%.*]] = bitcast i16 [[B1]] to <16 x i1>
+; CHECK-NEXT:    ret <16 x i1> [[BC3]]
+;
+  %bc1 = bitcast i16 %a to <16 x i1>
+  %bc2 = bitcast i16 %b to <16 x i1>
+  %or = xor <16 x i1> %bc1, %bc2
+  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(
@@ -480,3 +531,16 @@ define i16 @or_bitcast_v16i1_to_i16_constant(<16 x i1> %a) {
   %or = or i16 %bc, 3
   ret i16 %or
 }
+
+define i16 @or_bitcast_v16i1_to_i16(<16 x i1> %a, <16 x i1> %b) {
+; CHECK-LABEL: @or_bitcast_v16i1_to_i16(
+; CHECK-NEXT:    [[BC1:%.*]] = bitcast <16 x i1> [[A:%.*]] to i16
+; CHECK-NEXT:    [[BC2:%.*]] = bitcast <16 x i1> [[B:%.*]] to i16
+; CHECK-NEXT:    [[OR:%.*]] = or i16 [[BC1]], [[BC2]]
+; CHECK-NEXT:    ret i16 [[OR]]
+;
+  %bc1 = bitcast <16 x i1> %a to i16
+  %bc2 = bitcast <16 x i1> %b to i16
+  %or = or i16 %bc1, %bc2
+  ret i16 %or
+}


        


More information about the llvm-commits mailing list