diff options
author | Richard Earnshaw <rearnsha@arm.com> | 2019-10-18 19:03:35 +0000 |
---|---|---|
committer | Richard Earnshaw <rearnsha@gcc.gnu.org> | 2019-10-18 19:03:35 +0000 |
commit | 22060d0e575e7754eb1355763d22bbe37c3caa13 (patch) | |
tree | 3b043d4b797da18e48a2963b8c3b12f8102d6769 /gcc/config | |
parent | 5899656b61231cc0e2dac4d7a58fab58674ba344 (diff) | |
download | gcc-22060d0e575e7754eb1355763d22bbe37c3caa13.zip gcc-22060d0e575e7754eb1355763d22bbe37c3caa13.tar.gz gcc-22060d0e575e7754eb1355763d22bbe37c3caa13.tar.bz2 |
[arm] Improve handling of DImode comparisions against constants.
In almost all cases it is better to handle inequality handling against constants
by transforming comparisons of the form (reg <GE/LT/GEU/LTU> const) into
(reg <GT/LE/GTU/LEU> (const+1)). However, there are many cases that we could
handle but currently failed to do so because we forced the constant into a
register too early in the pattern expansion. To permit this to be done we need
to defer forcing the constant into a register until after we've had the chance
to do the transform - in some cases that may even mean that we no-longer need
to force the constant into a register at all. For example, on Arm, the case:
_Bool f8 (unsigned long long a) { return a > 0xffffffff; }
previously compiled to
mov r3, #0
cmp r1, r3
mvn r2, #0
cmpeq r0, r2
movhi r0, #1
movls r0, #0
bx lr
But now compiles to
cmp r1, #1
cmpeq r0, #0
movcs r0, #1
movcc r0, #0
bx lr
Which although not yet completely optimal, is certainly better than
previously.
* config/arm/arm.md (cbranchdi4): Accept reg_or_int_operand for
operand 2.
(cstoredi4): Similarly, but for operand 3.
* config/arm/arm.c (arm_canoncialize_comparison): Allow canonicalization
of unsigned compares with a constant on Arm. Prefer using const+1 and
adjusting the comparison over swapping the operands whenever the
original constant was not valid.
(arm_gen_dicompare_reg): If Y is not a valid operand, force it to a
register here.
(arm_validize_comparison): Do not force invalid DImode operands to
registers here.
From-SVN: r277178
Diffstat (limited to 'gcc/config')
-rw-r--r-- | gcc/config/arm/arm.c | 37 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 4 |
2 files changed, 25 insertions, 16 deletions
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 97ebf63..e7924df 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -5372,15 +5372,16 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, maxval = (HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (mode) - 1)) - 1; - /* For DImode, we have GE/LT/GEU/LTU comparisons. In ARM mode - we can also use cmp/cmpeq for GTU/LEU. GT/LE must be either - reversed or (for constant OP1) adjusted to GE/LT. Similarly - for GTU/LEU in Thumb mode. */ + /* For DImode, we have GE/LT/GEU/LTU comparisons (with cmp/sbc). In + ARM mode we can also use cmp/cmpeq for GTU/LEU. GT/LE must be + either reversed or (for constant OP1) adjusted to GE/LT. + Similarly for GTU/LEU in Thumb mode. */ if (mode == DImode) { if (*code == GT || *code == LE - || (!TARGET_ARM && (*code == GTU || *code == LEU))) + || ((!TARGET_ARM || CONST_INT_P (*op1)) + && (*code == GTU || *code == LEU))) { /* Missing comparison. First try to use an available comparison. */ @@ -5392,23 +5393,27 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, case GT: case LE: if (i != maxval - && arm_const_double_by_immediates (GEN_INT (i + 1))) + && (!arm_const_double_by_immediates (*op1) + || arm_const_double_by_immediates (GEN_INT (i + 1)))) { *op1 = GEN_INT (i + 1); *code = *code == GT ? GE : LT; return; } break; + case GTU: case LEU: if (i != ~((unsigned HOST_WIDE_INT) 0) - && arm_const_double_by_immediates (GEN_INT (i + 1))) + && (!arm_const_double_by_immediates (*op1) + || arm_const_double_by_immediates (GEN_INT (i + 1)))) { *op1 = GEN_INT (i + 1); *code = *code == GTU ? GEU : LTU; return; } break; + default: gcc_unreachable (); } @@ -15436,7 +15441,7 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) scratch = gen_reg_rtx (SImode); if (ylo == const0_rtx) { - yhi = GEN_INT (-INTVAL(yhi)); + yhi = gen_int_mode (-INTVAL (yhi), SImode); if (!arm_add_operand (yhi, SImode)) yhi = force_reg (SImode, yhi); emit_insn (gen_addsi3 (scratch, xhi, yhi)); @@ -15445,7 +15450,7 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) else { gcc_assert (yhi == const0_rtx); - ylo = GEN_INT (-INTVAL(ylo)); + ylo = gen_int_mode (-INTVAL (ylo), SImode); if (!arm_add_operand (ylo, SImode)) ylo = force_reg (SImode, ylo); emit_insn (gen_addsi3 (scratch, xlo, ylo)); @@ -15458,6 +15463,8 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) x = gen_rtx_IOR (SImode, gen_lowpart (SImode, x), gen_highpart (SImode, x)); } + else if (!cmpdi_operand (y, mode)) + y = force_reg (DImode, y); /* A scratch register is required. */ if (reload_completed) @@ -15470,7 +15477,12 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch) emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber))); } else - emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y)); + { + if (!cmpdi_operand (y, mode)) + y = force_reg (DImode, y); + + emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y)); + } return cc_reg; } @@ -30479,10 +30491,7 @@ arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2) return true; case E_DImode: - if (!cmpdi_operand (*op1, mode)) - *op1 = force_reg (mode, *op1); - if (!cmpdi_operand (*op2, mode)) - *op2 = force_reg (mode, *op2); + /* gen_compare_reg() will sort out any invalid operands. */ return true; case E_HFmode: diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index a6b0c19..9d8b137 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -6397,7 +6397,7 @@ [(set (pc) (if_then_else (match_operator 0 "expandable_comparison_operator" [(match_operand:DI 1 "s_register_operand") - (match_operand:DI 2 "cmpdi_operand")]) + (match_operand:DI 2 "reg_or_int_operand")]) (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_32BIT" @@ -6862,7 +6862,7 @@ [(set (match_operand:SI 0 "s_register_operand") (match_operator:SI 1 "expandable_comparison_operator" [(match_operand:DI 2 "s_register_operand") - (match_operand:DI 3 "cmpdi_operand")]))] + (match_operand:DI 3 "reg_or_int_operand")]))] "TARGET_32BIT" "{ if (!arm_validize_comparison (&operands[1], |