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 @@ -736,6 +736,10 @@ bool matchCombineFMinMaxNaN(MachineInstr &MI, unsigned &Info); + /// Transform G_ADD(x, G_SUB(y, x)) to y. + /// Transform G_ADD(G_SUB(y, x), x) to y. + bool matchAddSubSameReg(MachineInstr &MI, Register &Src); + private: /// Given a non-indexed load or store instruction \p MI, find an offset that /// can be usefully and legally folded into it as a post-indexing operation. 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 @@ -891,13 +891,21 @@ *${root}, ${info}); }]), (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; -def combine_minmax_nan_matchinfo: GIDefMatchData<"unsigned">; def combine_minmax_nan: GICombineRule< - (defs root:$root, combine_minmax_nan_matchinfo:$info), + (defs root:$root, unsigned_matchinfo:$info), (match (wip_match_opcode G_FMINNUM, G_FMAXNUM, G_FMINIMUM, G_FMAXIMUM):$root, [{ return Helper.matchCombineFMinMaxNaN(*${root}, ${info}); }]), (apply [{ Helper.replaceSingleDefInstWithOperand(*${root}, ${info}); }])>; +// Transform (add x, (sub y, x)) -> y +// Transform (add (sub y, x), x) -> y +def add_sub_reg: GICombineRule < + (defs root:$root, register_matchinfo:$matchinfo), + (match (wip_match_opcode G_ADD):$root, + [{ return Helper.matchAddSubSameReg(*${root}, ${matchinfo}); }]), + (apply [{ return Helper.replaceSingleDefInstWithReg(*${root}, + ${matchinfo}); }])>; + // 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, @@ -913,7 +921,8 @@ binop_same_val, binop_left_to_zero, binop_right_to_zero, p2i_to_i2p, i2p_to_p2i, anyext_trunc_fold, - fneg_fneg_fold, right_identity_one]>; + fneg_fneg_fold, right_identity_one, + add_sub_reg]>; def const_combines : GICombineGroup<[constant_fp_op, const_ptradd_to_i2p, overlapping_and, mulo_by_2, mulo_by_0, 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 @@ -5633,6 +5633,22 @@ return MatchNaN(1) || MatchNaN(2); } +bool CombinerHelper::matchAddSubSameReg(MachineInstr &MI, Register &Src) { + assert(MI.getOpcode() == TargetOpcode::G_ADD && "Expected a G_ADD"); + Register LHS = MI.getOperand(1).getReg(); + Register RHS = MI.getOperand(2).getReg(); + + // Helper lambda to check for opportunities for + // A + (B - A) -> B + // (B - A) + A -> B + auto CheckFold = [&](Register MaybeSub, Register MaybeSameReg) { + Register Reg; + return mi_match(MaybeSub, MRI, m_GSub(m_Reg(Src), m_Reg(Reg))) && + Reg == MaybeSameReg; + }; + return CheckFold(LHS, RHS) || CheckFold(RHS, LHS); +} + bool CombinerHelper::tryCombine(MachineInstr &MI) { if (tryCombineCopy(MI)) return true; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-add.mir @@ -0,0 +1,129 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s + +--- +name: add_lhs_sub_reg +alignment: 4 +tracksRegLiveness: true +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: add_lhs_sub_reg + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_SUB %0, %1 + %3:_(s32) = G_ADD %2, %1 + $w0 = COPY %3 +... +--- +name: add_lhs_sub_reg_wide +alignment: 4 +tracksRegLiveness: true +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.0: + liveins: $q0, $q1 + ; CHECK-LABEL: name: add_lhs_sub_reg_wide + ; CHECK: liveins: $q0, $q1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s128) = COPY $q0 + ; CHECK-NEXT: $q0 = COPY [[COPY]](s128) + %0:_(s128) = COPY $q0 + %1:_(s128) = COPY $q1 + %2:_(s128) = G_SUB %0, %1 + %3:_(s128) = G_ADD %2, %1 + $q0 = COPY %3 +... +--- +name: add_lhs_sub_reg_vec +alignment: 4 +tracksRegLiveness: true +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.0: + liveins: $x0, $x1 + ; CHECK-LABEL: name: add_lhs_sub_reg_vec + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x s16>) = COPY $x0 + ; CHECK-NEXT: $x0 = COPY [[COPY]](<4 x s16>) + %0:_(<4 x s16>) = COPY $x0 + %1:_(<4 x s16>) = COPY $x1 + %2:_(<4 x s16>) = G_SUB %0, %1 + %3:_(<4 x s16>) = G_ADD %2, %1 + $x0 = COPY %3 +... +--- +name: add_rhs_sub_reg +alignment: 4 +tracksRegLiveness: true +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.0: + liveins: $w0, $w1 + ; CHECK-LABEL: name: add_rhs_sub_reg + ; CHECK: liveins: $w0, $w1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK-NEXT: $w0 = COPY [[COPY]](s32) + %0:_(s32) = COPY $w0 + %1:_(s32) = COPY $w1 + %2:_(s32) = G_SUB %0, %1 + %3:_(s32) = G_ADD %1, %2 + $w0 = COPY %3 +... +--- +name: add_rhs_sub_reg_wide +alignment: 4 +tracksRegLiveness: true +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.0: + liveins: $q0, $q1 + ; CHECK-LABEL: name: add_rhs_sub_reg_wide + ; CHECK: liveins: $q0, $q1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s128) = COPY $q0 + ; CHECK-NEXT: $q0 = COPY [[COPY]](s128) + %0:_(s128) = COPY $q0 + %1:_(s128) = COPY $q1 + %2:_(s128) = G_SUB %0, %1 + %3:_(s128) = G_ADD %1, %2 + $q0 = COPY %3 +... +--- +name: add_rhs_sub_reg_vec +alignment: 4 +tracksRegLiveness: true +frameInfo: + maxAlignment: 1 +machineFunctionInfo: {} +body: | + bb.0: + liveins: $x0, $x1 + ; CHECK-LABEL: name: add_rhs_sub_reg_vec + ; CHECK: liveins: $x0, $x1 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(<4 x s16>) = COPY $x0 + ; CHECK-NEXT: $x0 = COPY [[COPY]](<4 x s16>) + %0:_(<4 x s16>) = COPY $x0 + %1:_(<4 x s16>) = COPY $x1 + %2:_(<4 x s16>) = G_SUB %0, %1 + %3:_(<4 x s16>) = G_ADD %1, %2 + $x0 = COPY %3 +...