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 ();
+}

Reply via email to