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)
>

Reply via email to