diff options
author | Uros Bizjak <uros@kss-loka.si> | 2004-04-06 21:34:33 +0200 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2004-04-06 19:34:33 +0000 |
commit | 6c7cf1f021db7313abecc4351b973d521c75bcaa (patch) | |
tree | 154509061a748c219394d85b40f993c80d2f7670 /gcc/optabs.c | |
parent | 23bd1514c1a09dfb60b93640f2e70d311745b430 (diff) | |
download | gcc-6c7cf1f021db7313abecc4351b973d521c75bcaa.zip gcc-6c7cf1f021db7313abecc4351b973d521c75bcaa.tar.gz gcc-6c7cf1f021db7313abecc4351b973d521c75bcaa.tar.bz2 |
builtins.c: Implement support for sincos function.
2004-04-06 Uros Bizjak <uros@kss-loka.si>
* 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
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c index 1091cc8..5fe24b7 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); |