Hello!

Attached patch applies min/max IEEE rules w.r.t. NaN and signed zeros
also to  SSE intrinsics. Before the patch, intrinsics were expanded to
a generic min/max pattern with commutative operands.

Patched compiler expands intrinsics to an UNSPEC or generic min/max,
depending on flag_finite_math_only or flag_signed_zeros.

2016-08-15  Uros Bizjak  <ubiz...@gmail.com>

    PR target/72867
    * config/i386/sse.md (<code><mode>3<mask_name><round_saeonly_name>):
    Emit ieee_<ieee_maxmin><mode>3<mask_name><round_saeonly_name>
    for !flag_finite_math_only or flag_signed_zeros.
    (*<code><mode>3<mask_name><round_saeonly_name>): Rename from
    *<code><mode>3_finite<mask_name><round_saeonly_name>.  Do not
    depend on flag_finite_math_only.
    (ieee_<ieee_maxmin><mode>3<mask_name><round_saeonly_name>):
    New insn pattern.
    (*<code><mode>3<mask_name><round_saeonly_name>): Remove.
    (*ieee_smin<mode>3): Ditto.
    (*ieee_smax<mode>3): Ditto.
    * config/i386/mmx.md (mmx_<code>v2sf3): Emit
    mmx_ieee_<ieee_maxmin>v2sf3 for !flag_finite_math_only or
    flag_signed_zeros.
    (*mmx_<code>v2sf3): Rename from *mmx_<code>v2sf3_finite.  Do not
    depend on flag_finite_math_only.
    (mmx_ieee_<ieee_maxmin>v2sf3): New insn pattern.
    (*mmx_<code>v2sf3): Remove.
    * config/i386/subst.md (round_saeonly_mask_arg3): New subst attribute.
    * config/i386/i386.c (ix86_expand_sse_fp_mimnax): Check
    flag_signed_zeros instead of !flag_unsafe_math_optimizations.

testsuite/ChangeLog:

2016-08-15  Uros Bizjak  <ubiz...@gmail.com>

    PR target/72867
    * gcc.target/i386/pr72867.c: New test.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32} .

Committed to mainline SVN.

Uros.
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c  (revision 239479)
+++ config/i386/i386.c  (working copy)
@@ -23404,7 +23404,7 @@ ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code
 
   /* We want to check HONOR_NANS and HONOR_SIGNED_ZEROS here,
      but MODE may be a vector mode and thus not appropriate.  */
-  if (!flag_finite_math_only || !flag_unsafe_math_optimizations)
+  if (!flag_finite_math_only || flag_signed_zeros)
     {
       int u = is_min ? UNSPEC_IEEE_MIN : UNSPEC_IEEE_MAX;
       rtvec v;
Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md (revision 239479)
+++ config/i386/i386.md (working copy)
@@ -885,6 +885,14 @@
                              (umax "maxu") (umin "minu")])
 (define_code_attr maxmin_float [(smax "max") (smin "min")])
 
+(define_int_iterator IEEE_MAXMIN
+       [UNSPEC_IEEE_MAX
+        UNSPEC_IEEE_MIN])
+
+(define_int_attr ieee_maxmin
+       [(UNSPEC_IEEE_MAX "max")
+        (UNSPEC_IEEE_MIN "min")])
+
 ;; Mapping of logic operators
 (define_code_iterator any_logic [and ior xor])
 (define_code_iterator any_or [ior xor])
@@ -17401,14 +17409,6 @@
 ;; Their operands are not commutative, and thus they may be used in the
 ;; presence of -0.0 and NaN.
 
-(define_int_iterator IEEE_MAXMIN
-       [UNSPEC_IEEE_MAX
-        UNSPEC_IEEE_MIN])
-
-(define_int_attr ieee_maxmin
-       [(UNSPEC_IEEE_MAX "max")
-        (UNSPEC_IEEE_MIN "min")])
-
 (define_insn "*ieee_s<ieee_maxmin><mode>3"
   [(set (match_operand:MODEF 0 "register_operand" "=x,v")
        (unspec:MODEF
Index: config/i386/mmx.md
===================================================================
--- config/i386/mmx.md  (revision 239479)
+++ config/i386/mmx.md  (working copy)
@@ -296,10 +296,6 @@
    (set_attr "prefix_extra" "1")
    (set_attr "mode" "V2SF")])
 
-;; ??? For !flag_finite_math_only, the representation with SMIN/SMAX
-;; isn't really correct, as those rtl operators aren't defined when
-;; applied to NaNs.  Hopefully the optimizers won't get too smart on us.
-
 (define_expand "mmx_<code>v2sf3"
   [(set (match_operand:V2SF 0 "register_operand")
         (smaxmin:V2SF
@@ -307,30 +303,47 @@
          (match_operand:V2SF 2 "nonimmediate_operand")))]
   "TARGET_3DNOW"
 {
-  if (!flag_finite_math_only)
-    operands[1] = force_reg (V2SFmode, operands[1]);
-  ix86_fixup_binary_operands_no_copy (<CODE>, V2SFmode, operands);
+  if (!flag_finite_math_only || flag_signed_zeros)
+    {
+      operands[1] = force_reg (V2SFmode, operands[1]);
+      emit_insn (gen_mmx_ieee_<maxmin_float>v2sf3
+                (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+  else
+    ix86_fixup_binary_operands_no_copy (<CODE>, V2SFmode, operands);
 })
 
-(define_insn "*mmx_<code>v2sf3_finite"
+;; These versions of the min/max patterns are intentionally ignorant of
+;; their behavior wrt -0.0 and NaN (via the commutative operand mark).
+;; Since both the tree-level MAX_EXPR and the rtl-level SMAX operator
+;; are undefined in this condition, we're certain this is correct.
+
+(define_insn "*mmx_<code>v2sf3"
   [(set (match_operand:V2SF 0 "register_operand" "=y")
         (smaxmin:V2SF
          (match_operand:V2SF 1 "nonimmediate_operand" "%0")
          (match_operand:V2SF 2 "nonimmediate_operand" "ym")))]
-  "TARGET_3DNOW && flag_finite_math_only
-   && ix86_binary_operator_ok (<CODE>, V2SFmode, operands)"
+  "TARGET_3DNOW && ix86_binary_operator_ok (<CODE>, V2SFmode, operands)"
   "pf<maxmin_float>\t{%2, %0|%0, %2}"
   [(set_attr "type" "mmxadd")
    (set_attr "prefix_extra" "1")
    (set_attr "mode" "V2SF")])
 
-(define_insn "*mmx_<code>v2sf3"
+;; These versions of the min/max patterns implement exactly the operations
+;;   min = (op1 < op2 ? op1 : op2)
+;;   max = (!(op1 < op2) ? op1 : op2)
+;; Their operands are not commutative, and thus they may be used in the
+;; presence of -0.0 and NaN.
+
+(define_insn "mmx_ieee_<ieee_maxmin>v2sf3"
   [(set (match_operand:V2SF 0 "register_operand" "=y")
-        (smaxmin:V2SF
-         (match_operand:V2SF 1 "register_operand" "0")
-         (match_operand:V2SF 2 "nonimmediate_operand" "ym")))]
+        (unspec:V2SF
+         [(match_operand:V2SF 1 "register_operand" "0")
+          (match_operand:V2SF 2 "nonimmediate_operand" "ym")]
+         IEEE_MAXMIN))]
   "TARGET_3DNOW"
-  "pf<maxmin_float>\t{%2, %0|%0, %2}"
+  "pf<ieee_maxmin>\t{%2, %0|%0, %2}"
   [(set_attr "type" "mmxadd")
    (set_attr "prefix_extra" "1")
    (set_attr "mode" "V2SF")])
Index: config/i386/sse.md
===================================================================
--- config/i386/sse.md  (revision 239479)
+++ config/i386/sse.md  (working copy)
@@ -1633,10 +1633,6 @@
    (set_attr "prefix" "orig,vex")
    (set_attr "mode" "SF")])
 
-;; ??? For !flag_finite_math_only, the representation with SMIN/SMAX
-;; isn't really correct, as those rtl operators aren't defined when
-;; applied to NaNs.  Hopefully the optimizers won't get too smart on us.
-
 (define_expand "<code><mode>3<mask_name><round_saeonly_name>"
   [(set (match_operand:VF 0 "register_operand")
        (smaxmin:VF
@@ -1644,18 +1640,30 @@
          (match_operand:VF 2 "<round_saeonly_nimm_predicate>")))]
   "TARGET_SSE && <mask_mode512bit_condition> && 
<round_saeonly_mode512bit_condition>"
 {
-  if (!flag_finite_math_only)
-    operands[1] = force_reg (<MODE>mode, operands[1]);
-  ix86_fixup_binary_operands_no_copy (<CODE>, <MODE>mode, operands);
+  if (!flag_finite_math_only || flag_signed_zeros)
+    {
+      operands[1] = force_reg (<MODE>mode, operands[1]);
+      emit_insn (gen_ieee_<maxmin_float><mode>3<mask_name><round_saeonly_name>
+                (operands[0], operands[1], operands[2]
+                 <mask_operand_arg34>
+                 <round_saeonly_mask_arg3>));
+      DONE;
+    }
+  else
+    ix86_fixup_binary_operands_no_copy (<CODE>, <MODE>mode, operands);
 })
 
-(define_insn "*<code><mode>3_finite<mask_name><round_saeonly_name>"
+;; These versions of the min/max patterns are intentionally ignorant of
+;; their behavior wrt -0.0 and NaN (via the commutative operand mark).
+;; Since both the tree-level MAX_EXPR and the rtl-level SMAX operator
+;; are undefined in this condition, we're certain this is correct.
+
+(define_insn "*<code><mode>3<mask_name><round_saeonly_name>"
   [(set (match_operand:VF 0 "register_operand" "=x,v")
        (smaxmin:VF
          (match_operand:VF 1 "<round_saeonly_nimm_predicate>" "%0,v")
          (match_operand:VF 2 "<round_saeonly_nimm_predicate>" 
"xBm,<round_saeonly_constraint>")))]
-  "TARGET_SSE && flag_finite_math_only
-   && ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)
+  "TARGET_SSE && ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)
    && <mask_mode512bit_condition> && <round_saeonly_mode512bit_condition>"
   "@
    <maxmin_float><ssemodesuffix>\t{%2, %0|%0, %2}
@@ -1666,16 +1674,23 @@
    (set_attr "prefix" "<mask_prefix3>")
    (set_attr "mode" "<MODE>")])
 
-(define_insn "*<code><mode>3<mask_name><round_saeonly_name>"
+;; These versions of the min/max patterns implement exactly the operations
+;;   min = (op1 < op2 ? op1 : op2)
+;;   max = (!(op1 < op2) ? op1 : op2)
+;; Their operands are not commutative, and thus they may be used in the
+;; presence of -0.0 and NaN.
+
+(define_insn "ieee_<ieee_maxmin><mode>3<mask_name><round_saeonly_name>"
   [(set (match_operand:VF 0 "register_operand" "=x,v")
-       (smaxmin:VF
-         (match_operand:VF 1 "register_operand" "0,v")
-         (match_operand:VF 2 "<round_saeonly_nimm_predicate>" 
"xBm,<round_saeonly_constraint>")))]
-  "TARGET_SSE && !flag_finite_math_only
+       (unspec:VF
+         [(match_operand:VF 1 "register_operand" "0,v")
+          (match_operand:VF 2 "<round_saeonly_nimm_predicate>" 
"xBm,<round_saeonly_constraint>")]
+         IEEE_MAXMIN))]
+  "TARGET_SSE
    && <mask_mode512bit_condition> && <round_saeonly_mode512bit_condition>"
   "@
-   <maxmin_float><ssemodesuffix>\t{%2, %0|%0, %2}
-   v<maxmin_float><ssemodesuffix>\t{<round_saeonly_mask_op3>%2, %1, 
%0<mask_operand3>|%0<mask_operand3>, %1, %2<round_saeonly_mask_op3>}"
+   <ieee_maxmin><ssemodesuffix>\t{%2, %0|%0, %2}
+   v<ieee_maxmin><ssemodesuffix>\t{<round_saeonly_mask_op3>%2, %1, 
%0<mask_operand3>|%0<mask_operand3>, %1, %2<round_saeonly_mask_op3>}"
   [(set_attr "isa" "noavx,avx")
    (set_attr "type" "sseadd")
    (set_attr "btver2_sse_attr" "maxmin")
@@ -1700,42 +1715,6 @@
    (set_attr "prefix" "<round_saeonly_prefix>")
    (set_attr "mode" "<ssescalarmode>")])
 
-;; These versions of the min/max patterns implement exactly the operations
-;;   min = (op1 < op2 ? op1 : op2)
-;;   max = (!(op1 < op2) ? op1 : op2)
-;; Their operands are not commutative, and thus they may be used in the
-;; presence of -0.0 and NaN.
-
-(define_insn "*ieee_smin<mode>3"
-  [(set (match_operand:VF 0 "register_operand" "=x,v")
-       (unspec:VF
-         [(match_operand:VF 1 "register_operand" "0,v")
-          (match_operand:VF 2 "vector_operand" "xBm,vm")]
-        UNSPEC_IEEE_MIN))]
-  "TARGET_SSE"
-  "@
-   min<ssemodesuffix>\t{%2, %0|%0, %2}
-   vmin<ssemodesuffix>\t{%2, %1, %0|%0, %1, %2}"
-  [(set_attr "isa" "noavx,avx")
-   (set_attr "type" "sseadd")
-   (set_attr "prefix" "orig,vex")
-   (set_attr "mode" "<MODE>")])
-
-(define_insn "*ieee_smax<mode>3"
-  [(set (match_operand:VF 0 "register_operand" "=x,v")
-       (unspec:VF
-         [(match_operand:VF 1 "register_operand" "0,v")
-          (match_operand:VF 2 "vector_operand" "xBm,vm")]
-        UNSPEC_IEEE_MAX))]
-  "TARGET_SSE"
-  "@
-   max<ssemodesuffix>\t{%2, %0|%0, %2}
-   vmax<ssemodesuffix>\t{%2, %1, %0|%0, %1, %2}"
-  [(set_attr "isa" "noavx,avx")
-   (set_attr "type" "sseadd")
-   (set_attr "prefix" "orig,vex")
-   (set_attr "mode" "<MODE>")])
-
 (define_insn "avx_addsubv4df3"
   [(set (match_operand:V4DF 0 "register_operand" "=x")
        (vec_merge:V4DF
Index: config/i386/subst.md
===================================================================
--- config/i386/subst.md        (revision 239479)
+++ config/i386/subst.md        (working copy)
@@ -161,6 +161,7 @@
 (define_subst_attr "round_saeonly_mask_op4" "round_saeonly" "" 
"<round_saeonly_mask_operand4>")
 (define_subst_attr "round_saeonly_mask_scalar_merge_op4" "round_saeonly" "" 
"<round_saeonly_mask_scalar_merge_operand4>")
 (define_subst_attr "round_saeonly_sd_mask_op5" "round_saeonly" "" 
"<round_saeonly_sd_mask_operand5>")
+(define_subst_attr "round_saeonly_mask_arg3" "round_saeonly" "" ", 
operands[<mask_expand_op3>]")
 (define_subst_attr "round_saeonly_constraint" "round_saeonly" "vm" "v")
 (define_subst_attr "round_saeonly_constraint2" "round_saeonly" "m" "v")
 (define_subst_attr "round_saeonly_nimm_predicate" "round_saeonly" 
"vector_operand" "register_operand")
Index: testsuite/gcc.target/i386/pr72867.c
===================================================================
--- testsuite/gcc.target/i386/pr72867.c (nonexistent)
+++ testsuite/gcc.target/i386/pr72867.c (working copy)
@@ -0,0 +1,23 @@
+/* PR target/72867 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target sse } */
+
+#include "sse-check.h"
+#include <xmmintrin.h>
+
+static void
+sse_test (void)
+{
+  float nan = __builtin_nanf ("");
+  
+  __m128 x = _mm_min_ps(_mm_set1_ps(nan), _mm_set1_ps(1.0f));
+
+  if (x[0] != 1.0f)
+    abort ();
+
+  x = _mm_min_ps(_mm_set1_ps(1.f), _mm_set1_ps(nan));
+
+  if (!__builtin_isnan (x[0]))
+    abort ();
+}

Reply via email to