aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorRichard Earnshaw <rearnsha@arm.com>2019-10-18 19:03:35 +0000
committerRichard Earnshaw <rearnsha@gcc.gnu.org>2019-10-18 19:03:35 +0000
commit22060d0e575e7754eb1355763d22bbe37c3caa13 (patch)
tree3b043d4b797da18e48a2963b8c3b12f8102d6769 /gcc/config
parent5899656b61231cc0e2dac4d7a58fab58674ba344 (diff)
downloadgcc-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.c37
-rw-r--r--gcc/config/arm/arm.md4
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],