Re: [PATCH 1/6] ccmp: Preserve traps from conditional comparisons

Andrea Pinski <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <CALvbMcCo9X-pF4wzfJ7f917zibX0zpwBeVFkS+oXLZLkogE3yg@mail.gmail.com>
On Mon, Aug 10, 2026 at 6:24 AM <[email protected]> wrote:
>
> From: Kyrylo Tkachov <[email protected]>
>
> A conditional comparison can skip its comparison operand.  This is not valid
> when the source evaluates both comparisons and the skipped comparison can
> trap.  For example:
>
>   int
>   f (double a, double b, double c, double d)
>   {
>     return (a < b) & (c < d);
>   }
>
> At -O2, AArch64 emitted:
>
>         fcmpe   d0, d1
>         fccmpe  d2, d3, 0, mi
>         cset    w0, mi
>
> If a < b is false, FCCMPE does not compare c and d.  A quiet NaN in c or d
> therefore does not raise Invalid, although bitwise AND evaluates both
> operands.  After this patch GCC emits:
>
>         fcmpe   d0, d1
>         cset    w1, mi
>         fcmpe   d2, d3
>         cset    w0, mi
>         and     w0, w1, w0
>
> Reject a potentially trapping comparison from every conditional position.
> A trapping comparison can still lead the sequence because the first
> comparison always executes.
>
> The runtime test clears FPSR with the AArch64 builtins and verifies that an
> ordered comparison with a quiet NaN raises Invalid.  The compile test covers
> signalling NaNs.
>
> Bootstrapped and tested on aarch64-none-linux-gnu.
> Ok for trunk?
> Thanks,
> Kyrill
>
> gcc/
>
>         * ccmp.cc (expand_ccmp_next): Reject a comparison that can trap.

I think it should be the target that rejects it and not the middle-end.
I think x86_64 rejects floating point types for ccmp_next already though.

>
> gcc/testsuite/
>
>         * gcc.target/aarch64/fccmp-trap-1.c: New test.
>         * gcc.target/aarch64/fccmp-trap-2.c: Likewise.
>
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
>  gcc/ccmp.cc                                   |  6 +++++
>  .../gcc.target/aarch64/fccmp-trap-1.c         | 25 +++++++++++++++++++
>  .../gcc.target/aarch64/fccmp-trap-2.c         | 12 +++++++++
>  3 files changed, 43 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c
>  create mode 100644 gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c
>
> diff --git a/gcc/ccmp.cc b/gcc/ccmp.cc
> index 0564ccf34bf..f63e44dcc84 100644
> --- a/gcc/ccmp.cc
> +++ b/gcc/ccmp.cc
> @@ -168,6 +168,12 @@ expand_ccmp_next (tree op, tree_code code, rtx prev,
>    rtx_code rcode;
>    tree rhs1, rhs2;
>
> +  /* A conditional comparison can skip OP.  Only the first comparison can
> +     therefore have observable traps.  */
> +  gimple *g = get_gimple_for_ssa_name (op);
> +  if (g && gimple_assign_rhs_could_trap_p (g))
> +    return NULL_RTX;
> +
>    get_compare_parts (op, &rcode, &rhs1, &rhs2);
>    return targetm.gen_ccmp_next (prep_seq, gen_seq, prev, rcode,
>                                 rhs1, rhs2, get_rtx_code (code, 0));
> diff --git a/gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c
> new file mode 100644
> index 00000000000..1d151f2f056
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-1.c
> @@ -0,0 +1,25 @@
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +enum { FPSR_IOC = 1 << 0 };
> +
> +__attribute__ ((noipa))
> +static int
> +and_lt (double a, double b, double c, double d)
> +{
> +  return (a < b) & (c < d);
> +}
> +
> +int
> +main (void)
> +{
> +  double qnan = __builtin_nan ("");
> +
> +  __builtin_aarch64_set_fpsr (0);
> +  if (and_lt (1.0, 0.0, qnan, 0.0) != 0)
> +    __builtin_abort ();
> +  if ((__builtin_aarch64_get_fpsr () & FPSR_IOC) == 0)
> +    __builtin_abort ();
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c
> new file mode 100644
> index 00000000000..4b48fe5b6aa
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/fccmp-trap-2.c
> @@ -0,0 +1,12 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fsignaling-nans" } */
> +
> +int
> +and_eq (double a, double b, double c, double d)
> +{
> +  return (a == b) & (c == d);
> +}
> +
> +/* Both comparisons can raise an exception for a signaling NaN.  */
> +/* { dg-final { scan-assembler-not {\tfccmp} } } */
> +/* { dg-final { scan-assembler-times {\tfcmp\td[0-9]+, d[0-9]+} 2 } } */
> --
> 2.50.1 (Apple Git-155)
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.