https://gcc.gnu.org/g:6d1b92ce276d4705b12c21723f94238a9d34b055
commit r17-4240-g6d1b92ce276d4705b12c21723f94238a9d34b055 Author: Hongyu Wang <[email protected]> Date: Thu Sep 10 15:50:06 2026 +0800 i386: Don't turn quiet FP comparisons into signaling ones [PR127177] The unordered compares (UNLT, UNLE, UNGT, UNGE and UNEQ) must not raise FE_INVALID on a quiet NaN. AVX and AVX512 have an imm8 encoding for the quiet _UQ predicate of each, so just select it. Legacy SSE2 has only 8 predicates and can express UNGE/UNGT/UNLT/UNLE only as the signaling NLT/NLE, so reject those four codes in the packed FP vec_cmp expanders when trapping math is in effect and NaNs are honored. gcc/ChangeLog: PR target/127177 * config/i386/i386-expand.cc (ix86_fp_cmp_code_to_pcmp_immediate): Return the _UQ predicate immediates for UNLE, UNLT, UNGE, UNGT and UNEQ. * config/i386/i386.cc (ix86_print_operand):Likewise to print the _uq suffixed AVX predicates for these codes. * config/i386/predicates.md (ix86_fp_vec_cmp_operator): New predicate. * config/i386/sse.md (vec_cmp<mode><sseintvecmodelower>): Use the new predicate for the VF_128 compare. * config/i386/mmx.md (vec_cmpv2sfv2si): Likewise. gcc/testsuite/ChangeLog: PR target/127177 * gcc.target/i386/pr127177-1.c: New test. * gcc.target/i386/pr127177-2.c: Likewise. * gcc.target/i386/pr127177-3.c: Likewise. * gcc.target/i386/pr127177-4.c: Likewise. * gcc.target/i386/pr127177-5.c: Likewise. Diff: --- gcc/config/i386/i386-expand.cc | 10 ++++---- gcc/config/i386/i386.cc | 11 +++++---- gcc/config/i386/mmx.md | 2 +- gcc/config/i386/predicates.md | 11 +++++++++ gcc/config/i386/sse.md | 2 +- gcc/testsuite/gcc.target/i386/pr127177-1.c | 27 +++++++++++++++++++++ gcc/testsuite/gcc.target/i386/pr127177-2.c | 13 ++++++++++ gcc/testsuite/gcc.target/i386/pr127177-3.c | 14 +++++++++++ gcc/testsuite/gcc.target/i386/pr127177-4.c | 9 +++++++ gcc/testsuite/gcc.target/i386/pr127177-5.c | 39 ++++++++++++++++++++++++++++++ 10 files changed, 126 insertions(+), 12 deletions(-) diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 68c6791c9928..1c049d0c4410 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -4803,15 +4803,15 @@ ix86_fp_cmp_code_to_pcmp_immediate (enum rtx_code code) case LT: return 0x01; case UNLE: - return 0x0a; + return 0x1a; case UNLT: - return 0x09; + return 0x19; case UNGE: - return 0x05; + return 0x15; case UNGT: - return 0x06; + return 0x16; case UNEQ: - return 0x18; + return 0x08; case LTGT: return 0x0c; case ORDERED: diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index a8edf28f687f..bbb60163a754 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -14485,7 +14485,7 @@ ix86_print_operand (FILE *file, rtx x, int code) case UNEQ: if (TARGET_AVX) { - fputs ("eq_us", file); + fputs ("eq_uq", file); break; } /* FALLTHRU */ @@ -14495,7 +14495,7 @@ ix86_print_operand (FILE *file, rtx x, int code) case UNLT: if (TARGET_AVX) { - fputs ("nge", file); + fputs ("nge_uq", file); break; } /* FALLTHRU */ @@ -14505,7 +14505,7 @@ ix86_print_operand (FILE *file, rtx x, int code) case UNLE: if (TARGET_AVX) { - fputs ("ngt", file); + fputs ("ngt_uq", file); break; } /* FALLTHRU */ @@ -14533,7 +14533,8 @@ ix86_print_operand (FILE *file, rtx x, int code) } /* FALLTHRU */ case UNGE: - fputs ("nlt", file); + /* Only AVX has the quiet form. */ + fputs (TARGET_AVX ? "nlt_uq" : "nlt", file); break; case GT: if (TARGET_AVX) @@ -14543,7 +14544,7 @@ ix86_print_operand (FILE *file, rtx x, int code) } /* FALLTHRU */ case UNGT: - fputs ("nle", file); + fputs (TARGET_AVX ? "nle_uq" : "nle", file); break; case ORDERED: fputs ("ord", file); diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md index 640b2c0e63f5..fc6286cfed2c 100644 --- a/gcc/config/i386/mmx.md +++ b/gcc/config/i386/mmx.md @@ -1254,7 +1254,7 @@ (define_expand "vec_cmpv2sfv2si" [(set (match_operand:V2SI 0 "register_operand") - (match_operator:V2SI 1 "" + (match_operator:V2SI 1 "ix86_fp_vec_cmp_operator" [(match_operand:V2SF 2 "nonimmediate_operand") (match_operand:V2SF 3 "nonimmediate_operand")]))] "TARGET_MMX_WITH_SSE && ix86_partial_vec_fp_math" diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index d295edd023de..2718232caf0f 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1568,6 +1568,17 @@ (and (match_test "TARGET_AVX") (match_code "ge,gt,uneq,unle,unlt,ltgt")))) +;; SSE2 doesn't have quiet vector compare for UNLT/UNLE/UNGT/UNGE, so reject +;; them in the packed FP vec_cmp expanders when trapping math is in effect +;; and NaNs are honored + +(define_predicate "ix86_fp_vec_cmp_operator" + (and (match_operand 0 "comparison_operator") + (ior (not (match_code "unlt,unle,ungt,unge")) + (match_test "TARGET_AVX") + (not (match_test "flag_trapping_math")) + (not (match_test "HONOR_NANS (GET_MODE (XEXP (op, 0)))"))))) + (define_predicate "ix86_comparison_int_operator" (match_code "ne,eq,ge,gt,le,lt")) diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index a19472d63aec..a02e061c35c3 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -5431,7 +5431,7 @@ (define_expand "vec_cmp<mode><sseintvecmodelower>" [(set (match_operand:<sseintvecmode> 0 "register_operand") - (match_operator:<sseintvecmode> 1 "" + (match_operator:<sseintvecmode> 1 "ix86_fp_vec_cmp_operator" [(match_operand:VF_128 2 "register_operand") (match_operand:VF_128 3 "vector_operand")]))] "TARGET_SSE" diff --git a/gcc/testsuite/gcc.target/i386/pr127177-1.c b/gcc/testsuite/gcc.target/i386/pr127177-1.c new file mode 100644 index 000000000000..979c677d3d6d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr127177-1.c @@ -0,0 +1,27 @@ +/* PR target/127177 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx -mno-avx512f -ftrapping-math -fdump-tree-vect-details" } */ + +/* The unordered compares are quiet, under AVX use the _uq predicates by + force. */ + +#define TEST(NAME, EXPR) \ + void NAME (int *r, float *a, float *b) \ + { \ + for (int i = 0; i < 1024; i++) \ + r[i] = EXPR; \ + } + +TEST (t_isless, __builtin_isless (a[i], b[i])) +TEST (t_islessequal, __builtin_islessequal (a[i], b[i])) +TEST (t_isgreater, __builtin_isgreater (a[i], b[i])) +TEST (t_isgreaterequal, __builtin_isgreaterequal (a[i], b[i])) +TEST (t_uneq, !__builtin_islessgreater (a[i], b[i])) + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 5 "vect" } } */ +/* { dg-final { scan-assembler-times "vcmpnlt_uqps" 2 } } */ +/* { dg-final { scan-assembler-times "vcmpnle_uqps" 2 } } */ +/* { dg-final { scan-assembler-times "vcmpeq_uqps" 1 } } */ +/* { dg-final { scan-assembler-not "vcmpnltps" } } */ +/* { dg-final { scan-assembler-not "vcmpnleps" } } */ +/* { dg-final { scan-assembler-not "vcmpeq_usps" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr127177-2.c b/gcc/testsuite/gcc.target/i386/pr127177-2.c new file mode 100644 index 000000000000..998ff323b7a9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr127177-2.c @@ -0,0 +1,13 @@ +/* PR target/127177 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -mavx512vl -ftrapping-math" } */ + +#include "pr127177-1.c" + +/* { dg-final { scan-assembler "vcmpps\[ \t\]*\\\$21," } } */ +/* { dg-final { scan-assembler "vcmpps\[ \t\]*\\\$22," } } */ +/* { dg-final { scan-assembler "vcmpps\[ \t\]*\\\$25," } } */ +/* { dg-final { scan-assembler "vcmpps\[ \t\]*\\\$26," } } */ +/* { dg-final { scan-assembler "vcmpps\[ \t\]*\\\$8," } } */ +/* { dg-final { scan-assembler-not "vcmpps\[ \t\]*\\\$\[569\]," } } */ +/* { dg-final { scan-assembler-not "vcmpps\[ \t\]*\\\$1\[08\]," } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr127177-3.c b/gcc/testsuite/gcc.target/i386/pr127177-3.c new file mode 100644 index 000000000000..8079f8cc7e52 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr127177-3.c @@ -0,0 +1,14 @@ +/* PR target/127177 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse2 -mno-avx -ftrapping-math -fdump-tree-vect-details" } */ +/* { dg-additional-options "-mfpmath=sse" { target ia32 } } */ + +/* With SSE2 only the unordered compares except UNEQ should not be vectorized under + -ftrapping-math, as they may raise FE_INVALID. */ + +#include "pr127177-1.c" + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ +/* { dg-final { scan-assembler-not "cmpnltps" } } */ +/* { dg-final { scan-assembler-not "cmpnleps" } } */ +/* { dg-final { scan-assembler "ucomiss" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr127177-4.c b/gcc/testsuite/gcc.target/i386/pr127177-4.c new file mode 100644 index 000000000000..96ec7ff88621 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr127177-4.c @@ -0,0 +1,9 @@ +/* PR target/127177 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -msse2 -mno-avx -fno-trapping-math -fdump-tree-vect-details" } */ + +/* Without -ftrapping-math the loops should be vectorized. */ + +#include "pr127177-1.c" + +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 5 "vect" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr127177-5.c b/gcc/testsuite/gcc.target/i386/pr127177-5.c new file mode 100644 index 000000000000..f388e0366ed0 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr127177-5.c @@ -0,0 +1,39 @@ +/* PR target/127177 */ +/* { dg-do run } */ +/* { dg-options "-O2 -msse2 -mno-avx -ftrapping-math" } */ +/* { dg-require-effective-target fenv_exceptions } */ +/* { dg-additional-options "-mfpmath=sse" { target ia32 } } */ + +#include <fenv.h> + +float a[64], b[64]; +int r[64]; + +__attribute__((noipa)) void +t_islessequal (int *r, float *a, float *b, int n) +{ + for (int i = 0; i < n; i++) + r[i] = __builtin_islessequal (a[i], b[i]); +} + +int +main (void) +{ + for (int i = 0; i < 64; i++) + { + a[i] = __builtin_nanf (""); /* quiet NaN */ + b[i] = 1.0f; + } + + /* A qNaN operand must not raise FE_INVALID here. */ + feclearexcept (FE_INVALID); + t_islessequal (r, a, b, 64); + if (fetestexcept (FE_INVALID)) + __builtin_abort (); + + for (int i = 0; i < 64; i++) + if (r[i] != 0) + __builtin_abort (); + + return 0; +}
