From: Uros Bizjak Date: Sat, 4 Sep 2004 07:55:12 +0000 (+0200) Subject: builtins.c (expand_builtin_mathfn): Handle BUILT_IN_RINT{,F,L} using rint_optab. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=edeacc1415d3cd9c67463c600fa11d0689bae9e9;p=gcc.git builtins.c (expand_builtin_mathfn): Handle BUILT_IN_RINT{,F,L} using rint_optab. 2004-09-04 Uros Bizjak * 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 --- 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 + + * 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 * 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")] @@ -16419,6 +16431,333 @@ emit_move_insn (operands[2], temp); 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 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 + + * testsuite/gcc.dg/builtins-46.c: New. + 2004-09-03 Devang Patel * 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); +}