diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -304,6 +304,10 @@ bool applyAshShlToSextInreg(MachineInstr &MI, std::tuple &MatchInfo); + /// Combine inverting a result of a compare into the opposite cond code. + bool matchNotCmp(MachineInstr &MI, Register &CmpReg); + bool applyNotCmp(MachineInstr &MI, Register &CmpReg); + /// Try to transform \p MI by using all of the above /// combine functions. Returns true if changed. bool tryCombine(MachineInstr &MI); diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h --- a/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h @@ -233,6 +233,12 @@ return BinaryOp_match(L, R); } +template +inline BinaryOp_match +m_GXor(const LHS &L, const RHS &R) { + return BinaryOp_match(L, R); +} + template inline BinaryOp_match m_GOr(const LHS &L, const RHS &R) { diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -300,6 +300,14 @@ (apply [{ return Helper.applyAshShlToSextInreg(*${root}, ${info});}]) >; +def not_cmp_fold_matchinfo : GIDefMatchData<"Register">; +def not_cmp_fold : GICombineRule< + (defs root:$d, not_cmp_fold_matchinfo:$info), + (match (wip_match_opcode G_XOR): $d, + [{ return Helper.matchNotCmp(*${d}, ${info}); }]), + (apply [{ return Helper.applyNotCmp(*${d}, ${info}); }]) +>; + // FIXME: These should use the custom predicate feature once it lands. def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero, undef_to_negative_one, @@ -318,4 +326,5 @@ combines_for_extload, combine_indexed_load_store, undef_combines, identity_combines, simplify_add_to_sub, hoist_logic_op_with_same_opcode_hands, - shl_ashr_to_sext_inreg, sext_inreg_of_load]>; + shl_ashr_to_sext_inreg, sext_inreg_of_load, + not_cmp_fold]>; diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1979,6 +1979,49 @@ return true; } +bool CombinerHelper::matchNotCmp(MachineInstr &MI, Register &CmpReg) { + assert(MI.getOpcode() == TargetOpcode::G_XOR); + LLT I1 = LLT::scalar(1); + Register XorSrc; + int64_t Cst; + // We match xor(src, i1) here. + if (!mi_match( + MI.getOperand(0).getReg(), MRI, + m_all_of(m_SpecificType(I1), m_GXor(m_Reg(XorSrc), m_ICst(Cst))))) + return false; + // The i1 true is be represented as a -1 as a sign-extended constant. + if (Cst != -1) + return false; + + // Now try match src to either icmp or fcmp. + if (!mi_match(XorSrc, MRI, m_GICmp(m_Pred(), m_Reg(), m_Reg()))) { + // Try fcmp. + if (!mi_match(XorSrc, MRI, m_GFCmp(m_Pred(), m_Reg(), m_Reg()))) + return false; + } + CmpReg = XorSrc; + return true; +} + +bool CombinerHelper::applyNotCmp(MachineInstr &MI, Register &CmpReg) { + MachineInstr *CmpDef = MRI.getVRegDef(CmpReg); + assert(CmpDef && "Should have been given an MI reg"); + assert(CmpDef->getOpcode() == TargetOpcode::G_ICMP || + CmpDef->getOpcode() == TargetOpcode::G_FCMP); + + Observer.changingInstr(*CmpDef); + MachineOperand &PredOp = CmpDef->getOperand(1); + CmpInst::Predicate NewP = CmpInst::getInversePredicate( + (CmpInst::Predicate)PredOp.getPredicate()); + PredOp.setPredicate(NewP); + Observer.changedInstr(*CmpDef); + + replaceRegWith(MRI, MI.getOperand(0).getReg(), + CmpDef->getOperand(0).getReg()); + MI.eraseFromParent(); + return true; +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-invert-cmp.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-invert-cmp.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-invert-cmp.mir @@ -0,0 +1,76 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple aarch64-apple-ios -run-pass=aarch64-prelegalizer-combiner %s -o - -verify-machineinstrs | FileCheck %s + +# Check that we fold an compare result inverted into just inverting the condition code. +--- +name: icmp +tracksRegLiveness: true +body: | + bb.1: + liveins: $x0 + + ; CHECK-LABEL: name: icmp + ; CHECK: liveins: $x0 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1 + ; CHECK: [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(sle), [[COPY]](s64), [[C]] + ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[ICMP]](s1) + ; CHECK: $w0 = COPY [[ANYEXT]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s64) = COPY $x0 + %1:_(s64) = G_CONSTANT i64 1 + %2:_(s1) = G_CONSTANT i1 1 + %3:_(s1) = G_ICMP intpred(sgt), %0(s64), %1 + %4:_(s1) = G_XOR %3, %2 + %5:_(s32) = G_ANYEXT %4 + $w0 = COPY %5(s32) + RET_ReallyLR implicit $w0 +... +--- +name: fcmp +tracksRegLiveness: true +body: | + bb.1: + liveins: $x0 + + ; CHECK-LABEL: name: fcmp + ; CHECK: liveins: $x0 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1 + ; CHECK: [[FCMP:%[0-9]+]]:_(s1) = G_FCMP floatpred(ule), [[COPY]](s64), [[C]] + ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[FCMP]](s1) + ; CHECK: $w0 = COPY [[ANYEXT]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s64) = COPY $x0 + %1:_(s64) = G_CONSTANT i64 1 + %2:_(s1) = G_CONSTANT i1 1 + %3:_(s1) = G_FCMP floatpred(ogt), %0(s64), %1 + %4:_(s1) = G_XOR %3, %2 + %5:_(s32) = G_ANYEXT %4 + $w0 = COPY %5(s32) + RET_ReallyLR implicit $w0 +... +--- +name: icmp_not_xor_with_1 +tracksRegLiveness: true +body: | + bb.1: + liveins: $x0 + + ; CHECK-LABEL: name: icmp_not_xor_with_1 + ; CHECK: liveins: $x0 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 1 + ; CHECK: [[ICMP:%[0-9]+]]:_(s1) = G_ICMP intpred(sgt), [[COPY]](s64), [[C]] + ; CHECK: [[ANYEXT:%[0-9]+]]:_(s32) = G_ANYEXT [[ICMP]](s1) + ; CHECK: $w0 = COPY [[ANYEXT]](s32) + ; CHECK: RET_ReallyLR implicit $w0 + %0:_(s64) = COPY $x0 + %1:_(s64) = G_CONSTANT i64 1 + %2:_(s1) = G_CONSTANT i1 0 + %3:_(s1) = G_ICMP intpred(sgt), %0(s64), %1 + %4:_(s1) = G_XOR %3, %2 + %5:_(s32) = G_ANYEXT %4 + $w0 = COPY %5(s32) + RET_ReallyLR implicit $w0 +...