builtins.c (expand_builtin_mathfn): Handle BUILT_IN_RINT{,F,L} using rint_optab.
authorUros Bizjak <uros@kss-loka.si>
Sat, 4 Sep 2004 07:55:12 +0000 (09:55 +0200)
committerUros Bizjak <uros@gcc.gnu.org>
Sat, 4 Sep 2004 07:55:12 +0000 (09:55 +0200)
2004-09-04  Uros Bizjak  <uros@kss-loka.si>

* builtins.c (expand_builtin_mathfn): Handle BUILT_IN_RINT{,F,L}
using rint_optab.
(expand_builtin): Expand BUILT_IN_RINT{,F,L} using
expand_builtin_mathfn.
* genopinit.c (optabs): Rename trunc_optab to btrunc_optab. Use
btrunc?f patterns for btrunc_optab. Implement rint_optab using
rint?f patterns.
* optabs.c (init_optabs): Initialize rint_optab.
* optabs.h (enum optab_index): Rename OTI_trunc to OTI_btrunc.
Add new OTI_rint.
(btrunc_optab): Rename macro from trunc_optab.
(rint_optab): Define corresponding macro.

* reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_FRNDINT_FLOOR,
UNSPEC_FRNDINT_CEIL, UNSPEC_FRNDINT_TRUNC, UNSPEC_FRNDINT_MASK_PM.

* config/i386/i386-protos.h (emit_i387_cw_initialization):
Change prototype. Add new int parameter.
* config/i386/i386.c (emit_i387_cw_initialization):
Handle new rounding modes.

* config/i386/i386.h (enum fp_cw_mode): Delete.
(MODE_NEEDED): Handle new rounding modes.
(EMIT_MODE_SET): Change condition to handle new rounding modes.

* config/i386/i386.md (UNSPEC_FRNDINT_FLOOR, UNSPEC_FRNDINT_CEIL,
UNSPEC_FRNDINT_TRUNC, UNSPEC_FRNDINT_MASK_PM): New unspecs to
represent different rounding modes of frndint insn.
(type): Add frndint type.
(i387, length, memory): Handle this type.
(i387_cw): New attribute definition.
(*fix_truncdi_1, fix_truncdi_nomemory, fix_truncdi_memory,
*fix_truncsi_1, fix_truncsi_nomemory, fix_truncsi_memory,
*fix_trunchi_1, fix_trunchi_nomemory, fix_trunchi_memory):
Add "i387_cw" attribute defined to "trunc".
(x86_fnstcw_1): Remove comment.
(*frndintxf2): Rename insn definition to frndintxf2. Move
insn definition near rint?f2 expanders.
(rintdf2, rintsf2, rintxf2): New expanders to implement rint,
rintf and rintl built-ins as inline x87 intrinsics.
(frndintxf2_floor): New pattern to implement floor rounding
mode with frndint x87 instruction.
(floordf2, floorsf2, floorxf2): New expanders to implement floor,
floorf and floorl built-ins as inline x87 intrinsics.
(frndintxf2_ceil): New pattern to implement ceil rounding
mode with frndint x87 instruction.
(ceildf2, ceilsf2, ceilxf2): New expanders to implement ceil,
ceilf and ceill built-ins as inline x87 intrinsics.
(frndintxf2_trunc): New pattern to implement trunc rounding
mode with frndint x87 instruction.
(btruncdf2, btruncsf2, btruncxf2): New expanders to implement trunc,
truncf and truncl built-ins as inline x87 intrinsics.
(frndintxf2_mask_pm): New pattern to implement rounding
mode with exceptions with frndint x87 instruction.
(nearbyintdf2, nearbyintsf2, nearbyintxf2): New expanders to
implement nearbyint, nearbyintf and nearbyintl built-ins as
inline x87 intrinsics.

* testsuite/gcc.dg/builtins-46.c: New.

From-SVN: r87076

12 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/genopinit.c
gcc/optabs.c
gcc/optabs.h
gcc/reg-stack.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/builtins-46.c [new file with mode: 0644]

index f19a4f411fbfe89945fa7e89a907356c4d503911..2cf1b5b5610879784b2c7367813846c9c0ffbadd 100644 (file)
@@ -1,3 +1,63 @@
+2004-09-04  Uros Bizjak  <uros@kss-loka.si>
+
+       * builtins.c (expand_builtin_mathfn): Handle BUILT_IN_RINT{,F,L}
+       using rint_optab.
+       (expand_builtin): Expand BUILT_IN_RINT{,F,L} using
+       expand_builtin_mathfn.
+       * genopinit.c (optabs): Rename trunc_optab to btrunc_optab. Use
+       btrunc?f patterns for btrunc_optab. Implement rint_optab using
+       rint?f patterns.
+       * optabs.c (init_optabs): Initialize rint_optab.
+       * optabs.h (enum optab_index): Rename OTI_trunc to OTI_btrunc.
+       Add new OTI_rint.
+       (btrunc_optab): Rename macro from trunc_optab.
+       (rint_optab): Define corresponding macro.
+
+       * reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_FRNDINT_FLOOR,
+       UNSPEC_FRNDINT_CEIL, UNSPEC_FRNDINT_TRUNC, UNSPEC_FRNDINT_MASK_PM.
+
+       * config/i386/i386-protos.h (emit_i387_cw_initialization):
+       Change prototype. Add new int parameter.
+       * config/i386/i386.c (emit_i387_cw_initialization):
+       Handle new rounding modes.
+
+       * config/i386/i386.h (enum fp_cw_mode): Delete.
+       (MODE_NEEDED): Handle new rounding modes. 
+       (EMIT_MODE_SET): Change condition to handle new rounding modes.
+
+       * config/i386/i386.md (UNSPEC_FRNDINT_FLOOR, UNSPEC_FRNDINT_CEIL,
+       UNSPEC_FRNDINT_TRUNC, UNSPEC_FRNDINT_MASK_PM): New unspecs to
+       represent different rounding modes of frndint insn.
+       (type): Add frndint type.
+       (i387, length, memory): Handle this type.
+       (i387_cw): New attribute definition.
+       (*fix_truncdi_1, fix_truncdi_nomemory, fix_truncdi_memory,
+       *fix_truncsi_1, fix_truncsi_nomemory, fix_truncsi_memory,
+       *fix_trunchi_1, fix_trunchi_nomemory, fix_trunchi_memory):
+       Add "i387_cw" attribute defined to "trunc".
+       (x86_fnstcw_1): Remove comment.
+       (*frndintxf2): Rename insn definition to frndintxf2. Move
+       insn definition near rint?f2 expanders.
+       (rintdf2, rintsf2, rintxf2): New expanders to implement rint,
+       rintf and rintl built-ins as inline x87 intrinsics.
+       (frndintxf2_floor): New pattern to implement floor rounding
+       mode with frndint x87 instruction.
+       (floordf2, floorsf2, floorxf2): New expanders to implement floor,
+       floorf and floorl built-ins as inline x87 intrinsics.
+       (frndintxf2_ceil): New pattern to implement ceil rounding
+       mode with frndint x87 instruction.
+       (ceildf2, ceilsf2, ceilxf2): New expanders to implement ceil,
+       ceilf and ceill built-ins as inline x87 intrinsics.
+       (frndintxf2_trunc): New pattern to implement trunc rounding
+       mode with frndint x87 instruction.
+       (btruncdf2, btruncsf2, btruncxf2): New expanders to implement trunc,
+       truncf and truncl built-ins as inline x87 intrinsics.
+       (frndintxf2_mask_pm): New pattern to implement rounding
+       mode with exceptions with frndint x87 instruction.
+       (nearbyintdf2, nearbyintsf2, nearbyintxf2): New expanders to
+       implement nearbyint, nearbyintf and nearbyintl built-ins as
+       inline x87 intrinsics.
+
 2004-09-04  Richard Sandiford  <rsandifo@redhat.com>
 
        * config/mips/mips.md (SHORT): New mode macro.
index b0d7c4c779eaa81ae0e4b6048fea84bee9a48155..97800bfef02dd0e4943d100417e7855b385aa6e8 100644 (file)
@@ -1737,6 +1737,10 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
     case BUILT_IN_NEARBYINTF:
     case BUILT_IN_NEARBYINTL:
       builtin_optab = nearbyint_optab; break;
+    case BUILT_IN_RINT:
+    case BUILT_IN_RINTF:
+    case BUILT_IN_RINTL:
+      builtin_optab = rint_optab; break;
     default:
       gcc_unreachable ();
     }
@@ -5599,6 +5603,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_NEARBYINT:
     case BUILT_IN_NEARBYINTF:
     case BUILT_IN_NEARBYINTL:
+    case BUILT_IN_RINT:
+    case BUILT_IN_RINTF:
+    case BUILT_IN_RINTL:
       target = expand_builtin_mathfn (exp, target, subtarget);
       if (target)
        return target;
index 57b6d054bafee9e8db3fba51b8f7b6d48d49559a..1c87da6385d0499e4d1b477988200b4b77e63389 100644 (file)
@@ -174,7 +174,7 @@ extern int ix86_secondary_memory_needed (enum reg_class, enum reg_class,
                                         enum machine_mode, int);
 extern enum reg_class ix86_preferred_reload_class (rtx, enum reg_class);
 extern int ix86_memory_move_cost (enum machine_mode, enum reg_class, int);
-extern void emit_i387_cw_initialization (rtx, rtx);
+extern void emit_i387_cw_initialization (rtx, rtx, int);
 extern bool ix86_fp_jump_nontrivial_p (enum rtx_code);
 extern void x86_order_regs_for_local_alloc (void);
 extern void x86_function_profiler (FILE *, int);
index 760c7f0d997fd35b5fd3a9a93f5367a985a7dd6c..4a8695275051342251b4ae48290c1966e9e7718e 100644 (file)
@@ -7108,22 +7108,79 @@ output_387_binary_op (rtx insn, rtx *operands)
   return buf;
 }
 
-/* Output code to initialize control word copies used by
-   trunc?f?i patterns.  NORMAL is set to current control word, while ROUND_DOWN
-   is set to control word rounding downwards.  */
+/* Output code to initialize control word copies used by trunc?f?i and
+   rounding patterns.  CURRENT_MODE is set to current control word,
+   while NEW_MODE is set to new control word.  */
+
 void
-emit_i387_cw_initialization (rtx normal, rtx round_down)
+emit_i387_cw_initialization (rtx current_mode, rtx new_mode, int mode)
 {
   rtx reg = gen_reg_rtx (HImode);
 
-  emit_insn (gen_x86_fnstcw_1 (normal));
-  emit_move_insn (reg, normal);
+  emit_insn (gen_x86_fnstcw_1 (current_mode));
+  emit_move_insn (reg, current_mode);
+
   if (!TARGET_PARTIAL_REG_STALL && !optimize_size
       && !TARGET_64BIT)
-    emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0xc)));
+    {
+      switch (mode)
+       {
+       case I387_CW_FLOOR:
+         /* round down toward -oo */
+         emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0x4)));
+         break;
+
+       case I387_CW_CEIL:
+         /* round up toward +oo */
+         emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0x8)));
+         break;
+
+       case I387_CW_TRUNC:
+         /* round toward zero (truncate) */
+         emit_insn (gen_movsi_insv_1 (reg, GEN_INT (0xc)));
+         break;
+       case I387_CW_MASK_PM:
+         /* mask precision exception for nearbyint() */
+         emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020)));
+         break;
+
+       default:
+         abort();
+       }
+    }
   else
-    emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0xc00)));
-  emit_move_insn (round_down, reg);
+    {
+      switch (mode)
+       {
+       case I387_CW_FLOOR:
+         /* round down toward -oo */
+         emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00)));
+         emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0400)));
+         break;
+
+       case I387_CW_CEIL:
+         /* round up toward +oo */
+         emit_insn (gen_andhi3 (reg, reg, GEN_INT (~0x0c00)));
+         emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0800)));
+         break;
+
+       case I387_CW_TRUNC:
+         /* round toward zero (truncate) */
+         emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0c00)));
+         break;
+
+       case I387_CW_MASK_PM:
+         /* mask precision exception for nearbyint() */
+         emit_insn (gen_iorhi3 (reg, reg, GEN_INT (0x0020)));
+         break;
+
+       default:
+         abort();
+       }
+    }
+
+  emit_move_insn (new_mode, reg);
 }
 
 /* Output code for INSN to convert a float to a signed int.  OPERANDS
index c786080e2b793e74ce7e83693a61f45b38b79b66..4c4ce5843dbc4f9011c4d54c6bd900dd7f974e5c 100644 (file)
@@ -2940,7 +2940,6 @@ extern rtx ix86_compare_op1;      /* operand 1 for comparisons */
    Post-reload pass may be later used to eliminate the redundant fildcw if
    needed.  */
 
-enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY};
 
 /* Define this macro if the port needs extra instructions inserted
    for mode switching in an optimizing compilation.  */
@@ -2955,7 +2954,7 @@ enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY};
    starting counting at zero - determines the integer that is used to
    refer to the mode-switched entity in question.  */
 
-#define NUM_MODES_FOR_MODE_SWITCHING { FP_CW_ANY }
+#define NUM_MODES_FOR_MODE_SWITCHING { I387_CW_ANY }
 
 /* ENTITY is an integer specifying a mode-switched entity.  If
    `OPTIMIZE_MODE_SWITCHING' is defined, you must define this macro to
@@ -2967,10 +2966,10 @@ enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY};
   (GET_CODE (I) == CALL_INSN                                           \
    || (GET_CODE (I) == INSN && (asm_noperands (PATTERN (I)) >= 0       \
                                || GET_CODE (PATTERN (I)) == ASM_INPUT))\
-   ? FP_CW_UNINITIALIZED                                               \
-   : recog_memoized (I) < 0 || get_attr_type (I) != TYPE_FISTP         \
-   ? FP_CW_ANY                                                         \
-   : FP_CW_STORED)
+   ? I387_CW_ANY                                                       \
+   : recog_memoized (I) < 0                                            \
+   ? I387_CW_ANY                                                       \
+   : get_attr_i387_cw (I))
 
 /* This macro specifies the order in which modes for ENTITY are
    processed.  0 is the highest priority.  */
@@ -2982,9 +2981,10 @@ enum fp_cw_mode {FP_CW_STORED, FP_CW_UNINITIALIZED, FP_CW_ANY};
    are to be inserted.  */
 
 #define EMIT_MODE_SET(ENTITY, MODE, HARD_REGS_LIVE)                    \
-  ((MODE) == FP_CW_STORED                                              \
+  ((MODE) != I387_CW_ANY                                               \
    ? emit_i387_cw_initialization (assign_386_stack_local (HImode, 1),  \
-                                 assign_386_stack_local (HImode, 2)), 0\
+                                 assign_386_stack_local (HImode, 2),   \
+                                 MODE), 0                              \
    : 0)
 \f
 /* Avoid renaming of stack registers, as doing so in combination with
index a32063d647e0284c6a4eb2ee75c0286961be96a5..3104e0aec2d11eab614731a83b64162c7b7d4dc2 100644 (file)
    (UNSPEC_FPREM1_F            90)
    (UNSPEC_FPREM1_U            91)
 
+   ; x87 Rounding
+   (UNSPEC_FRNDINT_FLOOR       96)
+   (UNSPEC_FRNDINT_CEIL        97)
+   (UNSPEC_FRNDINT_TRUNC       98)
+   (UNSPEC_FRNDINT_MASK_PM     99)
+
    ; REP instruction
    (UNSPEC_REP                 75)
 
    icmp,test,ibr,setcc,icmov,
    push,pop,call,callv,leave,
    str,cld,
-   fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,
+   fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,frndint,
    sselog,sseiadd,sseishft,sseimul,
    sse,ssemov,sseadd,ssemul,ssecmp,ssecomi,ssecvt,sseicvt,ssediv,
    mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft"
 
 ;; The CPU unit operations uses.
 (define_attr "unit" "integer,i387,sse,mmx,unknown"
-  (cond [(eq_attr "type" "fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp")
+  (cond [(eq_attr "type" "fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,frndint")
           (const_string "i387")
         (eq_attr "type" "sselog,sseiadd,sseishft,sseimul,
                          sse,ssemov,sseadd,ssemul,ssecmp,ssecomi,ssecvt,sseicvt,ssediv")
         (const_int 1)))
 
 ;; The (bounding maximum) length of an instruction in bytes.
-;; ??? fistp is in fact fldcw/fistp/fldcw sequence.  Later we may want
-;; to split it and compute proper length as for other insns.
+;; ??? fistp and frndint are in fact fldcw/{fistp,frndint}/fldcw sequences.
+;; Later we may want to split them and compute proper length as for
+;; other insns.
 (define_attr "length" ""
-  (cond [(eq_attr "type" "other,multi,fistp")
+  (cond [(eq_attr "type" "other,multi,fistp,frndint")
           (const_int 16)
         (eq_attr "type" "fcmp")
           (const_int 4)
           (const_string "none")
         (eq_attr "type" "fistp,leave")
           (const_string "both")
+        (eq_attr "type" "frndint")
+          (const_string "load")
         (eq_attr "type" "push")
           (if_then_else (match_operand 1 "memory_operand" "")
             (const_string "both")
 (define_attr "fp_int_src" "false,true"
   (const_string "false"))
 
+;; Defines rounding mode of an FP operation.
+
+(define_attr "i387_cw" "floor,ceil,trunc,mask_pm,any"
+  (const_string "any"))
+
 ;; Describe a user's asm statement.
 (define_asm_attributes
   [(set_attr "length" "128")
   DONE;
 }
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "DI")])
 
 (define_insn "fix_truncdi_nomemory"
    && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)"
   "#"
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "DI")])
 
 (define_insn "fix_truncdi_memory"
    && (!SSE_FLOAT_MODE_P (GET_MODE (operands[1])) || !TARGET_64BIT)"
   "* operands[5] = operands[4]; return output_fix_trunc (insn, operands);"
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "DI")])
 
 (define_split 
   DONE;
 }
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "SI")])
 
 (define_insn "fix_truncsi_nomemory"
    && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
   "#"
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "SI")])
 
 (define_insn "fix_truncsi_memory"
    && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
   "* return output_fix_trunc (insn, operands);"
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "SI")])
 
 ;; When SSE available, it is always faster to use it!
   DONE;
 }
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "HI")])
 
 (define_insn "fix_trunchi_nomemory"
    && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
   "#"
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "HI")])
 
 (define_insn "fix_trunchi_memory"
    && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
   "* return output_fix_trunc (insn, operands);"
   [(set_attr "type" "fistp")
+   (set_attr "i387_cw" "trunc")
    (set_attr "mode" "HI")])
 
 (define_split 
    (set (match_dup 0) (match_dup 4))]
   "")
 
-;; %% Not used yet.
 (define_insn "x86_fnstcw_1"
   [(set (match_operand:HI 0 "memory_operand" "=m")
        (unspec:HI [(reg:HI FPSR_REG)] UNSPEC_FSTCW))]
   operands[3] = gen_reg_rtx (XFmode);
 })
 
-(define_insn "*frndintxf2"
-  [(set (match_operand:XF 0 "register_operand" "=f")
-       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
-        UNSPEC_FRNDINT))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
-   && flag_unsafe_math_optimizations"
-  "frndint"
-  [(set_attr "type" "fpspc")
-   (set_attr "mode" "XF")])
-
 (define_insn "*f2xm1xf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
   emit_move_insn (operands[2], temp);
   emit_move_insn (operands[9], CONST1_RTX (XFmode));  /* fld1 */
 })
+\f
+
+(define_insn "frndintxf2"
+  [(set (match_operand:XF 0 "register_operand" "=f")
+       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
+        UNSPEC_FRNDINT))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+   && flag_unsafe_math_optimizations"
+  "frndint"
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "XF")])
+
+(define_expand "rintdf2"
+  [(use (match_operand:DF 0 "register_operand" ""))
+   (use (match_operand:DF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+
+  emit_insn (gen_extenddfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2 (op0, op1));
+
+  emit_insn (gen_truncxfdf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "rintsf2"
+  [(use (match_operand:SF 0 "register_operand" ""))
+   (use (match_operand:SF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+
+  emit_insn (gen_extendsfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2 (op0, op1));
+
+  emit_insn (gen_truncxfsf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "rintxf2"
+  [(use (match_operand:XF 0 "register_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  emit_insn (gen_frndintxf2 (operands[0], operands[1]));
+  DONE;
+})
+
+(define_insn "frndintxf2_floor"
+  [(set (match_operand:XF 0 "register_operand" "=f")
+       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
+        UNSPEC_FRNDINT_FLOOR))
+   (use (match_operand:HI 2 "memory_operand" "m"))
+   (use (match_operand:HI 3 "memory_operand" "m"))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+   && flag_unsafe_math_optimizations"
+  "fldcw\t%3\n\tfrndint\n\tfldcw\t%2"
+  [(set_attr "type" "frndint")
+   (set_attr "i387_cw" "floor")
+   (set_attr "mode" "XF")])
+
+(define_expand "floordf2"
+  [(use (match_operand:DF 0 "register_operand" ""))
+   (use (match_operand:DF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extenddfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_floor (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfdf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "floorsf2"
+  [(use (match_operand:SF 0 "register_operand" ""))
+   (use (match_operand:SF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extendsfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_floor (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfsf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "floorxf2"
+  [(use (match_operand:XF 0 "register_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_frndintxf2_floor (operands[0], operands[1], op2, op3));
+  DONE;
+})
+
+(define_insn "frndintxf2_ceil"
+  [(set (match_operand:XF 0 "register_operand" "=f")
+       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
+        UNSPEC_FRNDINT_CEIL))
+   (use (match_operand:HI 2 "memory_operand" "m"))
+   (use (match_operand:HI 3 "memory_operand" "m"))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+   && flag_unsafe_math_optimizations"
+  "fldcw\t%3\n\tfrndint\n\tfldcw\t%2"
+  [(set_attr "type" "frndint")
+   (set_attr "i387_cw" "ceil")
+   (set_attr "mode" "XF")])
+
+(define_expand "ceildf2"
+  [(use (match_operand:DF 0 "register_operand" ""))
+   (use (match_operand:DF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extenddfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_ceil (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfdf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "ceilsf2"
+  [(use (match_operand:SF 0 "register_operand" ""))
+   (use (match_operand:SF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extendsfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_ceil (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfsf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "ceilxf2"
+  [(use (match_operand:XF 0 "register_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_frndintxf2_ceil (operands[0], operands[1], op2, op3));
+  DONE;
+})
+
+(define_insn "frndintxf2_trunc"
+  [(set (match_operand:XF 0 "register_operand" "=f")
+       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
+        UNSPEC_FRNDINT_TRUNC))
+   (use (match_operand:HI 2 "memory_operand" "m"))
+   (use (match_operand:HI 3 "memory_operand" "m"))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+   && flag_unsafe_math_optimizations"
+  "fldcw\t%3\n\tfrndint\n\tfldcw\t%2"
+  [(set_attr "type" "frndint")
+   (set_attr "i387_cw" "trunc")
+   (set_attr "mode" "XF")])
+
+(define_expand "btruncdf2"
+  [(use (match_operand:DF 0 "register_operand" ""))
+   (use (match_operand:DF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extenddfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_trunc (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfdf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "btruncsf2"
+  [(use (match_operand:SF 0 "register_operand" ""))
+   (use (match_operand:SF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extendsfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_trunc (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfsf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "btruncxf2"
+  [(use (match_operand:XF 0 "register_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_frndintxf2_trunc (operands[0], operands[1], op2, op3));
+  DONE;
+})
+
+(define_insn "frndintxf2_mask_pm"
+  [(set (match_operand:XF 0 "register_operand" "=f")
+       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
+        UNSPEC_FRNDINT_MASK_PM))
+   (use (match_operand:HI 2 "memory_operand" "m"))
+   (use (match_operand:HI 3 "memory_operand" "m"))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+   && flag_unsafe_math_optimizations"
+  "fldcw\t%3\n\tfrndint\n\tfclex\n\tfldcw\t%2"
+  [(set_attr "type" "frndint")
+   (set_attr "i387_cw" "mask_pm")
+   (set_attr "mode" "XF")])
+
+(define_expand "nearbyintdf2"
+  [(use (match_operand:DF 0 "register_operand" ""))
+   (use (match_operand:DF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extenddfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_mask_pm (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfdf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "nearbyintsf2"
+  [(use (match_operand:SF 0 "register_operand" ""))
+   (use (match_operand:SF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_extendsfxf2 (op1, operands[1]));
+  emit_insn (gen_frndintxf2_mask_pm (op0, op1, op2, op3));
+
+  emit_insn (gen_truncxfsf2_noop (operands[0], op0));
+  DONE;
+})
+
+(define_expand "nearbyintxf2"
+  [(use (match_operand:XF 0 "register_operand" ""))
+   (use (match_operand:XF 1 "register_operand" ""))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
+   && flag_unsafe_math_optimizations"
+{
+  rtx op2 = assign_386_stack_local (HImode, 1);
+  rtx op3 = assign_386_stack_local (HImode, 2);
+       
+  ix86_optimize_mode_switching = 1;
+
+  emit_insn (gen_frndintxf2_mask_pm (operands[0], operands[1],
+                                    op2, op3));
+  DONE;
+})
+
 \f
 ;; Block operation instructions
 
index 23b6e28b9d428b938c71e5016a72a49a8aa1b3a9..40f1bbd182a955e46caef3b7f9f105452a401c31 100644 (file)
@@ -122,8 +122,9 @@ static const char * const optabs[] =
   "floor_optab->handlers[$A].insn_code = CODE_FOR_$(floor$a2$)",
   "ceil_optab->handlers[$A].insn_code = CODE_FOR_$(ceil$a2$)",
   "round_optab->handlers[$A].insn_code = CODE_FOR_$(round$a2$)",
-  "trunc_optab->handlers[$A].insn_code = CODE_FOR_$(trunc$a2$)",
+  "btrunc_optab->handlers[$A].insn_code = CODE_FOR_$(btrunc$a2$)",
   "nearbyint_optab->handlers[$A].insn_code = CODE_FOR_$(nearbyint$a2$)",
+  "rint_optab->handlers[$A].insn_code = CODE_FOR_$(rint$a2$)",
   "sincos_optab->handlers[$A].insn_code = CODE_FOR_$(sincos$a3$)",
   "sin_optab->handlers[$A].insn_code = CODE_FOR_$(sin$a2$)",
   "asin_optab->handlers[$A].insn_code = CODE_FOR_$(asin$a2$)",
index 6c47b57f00159f5ba3c3245f085ec4fe625edecc..de7f4dc2caa117f66d0dd511c28c48809b06950c 100644 (file)
@@ -4328,6 +4328,7 @@ init_optabs (void)
   round_optab = init_optab (UNKNOWN);
   btrunc_optab = init_optab (UNKNOWN);
   nearbyint_optab = init_optab (UNKNOWN);
+  rint_optab = init_optab (UNKNOWN);
   sincos_optab = init_optab (UNKNOWN);
   sin_optab = init_optab (UNKNOWN);
   asin_optab = init_optab (UNKNOWN);
index 7cf0f9a238a8759d79aac58aacfb5aba2f7c313d..648a158084ac1f48198666e7a54ff58d5c353d5e 100644 (file)
@@ -183,9 +183,10 @@ enum optab_index
   /* Rounding functions */
   OTI_floor,
   OTI_ceil,
-  OTI_trunc,
+  OTI_btrunc,
   OTI_round,
   OTI_nearbyint,
+  OTI_rint,
   /* Tangent */
   OTI_tan,
   /* Inverse tangent */
@@ -299,9 +300,10 @@ extern GTY(()) optab optab_table[OTI_MAX];
 #define log1p_optab (optab_table[OTI_log1p])
 #define floor_optab (optab_table[OTI_floor])
 #define ceil_optab (optab_table[OTI_ceil])
-#define btrunc_optab (optab_table[OTI_trunc])
+#define btrunc_optab (optab_table[OTI_btrunc])
 #define round_optab (optab_table[OTI_round])
 #define nearbyint_optab (optab_table[OTI_nearbyint])
+#define rint_optab (optab_table[OTI_rint])
 #define tan_optab (optab_table[OTI_tan])
 #define atan_optab (optab_table[OTI_atan])
 
index 04220bf0b2d794ecacdf2921a4d5f39879711b22..fc13759af49412d68a8b4ccc53031ddfdda5ca0a 100644 (file)
@@ -1728,6 +1728,12 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
              case UNSPEC_COS:
              case UNSPEC_FRNDINT:
              case UNSPEC_F2XM1:
+
+             case UNSPEC_FRNDINT_FLOOR:
+             case UNSPEC_FRNDINT_CEIL:
+             case UNSPEC_FRNDINT_TRUNC:
+             case UNSPEC_FRNDINT_MASK_PM:
+
                /* These insns only operate on the top of the stack.  */
 
                src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
index 276c31d819162b373b45c4425d4e3d69c48f2290..e0f86f13f7e9d3053d9b8d48eb4fa5dff9b0399f 100644 (file)
@@ -1,3 +1,7 @@
+2004-09-04  Uros Bizjak  <uros@kss-loka.si>
+
+       * testsuite/gcc.dg/builtins-46.c: New.
+
 2004-09-03  Devang Patel  <dpatel@apple.com>
        
        * gcc.dg/tree-ssa/ifc-20040816-1.c: New test.
diff --git a/gcc/testsuite/gcc.dg/builtins-46.c b/gcc/testsuite/gcc.dg/builtins-46.c
new file mode 100644 (file)
index 0000000..67c979f
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright (C) 2004 Free Software Foundation.
+
+   Check that rint, rintf, rintl, floor, floorf, floorl,
+   ceil, ceilf, ceill, trunc, truncf, truncl,
+   nearbyint, nearbyintf and nearbyintl
+   built-in functions compile.
+
+   Written by Uros Bizjak, 25th Aug 2004.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern double rint(double);
+extern double floor(double);
+extern double ceil(double);
+extern double trunc(double);
+extern double nearbyint(double);
+
+extern float rintf(float);
+extern float floorf(float);
+extern float ceilf(float);
+extern float truncf(float);
+extern float nearbyintf(float);
+
+extern long double rintl(long double);
+extern long double floorl(long double);
+extern long double ceill(long double);
+extern long double truncl(long double);
+extern long double nearbyintl(long double);
+
+
+double test1(double x)
+{
+  return rint(x);
+}
+
+double test2(double x)
+{
+  return floor(x);
+}
+
+double test3(double x)
+{
+  return ceil(x);
+}
+
+double test4(double x)
+{
+  return trunc(x);
+}
+
+double test5(double x)
+{
+  return nearbyint(x);
+}
+
+float test1f(float x)
+{
+  return rintf(x);
+}
+
+float test2f(float x)
+{
+  return floorf(x);
+}
+
+float test3f(float x)
+{
+  return ceilf(x);
+}
+
+float test4f(float x)
+{
+  return truncf(x);
+}
+
+float test5f(float x)
+{
+  return nearbyintf(x);
+}
+
+long double test1l(long double x)
+{
+  return rintl(x);
+}
+
+long double test2l(long double x)
+{
+  return floorl(x);
+}
+
+long double test3l(long double x)
+{
+  return ceill(x);
+}
+
+long double test4l(long double x)
+{
+  return truncl(x);
+}
+
+long double test5l(long double x)
+{
+  return nearbyintl(x);
+}