[GISel] Add new combines for G_ADD

Patch adds new GICombineRules for G_ADD:

G_ADD(x, G_SUB(y, x)) -> y
G_ADD(G_SUB(y, x), x) -> y

Patch additionally adds new combine tests for AArch64 target for
these new rules.

Reviewed by: paquette

Differential Revision: https://reviews.llvm.org/D87936
This commit is contained in:
Michael Kitzan 2022-05-18 14:41:48 -07:00
parent 99069ab212
commit b7fcf6632f
4 changed files with 161 additions and 3 deletions

View File

@ -736,6 +736,10 @@ public:
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.

View File

@ -891,13 +891,21 @@ def combine_fsub_fpext_fneg_fmul_to_fmad_or_fma: GICombineRule<
*${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 @@ def identity_combines : GICombineGroup<[select_same_val, right_identity_zero,
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,

View File

@ -5633,6 +5633,22 @@ bool CombinerHelper::matchCombineFMinMaxNaN(MachineInstr &MI,
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;

View File

@ -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
...