Skip to content

Commit 1790ea2

Browse files
author
rearnsha
committed
[arm] Early split simple DImode equality comparisons
This is the first step of early splitting all the DImode comparison operations. We start by factoring the DImode handling out of arm_gen_compare_reg into its own function. Simple DImode equality comparisions (such as equality with zero, or equality with a constant that is zero in one of the two word values that it comprises) can be done using a single subtract followed by an ORRS instruction. This avoids the need for conditional execution. For example, (r0 != 5) can be written as SUB Rt, R0, gcc-mirror#5 ORRS Rt, Rt, R1 The ORRS is now expanded using an SImode pattern that already exists in the MD file and this gives the register allocator more freedom to select registers (consecutive pairs are no-longer required). Furthermore, we can then delete the arm_cmpdi_zero pattern as it is no-longer required. We use SUB for the value adjustment as this has a generally more flexible range of immediates than XOR and what's more has the opportunity to be relaxed in thumb2 to a 16-bit SUBS instruction. * config/arm/arm.c (arm_select_cc_mode): For DImode equality tests return CC_Zmode if comparing against a constant where one word is zero. (arm_gen_compare_reg): Split DImode handling to ... (arm_gen_dicompare_reg): ... here. Handle equality comparisons against simple constants. * config/arm/arm.md (arm_cmpdi_zero): Delete pattern. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@277177 138bc75d-0d04-0410-961f-82ee72b054a4
1 parent 263f9e4 commit 1790ea2

File tree

3 files changed

+78
-30
lines changed

3 files changed

+78
-30
lines changed

gcc/ChangeLog

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2019-10-18 Richard Earnshaw <[email protected]>
2+
3+
* config/arm/arm.c (arm_select_cc_mode): For DImode equality tests
4+
return CC_Zmode if comparing against a constant where one word is
5+
zero.
6+
(arm_gen_compare_reg): Split DImode handling to ...
7+
(arm_gen_dicompare_reg): ... here. Handle equality comparisons
8+
against simple constants.
9+
* config/arm/arm.md (arm_cmpdi_zero): Delete pattern.
10+
111
2019-10-18 Richard Earnshaw <[email protected]>
212

313
* config/arm/arm.md (subsi3_carryin_shift_alt): New pattern.

gcc/config/arm/arm.c

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15350,8 +15350,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1535015350
case EQ:
1535115351
case NE:
1535215352
/* A DImode comparison against zero can be implemented by
15353-
or'ing the two halves together. */
15354-
if (y == const0_rtx)
15353+
or'ing the two halves together. We can also handle
15354+
immediates where one word of that value is zero by
15355+
subtracting the non-zero word from the corresponding word
15356+
in the other register and then ORRing it with the other
15357+
word. */
15358+
if (CONST_INT_P (y)
15359+
&& ((UINTVAL (y) & 0xffffffff) == 0
15360+
|| (UINTVAL (y) >> 32) == 0))
1535515361
return CC_Zmode;
1535615362

1535715363
/* We can do an equality test in three Thumb instructions. */
@@ -15393,37 +15399,64 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
1539315399
return CCmode;
1539415400
}
1539515401

15396-
/* X and Y are two things to compare using CODE. Emit the compare insn and
15397-
return the rtx for register 0 in the proper mode. FP means this is a
15398-
floating point compare: I don't think that it is needed on the arm. */
15399-
rtx
15400-
arm_gen_compare_reg (enum rtx_code code, rtx x, rtx y, rtx scratch)
15402+
/* X and Y are two (DImode) things to compare for the condition CODE. Emit
15403+
the sequence of instructions needed to generate a suitable condition
15404+
code register. Return the CC register result. */
15405+
static rtx
15406+
arm_gen_dicompare_reg (rtx_code code, rtx x, rtx y, rtx scratch)
1540115407
{
15402-
machine_mode mode;
15403-
rtx cc_reg;
15404-
int dimode_comparison = GET_MODE (x) == DImode || GET_MODE (y) == DImode;
15408+
/* We don't currently handle DImode in thumb1, but rely on libgcc. */
15409+
gcc_assert (TARGET_32BIT);
1540515410

1540615411
/* We might have X as a constant, Y as a register because of the predicates
1540715412
used for cmpdi. If so, force X to a register here. */
15408-
if (dimode_comparison && !REG_P (x))
15413+
if (!REG_P (x))
1540915414
x = force_reg (DImode, x);
1541015415

15411-
mode = SELECT_CC_MODE (code, x, y);
15412-
cc_reg = gen_rtx_REG (mode, CC_REGNUM);
15416+
machine_mode mode = SELECT_CC_MODE (code, x, y);
15417+
rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
1541315418

15414-
if (dimode_comparison
15415-
&& mode != CC_CZmode)
15419+
if (mode != CC_CZmode)
1541615420
{
1541715421
rtx clobber, set;
1541815422

1541915423
/* To compare two non-zero values for equality, XOR them and
1542015424
then compare against zero. Not used for ARM mode; there
1542115425
CC_CZmode is cheaper. */
15422-
if (mode == CC_Zmode && y != const0_rtx)
15426+
if (mode == CC_Zmode)
1542315427
{
15424-
gcc_assert (!reload_completed);
15425-
x = expand_binop (DImode, xor_optab, x, y, NULL_RTX, 0, OPTAB_WIDEN);
15426-
y = const0_rtx;
15428+
mode = CC_NOOVmode;
15429+
PUT_MODE (cc_reg, mode);
15430+
if (y != const0_rtx)
15431+
{
15432+
gcc_assert (CONST_INT_P (y));
15433+
rtx xlo, xhi, ylo, yhi;
15434+
arm_decompose_di_binop (x, y, &xlo, &xhi, &ylo, &yhi);
15435+
if (!scratch)
15436+
scratch = gen_reg_rtx (SImode);
15437+
if (ylo == const0_rtx)
15438+
{
15439+
yhi = GEN_INT (-INTVAL(yhi));
15440+
if (!arm_add_operand (yhi, SImode))
15441+
yhi = force_reg (SImode, yhi);
15442+
emit_insn (gen_addsi3 (scratch, xhi, yhi));
15443+
y = xlo;
15444+
}
15445+
else
15446+
{
15447+
gcc_assert (yhi == const0_rtx);
15448+
ylo = GEN_INT (-INTVAL(ylo));
15449+
if (!arm_add_operand (ylo, SImode))
15450+
ylo = force_reg (SImode, ylo);
15451+
emit_insn (gen_addsi3 (scratch, xlo, ylo));
15452+
y = xhi;
15453+
}
15454+
x = gen_rtx_IOR (SImode, scratch, y);
15455+
y = const0_rtx;
15456+
}
15457+
else
15458+
x = gen_rtx_IOR (SImode, gen_lowpart (SImode, x),
15459+
gen_highpart (SImode, x));
1542715460
}
1542815461

1542915462
/* A scratch register is required. */
@@ -15442,6 +15475,22 @@ arm_gen_compare_reg (enum rtx_code code, rtx x, rtx y, rtx scratch)
1544215475
return cc_reg;
1544315476
}
1544415477

15478+
/* X and Y are two things to compare using CODE. Emit the compare insn and
15479+
return the rtx for register 0 in the proper mode. */
15480+
rtx
15481+
arm_gen_compare_reg (rtx_code code, rtx x, rtx y, rtx scratch)
15482+
{
15483+
if (GET_MODE (x) == DImode || GET_MODE (y) == DImode)
15484+
return arm_gen_dicompare_reg (code, x, y, scratch);
15485+
15486+
machine_mode mode = SELECT_CC_MODE (code, x, y);
15487+
rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
15488+
15489+
emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
15490+
15491+
return cc_reg;
15492+
}
15493+
1544515494
/* Generate a sequence of insns that will generate the correct return
1544615495
address mask depending on the physical architecture that the program
1544715496
is running on. */

gcc/config/arm/arm.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6518,17 +6518,6 @@
65186518
(set_attr "type" "multiple")]
65196519
)
65206520

6521-
(define_insn "*arm_cmpdi_zero"
6522-
[(set (reg:CC_Z CC_REGNUM)
6523-
(compare:CC_Z (match_operand:DI 0 "s_register_operand" "r")
6524-
(const_int 0)))
6525-
(clobber (match_scratch:SI 1 "=r"))]
6526-
"TARGET_32BIT"
6527-
"orrs%?\\t%1, %Q0, %R0"
6528-
[(set_attr "conds" "set")
6529-
(set_attr "type" "logics_reg")]
6530-
)
6531-
65326521
; This insn allows redundant compares to be removed by cse, nothing should
65336522
; ever appear in the output file since (set (reg x) (reg x)) is a no-op that
65346523
; is deleted later on. The match_dup will match the mode here, so that

0 commit comments

Comments
 (0)