> This patch is for expanding roundeven inline for SSE4.1 and later.
> Note that this patch is to be applied on top of
> <https://gcc.gnu.org/ml/gcc-patches/2019-06/msg01828.html>. The patch
> is bootstrapped and regression tested on x86_64-linux-gnu.

Actually, your patch at [1] is the way to go, but you need several
other changes to get x87 mode switching in order. Please also note
that there is no corresponding non-SSE4 ix86_expand_... function for
roundeven, so non-SSE4 SSE FP-math <rounding_insn><mode>2 expander has
to be disabled for ROUNDEVEN int iterator. Please see (otherwise
untested) attached patch which fixes both issues.

[1] https://gcc.gnu.org/ml/gcc/2019-06/msg00352.html

Uros.
Index: builtins.c
===================================================================
--- builtins.c  (revision 273480)
+++ builtins.c  (working copy)
@@ -2056,6 +2056,7 @@ mathfn_built_in_2 (tree type, combined_fn fn)
     CASE_MATHFN (REMQUO)
     CASE_MATHFN_FLOATN (RINT)
     CASE_MATHFN_FLOATN (ROUND)
+    CASE_MATHFN_FLOATN (ROUNDEVEN)
     CASE_MATHFN (SCALB)
     CASE_MATHFN (SCALBLN)
     CASE_MATHFN (SCALBN)
Index: builtins.def
===================================================================
--- builtins.def        (revision 273480)
+++ builtins.def        (working copy)
@@ -548,6 +548,12 @@ DEF_C99_BUILTIN        (BUILT_IN_ROUNDL, "roundl",
 #define ROUND_TYPE(F) BT_FN_##F##_##F
 DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_ROUND, "round", ROUND_TYPE, 
ATTR_CONST_NOTHROW_LEAF_LIST)
 #undef ROUND_TYPE
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_ROUNDEVEN, "roundeven", BT_FN_DOUBLE_DOUBLE, 
ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_ROUNDEVENF, "roundevenf", BT_FN_FLOAT_FLOAT, 
ATTR_CONST_NOTHROW_LEAF_LIST)
+DEF_EXT_LIB_BUILTIN    (BUILT_IN_ROUNDEVENL, "roundevenl", 
BT_FN_LONGDOUBLE_LONGDOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#define ROUNDEVEN_TYPE(F) BT_FN_##F##_##F
+DEF_EXT_LIB_FLOATN_NX_BUILTINS (BUILT_IN_ROUNDEVEN, "roundeven", 
ROUNDEVEN_TYPE, ATTR_CONST_NOTHROW_LEAF_LIST)
+#undef ROUNDEVEN_TYPE
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SCALB, "scalb", BT_FN_DOUBLE_DOUBLE_DOUBLE, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SCALBF, "scalbf", BT_FN_FLOAT_FLOAT_FLOAT, 
ATTR_MATHFN_FPROUNDING_ERRNO)
 DEF_EXT_LIB_BUILTIN    (BUILT_IN_SCALBL, "scalbl", 
BT_FN_LONGDOUBLE_LONGDOUBLE_LONGDOUBLE, ATTR_MATHFN_FPROUNDING_ERRNO)
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c  (revision 273480)
+++ config/i386/i386.c  (working copy)
@@ -13593,6 +13593,11 @@ ix86_i387_mode_needed (int entity, rtx_insn *insn)
 
   switch (entity)
     {
+    case I387_ROUNDEVEN:
+      if (mode == I387_CW_ROUNDEVEN)
+       return mode;
+      break;
+
     case I387_TRUNC:
       if (mode == I387_CW_TRUNC)
        return mode;
@@ -13627,6 +13632,7 @@ ix86_mode_needed (int entity, rtx_insn *insn)
       return ix86_dirflag_mode_needed (insn);
     case AVX_U128:
       return ix86_avx_u128_mode_needed (insn);
+    case I387_ROUNDEVEN:
     case I387_TRUNC:
     case I387_FLOOR:
     case I387_CEIL:
@@ -13687,6 +13693,7 @@ ix86_mode_after (int entity, int mode, rtx_insn *i
       return mode;
     case AVX_U128:
       return ix86_avx_u128_mode_after (mode, insn);
+    case I387_ROUNDEVEN:
     case I387_TRUNC:
     case I387_FLOOR:
     case I387_CEIL:
@@ -13739,6 +13746,7 @@ ix86_mode_entry (int entity)
       return ix86_dirflag_mode_entry ();
     case AVX_U128:
       return ix86_avx_u128_mode_entry ();
+    case I387_ROUNDEVEN:
     case I387_TRUNC:
     case I387_FLOOR:
     case I387_CEIL:
@@ -13776,6 +13784,7 @@ ix86_mode_exit (int entity)
       return X86_DIRFLAG_ANY;
     case AVX_U128:
       return ix86_avx_u128_mode_exit ();
+    case I387_ROUNDEVEN:
     case I387_TRUNC:
     case I387_FLOOR:
     case I387_CEIL:
@@ -13810,6 +13819,12 @@ emit_i387_cw_initialization (int mode)
 
   switch (mode)
     {
+    case I387_CW_ROUNDEVEN:
+      /* round to nearest */
+      emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00)));
+      slot = SLOT_CW_ROUNDEVEN;
+      break;
+
     case I387_CW_TRUNC:
       /* round toward zero (truncate) */
       emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0c00)));
@@ -13856,6 +13871,7 @@ ix86_emit_mode_set (int entity, int mode, int prev
       if (mode == AVX_U128_CLEAN)
        emit_insn (gen_avx_vzeroupper ());
       break;
+    case I387_ROUNDEVEN:
     case I387_TRUNC:
     case I387_FLOOR:
     case I387_CEIL:
Index: config/i386/i386.h
===================================================================
--- config/i386/i386.h  (revision 273480)
+++ config/i386/i386.h  (working copy)
@@ -2471,6 +2471,7 @@ enum ix86_stack_slot
 {
   SLOT_TEMP = 0,
   SLOT_CW_STORED,
+  SLOT_CW_ROUNDEVEN,
   SLOT_CW_TRUNC,
   SLOT_CW_FLOOR,
   SLOT_CW_CEIL,
@@ -2482,6 +2483,7 @@ enum ix86_entity
 {
   X86_DIRFLAG = 0,
   AVX_U128,
+  I387_ROUNDEVEN,
   I387_TRUNC,
   I387_FLOOR,
   I387_CEIL,
@@ -2517,7 +2519,7 @@ enum avx_u128_state
 
 #define NUM_MODES_FOR_MODE_SWITCHING                   \
   { X86_DIRFLAG_ANY, AVX_U128_ANY,                     \
-    I387_CW_ANY, I387_CW_ANY, I387_CW_ANY }
+    I387_CW_ANY, I387_CW_ANY, I387_CW_ANY, I387_CW_ANY }
 
 
 /* Avoid renaming of stack registers, as doing so in combination with
Index: config/i386/i386.md
===================================================================
--- config/i386/i386.md (revision 273482)
+++ config/i386/i386.md (working copy)
@@ -141,6 +141,7 @@
   UNSPEC_FXAM
 
   ;; x87 Rounding
+  UNSPEC_FRNDINT_ROUNDEVEN
   UNSPEC_FRNDINT_FLOOR
   UNSPEC_FRNDINT_CEIL
   UNSPEC_FRNDINT_TRUNC
@@ -303,7 +304,8 @@
 
 ;; Constants to represent rounding modes in the ROUND instruction
 (define_constants
-  [(ROUND_FLOOR                        0x1)
+  [(ROUND_ROUNDEVEN            0x0)
+   (ROUND_FLOOR                        0x1)
    (ROUND_CEIL                 0x2)
    (ROUND_TRUNC                        0x3)
    (ROUND_MXCSR                        0x4)
@@ -779,7 +781,7 @@
 
 ;; Defines rounding mode of an FP operation.
 
-(define_attr "i387_cw" "trunc,floor,ceil,uninitialized,any"
+(define_attr "i387_cw" "roundeven,floor,ceil,trunc,uninitialized,any"
   (const_string "any"))
 
 ;; Define attribute to indicate AVX insns with partial XMM register update.
@@ -16248,7 +16250,8 @@
 })
 
 (define_int_iterator FRNDINT_ROUNDING
-       [UNSPEC_FRNDINT_FLOOR
+       [UNSPEC_FRNDINT_ROUNDEVEN
+        UNSPEC_FRNDINT_FLOOR
         UNSPEC_FRNDINT_CEIL
         UNSPEC_FRNDINT_TRUNC])
 
@@ -16258,7 +16261,8 @@
 
 ;; Base name for define_insn
 (define_int_attr rounding_insn
-       [(UNSPEC_FRNDINT_FLOOR "floor")
+       [(UNSPEC_FRNDINT_ROUNDEVEN "roundeven")
+        (UNSPEC_FRNDINT_FLOOR "floor")
         (UNSPEC_FRNDINT_CEIL "ceil")
         (UNSPEC_FRNDINT_TRUNC "btrunc")
         (UNSPEC_FIST_FLOOR "floor")
@@ -16265,7 +16269,8 @@
         (UNSPEC_FIST_CEIL "ceil")])
 
 (define_int_attr rounding
-       [(UNSPEC_FRNDINT_FLOOR "floor")
+       [(UNSPEC_FRNDINT_ROUNDEVEN "roundeven")
+        (UNSPEC_FRNDINT_FLOOR "floor")
         (UNSPEC_FRNDINT_CEIL "ceil")
         (UNSPEC_FRNDINT_TRUNC "trunc")
         (UNSPEC_FIST_FLOOR "floor")
@@ -16272,7 +16277,8 @@
         (UNSPEC_FIST_CEIL "ceil")])
 
 (define_int_attr ROUNDING
-       [(UNSPEC_FRNDINT_FLOOR "FLOOR")
+       [(UNSPEC_FRNDINT_ROUNDEVEN "ROUNDEVEN")
+        (UNSPEC_FRNDINT_FLOOR "FLOOR")
         (UNSPEC_FRNDINT_CEIL "CEIL")
         (UNSPEC_FRNDINT_TRUNC "TRUNC")
         (UNSPEC_FIST_FLOOR "FLOOR")
@@ -16335,8 +16341,9 @@
        || TARGET_MIX_SSE_I387)
     && (flag_fp_int_builtin_inexact || !flag_trapping_math))
    || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
-       && (TARGET_SSE4_1 || flag_fp_int_builtin_inexact
-          || !flag_trapping_math))"
+       && (TARGET_SSE4_1
+          || (ROUND_<ROUNDING> != ROUND_ROUNDEVEN
+              && (flag_fp_int_builtin_inexact || !flag_trapping_math))))"
 {
   if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
       && (TARGET_SSE4_1 || flag_fp_int_builtin_inexact || !flag_trapping_math))
Index: internal-fn.def
===================================================================
--- internal-fn.def     (revision 273480)
+++ internal-fn.def     (working copy)
@@ -234,6 +234,7 @@ DEF_INTERNAL_FLT_FLOATN_FN (FLOOR, ECF_CONST, floo
 DEF_INTERNAL_FLT_FLOATN_FN (NEARBYINT, ECF_CONST, nearbyint, unary)
 DEF_INTERNAL_FLT_FLOATN_FN (RINT, ECF_CONST, rint, unary)
 DEF_INTERNAL_FLT_FLOATN_FN (ROUND, ECF_CONST, round, unary)
+DEF_INTERNAL_FLT_FLOATN_FN (ROUNDEVEN, ECF_CONST, roundeven, unary)
 DEF_INTERNAL_FLT_FLOATN_FN (TRUNC, ECF_CONST, btrunc, unary)
 
 /* Binary math functions.  */
Index: optabs.def
===================================================================
--- optabs.def  (revision 273480)
+++ optabs.def  (working copy)
@@ -268,6 +268,7 @@ OPTAB_D (fnms_optab, "fnms$a4")
 
 OPTAB_D (rint_optab, "rint$a2")
 OPTAB_D (round_optab, "round$a2")
+OPTAB_D (roundeven_optab, "roundeven$a2")
 OPTAB_D (floor_optab, "floor$a2")
 OPTAB_D (ceil_optab, "ceil$a2")
 OPTAB_D (btrunc_optab, "btrunc$a2")
Index: reg-stack.c
===================================================================
--- reg-stack.c (revision 273480)
+++ reg-stack.c (working copy)
@@ -1817,6 +1817,7 @@ subst_stack_regs_pat (rtx_insn *insn, stack_ptr re
              case UNSPEC_FRNDINT:
              case UNSPEC_F2XM1:
 
+             case UNSPEC_FRNDINT_ROUNDEVEN:
              case UNSPEC_FRNDINT_FLOOR:
              case UNSPEC_FRNDINT_CEIL:
              case UNSPEC_FRNDINT_TRUNC:

Reply via email to