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
This commit is contained in:
parent
23bd1514c1
commit
6c7cf1f021
9 changed files with 588 additions and 21 deletions
|
@ -1,3 +1,37 @@
|
|||
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.
|
||||
|
||||
2004-04-06 Devang Patel <dpatel@apple.com>
|
||||
|
||||
PR 14467
|
||||
|
|
162
gcc/builtins.c
162
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 ();
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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$)",
|
||||
|
|
104
gcc/optabs.c
104
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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2004-04-06 Uros Bizjak <uros@kss-loka.si>
|
||||
|
||||
* gcc.dg/builtins-36.c: New test.
|
||||
|
||||
2004-04-06 Paul Brook <paul@codesourcery.com>
|
||||
|
||||
* README.gcc: Remove obsolete contraint on testcases.
|
||||
|
|
79
gcc/testsuite/gcc.dg/builtins-36.c
Normal file
79
gcc/testsuite/gcc.dg/builtins-36.c
Normal file
|
@ -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);
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue