Skip to content

Commit c363fc2

Browse files
committed
[VectorCombine] Support pattern bitop(cast(x), C) -> bitop(cast(x), cast(InvC))
1 parent df5a693 commit c363fc2

File tree

3 files changed

+190
-34
lines changed

3 files changed

+190
-34
lines changed

llvm/lib/Transforms/Vectorize/VectorCombine.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ class VectorCombine {
122122
bool foldInsExtBinop(Instruction &I);
123123
bool foldInsExtVectorToShuffle(Instruction &I);
124124
bool foldBitOpOfCastops(Instruction &I);
125+
bool foldBitOpOfCastConstant(Instruction &I);
125126
bool foldBitcastShuffle(Instruction &I);
126127
bool scalarizeOpOrCmp(Instruction &I);
127128
bool scalarizeVPIntrinsic(Instruction &I);
@@ -937,6 +938,159 @@ bool VectorCombine::foldBitOpOfCastops(Instruction &I) {
937938
return true;
938939
}
939940

941+
struct PreservedCastFlags {
942+
bool NNeg = false;
943+
bool NUW = false;
944+
bool NSW = false;
945+
};
946+
947+
// Try to cast C to InvC losslessly, satisfying CastOp(InvC) == C.
948+
// Will try best to preserve the flags.
949+
static Constant *getLosslessInvCast(Constant *C, Type *InvCastTo,
950+
Instruction::CastOps CastOp,
951+
const DataLayout &DL,
952+
PreservedCastFlags &Flags) {
953+
switch (CastOp) {
954+
case Instruction::BitCast:
955+
// Bitcast is always lossless.
956+
return ConstantFoldCastOperand(Instruction::BitCast, C, InvCastTo, DL);
957+
case Instruction::Trunc: {
958+
auto *ZExtC = ConstantFoldCastOperand(Instruction::ZExt, C, InvCastTo, DL);
959+
auto *SExtC = ConstantFoldCastOperand(Instruction::SExt, C, InvCastTo, DL);
960+
// Truncation back on ZExt value is always NUW.
961+
Flags.NUW = true;
962+
// Test positivity of C.
963+
Flags.NSW = ZExtC == SExtC;
964+
return ZExtC;
965+
}
966+
case Instruction::SExt:
967+
case Instruction::ZExt: {
968+
auto *InvC = ConstantExpr::getTrunc(C, InvCastTo);
969+
auto *CastInvC = ConstantFoldCastOperand(CastOp, InvC, C->getType(), DL);
970+
// Must satisfy CastOp(InvC) == C.
971+
if (!CastInvC || CastInvC != C)
972+
return nullptr;
973+
if (CastOp == Instruction::ZExt) {
974+
auto *SExtInvC =
975+
ConstantFoldCastOperand(Instruction::SExt, InvC, C->getType(), DL);
976+
// Test positivity of InvC.
977+
Flags.NNeg = CastInvC == SExtInvC;
978+
}
979+
return InvC;
980+
}
981+
default:
982+
return nullptr;
983+
}
984+
}
985+
986+
/// Match:
987+
// bitop(castop(x), C) ->
988+
// bitop(castop(x), castop(InvC)) ->
989+
// castop(bitop(x, InvC))
990+
// Supports: bitcast, trunc, sext, zext
991+
bool VectorCombine::foldBitOpOfCastConstant(Instruction &I) {
992+
Instruction *LHS;
993+
Constant *C;
994+
995+
// Check if this is a bitwise logic operation
996+
if (!match(&I, m_c_BitwiseLogic(m_Instruction(LHS), m_Constant(C))))
997+
return false;
998+
999+
// Get the cast instructions
1000+
auto *LHSCast = dyn_cast<CastInst>(LHS);
1001+
if (!LHSCast)
1002+
return false;
1003+
1004+
Instruction::CastOps CastOpcode = LHSCast->getOpcode();
1005+
1006+
// Only handle supported cast operations
1007+
switch (CastOpcode) {
1008+
case Instruction::BitCast:
1009+
case Instruction::Trunc:
1010+
case Instruction::SExt:
1011+
case Instruction::ZExt:
1012+
break;
1013+
default:
1014+
return false;
1015+
}
1016+
1017+
Value *LHSSrc = LHSCast->getOperand(0);
1018+
1019+
// Only handle vector types with integer elements
1020+
auto *SrcVecTy = dyn_cast<FixedVectorType>(LHSSrc->getType());
1021+
auto *DstVecTy = dyn_cast<FixedVectorType>(I.getType());
1022+
if (!SrcVecTy || !DstVecTy)
1023+
return false;
1024+
1025+
if (!SrcVecTy->getScalarType()->isIntegerTy() ||
1026+
!DstVecTy->getScalarType()->isIntegerTy())
1027+
return false;
1028+
1029+
// Find the constant InvC, such that castop(InvC) equals to C.
1030+
PreservedCastFlags RHSFlags;
1031+
Constant *InvC = getLosslessInvCast(C, SrcVecTy, CastOpcode, *DL, RHSFlags);
1032+
if (!InvC)
1033+
return false;
1034+
1035+
// Cost Check :
1036+
// OldCost = bitlogic + cast
1037+
// NewCost = bitlogic + cast
1038+
1039+
// Calculate specific costs for each cast with instruction context
1040+
InstructionCost LHSCastCost =
1041+
TTI.getCastInstrCost(CastOpcode, DstVecTy, SrcVecTy,
1042+
TTI::CastContextHint::None, CostKind, LHSCast);
1043+
1044+
InstructionCost OldCost =
1045+
TTI.getArithmeticInstrCost(I.getOpcode(), DstVecTy, CostKind) +
1046+
LHSCastCost;
1047+
1048+
// For new cost, we can't provide an instruction (it doesn't exist yet)
1049+
InstructionCost GenericCastCost = TTI.getCastInstrCost(
1050+
CastOpcode, DstVecTy, SrcVecTy, TTI::CastContextHint::None, CostKind);
1051+
1052+
InstructionCost NewCost =
1053+
TTI.getArithmeticInstrCost(I.getOpcode(), SrcVecTy, CostKind) +
1054+
GenericCastCost;
1055+
1056+
// Account for multi-use casts using specific costs
1057+
if (!LHSCast->hasOneUse())
1058+
NewCost += LHSCastCost;
1059+
1060+
LLVM_DEBUG(dbgs() << "foldBitOpOfCastConstant: OldCost=" << OldCost
1061+
<< " NewCost=" << NewCost << "\n");
1062+
1063+
if (NewCost > OldCost)
1064+
return false;
1065+
1066+
// Create the operation on the source type
1067+
Value *NewOp = Builder.CreateBinOp((Instruction::BinaryOps)I.getOpcode(),
1068+
LHSSrc, InvC, I.getName() + ".inner");
1069+
if (auto *NewBinOp = dyn_cast<BinaryOperator>(NewOp))
1070+
NewBinOp->copyIRFlags(&I);
1071+
1072+
Worklist.pushValue(NewOp);
1073+
1074+
// Create the cast operation directly to ensure we get a new instruction
1075+
Instruction *NewCast = CastInst::Create(CastOpcode, NewOp, I.getType());
1076+
1077+
// Preserve cast instruction flags
1078+
if (RHSFlags.NNeg)
1079+
NewCast->setNonNeg();
1080+
if (RHSFlags.NSW)
1081+
NewCast->setHasNoSignedWrap();
1082+
if (RHSFlags.NUW)
1083+
NewCast->setHasNoUnsignedWrap();
1084+
1085+
NewCast->andIRFlags(LHSCast);
1086+
1087+
// Insert the new instruction
1088+
Value *Result = Builder.Insert(NewCast);
1089+
1090+
replaceValue(I, *Result);
1091+
return true;
1092+
}
1093+
9401094
/// If this is a bitcast of a shuffle, try to bitcast the source vector to the
9411095
/// destination type followed by shuffle. This can enable further transforms by
9421096
/// moving bitcasts or shuffles together.
@@ -4474,6 +4628,8 @@ bool VectorCombine::run() {
44744628
case Instruction::Xor:
44754629
if (foldBitOpOfCastops(I))
44764630
return true;
4631+
if (foldBitOpOfCastConstant(I))
4632+
return true;
44774633
break;
44784634
case Instruction::PHI:
44794635
if (shrinkPhiOfShuffles(I))

llvm/test/Transforms/VectorCombine/AArch64/shrink-types.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ define i32 @multiuse(<16 x i32> %u, <16 x i32> %v, ptr %b) {
4545
; CHECK-NEXT: [[U_MASKED:%.*]] = and <16 x i32> [[U:%.*]], splat (i32 255)
4646
; CHECK-NEXT: [[V_MASKED:%.*]] = and <16 x i32> [[V:%.*]], splat (i32 255)
4747
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <16 x i8>, ptr [[B:%.*]], align 1
48-
; CHECK-NEXT: [[TMP0:%.*]] = zext <16 x i8> [[WIDE_LOAD]] to <16 x i32>
4948
; CHECK-NEXT: [[TMP6:%.*]] = lshr <16 x i8> [[WIDE_LOAD]], splat (i8 4)
5049
; CHECK-NEXT: [[TMP7:%.*]] = zext <16 x i8> [[TMP6]] to <16 x i32>
5150
; CHECK-NEXT: [[TMP3:%.*]] = or <16 x i32> [[TMP7]], [[V_MASKED]]
52-
; CHECK-NEXT: [[TMP4:%.*]] = and <16 x i32> [[TMP0]], splat (i32 15)
51+
; CHECK-NEXT: [[DOTINNER:%.*]] = and <16 x i8> [[WIDE_LOAD]], splat (i8 15)
52+
; CHECK-NEXT: [[TMP4:%.*]] = zext <16 x i8> [[DOTINNER]] to <16 x i32>
5353
; CHECK-NEXT: [[TMP5:%.*]] = or <16 x i32> [[TMP4]], [[U_MASKED]]
5454
; CHECK-NEXT: [[TMP8:%.*]] = add nuw nsw <16 x i32> [[TMP3]], [[TMP5]]
5555
; CHECK-NEXT: [[TMP9:%.*]] = call i32 @llvm.vector.reduce.add.v16i32(<16 x i32> [[TMP8]])

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

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,9 @@ define <4 x i32> @or_zext_nneg(<4 x i16> %a, <4 x i16> %b) {
264264
; Test bitwise operations with integer-to-integer bitcast with one constant
265265
define <2 x i32> @or_bitcast_v4i16_to_v2i32_constant(<4 x i16> %a) {
266266
; CHECK-LABEL: @or_bitcast_v4i16_to_v2i32_constant(
267-
; CHECK-NEXT: [[BC1:%.*]] = bitcast <4 x i16> [[A:%.*]] to <2 x i32>
268-
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> [[BC1]], <i32 1000000, i32 2000000>
269-
; CHECK-NEXT: ret <2 x i32> [[OR]]
267+
; CHECK-NEXT: [[A:%.*]] = or <4 x i16> [[A1:%.*]], <i16 16960, i16 15, i16 -31616, i16 30>
268+
; CHECK-NEXT: [[BC1:%.*]] = bitcast <4 x i16> [[A]] to <2 x i32>
269+
; CHECK-NEXT: ret <2 x i32> [[BC1]]
270270
;
271271
%bc1 = bitcast <4 x i16> %a to <2 x i32>
272272
%or = or <2 x i32> %bc1, <i32 1000000, i32 2000000>
@@ -275,9 +275,9 @@ define <2 x i32> @or_bitcast_v4i16_to_v2i32_constant(<4 x i16> %a) {
275275

276276
define <2 x i32> @or_bitcast_v4i16_to_v2i32_constant_commuted(<4 x i16> %a) {
277277
; CHECK-LABEL: @or_bitcast_v4i16_to_v2i32_constant_commuted(
278-
; CHECK-NEXT: [[BC1:%.*]] = bitcast <4 x i16> [[A:%.*]] to <2 x i32>
279-
; CHECK-NEXT: [[OR:%.*]] = or <2 x i32> <i32 1000000, i32 2000000>, [[BC1]]
280-
; CHECK-NEXT: ret <2 x i32> [[OR]]
278+
; CHECK-NEXT: [[A:%.*]] = or <4 x i16> [[A1:%.*]], <i16 16960, i16 15, i16 -31616, i16 30>
279+
; CHECK-NEXT: [[BC1:%.*]] = bitcast <4 x i16> [[A]] to <2 x i32>
280+
; CHECK-NEXT: ret <2 x i32> [[BC1]]
281281
;
282282
%bc1 = bitcast <4 x i16> %a to <2 x i32>
283283
%or = or <2 x i32> <i32 1000000, i32 2000000>, %bc1
@@ -287,9 +287,9 @@ define <2 x i32> @or_bitcast_v4i16_to_v2i32_constant_commuted(<4 x i16> %a) {
287287
; Test bitwise operations with truncate and one constant
288288
define <4 x i16> @or_trunc_v4i32_to_v4i16_constant(<4 x i32> %a) {
289289
; CHECK-LABEL: @or_trunc_v4i32_to_v4i16_constant(
290-
; CHECK-NEXT: [[T1:%.*]] = trunc <4 x i32> [[A:%.*]] to <4 x i16>
291-
; CHECK-NEXT: [[AND:%.*]] = or <4 x i16> [[T1]], <i16 1, i16 2, i16 3, i16 4>
292-
; CHECK-NEXT: ret <4 x i16> [[AND]]
290+
; CHECK-NEXT: [[A:%.*]] = or <4 x i32> [[A1:%.*]], <i32 1, i32 2, i32 3, i32 4>
291+
; CHECK-NEXT: [[T1:%.*]] = trunc <4 x i32> [[A]] to <4 x i16>
292+
; CHECK-NEXT: ret <4 x i16> [[T1]]
293293
;
294294
%t1 = trunc <4 x i32> %a to <4 x i16>
295295
%or = or <4 x i16> %t1, <i16 1, i16 2, i16 3, i16 4>
@@ -299,9 +299,9 @@ define <4 x i16> @or_trunc_v4i32_to_v4i16_constant(<4 x i32> %a) {
299299
; Test bitwise operations with zero extend and one constant
300300
define <4 x i32> @or_zext_v4i16_to_v4i32_constant(<4 x i16> %a) {
301301
; CHECK-LABEL: @or_zext_v4i16_to_v4i32_constant(
302-
; CHECK-NEXT: [[Z1:%.*]] = zext <4 x i16> [[A:%.*]] to <4 x i32>
303-
; CHECK-NEXT: [[AND:%.*]] = or <4 x i32> [[Z1]], <i32 1, i32 2, i32 3, i32 4>
304-
; CHECK-NEXT: ret <4 x i32> [[AND]]
302+
; CHECK-NEXT: [[A:%.*]] = or <4 x i16> [[A1:%.*]], <i16 1, i16 2, i16 3, i16 4>
303+
; CHECK-NEXT: [[Z1:%.*]] = zext <4 x i16> [[A]] to <4 x i32>
304+
; CHECK-NEXT: ret <4 x i32> [[Z1]]
305305
;
306306
%z1 = zext <4 x i16> %a to <4 x i32>
307307
%or = or <4 x i32> %z1, <i32 1, i32 2, i32 3, i32 4>
@@ -322,9 +322,9 @@ define <4 x i32> @or_zext_v4i8_to_v4i32_constant_with_loss(<4 x i8> %a) {
322322
; Test bitwise operations with sign extend and one constant
323323
define <4 x i32> @or_sext_v4i8_to_v4i32_positive_constant(<4 x i8> %a) {
324324
; CHECK-LABEL: @or_sext_v4i8_to_v4i32_positive_constant(
325-
; CHECK-NEXT: [[S1:%.*]] = sext <4 x i8> [[A:%.*]] to <4 x i32>
326-
; CHECK-NEXT: [[OR:%.*]] = or <4 x i32> [[S1]], <i32 1, i32 2, i32 3, i32 4>
327-
; CHECK-NEXT: ret <4 x i32> [[OR]]
325+
; CHECK-NEXT: [[A:%.*]] = or <4 x i8> [[A1:%.*]], <i8 1, i8 2, i8 3, i8 4>
326+
; CHECK-NEXT: [[S1:%.*]] = sext <4 x i8> [[A]] to <4 x i32>
327+
; CHECK-NEXT: ret <4 x i32> [[S1]]
328328
;
329329
%s1 = sext <4 x i8> %a to <4 x i32>
330330
%or = or <4 x i32> %s1, <i32 1, i32 2, i32 3, i32 4>
@@ -333,9 +333,9 @@ define <4 x i32> @or_sext_v4i8_to_v4i32_positive_constant(<4 x i8> %a) {
333333

334334
define <4 x i32> @or_sext_v4i8_to_v4i32_minus_constant(<4 x i8> %a) {
335335
; CHECK-LABEL: @or_sext_v4i8_to_v4i32_minus_constant(
336-
; CHECK-NEXT: [[S1:%.*]] = sext <4 x i8> [[A:%.*]] to <4 x i32>
337-
; CHECK-NEXT: [[OR:%.*]] = or <4 x i32> [[S1]], <i32 -1, i32 -2, i32 -3, i32 -4>
338-
; CHECK-NEXT: ret <4 x i32> [[OR]]
336+
; CHECK-NEXT: [[A:%.*]] = or <4 x i8> [[A1:%.*]], <i8 -1, i8 -2, i8 -3, i8 -4>
337+
; CHECK-NEXT: [[S1:%.*]] = sext <4 x i8> [[A]] to <4 x i32>
338+
; CHECK-NEXT: ret <4 x i32> [[S1]]
339339
;
340340
%s1 = sext <4 x i8> %a to <4 x i32>
341341
%or = or <4 x i32> %s1, <i32 -1, i32 -2, i32 -3, i32 -4>
@@ -356,9 +356,9 @@ define <4 x i32> @or_sext_v4i8_to_v4i32_constant_with_loss(<4 x i8> %a) {
356356
; Test truncate with flag preservation and one constant
357357
define <4 x i16> @and_trunc_nuw_nsw_constant(<4 x i32> %a) {
358358
; CHECK-LABEL: @and_trunc_nuw_nsw_constant(
359-
; CHECK-NEXT: [[T1:%.*]] = trunc nuw nsw <4 x i32> [[A:%.*]] to <4 x i16>
360-
; CHECK-NEXT: [[AND:%.*]] = and <4 x i16> [[T1]], <i16 1, i16 2, i16 3, i16 4>
361-
; CHECK-NEXT: ret <4 x i16> [[AND]]
359+
; CHECK-NEXT: [[A:%.*]] = and <4 x i32> [[A1:%.*]], <i32 1, i32 2, i32 3, i32 4>
360+
; CHECK-NEXT: [[T1:%.*]] = trunc nuw nsw <4 x i32> [[A]] to <4 x i16>
361+
; CHECK-NEXT: ret <4 x i16> [[T1]]
362362
;
363363
%t1 = trunc nuw nsw <4 x i32> %a to <4 x i16>
364364
%and = and <4 x i16> %t1, <i16 1, i16 2, i16 3, i16 4>
@@ -367,8 +367,8 @@ define <4 x i16> @and_trunc_nuw_nsw_constant(<4 x i32> %a) {
367367

368368
define <4 x i8> @and_trunc_nuw_nsw_minus_constant(<4 x i32> %a) {
369369
; CHECK-LABEL: @and_trunc_nuw_nsw_minus_constant(
370-
; CHECK-NEXT: [[T1:%.*]] = trunc nuw nsw <4 x i32> [[A:%.*]] to <4 x i8>
371-
; CHECK-NEXT: [[AND:%.*]] = and <4 x i8> [[T1]], <i8 -16, i8 -15, i8 -14, i8 -13>
370+
; CHECK-NEXT: [[AND_INNER:%.*]] = and <4 x i32> [[A:%.*]], <i32 240, i32 241, i32 242, i32 243>
371+
; CHECK-NEXT: [[AND:%.*]] = trunc nuw <4 x i32> [[AND_INNER]] to <4 x i8>
372372
; CHECK-NEXT: ret <4 x i8> [[AND]]
373373
;
374374
%t1 = trunc nuw nsw <4 x i32> %a to <4 x i8>
@@ -378,8 +378,8 @@ define <4 x i8> @and_trunc_nuw_nsw_minus_constant(<4 x i32> %a) {
378378

379379
define <4 x i8> @and_trunc_nuw_nsw_multiconstant(<4 x i32> %a) {
380380
; CHECK-LABEL: @and_trunc_nuw_nsw_multiconstant(
381-
; CHECK-NEXT: [[T1:%.*]] = trunc nuw nsw <4 x i32> [[A:%.*]] to <4 x i8>
382-
; CHECK-NEXT: [[AND:%.*]] = and <4 x i8> [[T1]], <i8 -16, i8 1, i8 -14, i8 3>
381+
; CHECK-NEXT: [[AND_INNER:%.*]] = and <4 x i32> [[A:%.*]], <i32 240, i32 1, i32 242, i32 3>
382+
; CHECK-NEXT: [[AND:%.*]] = trunc nuw <4 x i32> [[AND_INNER]] to <4 x i8>
383383
; CHECK-NEXT: ret <4 x i8> [[AND]]
384384
;
385385
%t1 = trunc nuw nsw <4 x i32> %a to <4 x i8>
@@ -390,9 +390,9 @@ define <4 x i8> @and_trunc_nuw_nsw_multiconstant(<4 x i32> %a) {
390390
; Test sign extend with nneg flag and one constant
391391
define <4 x i32> @or_zext_nneg_constant(<4 x i16> %a) {
392392
; CHECK-LABEL: @or_zext_nneg_constant(
393-
; CHECK-NEXT: [[Z1:%.*]] = zext nneg <4 x i16> [[A:%.*]] to <4 x i32>
394-
; CHECK-NEXT: [[OR:%.*]] = or <4 x i32> [[Z1]], <i32 1, i32 2, i32 3, i32 4>
395-
; CHECK-NEXT: ret <4 x i32> [[OR]]
393+
; CHECK-NEXT: [[A:%.*]] = or <4 x i16> [[A1:%.*]], <i16 1, i16 2, i16 3, i16 4>
394+
; CHECK-NEXT: [[Z1:%.*]] = zext nneg <4 x i16> [[A]] to <4 x i32>
395+
; CHECK-NEXT: ret <4 x i32> [[Z1]]
396396
;
397397
%z1 = zext nneg <4 x i16> %a to <4 x i32>
398398
%or = or <4 x i32> %z1, <i32 1, i32 2, i32 3, i32 4>
@@ -401,8 +401,8 @@ define <4 x i32> @or_zext_nneg_constant(<4 x i16> %a) {
401401

402402
define <4 x i32> @or_zext_nneg_minus_constant(<4 x i8> %a) {
403403
; CHECK-LABEL: @or_zext_nneg_minus_constant(
404-
; CHECK-NEXT: [[Z1:%.*]] = zext nneg <4 x i8> [[A:%.*]] to <4 x i32>
405-
; CHECK-NEXT: [[OR:%.*]] = or <4 x i32> [[Z1]], <i32 240, i32 241, i32 242, i32 243>
404+
; CHECK-NEXT: [[OR_INNER:%.*]] = or <4 x i8> [[A:%.*]], <i8 -16, i8 -15, i8 -14, i8 -13>
405+
; CHECK-NEXT: [[OR:%.*]] = zext <4 x i8> [[OR_INNER]] to <4 x i32>
406406
; CHECK-NEXT: ret <4 x i32> [[OR]]
407407
;
408408
%z1 = zext nneg <4 x i8> %a to <4 x i32>
@@ -412,8 +412,8 @@ define <4 x i32> @or_zext_nneg_minus_constant(<4 x i8> %a) {
412412

413413
define <4 x i32> @or_zext_nneg_multiconstant(<4 x i8> %a) {
414414
; CHECK-LABEL: @or_zext_nneg_multiconstant(
415-
; CHECK-NEXT: [[Z1:%.*]] = zext nneg <4 x i8> [[A:%.*]] to <4 x i32>
416-
; CHECK-NEXT: [[OR:%.*]] = or <4 x i32> [[Z1]], <i32 240, i32 1, i32 242, i32 3>
415+
; CHECK-NEXT: [[OR_INNER:%.*]] = or <4 x i8> [[A:%.*]], <i8 -16, i8 1, i8 -14, i8 3>
416+
; CHECK-NEXT: [[OR:%.*]] = zext <4 x i8> [[OR_INNER]] to <4 x i32>
417417
; CHECK-NEXT: ret <4 x i32> [[OR]]
418418
;
419419
%z1 = zext nneg <4 x i8> %a to <4 x i32>

0 commit comments

Comments
 (0)