After three uses find_flags_uses_in_insn gives up and marks the uses
of a compare as unknown, so try_eliminate_compare keeps the original
CC mode and fails when the arithmetic only sets a narrower one, as
ANDS, ADDS and SUBS do on Arm and AArch64. Four conditional moves or
csels fed by one "and; cmp #0" keep the compare. Record the uses in
an auto_vec with inline room for three, so the common case still
needs no heap allocation.
Arm -O2 Linux .text: bcmrpi_defconfig -68 B (13 functions shrink, none
grow), bcm2709_defconfig -44 B. No gcc.c-torture asm change on x86_64
or AArch64.
Bootstrapped and regression tested on x86_64-pc-linux-gnu; regression
tested on arm-none-eabi and aarch64-linux-gnu.
Assisted-by: Claude Opus 5 (Anthropic)
gcc/ChangeLog:
* compare-elim.cc (MAX_CMP_USE): Remove.
(struct comparison): Make uses an auto_vec. Remove n_uses.
(find_flags_uses_in_insn): Do not limit the number of uses.
(maybe_select_cc_mode): Use uses.length ().
(find_comparison_dom_walker::before_dom_children): Allocate
comparisons with new.
(execute_compare_elim_after_reload): Free them with delete.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/cmpelim_mult_uses_2.c: New test.
* gcc.target/arm/cmpelim_mult_uses_1.c: New test.
Signed-off-by: Dominic P <[email protected]>
---
Changes in v2, from Andrea Pinski's review:
- uses is an auto_vec<comparison_use, 3>, so up to three uses need no
allocation, as before; hence new/delete in place of XCNEW.
- The push names comparison_use.
Uses seen: at most 7 on one compare (none eliminated); each
Arm kernel has 11 eliminations needing more than 3 uses, 4 of them 5
(e.g. fbcon_resize), and nothing needed 6. So 5 would cover all I saw
(two Arm kernels, two Arm firmwares, gcc.c-torture on Arm, AArch64 and
x86_64, ten large GCC sources), but unlimited costs nothing: 158 of
bcmrpi's 187,237 compares need the heap, and cc1plus time on
insn-recog-3.cc is unchanged.
x86_64 bootstrap and regression test redone; the Arm and AArch64 runs
are v1's, as v2 generates identical gcc.c-torture asm on all three.
OK for trunk?
gcc/compare-elim.cc | 30 ++++------------
.../gcc.target/aarch64/cmpelim_mult_uses_2.c | 36 +++++++++++++++++++
.../gcc.target/arm/cmpelim_mult_uses_1.c | 31 ++++++++++++++++
3 files changed, 73 insertions(+), 24 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_2.c
create mode 100644 gcc/testsuite/gcc.target/arm/cmpelim_mult_uses_1.c
diff --git a/gcc/compare-elim.cc b/gcc/compare-elim.cc
index 6218324e1ab..560b7ee7919 100644
--- a/gcc/compare-elim.cc
+++ b/gcc/compare-elim.cc
@@ -71,12 +71,6 @@ along with GCC; see the file COPYING3. If not see
/* These structures describe a comparison and how it is used. */
-/* The choice of maximum 3 uses comes from wanting to eliminate the two
- duplicate compares from a three-way branch on the sign of a value.
- This is also sufficient to eliminate the duplicate compare against the
- high-part of a double-word comparison. */
-#define MAX_CMP_USE 3
-
struct comparison_use
{
/* The instruction in which the result of the compare is used. */
@@ -106,17 +100,12 @@ struct comparison
rtx eh_note;
/* Information about how this comparison is used. */
- struct comparison_use uses[MAX_CMP_USE];
+ auto_vec<comparison_use, 3> uses;
/* The original CC_MODE for this comparison. */
machine_mode orig_mode;
- /* The number of uses identified for this comparison. */
- unsigned short n_uses;
-
- /* True if not all uses of this comparison have been identified.
- This can happen either for overflowing the array above, or if
- the flags register is used in some unusual context. */
+ /* True if not all uses of this comparison have been identified. */
bool missing_uses;
/* True if its inputs are still valid at the end of the block. */
@@ -243,10 +232,6 @@ find_flags_uses_in_insn (struct comparison *cmp, rtx_insn
*insn)
if (DF_REF_TYPE (use) != DF_REF_REG_USE)
goto fail;
- /* If we've run out of slots to record uses, quit. */
- if (cmp->n_uses == MAX_CMP_USE)
- goto fail;
-
/* Unfortunately the location of the flags register, while present
in the reference structure, doesn't help. We need to find the
comparison code that is outer to the actual flags use. */
@@ -265,10 +250,7 @@ find_flags_uses_in_insn (struct comparison *cmp, rtx_insn
*insn)
&& XEXP (x, 1) == const0_rtx)
{
/* We've found a use of the flags that we understand. */
- struct comparison_use *cuse = &cmp->uses[cmp->n_uses++];
- cuse->insn = insn;
- cuse->loc = loc;
- cuse->code = GET_CODE (x);
+ cmp->uses.safe_push (comparison_use { insn, loc, GET_CODE (x) });
}
else
goto fail;
@@ -388,7 +370,7 @@ find_comparison_dom_walker::before_dom_children
(basic_block bb)
continue;
}
- last_cmp = XCNEW (struct comparison);
+ last_cmp = new comparison ();
last_cmp->insn = insn;
last_cmp->prev_clobber = last_clobber;
last_cmp->in_a = strip_not (XEXP (src, 0));
@@ -508,7 +490,7 @@ maybe_select_cc_mode (struct comparison *cmp, rtx a
ATTRIBUTE_UNUSED,
rtx b ATTRIBUTE_UNUSED)
{
machine_mode sel_mode;
- const int n = cmp->n_uses;
+ const int n = cmp->uses.length ();
rtx flags = NULL;
#ifndef SELECT_CC_MODE
@@ -925,7 +907,7 @@ execute_compare_elim_after_reload (void)
FOR_EACH_VEC_ELT (all_compares, i, cmp)
{
try_eliminate_compare (cmp);
- XDELETE (cmp);
+ delete cmp;
}
all_compares.release ();
diff --git a/gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_2.c
b/gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_2.c
new file mode 100644
index 00000000000..3153956cdd3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_2.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** f:
+** ands w0, w0, w1
+** ...
+*/
+int
+f (int x, int y, int a, int b, int c, int d, int *p)
+{
+ int t = x & y;
+ p[0] = t ? a : b;
+ p[1] = t ? b : c;
+ p[2] = t ? c : d;
+ p[3] = t ? d : a;
+ return t;
+}
+
+/*
+** g:
+** subs x0, x0, x1
+** ...
+*/
+long long
+g (long long x, long long y, long long a, long long b, long long c,
+ long long d, long long *p)
+{
+ long long t = x - y;
+ p[0] = t ? a : b;
+ p[1] = t ? b : c;
+ p[2] = t ? c : d;
+ p[3] = t ? d : a;
+ return t;
+}
diff --git a/gcc/testsuite/gcc.target/arm/cmpelim_mult_uses_1.c
b/gcc/testsuite/gcc.target/arm/cmpelim_mult_uses_1.c
new file mode 100644
index 00000000000..b64914d5389
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/cmpelim_mult_uses_1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm32 } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** f:
+** ands r0, r0, #2097152
+** ...
+*/
+void
+f (unsigned x, int *p, int *q)
+{
+ int t = x & (1 << 21);
+ *p = t ? 3 : 1;
+ *q = t ? 2 : 0;
+}
+
+/*
+** g:
+** adds r0, r0, r1
+** ...
+*/
+int
+g (int x, int y, int *p, int *q)
+{
+ int t = x + y;
+ *p = t ? 3 : 1;
+ *q = t ? 5 : 0;
+ return t;
+}
--
2.55.0