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