From 22060d0e575e7754eb1355763d22bbe37c3caa13 Mon Sep 17 00:00:00 2001 From: Richard Earnshaw Date: Fri, 18 Oct 2019 19:03:35 +0000 Subject: [PATCH] [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 const) into (reg (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 --- gcc/ChangeLog | 14 ++++++++++++++ gcc/config/arm/arm.c | 37 +++++++++++++++++++++++-------------- gcc/config/arm/arm.md | 4 ++-- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 51a2c3f2ed0..52d14e92e64 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2019-10-18 Richard Earnshaw + + * 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. + 2019-10-18 Richard Earnshaw * config/arm/arm.c (arm_select_cc_mode): For DImode equality tests diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 97ebf638988..e7924df9b80 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 a6b0c196c58..9d8b137651f 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], -- 2.30.2