Skip to content

Commit d6852b4

Browse files
author
rearnsha
committed
[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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@277178 138bc75d-0d04-0410-961f-82ee72b054a4
1 parent 1790ea2 commit d6852b4

File tree

3 files changed

+39
-16
lines changed

3 files changed

+39
-16
lines changed

gcc/ChangeLog

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
2019-10-18 Richard Earnshaw <[email protected]>
2+
3+
* config/arm/arm.md (cbranchdi4): Accept reg_or_int_operand for
4+
operand 2.
5+
(cstoredi4): Similarly, but for operand 3.
6+
* config/arm/arm.c (arm_canoncialize_comparison): Allow
7+
canonicalization of unsigned compares with a constant on Arm.
8+
Prefer using const+1 and adjusting the comparison over swapping the
9+
operands whenever the original constant was not valid.
10+
(arm_gen_dicompare_reg): If Y is not a valid operand, force it to a
11+
register here.
12+
(arm_validize_comparison): Do not force invalid DImode operands to
13+
registers here.
14+
115
2019-10-18 Richard Earnshaw <[email protected]>
216

317
* config/arm/arm.c (arm_select_cc_mode): For DImode equality tests

gcc/config/arm/arm.c

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5372,15 +5372,16 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
53725372

53735373
maxval = (HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (mode) - 1)) - 1;
53745374

5375-
/* For DImode, we have GE/LT/GEU/LTU comparisons. In ARM mode
5376-
we can also use cmp/cmpeq for GTU/LEU. GT/LE must be either
5377-
reversed or (for constant OP1) adjusted to GE/LT. Similarly
5378-
for GTU/LEU in Thumb mode. */
5375+
/* For DImode, we have GE/LT/GEU/LTU comparisons (with cmp/sbc). In
5376+
ARM mode we can also use cmp/cmpeq for GTU/LEU. GT/LE must be
5377+
either reversed or (for constant OP1) adjusted to GE/LT.
5378+
Similarly for GTU/LEU in Thumb mode. */
53795379
if (mode == DImode)
53805380
{
53815381

53825382
if (*code == GT || *code == LE
5383-
|| (!TARGET_ARM && (*code == GTU || *code == LEU)))
5383+
|| ((!TARGET_ARM || CONST_INT_P (*op1))
5384+
&& (*code == GTU || *code == LEU)))
53845385
{
53855386
/* Missing comparison. First try to use an available
53865387
comparison. */
@@ -5392,23 +5393,27 @@ arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
53925393
case GT:
53935394
case LE:
53945395
if (i != maxval
5395-
&& arm_const_double_by_immediates (GEN_INT (i + 1)))
5396+
&& (!arm_const_double_by_immediates (*op1)
5397+
|| arm_const_double_by_immediates (GEN_INT (i + 1))))
53965398
{
53975399
*op1 = GEN_INT (i + 1);
53985400
*code = *code == GT ? GE : LT;
53995401
return;
54005402
}
54015403
break;
5404+
54025405
case GTU:
54035406
case LEU:
54045407
if (i != ~((unsigned HOST_WIDE_INT) 0)
5405-
&& arm_const_double_by_immediates (GEN_INT (i + 1)))
5408+
&& (!arm_const_double_by_immediates (*op1)
5409+
|| arm_const_double_by_immediates (GEN_INT (i + 1))))
54065410
{
54075411
*op1 = GEN_INT (i + 1);
54085412
*code = *code == GTU ? GEU : LTU;
54095413
return;
54105414
}
54115415
break;
5416+
54125417
default:
54135418
gcc_unreachable ();
54145419
}
@@ -15436,7 +15441,7 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch)
1543615441
scratch = gen_reg_rtx (SImode);
1543715442
if (ylo == const0_rtx)
1543815443
{
15439-
yhi = GEN_INT (-INTVAL(yhi));
15444+
yhi = gen_int_mode (-INTVAL (yhi), SImode);
1544015445
if (!arm_add_operand (yhi, SImode))
1544115446
yhi = force_reg (SImode, yhi);
1544215447
emit_insn (gen_addsi3 (scratch, xhi, yhi));
@@ -15445,7 +15450,7 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch)
1544515450
else
1544615451
{
1544715452
gcc_assert (yhi == const0_rtx);
15448-
ylo = GEN_INT (-INTVAL(ylo));
15453+
ylo = gen_int_mode (-INTVAL (ylo), SImode);
1544915454
if (!arm_add_operand (ylo, SImode))
1545015455
ylo = force_reg (SImode, ylo);
1545115456
emit_insn (gen_addsi3 (scratch, xlo, ylo));
@@ -15458,6 +15463,8 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch)
1545815463
x = gen_rtx_IOR (SImode, gen_lowpart (SImode, x),
1545915464
gen_highpart (SImode, x));
1546015465
}
15466+
else if (!cmpdi_operand (y, mode))
15467+
y = force_reg (DImode, y);
1546115468

1546215469
/* A scratch register is required. */
1546315470
if (reload_completed)
@@ -15470,7 +15477,12 @@ arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch)
1547015477
emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
1547115478
}
1547215479
else
15473-
emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
15480+
{
15481+
if (!cmpdi_operand (y, mode))
15482+
y = force_reg (DImode, y);
15483+
15484+
emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
15485+
}
1547415486

1547515487
return cc_reg;
1547615488
}
@@ -30479,10 +30491,7 @@ arm_validize_comparison (rtx *comparison, rtx * op1, rtx * op2)
3047930491
return true;
3048030492

3048130493
case E_DImode:
30482-
if (!cmpdi_operand (*op1, mode))
30483-
*op1 = force_reg (mode, *op1);
30484-
if (!cmpdi_operand (*op2, mode))
30485-
*op2 = force_reg (mode, *op2);
30494+
/* gen_compare_reg() will sort out any invalid operands. */
3048630495
return true;
3048730496

3048830497
case E_HFmode:

gcc/config/arm/arm.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6397,7 +6397,7 @@
63976397
[(set (pc) (if_then_else
63986398
(match_operator 0 "expandable_comparison_operator"
63996399
[(match_operand:DI 1 "s_register_operand")
6400-
(match_operand:DI 2 "cmpdi_operand")])
6400+
(match_operand:DI 2 "reg_or_int_operand")])
64016401
(label_ref (match_operand 3 "" ""))
64026402
(pc)))]
64036403
"TARGET_32BIT"
@@ -6862,7 +6862,7 @@
68626862
[(set (match_operand:SI 0 "s_register_operand")
68636863
(match_operator:SI 1 "expandable_comparison_operator"
68646864
[(match_operand:DI 2 "s_register_operand")
6865-
(match_operand:DI 3 "cmpdi_operand")]))]
6865+
(match_operand:DI 3 "reg_or_int_operand")]))]
68666866
"TARGET_32BIT"
68676867
"{
68686868
if (!arm_validize_comparison (&operands[1],

0 commit comments

Comments
 (0)