From: Uros Bizjak Date: Tue, 6 Apr 2004 19:34:33 +0000 (+0200) Subject: builtins.c: Implement support for sincos function. X-Git-Tag: releases/gcc-4.0.0~9029 X-Git-Url: https://gcc.gnu.org/git/?a=commitdiff_plain;h=6c7cf1f021db7313abecc4351b973d521c75bcaa;p=gcc.git builtins.c: Implement support for sincos function. 2004-04-06 Uros Bizjak * builtins.c: Implement support for sincos function. (expand_builtin_mathfn): Remove BUILT_IN_SIN{,F,L} and BUILT_IN_COS{,F,L}. (expand_builtin_mathfn_3): New function. (expand_builtin): Expand BUILT_IN_SIN{,F,L} and BUILT_IN_COS{,F,L} using expand_builtin_mathfn_3 if flag_unsafe_math_optimization is set. * optabs.h (enum optab_index): Add new OTI_sincos. (sincos_optab): Define corresponding macro. * optabs.c (init_optabs): Initialize sincos_optab. (expand_twoval_unop): New function. * genopinit.c (optabs): Implement sincos_optab using sincos?f3 patterns. * reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_SINCOS_COS and UNSPEC_SINCOS_SIN. * config/i386/i386.md (sincosdf3, sincossf3, *sincosextendsfdf3, sincosxf3): New patterns to implement sincos, sincosf and sincosl built-ins as inline x87 intrinsics. Define splits for sindf2, sinsf2, *sinextendsfdf2, sinxf2, cosdf2, cossf2, *cosextendsfdf2 and cosxf2 patterns from corresponding sincos patterns. (sindf2, sinsf2, sinxf2): Rename to *sindf2, *sinsf2, *sinxf2. (cosdf2, cossf2, cosxf2): Rename to *cosdf2, *cossf2, *cosxf2. (UNSPEC_SINCOS_SIN, UNPEC_SINCOS_COS): New unspecs to represent x87's unspec insn. * gcc.dg/builtins-36.c: New test. From-SVN: r80463 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c83da8aeac3f..a6df24a238a9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2004-04-06 Uros Bizjak + + * builtins.c: Implement support for sincos function. + (expand_builtin_mathfn): Remove BUILT_IN_SIN{,F,L} and + BUILT_IN_COS{,F,L}. + (expand_builtin_mathfn_3): New function. + (expand_builtin): Expand BUILT_IN_SIN{,F,L} and + BUILT_IN_COS{,F,L} using expand_builtin_mathfn_3 if + flag_unsafe_math_optimization is set. + + * optabs.h (enum optab_index): Add new OTI_sincos. + (sincos_optab): Define corresponding macro. + + * optabs.c (init_optabs): Initialize sincos_optab. + (expand_twoval_unop): New function. + + * genopinit.c (optabs): Implement sincos_optab using sincos?f3 + patterns. + + * reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_SINCOS_COS + and UNSPEC_SINCOS_SIN. + + * config/i386/i386.md (sincosdf3, sincossf3, *sincosextendsfdf3, + sincosxf3): New patterns to implement sincos, sincosf and sincosl + built-ins as inline x87 intrinsics. Define splits for + sindf2, sinsf2, *sinextendsfdf2, sinxf2, cosdf2, + cossf2, *cosextendsfdf2 and cosxf2 patterns from corresponding + sincos patterns. + (sindf2, sinsf2, sinxf2): Rename to *sindf2, *sinsf2, *sinxf2. + (cosdf2, cossf2, cosxf2): Rename to *cosdf2, *cossf2, *cosxf2. + + (UNSPEC_SINCOS_SIN, UNPEC_SINCOS_COS): New unspecs to represent + x87's unspec insn. + 2004-04-06 Devang Patel PR 14467 diff --git a/gcc/builtins.c b/gcc/builtins.c index 33df5eca6846..b0d0d48f2fdd 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -94,6 +94,7 @@ static rtx expand_builtin_classify_type (tree); static void expand_errno_check (tree, rtx); static rtx expand_builtin_mathfn (tree, rtx, rtx); static rtx expand_builtin_mathfn_2 (tree, rtx, rtx); +static rtx expand_builtin_mathfn_3 (tree, rtx, rtx); static rtx expand_builtin_constant_p (tree, enum machine_mode); static rtx expand_builtin_args_info (tree); static rtx expand_builtin_next_arg (tree); @@ -1520,7 +1521,7 @@ expand_errno_check (tree exp, rtx target) } -/* Expand a call to one of the builtin math functions (sin, cos, or sqrt). +/* Expand a call to one of the builtin math functions (sqrt, exp, or log). Return 0 if a normal call should be emitted rather than expanding the function in-line. EXP is the expression that is a call to the builtin function; if convenient, the result should be placed in TARGET. @@ -1544,14 +1545,6 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) switch (DECL_FUNCTION_CODE (fndecl)) { - case BUILT_IN_SIN: - case BUILT_IN_SINF: - case BUILT_IN_SINL: - builtin_optab = sin_optab; break; - case BUILT_IN_COS: - case BUILT_IN_COSF: - case BUILT_IN_COSL: - builtin_optab = cos_optab; break; case BUILT_IN_SQRT: case BUILT_IN_SQRTF: case BUILT_IN_SQRTL: @@ -1815,6 +1808,138 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) return target; } +/* Expand a call to the builtin sin and cos math functions. + Return 0 if a normal call should be emitted rather than expanding the + function in-line. EXP is the expression that is a call to the builtin + function; if convenient, the result should be placed in TARGET. + SUBTARGET may be used as the target for computing one of EXP's + operands. */ + +static rtx +expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget) +{ + optab builtin_optab; + rtx op0, insns, before_call; + tree fndecl = get_callee_fndecl (exp); + tree arglist = TREE_OPERAND (exp, 1); + enum machine_mode mode; + bool errno_set = false; + tree arg, narg; + + if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) + return 0; + + arg = TREE_VALUE (arglist); + + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + case BUILT_IN_COS: + case BUILT_IN_COSF: + case BUILT_IN_COSL: + builtin_optab = sincos_optab; break; + default: + abort (); + } + + /* Make a suitable register to place result in. */ + mode = TYPE_MODE (TREE_TYPE (exp)); + + if (! flag_errno_math || ! HONOR_NANS (mode)) + errno_set = false; + + /* Check if sincos insn is available, otherwise fallback + to sin or cos insn. */ + if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) { + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + builtin_optab = sin_optab; break; + case BUILT_IN_COS: + case BUILT_IN_COSF: + case BUILT_IN_COSL: + builtin_optab = cos_optab; break; + default: + abort(); + } + } + + /* Before working hard, check whether the instruction is available. */ + if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + { + target = gen_reg_rtx (mode); + + /* Wrap the computation of the argument in a SAVE_EXPR, as we may + need to expand the argument again. This way, we will not perform + side-effects more the once. */ + narg = save_expr (arg); + if (narg != arg) + { + arglist = build_tree_list (NULL_TREE, arg); + exp = build_function_call_expr (fndecl, arglist); + } + + op0 = expand_expr (arg, subtarget, VOIDmode, 0); + + emit_queue (); + start_sequence (); + + /* Compute into TARGET. + Set TARGET to wherever the result comes back. */ + if (builtin_optab == sincos_optab) + { + switch (DECL_FUNCTION_CODE (fndecl)) + { + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + if (! expand_twoval_unop(builtin_optab, 0, target, op0, 0)) + abort(); + break; + case BUILT_IN_COS: + case BUILT_IN_COSF: + case BUILT_IN_COSL: + if (! expand_twoval_unop(builtin_optab, target, 0, op0, 0)) + abort(); + break; + default: + abort(); + } + } + else + { + target = expand_unop (mode, builtin_optab, op0, target, 0); + } + + if (target != 0) + { + if (errno_set) + expand_errno_check (exp, target); + + /* Output the entire sequence. */ + insns = get_insns (); + end_sequence (); + emit_insn (insns); + return target; + } + + /* If we were unable to expand via the builtin, stop the sequence + (without outputting the insns) and call to the library function + with the stabilized argument list. */ + end_sequence (); + } + + before_call = get_last_insn (); + + target = expand_call (exp, target, target == const0_rtx); + + return target; +} + /* To evaluate powi(x,n), the floating point value x raised to the constant integer exponent n, we use a hybrid algorithm that combines the "window method" with look-up tables. For an @@ -5042,12 +5167,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, and IMAGPART_EXPR. */ abort (); - case BUILT_IN_SIN: - case BUILT_IN_SINF: - case BUILT_IN_SINL: - case BUILT_IN_COS: - case BUILT_IN_COSF: - case BUILT_IN_COSL: case BUILT_IN_EXP: case BUILT_IN_EXPF: case BUILT_IN_EXPL: @@ -5120,6 +5239,19 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + case BUILT_IN_COS: + case BUILT_IN_COSF: + case BUILT_IN_COSL: + if (! flag_unsafe_math_optimizations) + break; + target = expand_builtin_mathfn_3 (exp, target, subtarget); + if (target) + return target; + break; + case BUILT_IN_APPLY_ARGS: return expand_builtin_apply_args (); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index ad8731b2c654..e9afa7730669 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -121,6 +121,9 @@ (UNSPEC_FRNDINT 68) (UNSPEC_F2XM1 69) + (UNSPEC_SINCOS_COS 80) + (UNSPEC_SINCOS_SIN 81) + ; REP instruction (UNSPEC_REP 75) ]) @@ -14916,7 +14919,7 @@ (set_attr "mode" "XF") (set_attr "athlon_decode" "direct")]) -(define_insn "sindf2" +(define_insn "*sindf2" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 1 "register_operand" "0")] UNSPEC_SIN))] "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 @@ -14925,7 +14928,7 @@ [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "sinsf2" +(define_insn "*sinsf2" [(set (match_operand:SF 0 "register_operand" "=f") (unspec:SF [(match_operand:SF 1 "register_operand" "0")] UNSPEC_SIN))] "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 @@ -14945,7 +14948,7 @@ [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "sinxf2" +(define_insn "*sinxf2" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 1 "register_operand" "0")] UNSPEC_SIN))] "TARGET_80387 && !TARGET_NO_FANCY_MATH_387 @@ -14954,7 +14957,7 @@ [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) -(define_insn "cosdf2" +(define_insn "*cosdf2" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 1 "register_operand" "0")] UNSPEC_COS))] "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 @@ -14963,7 +14966,7 @@ [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "cossf2" +(define_insn "*cossf2" [(set (match_operand:SF 0 "register_operand" "=f") (unspec:SF [(match_operand:SF 1 "register_operand" "0")] UNSPEC_COS))] "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 @@ -14983,7 +14986,7 @@ [(set_attr "type" "fpspc") (set_attr "mode" "DF")]) -(define_insn "cosxf2" +(define_insn "*cosxf2" [(set (match_operand:XF 0 "register_operand" "=f") (unspec:XF [(match_operand:XF 1 "register_operand" "0")] UNSPEC_COS))] "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 @@ -14992,6 +14995,156 @@ [(set_attr "type" "fpspc") (set_attr "mode" "XF")]) +;; With sincos pattern defined, sin and cos builtin function will be +;; expanded to sincos pattern with one of its outputs left unused. +;; Cse pass will detected, if two sincos patterns can be combined, +;; otherwise sincos pattern will be splitted back to sin or cos pattern, +;; depending on the unused output. + +(define_insn "sincosdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(match_operand:DF 2 "register_operand" "0")] + UNSPEC_SINCOS_COS)) + (set (match_operand:DF 1 "register_operand" "=u") + (unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && flag_unsafe_math_optimizations" + "fsincos" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (unspec:DF [(match_operand:DF 2 "register_operand" "")] + UNSPEC_SINCOS_COS)) + (set (match_operand:DF 1 "register_operand" "") + (unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 1) (unspec:DF [(match_dup 2)] UNSPEC_SIN))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (unspec:DF [(match_operand:DF 2 "register_operand" "")] + UNSPEC_SINCOS_COS)) + (set (match_operand:DF 1 "register_operand" "") + (unspec:DF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 0) (unspec:DF [(match_dup 2)] UNSPEC_COS))] + "") + +(define_insn "sincossf3" + [(set (match_operand:SF 0 "register_operand" "=f") + (unspec:SF [(match_operand:SF 2 "register_operand" "0")] + UNSPEC_SINCOS_COS)) + (set (match_operand:SF 1 "register_operand" "=u") + (unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && flag_unsafe_math_optimizations" + "fsincos" + [(set_attr "type" "fpspc") + (set_attr "mode" "SF")]) + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (unspec:SF [(match_operand:SF 2 "register_operand" "")] + UNSPEC_SINCOS_COS)) + (set (match_operand:SF 1 "register_operand" "") + (unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 1) (unspec:SF [(match_dup 2)] UNSPEC_SIN))] + "") + +(define_split + [(set (match_operand:SF 0 "register_operand" "") + (unspec:SF [(match_operand:SF 2 "register_operand" "")] + UNSPEC_SINCOS_COS)) + (set (match_operand:SF 1 "register_operand" "") + (unspec:SF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 0) (unspec:SF [(match_dup 2)] UNSPEC_COS))] + "") + +(define_insn "*sincosextendsfdf3" + [(set (match_operand:DF 0 "register_operand" "=f") + (unspec:DF [(float_extend:DF + (match_operand:SF 2 "register_operand" "0"))] + UNSPEC_SINCOS_COS)) + (set (match_operand:DF 1 "register_operand" "=u") + (unspec:DF [(float_extend:DF + (match_dup 2))] UNSPEC_SINCOS_SIN))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && flag_unsafe_math_optimizations" + "fsincos" + [(set_attr "type" "fpspc") + (set_attr "mode" "DF")]) + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (unspec:DF [(float_extend:DF + (match_operand:SF 2 "register_operand" ""))] + UNSPEC_SINCOS_COS)) + (set (match_operand:DF 1 "register_operand" "") + (unspec:DF [(float_extend:DF + (match_dup 2))] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 1) (unspec:DF [(float_extend:DF + (match_dup 2))] UNSPEC_SIN))] + "") + +(define_split + [(set (match_operand:DF 0 "register_operand" "") + (unspec:DF [(float_extend:DF + (match_operand:SF 2 "register_operand" ""))] + UNSPEC_SINCOS_COS)) + (set (match_operand:DF 1 "register_operand" "") + (unspec:DF [(float_extend:DF + (match_dup 2))] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 0) (unspec:DF [(float_extend:DF + (match_dup 2))] UNSPEC_COS))] + "") + +(define_insn "sincosxf3" + [(set (match_operand:XF 0 "register_operand" "=f") + (unspec:XF [(match_operand:XF 2 "register_operand" "0")] + UNSPEC_SINCOS_COS)) + (set (match_operand:XF 1 "register_operand" "=u") + (unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 + && flag_unsafe_math_optimizations" + "fsincos" + [(set_attr "type" "fpspc") + (set_attr "mode" "XF")]) + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (unspec:XF [(match_operand:XF 2 "register_operand" "")] + UNSPEC_SINCOS_COS)) + (set (match_operand:XF 1 "register_operand" "") + (unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[0])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 1) (unspec:XF [(match_dup 2)] UNSPEC_SIN))] + "") + +(define_split + [(set (match_operand:XF 0 "register_operand" "") + (unspec:XF [(match_operand:XF 2 "register_operand" "")] + UNSPEC_SINCOS_COS)) + (set (match_operand:XF 1 "register_operand" "") + (unspec:XF [(match_dup 2)] UNSPEC_SINCOS_SIN))] + "find_regno_note (insn, REG_UNUSED, REGNO (operands[1])) + && !reload_completed && !reload_in_progress" + [(set (match_dup 0) (unspec:XF [(match_dup 2)] UNSPEC_COS))] + "") + (define_insn "atan2df3_1" [(set (match_operand:DF 0 "register_operand" "=f") (unspec:DF [(match_operand:DF 2 "register_operand" "0") diff --git a/gcc/genopinit.c b/gcc/genopinit.c index b3b651821c0b..fad18793e509 100644 --- a/gcc/genopinit.c +++ b/gcc/genopinit.c @@ -122,6 +122,7 @@ static const char * const optabs[] = "round_optab->handlers[$A].insn_code = CODE_FOR_$(round$a2$)", "trunc_optab->handlers[$A].insn_code = CODE_FOR_$(trunc$a2$)", "nearbyint_optab->handlers[$A].insn_code = CODE_FOR_$(nearbyint$a2$)", + "sincos_optab->handlers[$A].insn_code = CODE_FOR_$(sincos$a3$)", "sin_optab->handlers[$A].insn_code = CODE_FOR_$(sin$a2$)", "cos_optab->handlers[$A].insn_code = CODE_FOR_$(cos$a2$)", "exp_optab->handlers[$A].insn_code = CODE_FOR_$(exp$a2$)", diff --git a/gcc/optabs.c b/gcc/optabs.c index 1091cc81201a..5fe24b7d1fbe 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -2147,6 +2147,109 @@ sign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab, return 0; } +/* Generate code to perform an operation specified by UNOPPTAB + on operand OP0, with two results to TARG0 and TARG1. + We assume that the order of the operands for the instruction + is TARG0, TARG1, OP0. + + Either TARG0 or TARG1 may be zero, but what that means is that + the result is not actually wanted. We will generate it into + a dummy pseudo-reg and discard it. They may not both be zero. + + Returns 1 if this operation can be performed; 0 if not. */ + +int +expand_twoval_unop (optab unoptab, rtx targ0, rtx targ1, rtx op0, + int unsignedp) +{ + enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1); + enum mode_class class; + enum machine_mode wider_mode; + rtx entry_last = get_last_insn (); + rtx last; + + class = GET_MODE_CLASS (mode); + + op0 = protect_from_queue (op0, 0); + + if (flag_force_mem) + { + op0 = force_not_mem (op0); + } + + if (targ0) + targ0 = protect_from_queue (targ0, 1); + else + targ0 = gen_reg_rtx (mode); + if (targ1) + targ1 = protect_from_queue (targ1, 1); + else + targ1 = gen_reg_rtx (mode); + + /* Record where to go back to if we fail. */ + last = get_last_insn (); + + if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + { + int icode = (int) unoptab->handlers[(int) mode].insn_code; + enum machine_mode mode0 = insn_data[icode].operand[2].mode; + rtx pat; + rtx xop0 = op0; + + if (GET_MODE (xop0) != VOIDmode + && GET_MODE (xop0) != mode0) + xop0 = convert_to_mode (mode0, xop0, unsignedp); + + /* Now, if insn doesn't accept these operands, put them into pseudos. */ + if (! (*insn_data[icode].operand[2].predicate) (xop0, mode0)) + xop0 = copy_to_mode_reg (mode0, xop0); + + /* We could handle this, but we should always be called with a pseudo + for our targets and all insns should take them as outputs. */ + if (! (*insn_data[icode].operand[0].predicate) (targ0, mode) + || ! (*insn_data[icode].operand[1].predicate) (targ1, mode)) + abort (); + + pat = GEN_FCN (icode) (targ0, targ1, xop0); + if (pat) + { + emit_insn (pat); + return 1; + } + else + delete_insns_since (last); + } + + /* It can't be done in this mode. Can we do it in a wider mode? */ + + if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT) + { + for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; + wider_mode = GET_MODE_WIDER_MODE (wider_mode)) + { + if (unoptab->handlers[(int) wider_mode].insn_code + != CODE_FOR_nothing) + { + rtx t0 = gen_reg_rtx (wider_mode); + rtx t1 = gen_reg_rtx (wider_mode); + rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp); + + if (expand_twoval_unop (unoptab, t0, t1, cop0, unsignedp)) + { + convert_move (targ0, t0, unsignedp); + convert_move (targ1, t1, unsignedp); + return 1; + } + else + delete_insns_since (last); + } + } + } + + delete_insns_since (entry_last); + return 0; +} + /* Generate code to perform an operation specified by BINOPTAB on operands OP0 and OP1, with two results to TARG1 and TARG2. We assume that the order of the operands for the instruction @@ -5275,6 +5378,7 @@ init_optabs (void) round_optab = init_optab (UNKNOWN); btrunc_optab = init_optab (UNKNOWN); nearbyint_optab = init_optab (UNKNOWN); + sincos_optab = init_optab (UNKNOWN); sin_optab = init_optab (UNKNOWN); cos_optab = init_optab (UNKNOWN); exp_optab = init_optab (UNKNOWN); diff --git a/gcc/optabs.h b/gcc/optabs.h index 765e169cb465..524cb678200c 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -148,6 +148,8 @@ enum optab_index OTI_parity, /* Square root */ OTI_sqrt, + /* Sine-Cosine */ + OTI_sincos, /* Sine */ OTI_sin, /* Cosine */ @@ -264,6 +266,7 @@ extern GTY(()) optab optab_table[OTI_MAX]; #define popcount_optab (optab_table[OTI_popcount]) #define parity_optab (optab_table[OTI_parity]) #define sqrt_optab (optab_table[OTI_sqrt]) +#define sincos_optab (optab_table[OTI_sincos]) #define sin_optab (optab_table[OTI_sin]) #define cos_optab (optab_table[OTI_cos]) #define exp_optab (optab_table[OTI_exp]) @@ -386,6 +389,9 @@ extern rtx expand_binop (enum machine_mode, optab, rtx, rtx, rtx, int, extern rtx sign_expand_binop (enum machine_mode, optab, optab, rtx, rtx, rtx, int, enum optab_methods); +/* Generate code to perform an operation on one operand with two results. */ +extern int expand_twoval_unop (optab, rtx, rtx, rtx, int); + /* Generate code to perform an operation on two operands with two results. */ extern int expand_twoval_binop (optab, rtx, rtx, rtx, rtx, int); diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 31ebddb46401..f238267987af 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -1768,6 +1768,60 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat) replace_reg (dest, FIRST_STACK_REG); break; + case UNSPEC_SINCOS_COS: + /* These insns operate on the top two stack slots, + first part of one input, double output insn. */ + + src1 = get_true_reg (&XVECEXP (pat_src, 0, 0)); + + emit_swap_insn (insn, regstack, *src1); + + src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); + + /* Push the result back onto stack. Empty stack slot + will be filled in second part of insn. */ + if (STACK_REG_P (*dest)) { + regstack->reg[regstack->top + 1] = REGNO (*dest); + SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); + replace_reg (dest, FIRST_STACK_REG); + } + + if (src1_note) + { + replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG); + regstack->top--; + CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1)); + } + replace_reg (src1, FIRST_STACK_REG); + break; + + case UNSPEC_SINCOS_SIN: + src1 = get_true_reg (&XVECEXP (pat_src, 0, 0)); + + emit_swap_insn (insn, regstack, *src1); + + src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1)); + + /* Push the result back onto stack. Fill empty slot from + first part of insn and fix top of stack pointer. */ + if (STACK_REG_P (*dest)) { + regstack->reg[regstack->top] = REGNO (*dest); + SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest)); + replace_reg (dest, FIRST_STACK_REG + 1); + + regstack->top++; + } + + if (src1_note) + { + replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG); + regstack->top--; + CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1)); + } + + replace_reg (src1, FIRST_STACK_REG); + break; + case UNSPEC_SAHF: /* (unspec [(unspec [(compare)] UNSPEC_FNSTSW)] UNSPEC_SAHF) The combination matches the PPRO fcomi instruction. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c7c589da9deb..e4d8c8abfb99 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2004-04-06 Uros Bizjak + + * gcc.dg/builtins-36.c: New test. + 2004-04-06 Paul Brook * README.gcc: Remove obsolete contraint on testcases. diff --git a/gcc/testsuite/gcc.dg/builtins-36.c b/gcc/testsuite/gcc.dg/builtins-36.c new file mode 100644 index 000000000000..dc7119884482 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtins-36.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2004 Free Software Foundation. + + Check sin, sinf, sinl, cos, cosf and cosl built-in functions + eventually compile to sincos, sincosf and sincosl. + + Written by Uros Bizjak, 5th April 2004. */ + +/* { dg-do compile } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern double sin(double); +extern float sinf(float); +extern long double sinl(long double); + +extern double cos(double); +extern float cosf(float); +extern long double cosl(long double); + + +double test1(double x) +{ + double y1, y2; + + y1 = sin(x); + y2 = cos(x); + + return y1 - y2; +} + +float test1f(float x) +{ + float y1, y2; + + y1 = sinf(x); + y2 = cosf(x); + + return y1 - y2; +} + +long double test1l(long double x) +{ + long double y1, y2; + + y1 = sinl(x); + y2 = cosl(x); + + return y1 - y2; +} + +double test2(double x) +{ + return sin(x); +} + +float test2f(float x) +{ + return sinf(x); +} + +long double test2l(long double x) +{ + return sinl(x); +} + +double test3(double x) +{ + return cos(x); +} + +float test3f(float x) +{ + return cosf(x); +} + +long double test3l(long double x) +{ + return cosl(x); +} +