https://gcc.gnu.org/g:11195a9e0a46f5204f2506caaea815830d1d9491
commit r14-10768-g11195a9e0a46f5204f2506caaea815830d1d9491 Author: Jakub Jelinek <ja...@redhat.com> Date: Fri Sep 20 09:14:29 2024 +0200 i386: Fix up _mm_min_ss etc. handling of zeros and NaNs [PR116738] min/max patterns for intrinsics which on x86 result in the second input operand if the two operands are both zeros or one or both of them are a NaN shouldn't use SMIN/SMAX RTL, because that is similarly to MIN_EXPR/MAX_EXPR undefined what will be the result in those cases. The following patch adds an expander which uses either a new pattern with UNSPEC_IEEE_M{AX,IN} or use the S{MIN,MAX} representation of the same. 2024-09-20 Uros Bizjak <ubiz...@gmail.com> Jakub Jelinek <ja...@redhat.com> PR target/116738 * config/i386/subst.md (mask_scalar_operand_arg34, mask_scalar_expand_op3, round_saeonly_scalar_mask_arg3): New subst attributes. * config/i386/sse.md (<sse>_vm<code><mode>3<mask_scalar_name><round_saeonly_scalar_name>): Change from define_insn to define_expand, rename the old define_insn to ... (*<sse>_vm<code><mode>3<mask_scalar_name><round_saeonly_scalar_name>): ... this. (<sse>_ieee_vm<ieee_maxmin><mode>3<mask_scalar_name><round_saeonly_scalar_name>): New define_insn. * gcc.target/i386/sse-pr116738.c: New test. (cherry picked from commit 624d3af025e820ede7ec4334f7a2d5d4731c99a9) Diff: --- gcc/config/i386/sse.md | 41 +++++++++++++++++++++++++++- gcc/config/i386/subst.md | 3 ++ gcc/testsuite/gcc.target/i386/sse-pr116738.c | 28 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 40880f2cd580..c91a7e07bc76 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -3047,7 +3047,27 @@ (const_string "*"))) (set_attr "mode" "<ssescalarmode>")]) -(define_insn "<sse>_vm<code><mode>3<mask_scalar_name><round_saeonly_scalar_name>" +(define_expand "<sse>_vm<code><mode>3<mask_scalar_name><round_saeonly_scalar_name>" + [(set (match_operand:VFH_128 0 "register_operand") + (vec_merge:VFH_128 + (smaxmin:VFH_128 + (match_operand:VFH_128 1 "register_operand") + (match_operand:VFH_128 2 "nonimmediate_operand")) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" +{ + if (!flag_finite_math_only || flag_signed_zeros) + { + emit_insn (gen_<sse>_ieee_vm<maxmin_float><mode>3<mask_scalar_name><round_saeonly_scalar_name> + (operands[0], operands[1], operands[2] + <mask_scalar_operand_arg34> + <round_saeonly_scalar_mask_arg3>)); + DONE; + } +}) + +(define_insn "*<sse>_vm<code><mode>3<mask_scalar_name><round_saeonly_scalar_name>" [(set (match_operand:VFH_128 0 "register_operand" "=x,v") (vec_merge:VFH_128 (smaxmin:VFH_128 @@ -3065,6 +3085,25 @@ (set_attr "prefix" "<round_saeonly_scalar_prefix>") (set_attr "mode" "<ssescalarmode>")]) +(define_insn "<sse>_ieee_vm<ieee_maxmin><mode>3<mask_scalar_name><round_saeonly_scalar_name>" + [(set (match_operand:VFH_128 0 "register_operand" "=x,v") + (vec_merge:VFH_128 + (unspec:VFH_128 + [(match_operand:VFH_128 1 "register_operand" "0,v") + (match_operand:VFH_128 2 "nonimmediate_operand" "xm,<round_saeonly_scalar_constraint>")] + IEEE_MAXMIN) + (match_dup 1) + (const_int 1)))] + "TARGET_SSE" + "@ + <ieee_maxmin><ssescalarmodesuffix>\t{%2, %0|%0, %<iptr>2} + v<ieee_maxmin><ssescalarmodesuffix>\t{<round_saeonly_scalar_mask_op3>%2, %1, %0<mask_scalar_operand3>|%0<mask_scalar_operand3>, %1, %<iptr>2<round_saeonly_scalar_mask_op3>}" + [(set_attr "isa" "noavx,avx") + (set_attr "type" "sse") + (set_attr "btver2_sse_attr" "maxmin") + (set_attr "prefix" "<round_saeonly_scalar_prefix>") + (set_attr "mode" "<ssescalarmode>")]) + (define_mode_attr addsub_cst [(V4DF "5") (V2DF "1") (V4SF "5") (V8SF "85")]) diff --git a/gcc/config/i386/subst.md b/gcc/config/i386/subst.md index 7a9b697e0f67..763e4a8de69c 100644 --- a/gcc/config/i386/subst.md +++ b/gcc/config/i386/subst.md @@ -345,6 +345,8 @@ (define_subst_attr "mask_scalarcz_operand4" "mask_scalarcz" "" "%{%5%}%N4") (define_subst_attr "mask_scalar4_dest_false_dep_for_glc_cond" "mask_scalar" "1" "operands[4] == CONST0_RTX(<MODE>mode)") (define_subst_attr "mask_scalarc_dest_false_dep_for_glc_cond" "mask_scalarc" "1" "operands[3] == CONST0_RTX(V8HFmode)") +(define_subst_attr "mask_scalar_operand_arg34" "mask_scalar" "" ", operands[3], operands[4]") +(define_subst_attr "mask_scalar_expand_op3" "mask_scalar" "3" "5") (define_subst "mask_scalar" [(set (match_operand:SUBST_V 0) @@ -452,6 +454,7 @@ (define_subst_attr "round_saeonly_scalar_constraint" "round_saeonly_scalar" "vm" "v") (define_subst_attr "round_saeonly_scalar_prefix" "round_saeonly_scalar" "vex" "evex") (define_subst_attr "round_saeonly_scalar_nimm_predicate" "round_saeonly_scalar" "nonimmediate_operand" "register_operand") +(define_subst_attr "round_saeonly_scalar_mask_arg3" "round_saeonly_scalar" "" ", operands[<mask_scalar_expand_op3>]") (define_subst "round_saeonly_scalar" [(set (match_operand:SUBST_V 0) diff --git a/gcc/testsuite/gcc.target/i386/sse-pr116738.c b/gcc/testsuite/gcc.target/i386/sse-pr116738.c new file mode 100644 index 000000000000..5b31bf247488 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/sse-pr116738.c @@ -0,0 +1,28 @@ +/* PR target/116738 */ +/* { dg-do run } */ +/* { dg-options "-O2 -msse" } */ +/* { dg-require-effective-target sse } */ + +#include "sse-check.h" + +static inline float +clamp (float f) +{ + __m128 v = _mm_set_ss (f); + __m128 zero = _mm_setzero_ps (); + __m128 greatest = _mm_set_ss (__FLT_MAX__); + v = _mm_min_ss (v, greatest); + v = _mm_max_ss (v, zero); + return _mm_cvtss_f32 (v); +} + +static void +sse_test (void) +{ + float f = clamp (-0.0f); + if (f != 0.0f || __builtin_signbitf (f)) + abort (); + f = clamp (__builtin_nanf ("")); + if (__builtin_isnanf (f) || f != __FLT_MAX__) + abort (); +}