summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authoruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-04 07:55:12 +0000
committeruros <uros@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-04 07:55:12 +0000
commitaef94a0f415f1b061e801ced6f2f9c104fe0e9e5 (patch)
tree5beec64804178bdcce9d3a40bbad23d26dc23d85 /gcc
parent4ac89247888f33698d49c7d92bd505fe78d852c1 (diff)
downloadgcc-aef94a0f415f1b061e801ced6f2f9c104fe0e9e5.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@87076 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog60
-rw-r--r--gcc/builtins.c7
-rw-r--r--gcc/config/i386/i386-protos.h2
-rw-r--r--gcc/config/i386/i386.c75
-rw-r--r--gcc/config/i386/i386.h16
-rw-r--r--gcc/config/i386/i386.md371
-rw-r--r--gcc/genopinit.c3
-rw-r--r--gcc/optabs.c1
-rw-r--r--gcc/optabs.h6
-rw-r--r--gcc/reg-stack.c6
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/builtins-46.c105
12 files changed, 619 insertions, 37 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f19a4f411fb..2cf1b5b5610 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index b0d7c4c779e..97800bfef02 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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;
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 57b6d054baf..1c87da6385d 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -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);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 760c7f0d997..4a869527505 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index c786080e2b7..4c4ce5843db 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -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)
/* Avoid renaming of stack registers, as doing so in combination with
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index a32063d647e..3104e0aec2d 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -134,6 +134,12 @@
(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)
@@ -185,7 +191,7 @@
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"
@@ -198,7 +204,7 @@
;; 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")
@@ -315,10 +321,11 @@
(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)
@@ -346,6 +353,8 @@
(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")
@@ -420,6 +429,11 @@
(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")
@@ -4098,6 +4112,7 @@
DONE;
}
[(set_attr "type" "fistp")
+ (set_attr "i387_cw" "trunc")
(set_attr "mode" "DI")])
(define_insn "fix_truncdi_nomemory"
@@ -4111,6 +4126,7 @@
&& (!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"
@@ -4123,6 +4139,7 @@
&& (!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
@@ -4263,6 +4280,7 @@
DONE;
}
[(set_attr "type" "fistp")
+ (set_attr "i387_cw" "trunc")
(set_attr "mode" "SI")])
(define_insn "fix_truncsi_nomemory"
@@ -4275,6 +4293,7 @@
&& !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"
@@ -4286,6 +4305,7 @@
&& !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!
@@ -4404,6 +4424,7 @@
DONE;
}
[(set_attr "type" "fistp")
+ (set_attr "i387_cw" "trunc")
(set_attr "mode" "HI")])
(define_insn "fix_trunchi_nomemory"
@@ -4416,6 +4437,7 @@
&& !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"
@@ -4427,6 +4449,7 @@
&& !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
@@ -4455,7 +4478,6 @@
(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))]
@@ -16040,16 +16062,6 @@
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")]
@@ -16420,6 +16432,333 @@
emit_move_insn (operands[9], CONST1_RTX (XFmode)); /* fld1 */
})
+
+(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;
+})
+
+
;; Block operation instructions
(define_insn "cld"
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 23b6e28b9d4..40f1bbd182a 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -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$)",
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 6c47b57f001..de7f4dc2caa 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -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);
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 7cf0f9a238a..648a158084a 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -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])
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index 04220bf0b2d..fc13759af49 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -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));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 276c31d8191..e0f86f13f7e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..67c979f73f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-46.c
@@ -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);
+}