On Wed Oct 14, 2026 at 12:29 AM PDT, Hongyu Wang wrote:
> Hi,
>
> LTGT is a signaling compare and must raise FE_INVALID on a quiet NaN,
> like the scalar comiss it expands to. The vector expansion used quiet
> compares instead: NEQ_OQ for AVX and AVX512, and ORDERED & NE for SSE.
>
> Use the signaling NEQ_OS predicate for AVX and AVX512. Legacy SSE has
> no ordered not-equal predicate, so expand LTGT as LT | GT, which uses
> the signaling cmpltps and needs no extra instruction.
>
> Bootstrapped & regtested on x86_64-pc-linux-gnu{-m32,}.
>
> Ok for trunk?
Ok.

>
> gcc/ChangeLog:
>
>       PR target/127649
>       * config/i386/i386-expand.cc (ix86_fp_cmp_code_to_pcmp_immediate):
>       Use NEQ_OS for LTGT.
>       (ix86_expand_fp_vec_cmp): Expand LTGT as LT | GT.
>       * config/i386/i386.cc (ix86_print_operand): Print neq_os for LTGT.
>
> gcc/testsuite/ChangeLog:
>
>       PR target/127649
>       * gcc.target/i386/pr127649-1.c: New test.
>       * gcc.target/i386/pr127649-2.c: Likewise.
> ---
>  gcc/config/i386/i386-expand.cc             | 10 ++---
>  gcc/config/i386/i386.cc                    |  2 +-
>  gcc/testsuite/gcc.target/i386/pr127649-1.c | 37 +++++++++++++++++
>  gcc/testsuite/gcc.target/i386/pr127649-2.c | 46 ++++++++++++++++++++++
>  4 files changed, 89 insertions(+), 6 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr127649-1.c
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr127649-2.c
>
> diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
> index a81993c29c5..98f8111e539 100644
> --- a/gcc/config/i386/i386-expand.cc
> +++ b/gcc/config/i386/i386-expand.cc
> @@ -4818,7 +4818,7 @@ ix86_fp_cmp_code_to_pcmp_immediate (enum rtx_code code)
>      case UNEQ:
>        return 0x08;
>      case LTGT:
> -      return 0x0c;
> +      return 0x1c;
>      case ORDERED:
>        return 0x07;
>      case UNORDERED:
> @@ -4886,11 +4886,11 @@ ix86_expand_fp_vec_cmp (rtx operands[])
>        switch (GET_CODE (operands[1]))
>       {
>       case LTGT:
> -       temp = ix86_expand_sse_cmp (operands[0], ORDERED, operands[2],
> +       temp = ix86_expand_sse_cmp (operands[0], LT, operands[2],
>                                     operands[3], NULL, NULL);
> -       cmp = ix86_expand_sse_cmp (operands[0], NE, operands[2],
> -                                  operands[3], NULL, NULL);
> -       code = AND;
> +       cmp = ix86_expand_sse_cmp (operands[0], LT, operands[3],
> +                                  operands[2], NULL, NULL);
> +       code = IOR;
>         break;
>       case UNEQ:
>         temp = ix86_expand_sse_cmp (operands[0], UNORDERED, operands[2],
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index 553fa046fa9..218a59a6c1d 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -14545,7 +14545,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
>           case LTGT:
>             if (TARGET_AVX)
>               {
> -               fputs ("neq_oq", file);
> +               fputs ("neq_os", file);
>                 break;
>               }
>            /* FALLTHRU */
> diff --git a/gcc/testsuite/gcc.target/i386/pr127649-1.c 
> b/gcc/testsuite/gcc.target/i386/pr127649-1.c
> new file mode 100644
> index 00000000000..e1b1cb981dc
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr127649-1.c
> @@ -0,0 +1,37 @@
> +/* PR target/127649 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -msse2 -mno-avx" } */
> +
> +/* LTGT is a signaling compare.  Use LT | GT for SSE and the NEQ_OS
> +   predicate for AVX.  */
> +
> +void
> +ltgt_sse (int *r, float *a, float *b)
> +{
> +  for (int i = 0; i < 1024; i++)
> +    r[i] = (a[i] < b[i]) | (a[i] > b[i]);
> +}
> +
> +__attribute__((target ("avx,no-avx512f")))
> +void
> +ltgt_avx (int *r, float *a, float *b)
> +{
> +  for (int i = 0; i < 1024; i++)
> +    r[i] = (a[i] < b[i]) | (a[i] > b[i]);
> +}
> +
> +__attribute__((target ("avx512vl")))
> +void
> +ltgt_avx512 (int *r, float *a, float *b)
> +{
> +  for (int i = 0; i < 1024; i++)
> +    r[i] = (a[i] < b[i]) | (a[i] > b[i]);
> +}
> +
> +/* { dg-final { scan-assembler-times "\[ \t\]cmpltps" 2 } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]cmpordps" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]cmpneqps" } } */
> +/* { dg-final { scan-assembler-times "vcmpneq_osps" 1 } } */
> +/* { dg-final { scan-assembler-times "vcmpps\[ \t\]*\\\$28," 1 } } */
> +/* { dg-final { scan-assembler-not "vcmpneq_oqps" } } */
> +/* { dg-final { scan-assembler-not "vcmpps\[ \t\]*\\\$12," } } */
> diff --git a/gcc/testsuite/gcc.target/i386/pr127649-2.c 
> b/gcc/testsuite/gcc.target/i386/pr127649-2.c
> new file mode 100644
> index 00000000000..04d74a22936
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr127649-2.c
> @@ -0,0 +1,46 @@
> +/* PR target/127649 */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -msse2 -mno-avx" } */
> +/* { dg-require-effective-target fenv_exceptions } */
> +/* { dg-additional-options "-mfpmath=sse" { target ia32 } } */
> +
> +#include <fenv.h>
> +#include "pr127649-1.c"
> +
> +#define N 1024
> +
> +static float a[N], b[N];
> +static int r[N];
> +
> +static void
> +check (void (*fn) (int *, float *, float *))
> +{
> +  for (int i = 0; i < N; i++)
> +    r[i] = -1;
> +  feclearexcept (FE_ALL_EXCEPT);
> +  fn (r, a, b);
> +  if (!fetestexcept (FE_INVALID))
> +    __builtin_abort ();
> +  for (int i = 0; i < N; i++)
> +    if (r[i] != 0)
> +      __builtin_abort ();
> +}
> +
> +int
> +main (void)
> +{
> +  __builtin_cpu_init ();
> +
> +  for (int i = 0; i < N; i++)
> +    {
> +      a[i] = __builtin_nanf ("");
> +      b[i] = 1.0f;
> +    }
> +
> +  check (ltgt_sse);
> +  if (__builtin_cpu_supports ("avx"))
> +    check (ltgt_avx);
> +  if (__builtin_cpu_supports ("avx512vl"))
> +    check (ltgt_avx512);
> +  return 0;
> +}
> -- 
> 2.31.1

Reply via email to