Skip to content

Commit db2fc84

Browse files
authored
[VectorCombine] Relax vector type constraint on bitop(bitcast, constant) (#157246)
Fixes llvm/llvm-project#157131. This patch allows bitop(bitcast, constant) -> bitcast(bitop) for scalar integer types.
1 parent 6782346 commit db2fc84

File tree

2 files changed

+75
-14
lines changed

2 files changed

+75
-14
lines changed

llvm/lib/Transforms/Vectorize/VectorCombine.cpp

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,19 +1013,22 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {
10131013

10141014
Value *LHSSrc = LHSCast->getOperand(0);
10151015

1016-
// Only handle vector types with integer elements
1017-
auto *SrcVecTy = dyn_cast<FixedVectorType>(LHSSrc->getType());
1018-
auto *DstVecTy = dyn_cast<FixedVectorType>(I.getType());
1019-
if (!SrcVecTy || !DstVecTy)
1016+
auto *SrcTy = LHSSrc->getType();
1017+
auto *DstTy = I.getType();
1018+
// Bitcasts can handle scalar/vector mixes, such as i16 -> <16 x i1>.
1019+
// Other casts only handle vector types with integer elements.
1020+
if (CastOpcode != Instruction::BitCast &&
1021+
(!isa<FixedVectorType>(SrcTy) || !isa<FixedVectorType>(DstTy)))
10201022
return false;
10211023

1022-
if (!SrcVecTy->getScalarType()->isIntegerTy() ||
1023-
!DstVecTy->getScalarType()->isIntegerTy())
1024+
// Only integer scalar/vector values are legal for bitwise logic operations.
1025+
if (!SrcTy->getScalarType()->isIntegerTy() ||
1026+
!DstTy->getScalarType()->isIntegerTy())
10241027
return false;
10251028

10261029
// Find the constant InvC, such that castop(InvC) equals to C.
10271030
PreservedCastFlags RHSFlags;
1028-
Constant *InvC = getLosslessInvCast(C, SrcVecTy, CastOpcode, *DL, RHSFlags);
1031+
Constant *InvC = getLosslessInvCast(C, SrcTy, CastOpcode, *DL, RHSFlags);
10291032
if (!InvC)
10301033
return false;
10311034

@@ -1034,20 +1037,18 @@ bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {
10341037
// NewCost = bitlogic + cast
10351038

10361039
// Calculate specific costs for each cast with instruction context
1037-
InstructionCost LHSCastCost =
1038-
TTI.getCastInstrCost(CastOpcode, DstVecTy, SrcVecTy,
1039-
TTI::CastContextHint::None, CostKind, LHSCast);
1040+
InstructionCost LHSCastCost = TTI.getCastInstrCost(
1041+
CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind, LHSCast);
10401042

10411043
InstructionCost OldCost =
1042-
TTI.getArithmeticInstrCost(I.getOpcode(), DstVecTy, CostKind) +
1043-
LHSCastCost;
1044+
TTI.getArithmeticInstrCost(I.getOpcode(), DstTy, CostKind) + LHSCastCost;
10441045

10451046
// For new cost, we can't provide an instruction (it doesn't exist yet)
10461047
InstructionCost GenericCastCost = TTI.getCastInstrCost(
1047-
CastOpcode, DstVecTy, SrcVecTy, TTI::CastContextHint::None, CostKind);
1048+
CastOpcode, DstTy, SrcTy, TTI::CastContextHint::None, CostKind);
10481049

10491050
InstructionCost NewCost =
1050-
TTI.getArithmeticInstrCost(I.getOpcode(), SrcVecTy, CostKind) +
1051+
TTI.getArithmeticInstrCost(I.getOpcode(), SrcTy, CostKind) +
10511052
GenericCastCost;
10521053

10531054
// Account for multi-use casts using specific costs

llvm/test/Transforms/VectorCombine/X86/bitop-of-castops.ll

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,3 +420,63 @@ define <4 x i32> @or_zext_nneg_multiconstant(<4 x i8> %a) {
420420
%or = or <4 x i32> %z1, <i32 240, i32 1, i32 242, i32 3>
421421
ret <4 x i32> %or
422422
}
423+
424+
; Negative test: bitcast from scalar float to vector int (optimization should not apply)
425+
define <2 x i16> @and_bitcast_f32_to_v2i16_constant(float %a) {
426+
; CHECK-LABEL: @and_bitcast_f32_to_v2i16_constant(
427+
; CHECK-NEXT: [[BC2:%.*]] = bitcast float [[B:%.*]] to <2 x i16>
428+
; CHECK-NEXT: [[AND:%.*]] = and <2 x i16> <i16 0, i16 1>, [[BC2]]
429+
; CHECK-NEXT: ret <2 x i16> [[AND]]
430+
;
431+
%bc = bitcast float %a to <2 x i16>
432+
%and = and <2 x i16> <i16 0, i16 1>, %bc
433+
ret <2 x i16> %and
434+
}
435+
436+
; Negative test: bitcast from vector float to scalar int (optimization should not apply)
437+
define i64 @and_bitcast_v2f32_to_i64_constant(<2 x float> %a) {
438+
; CHECK-LABEL: @and_bitcast_v2f32_to_i64_constant(
439+
; CHECK-NEXT: [[BC2:%.*]] = bitcast <2 x float> [[B:%.*]] to i64
440+
; CHECK-NEXT: [[AND:%.*]] = and i64 123, [[BC2]]
441+
; CHECK-NEXT: ret i64 [[AND]]
442+
;
443+
%bc = bitcast <2 x float> %a to i64
444+
%and = and i64 123, %bc
445+
ret i64 %and
446+
}
447+
448+
; Test no-op bitcast
449+
define i16 @xor_bitcast_i16_to_i16_constant(i16 %a) {
450+
; CHECK-LABEL: @xor_bitcast_i16_to_i16_constant(
451+
; CHECK-NEXT: [[BC2:%.*]] = bitcast i16 [[B:%.*]] to i16
452+
; CHECK-NEXT: [[OR:%.*]] = xor i16 123, [[BC2]]
453+
; CHECK-NEXT: ret i16 [[OR]]
454+
;
455+
%bc = bitcast i16 %a to i16
456+
%or = xor i16 123, %bc
457+
ret i16 %or
458+
}
459+
460+
; Test bitwise operations with integer vector to integer bitcast
461+
define <16 x i1> @xor_bitcast_i16_to_v16i1_constant(i16 %a) {
462+
; CHECK-LABEL: @xor_bitcast_i16_to_v16i1_constant(
463+
; CHECK-NEXT: [[B:%.*]] = xor i16 [[A:%.*]], -1
464+
; CHECK-NEXT: [[BC2:%.*]] = bitcast i16 [[B]] to <16 x i1>
465+
; CHECK-NEXT: ret <16 x i1> [[BC2]]
466+
;
467+
%bc = bitcast i16 %a to <16 x i1>
468+
%or = xor <16 x i1> %bc, splat (i1 true)
469+
ret <16 x i1> %or
470+
}
471+
472+
; Test bitwise operations with integer vector to integer bitcast
473+
define i16 @or_bitcast_v16i1_to_i16_constant(<16 x i1> %a) {
474+
; CHECK-LABEL: @or_bitcast_v16i1_to_i16_constant(
475+
; CHECK-NEXT: [[BC2:%.*]] = bitcast <16 x i1> [[B:%.*]] to i16
476+
; CHECK-NEXT: [[OR:%.*]] = or i16 [[BC2]], 3
477+
; CHECK-NEXT: ret i16 [[OR]]
478+
;
479+
%bc = bitcast <16 x i1> %a to i16
480+
%or = or i16 %bc, 3
481+
ret i16 %or
482+
}

0 commit comments

Comments
 (0)