On Mon, Sep 28, 2026 at 10:44 AM Dominic P <[email protected]> wrote:
>
> 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
> a vec instead; the work stays linear in the number of uses.
>
> 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 (default and Thumb-2 hard-float boards, arm1176
> qemu for execution) and aarch64-linux-gnu (qemu).
>
> Assisted-by: Claude Opus 5 (Anthropic)
>
> gcc/ChangeLog:
>
>         * compare-elim.cc (MAX_CMP_USE): Remove.
>         (struct comparison): Make uses a vec.  Remove n_uses.
>         (find_flags_uses_in_insn): Do not limit the number of uses.
>         (maybe_select_cc_mode): Use uses.length ().
>         (execute_compare_elim_after_reload): Release the uses.

I Know not having a restricted value is better.  Though I wonder 2
things.  What is the max have you seen in the wild?  Maybe an increase
to 5 or 6 should be enough for most things.
A few comments below.

>
> 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]>
> ---
> OK for trunk?
>
>  gcc/compare-elim.cc                           | 27 +++-----------
>  .../gcc.target/aarch64/cmpelim_mult_uses_2.c  | 36 +++++++++++++++++++
>  .../gcc.target/arm/cmpelim_mult_uses_1.c      | 31 ++++++++++++++++
>  3 files changed, 72 insertions(+), 22 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..1737eddb9f8 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];
> +  vec<comparison_use> uses;

Hmm,  I would have expected an auto_vec here but maybe I am wrong.
Also would it make sense to reserve space at the allocation of the vec
so a safe_push up to a specific amount is basically "free".
That is after:
last_cmp = XCNEW (struct comparison);
Do:
last_cmp->uses.reserve(3);

So at least the original speed is similar.

>
>    /* 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 ({ insn, loc, GET_CODE (x) });
cmp->uses.safe_push (comparison_use{ insn, loc, GET_CODE (x) });

Just so it is obvious what the struct is.

>           }
>         else
>           goto fail;
> @@ -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,6 +907,7 @@ execute_compare_elim_after_reload (void)
>        FOR_EACH_VEC_ELT (all_compares, i, cmp)
>         {
>           try_eliminate_compare (cmp);
> +         cmp->uses.release ();
>           XDELETE (cmp);
>         }
>
> 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
>

Reply via email to