Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -511,6 +511,10 @@ bool matchFunnelShiftToRotate(MachineInstr &MI); void applyFunnelShiftToRotate(MachineInstr &MI); + /// \return true if a G_ICMP can be replaced with its LHS. + bool matchReplaceICmpWithLHS(MachineInstr &MI); + bool applyReplaceICmpWithLHS(MachineInstr &MI); + /// Try to transform \p MI by using all of the above /// combine functions. Returns true if changed. bool tryCombine(MachineInstr &MI); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -605,6 +605,13 @@ (apply [{ Helper.applyFunnelShiftToRotate(*${root}); }]) >; +def replace_icmp_with_lhs: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_ICMP):$root, + [{ return Helper.matchReplaceICmpWithLHS(*${root}); }]), + (apply [{ Helper.applyReplaceICmpWithLHS(*${root}); }]) +>; + def funnel_shift_combines : GICombineGroup<[funnel_shift_to_rotate]>; // FIXME: These should use the custom predicate feature once it lands. @@ -626,7 +633,7 @@ def known_bits_simplifications : GICombineGroup<[ redundant_and, redundant_sext_inreg, redundant_or, urem_pow2_to_mask, - zext_trunc_fold]>; + zext_trunc_fold, replace_icmp_with_lhs]>; def width_reduction_combines : GICombineGroup<[reduce_shl_of_extend]>; Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -3894,6 +3894,61 @@ Observer.changedInstr(MI); } +bool CombinerHelper::matchReplaceICmpWithLHS(MachineInstr &MI) { + // When we have + // + // %c = icmp eq/ne %x, cst + // + // If we know that true == 1 and false == 0, and we know that %x is either 0 + // or 1, then + // + // %c = icmp eq %x, 1 -> %x + // %c = icmp ne %x, 0 -> %x + assert(MI.getOpcode() == TargetOpcode::G_ICMP); + assert(KB && "Combiner should have KnownBits!"); + auto Pred = static_cast(MI.getOperand(1).getPredicate()); + if (!ICmpInst::isEquality(Pred)) + return false; + Register LHS = MI.getOperand(2).getReg(); + bool IsVector = MRI.getType(LHS).isVector(); + // Need to have ZeroOrOneBooleanContent, otherwise we can't tell if we have + // exactly one of true/false via KB. + if (getICmpTrueVal(getTargetLowering(), IsVector, + /*IsFP = */ false) != 1) + return false; + int64_t ValToMatch = Pred == CmpInst::ICMP_EQ ? 1 : 0; + Register RHS = MI.getOperand(3).getReg(); + if (IsVector) { + // FIXME: Once mi_match handles splats/vector constants, we can simplify + // this. + auto MaybeSplat = getBuildVectorConstantSplat(*MRI.getVRegDef(RHS), MRI); + if (!MaybeSplat || *MaybeSplat != ValToMatch) + return false; + } else if (!mi_match(RHS, MRI, m_SpecificICst(ValToMatch))) + return false; + + // Check if the value is known to be exactly one of 0 (false) or 1 (true). + auto KnownLHS = KB->getKnownBits(LHS); + return KnownLHS.getMinValue() == 0 && KnownLHS.getMaxValue() == 1; +} + +bool CombinerHelper::applyReplaceICmpWithLHS(MachineInstr &MI) { + assert(MI.getOpcode() == TargetOpcode::G_ICMP); + // Apply: + // %c = icmp eq %x, 1 -> %x + // %c = icmp ne %x, 0 -> %x + Register LHS = MI.getOperand(2).getReg(); + Register Dst = MI.getOperand(0).getReg(); + if (MRI.getType(LHS) == MRI.getType(Dst)) + return replaceSingleDefInstWithOperand(MI, 2); + // Note that we assume that we have ZeroOrOneBooleanContents, so ZExting is + // always correct here. + Builder.setInstrAndDebugLoc(MI); + Builder.buildZExtOrTrunc(Dst, LHS); + MI.eraseFromParent(); + return true; +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; Index: llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-simplify-cmp-known-true-false.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-simplify-cmp-known-true-false.mir @@ -0,0 +1,283 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple aarch64-apple-ios -run-pass=aarch64-prelegalizer-combiner --aarch64prelegalizercombinerhelper-only-enable-rule="replace_icmp_with_lhs" %s -o - -verify-machineinstrs | FileCheck %s +# REQUIRES: asserts + +# Check that we can combine patterns like this: +# %c = icmp eq %x, 1 -> %x +# %c = icmp ne %x, 0 -> %x + +... +--- +name: eq_one +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; CHECK-LABEL: name: eq_one + ; CHECK: liveins: $x0 + ; CHECK: %x:_(s64) = COPY $x0 + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %lhs:_(s64) = G_AND %x, %one + ; CHECK: %cmp:_(s1) = G_TRUNC %lhs(s64) + ; CHECK: %ext:_(s32) = G_ANYEXT %cmp(s1) + ; CHECK: $w0 = COPY %ext(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + %lhs:_(s64) = G_AND %x, %one + %cmp:_(s1) = G_ICMP intpred(eq), %lhs(s64), %one + %ext:_(s32) = G_ANYEXT %cmp + $w0 = COPY %ext(s32) + RET_ReallyLR implicit $w0 +... +--- +name: ne_zero +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0 + ; CHECK-LABEL: name: ne_zero + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s64) = G_IMPLICIT_DEF + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %lhs:_(s64) = G_AND %x, %one + ; CHECK: %cmp:_(s1) = G_TRUNC %lhs(s64) + ; CHECK: %ext:_(s32) = G_ANYEXT %cmp(s1) + ; CHECK: $w0 = COPY %ext(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s64) = G_IMPLICIT_DEF + %one:_(s64) = G_CONSTANT i64 1 + %zero:_(s64) = G_CONSTANT i64 0 + %lhs:_(s64) = G_AND %x, %one + %cmp:_(s1) = G_ICMP intpred(ne), %lhs(s64), %zero + %ext:_(s32) = G_ANYEXT %cmp + $w0 = COPY %ext(s32) + RET_ReallyLR implicit $w0 +... +--- +name: eq_zero +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0 + ; CHECK-LABEL: name: eq_zero + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s64) = G_IMPLICIT_DEF + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %zero:_(s64) = G_CONSTANT i64 0 + ; CHECK: %lhs:_(s64) = G_AND %x, %one + ; CHECK: %cmp:_(s1) = G_ICMP intpred(eq), %lhs(s64), %zero + ; CHECK: %ext:_(s32) = G_ANYEXT %cmp(s1) + ; CHECK: $w0 = COPY %ext(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s64) = G_IMPLICIT_DEF + %one:_(s64) = G_CONSTANT i64 1 + %zero:_(s64) = G_CONSTANT i64 0 + ; Mask to 0 or 1 + %lhs:_(s64) = G_AND %x, %one + %cmp:_(s1) = G_ICMP intpred(eq), %lhs(s64), %zero + %ext:_(s32) = G_ANYEXT %cmp + $w0 = COPY %ext(s32) + RET_ReallyLR implicit $w0 +... +--- +name: matching_size +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; Apply, but don't truncate or zero extend. + ; CHECK-LABEL: name: matching_size + ; CHECK: liveins: $x0 + ; CHECK: %x:_(s64) = COPY $x0 + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %lhs:_(s64) = G_AND %x, %one + ; CHECK: $x0 = COPY %lhs(s64) + ; CHECK: RET_ReallyLR implicit $x0 + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + %lhs:_(s64) = G_AND %x, %one + %cmp:_(s64) = G_ICMP intpred(eq), %lhs(s64), %one + $x0 = COPY %cmp(s64) + RET_ReallyLR implicit $x0 +... +--- +name: cmp_larger +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; Apply, and zero extend. + ; CHECK-LABEL: name: cmp_larger + ; CHECK: liveins: $x0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %lhs:_(s32) = G_AND %x, %one + ; CHECK: %cmp:_(s64) = G_ZEXT %lhs(s32) + ; CHECK: $x0 = COPY %cmp(s64) + ; CHECK: RET_ReallyLR implicit $x0 + %x:_(s32) = COPY $w0 + %one:_(s32) = G_CONSTANT i32 1 + %lhs:_(s32) = G_AND %x, %one + %cmp:_(s64) = G_ICMP intpred(eq), %lhs(s32), %one + $x0 = COPY %cmp(s64) + RET_ReallyLR implicit $x0 +... +--- +name: ne_one +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; CHECK-LABEL: name: ne_one + ; CHECK: liveins: $x0 + ; CHECK: %x:_(s64) = COPY $x0 + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %lhs:_(s64) = G_AND %x, %one + ; CHECK: %cmp:_(s1) = G_ICMP intpred(ne), %lhs(s64), %one + ; CHECK: %ext:_(s32) = G_ANYEXT %cmp(s1) + ; CHECK: $w0 = COPY %ext(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + ; Mask to 0 or 1 + %lhs:_(s64) = G_AND %x, %one + %cmp:_(s1) = G_ICMP intpred(ne), %lhs(s64), %one + %ext:_(s32) = G_ANYEXT %cmp + $w0 = COPY %ext(s32) + RET_ReallyLR implicit $w0 +... +--- +name: wrong_cst_ne +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; CHECK-LABEL: name: wrong_cst_ne + ; CHECK: liveins: $x0 + ; CHECK: %x:_(s64) = COPY $x0 + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %cst:_(s64) = G_CONSTANT i64 2 + ; CHECK: %lhs:_(s64) = G_AND %x, %one + ; CHECK: %cmp:_(s1) = G_ICMP intpred(ne), %lhs(s64), %cst + ; CHECK: %ext:_(s32) = G_ANYEXT %cmp(s1) + ; CHECK: $w0 = COPY %ext(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + %cst:_(s64) = G_CONSTANT i64 2 + %lhs:_(s64) = G_AND %x, %one + %cmp:_(s1) = G_ICMP intpred(ne), %lhs(s64), %cst + %ext:_(s32) = G_ANYEXT %cmp + $w0 = COPY %ext(s32) + RET_ReallyLR implicit $w0 +... +--- +name: wrong_cst_eq +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; CHECK-LABEL: name: wrong_cst_eq + ; CHECK: liveins: $x0 + ; CHECK: %x:_(s64) = COPY $x0 + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %cst:_(s64) = G_CONSTANT i64 -1 + ; CHECK: %lhs:_(s64) = G_AND %x, %one + ; CHECK: %cmp:_(s1) = G_ICMP intpred(ne), %lhs(s64), %cst + ; CHECK: %ext:_(s32) = G_ANYEXT %cmp(s1) + ; CHECK: $w0 = COPY %ext(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + %cst:_(s64) = G_CONSTANT i64 -1 + %lhs:_(s64) = G_AND %x, %one + %cmp:_(s1) = G_ICMP intpred(ne), %lhs(s64), %cst + %ext:_(s32) = G_ANYEXT %cmp + $w0 = COPY %ext(s32) + RET_ReallyLR implicit $w0 +... +--- +name: dont_combine_vector_neg_one +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; AArch64 has -1 as true when we have a vector. Don't combine. + + ; CHECK-LABEL: name: dont_combine_vector_neg_one + ; CHECK: liveins: $x0 + ; CHECK: %x:_(<2 x s32>) = COPY $x0 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: %neg_one:_(s32) = G_CONSTANT i32 -1 + ; CHECK: %neg_one_vec:_(<2 x s32>) = G_BUILD_VECTOR %neg_one(s32), %neg_one(s32) + ; CHECK: %cmp:_(<2 x s1>) = G_ICMP intpred(eq), %lhs(<2 x s32>), %neg_one_vec + ; CHECK: %ext:_(<2 x s32>) = G_ANYEXT %cmp(<2 x s1>) + ; CHECK: $x0 = COPY %ext(<2 x s32>) + ; CHECK: RET_ReallyLR implicit $x0 + %x:_(<2 x s32>) = COPY $x0 + + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + + %neg_one:_(s32) = G_CONSTANT i32 -1 + %neg_one_vec:_(<2 x s32>) = G_BUILD_VECTOR %neg_one, %neg_one + %cmp:_(<2 x s1>) = G_ICMP intpred(eq), %lhs(<2 x s32>), %neg_one_vec + %ext:_(<2 x s32>) = G_ANYEXT %cmp + $x0 = COPY %ext(<2 x s32>) + RET_ReallyLR implicit $x0 +... +--- +name: dont_combine_vector_one +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; 1 is not the true value for vectors on AArch64. Don't combine. + + ; CHECK-LABEL: name: dont_combine_vector_one + ; CHECK: liveins: $x0 + ; CHECK: %x:_(<2 x s32>) = COPY $x0 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: %cmp:_(<2 x s1>) = G_ICMP intpred(eq), %lhs(<2 x s32>), %one_vec + ; CHECK: %ext:_(<2 x s32>) = G_ANYEXT %cmp(<2 x s1>) + ; CHECK: $x0 = COPY %ext(<2 x s32>) + ; CHECK: RET_ReallyLR implicit $x0 + %x:_(<2 x s32>) = COPY $x0 + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + %cmp:_(<2 x s1>) = G_ICMP intpred(eq), %lhs(<2 x s32>), %one_vec + %ext:_(<2 x s32>) = G_ANYEXT %cmp + $x0 = COPY %ext(<2 x s32>) + RET_ReallyLR implicit $x0 +... +--- +name: val_not_between_zero_and_one +tracksRegLiveness: true +body: | + bb.0: + liveins: $x0 + ; CHECK-LABEL: name: val_not_between_zero_and_one + ; CHECK: liveins: $x0 + ; CHECK: %x:_(s64) = COPY $x0 + ; CHECK: %one:_(s64) = G_CONSTANT i64 1 + ; CHECK: %three:_(s64) = G_CONSTANT i64 3 + ; CHECK: %lhs:_(s64) = G_AND %x, %three + ; CHECK: %cmp:_(s1) = G_ICMP intpred(eq), %lhs(s64), %one + ; CHECK: %ext:_(s32) = G_ANYEXT %cmp(s1) + ; CHECK: $w0 = COPY %ext(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s64) = COPY $x0 + %one:_(s64) = G_CONSTANT i64 1 + %three:_(s64) = G_CONSTANT i64 3 + %lhs:_(s64) = G_AND %x, %three + %cmp:_(s1) = G_ICMP intpred(eq), %lhs(s64), %one + %ext:_(s32) = G_ANYEXT %cmp + $w0 = COPY %ext(s32) + RET_ReallyLR implicit $w0 Index: llvm/test/CodeGen/AMDGPU/GlobalISel/prelegalizercombiner-simplify-cmp-known-true-false.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AMDGPU/GlobalISel/prelegalizercombiner-simplify-cmp-known-true-false.mir @@ -0,0 +1,158 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -run-pass=amdgpu-prelegalizer-combiner --amdgpuprelegalizercombinerhelper-only-enable-rule="replace_icmp_with_lhs" -verify-machineinstrs -o - %s | FileCheck %s +# REQUIRES: asserts + +# Check that we can combine patterns like this: +# %c = icmp eq %x, 1 -> %x +# %c = icmp ne %x, 0 -> %x + +... +--- +name: eq_vector +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0_vgpr1 + ; CHECK-LABEL: name: eq_vector + ; CHECK: liveins: $vgpr0_vgpr1 + ; CHECK: %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: %cmp:_(<2 x s1>) = G_TRUNC %lhs(<2 x s32>) + ; CHECK: %ext:_(<2 x s32>) = G_ANYEXT %cmp(<2 x s1>) + ; CHECK: $vgpr0_vgpr1 = COPY %ext(<2 x s32>) + %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + %cmp:_(<2 x s1>) = G_ICMP intpred(eq), %lhs(<2 x s32>), %one_vec + %ext:_(<2 x s32>) = G_ANYEXT %cmp + $vgpr0_vgpr1 = COPY %ext(<2 x s32>) + +... +--- +name: ne_vector +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0_vgpr1 + ; CHECK-LABEL: name: ne_vector + ; CHECK: liveins: $vgpr0_vgpr1 + ; CHECK: %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: %cmp:_(<2 x s1>) = G_TRUNC %lhs(<2 x s32>) + ; CHECK: %ext:_(<2 x s32>) = G_ANYEXT %cmp(<2 x s1>) + ; CHECK: $vgpr0_vgpr1 = COPY %ext(<2 x s32>) + %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + %zero:_(s32) = G_CONSTANT i32 0 + %zero_vec:_(<2 x s32>) = G_BUILD_VECTOR %zero, %zero + %cmp:_(<2 x s1>) = G_ICMP intpred(ne), %lhs(<2 x s32>), %zero_vec + %ext:_(<2 x s32>) = G_ANYEXT %cmp + $vgpr0_vgpr1 = COPY %ext(<2 x s32>) + +... +--- +name: no_trunc +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0_vgpr1 + + ; Don't truncate when %cmp and %lhs are the same size. + + ; CHECK-LABEL: name: no_trunc + ; CHECK: liveins: $vgpr0_vgpr1 + ; CHECK: %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: $vgpr0_vgpr1 = COPY %lhs(<2 x s32>) + %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + %cmp:_(<2 x s32>) = G_ICMP intpred(eq), %lhs(<2 x s32>), %one_vec + $vgpr0_vgpr1 = COPY %cmp(<2 x s32>) + +... +--- +name: zext +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0_vgpr1 + + ; %cmp is larger than %lhs, so we should zero-extend + + ; CHECK-LABEL: name: zext + ; CHECK: liveins: $vgpr0_vgpr1 + ; CHECK: %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: %cmp:_(<2 x s64>) = G_ZEXT %lhs(<2 x s32>) + ; CHECK: $vgpr0_vgpr1_vgpr2_vgpr3 = COPY %cmp(<2 x s64>) + %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + %cmp:_(<2 x s64>) = G_ICMP intpred(eq), %lhs(<2 x s32>), %one_vec + $vgpr0_vgpr1_vgpr2_vgpr3 = COPY %cmp(<2 x s64>) + +... +--- +name: wrong_cst +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0_vgpr1 + ; CHECK-LABEL: name: wrong_cst + ; CHECK: liveins: $vgpr0_vgpr1 + ; CHECK: %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: %neg_one:_(s32) = G_CONSTANT i32 -1 + ; CHECK: %neg_one_vec:_(<2 x s32>) = G_BUILD_VECTOR %neg_one(s32), %neg_one(s32) + ; CHECK: %cmp:_(<2 x s1>) = G_ICMP intpred(ne), %lhs(<2 x s32>), %neg_one_vec + ; CHECK: %ext:_(<2 x s32>) = G_ANYEXT %cmp(<2 x s1>) + ; CHECK: $vgpr0_vgpr1 = COPY %ext(<2 x s32>) + %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + %neg_one:_(s32) = G_CONSTANT i32 -1 + %neg_one_vec:_(<2 x s32>) = G_BUILD_VECTOR %neg_one, %neg_one + %cmp:_(<2 x s1>) = G_ICMP intpred(ne), %lhs(<2 x s32>), %neg_one_vec + %ext:_(<2 x s32>) = G_ANYEXT %cmp + $vgpr0_vgpr1 = COPY %ext(<2 x s32>) + +... +--- +name: wrong_pred +tracksRegLiveness: true +body: | + bb.0: + liveins: $vgpr0_vgpr1 + ; CHECK-LABEL: name: wrong_pred + ; CHECK: liveins: $vgpr0_vgpr1 + ; CHECK: %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + ; CHECK: %one:_(s32) = G_CONSTANT i32 1 + ; CHECK: %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one(s32), %one(s32) + ; CHECK: %lhs:_(<2 x s32>) = G_AND %x, %one_vec + ; CHECK: %cmp:_(<2 x s1>) = G_ICMP intpred(sge), %lhs(<2 x s32>), %one_vec + ; CHECK: %ext:_(<2 x s32>) = G_ANYEXT %cmp(<2 x s1>) + ; CHECK: $vgpr0_vgpr1 = COPY %ext(<2 x s32>) + %x:_(<2 x s32>) = COPY $vgpr0_vgpr1 + %one:_(s32) = G_CONSTANT i32 1 + %one_vec:_(<2 x s32>) = G_BUILD_VECTOR %one, %one + %lhs:_(<2 x s32>) = G_AND %x, %one_vec + %cmp:_(<2 x s1>) = G_ICMP intpred(sge), %lhs(<2 x s32>), %one_vec + %ext:_(<2 x s32>) = G_ANYEXT %cmp + $vgpr0_vgpr1 = COPY %ext(<2 x s32>)