Commit 6dab8d4c by Roger Sayle Committed by Roger Sayle

builtins.c (expand_errno_check): Assume that flag_errno_math and HONOR_NANS have…

builtins.c (expand_errno_check): Assume that flag_errno_math and HONOR_NANS have been tested before calling here.


	* builtins.c (expand_errno_check): Assume that flag_errno_math
	and HONOR_NANS have been tested before calling here.  Only try
	to set errno ourselves if the decl can't throw an exception.
	(expand_builtin_mathfn): Move the code to stabilize the arg
	after the main switch, so that that its only done when needed.
	BUILT_IN_SQRT{,F,L} doesn't set errno if its arg is nonnegative.
	Don't modify the original expr when stabilizing the argument.
	(expand_builtin_mathfn_2): Likewise, move the code to stabilize
	the args after the main switch, and don't modify the orginal exp.

From-SVN: r68217
parent cf8e4b78
2003-06-19 Roger Sayle <roger@eyesopen.com>
* builtins.c (expand_errno_check): Assume that flag_errno_math
and HONOR_NANS have been tested before calling here. Only try
to set errno ourselves if the decl can't throw an exception.
(expand_builtin_mathfn): Move the code to stabilize the arg
after the main switch, so that that its only done when needed.
BUILT_IN_SQRT{,F,L} doesn't set errno if its arg is nonnegative.
Don't modify the original expr when stabilizing the argument.
(expand_builtin_mathfn_2): Likewise, move the code to stabilize
the args after the main switch, and don't modify the orginal exp.
2003-06-19 Aldy Hernandez <aldyh@redhat.com> 2003-06-19 Aldy Hernandez <aldyh@redhat.com>
* expr.c (const_vector_from_tree): Initialize remaining elements * expr.c (const_vector_from_tree): Initialize remaining elements
......
...@@ -1653,11 +1653,7 @@ mathfn_built_in (tree type, enum built_in_function fn) ...@@ -1653,11 +1653,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
static void static void
expand_errno_check (tree exp, rtx target) expand_errno_check (tree exp, rtx target)
{ {
rtx lab; rtx lab = gen_label_rtx ();
if (flag_errno_math && HONOR_NANS (GET_MODE (target)))
{
lab = gen_label_rtx ();
/* Test the result; if it is NaN, set errno=EDOM because /* Test the result; if it is NaN, set errno=EDOM because
the argument was not in the domain. */ the argument was not in the domain. */
...@@ -1665,6 +1661,8 @@ expand_errno_check (tree exp, rtx target) ...@@ -1665,6 +1661,8 @@ expand_errno_check (tree exp, rtx target)
0, lab); 0, lab);
#ifdef TARGET_EDOM #ifdef TARGET_EDOM
/* If this built-in doesn't throw an exception, set errno directly. */
if (TREE_NOTHROW (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
{ {
#ifdef GEN_ERRNO_RTX #ifdef GEN_ERRNO_RTX
rtx errno_rtx = GEN_ERRNO_RTX; rtx errno_rtx = GEN_ERRNO_RTX;
...@@ -1672,19 +1670,18 @@ expand_errno_check (tree exp, rtx target) ...@@ -1672,19 +1670,18 @@ expand_errno_check (tree exp, rtx target)
rtx errno_rtx rtx errno_rtx
= gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno")); = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
#endif #endif
emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM)); emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
emit_label (lab);
return;
} }
#else #endif
/* We can't set errno=EDOM directly; let the library call do it. /* We can't set errno=EDOM directly; let the library call do it.
Pop the arguments right away in case the call gets deleted. */ Pop the arguments right away in case the call gets deleted. */
NO_DEFER_POP; NO_DEFER_POP;
expand_call (exp, target, 0); expand_call (exp, target, 0);
OK_DEFER_POP; OK_DEFER_POP;
#endif
emit_label (lab); emit_label (lab);
}
} }
...@@ -1701,35 +1698,14 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) ...@@ -1701,35 +1698,14 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
rtx op0, insns; rtx op0, insns;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1); tree arglist = TREE_OPERAND (exp, 1);
enum machine_mode argmode; enum machine_mode mode;
bool errno_set = false; bool errno_set = false;
tree arg;
if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
return 0; return 0;
/* Stabilize and compute the argument. */ arg = TREE_VALUE (arglist);
if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
&& TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
{
exp = copy_node (exp);
TREE_OPERAND (exp, 1) = arglist;
/* Wrap the computation of the argument in a SAVE_EXPR. That
way, if we need to expand the argument again (as in the
flag_errno_math case below where we cannot directly set
errno), we will not perform side-effects more than once.
Note that here we're mutating the original EXP as well as the
copy; that's the right thing to do in case the original EXP
is expanded later. */
TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
arglist = copy_node (arglist);
}
op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
/* Make a suitable register to place result in. */
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
emit_queue ();
start_sequence ();
switch (DECL_FUNCTION_CODE (fndecl)) switch (DECL_FUNCTION_CODE (fndecl))
{ {
...@@ -1744,7 +1720,9 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) ...@@ -1744,7 +1720,9 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
case BUILT_IN_SQRT: case BUILT_IN_SQRT:
case BUILT_IN_SQRTF: case BUILT_IN_SQRTF:
case BUILT_IN_SQRTL: case BUILT_IN_SQRTL:
errno_set = true; builtin_optab = sqrt_optab; break; errno_set = ! tree_expr_nonnegative_p (arg);
builtin_optab = sqrt_optab;
break;
case BUILT_IN_EXP: case BUILT_IN_EXP:
case BUILT_IN_EXPF: case BUILT_IN_EXPF:
case BUILT_IN_EXPL: case BUILT_IN_EXPL:
...@@ -1785,10 +1763,41 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) ...@@ -1785,10 +1763,41 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
abort (); abort ();
} }
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
target = gen_reg_rtx (mode);
if (! flag_errno_math || ! HONOR_NANS (mode))
errno_set = false;
/* Stabilize and compute the argument. */
if (errno_set)
switch (TREE_CODE (arg))
{
case VAR_DECL:
case PARM_DECL:
case SAVE_EXPR:
case REAL_CST:
break;
default:
/* Wrap the computation of the argument in a SAVE_EXPR, as we
need to expand the argument again in expand_errno_check. This
way, we will not perform side-effects more the once. */
arg = save_expr (arg);
arglist = build_tree_list (NULL_TREE, arg);
exp = build_function_call_expr (fndecl, arglist);
break;
}
op0 = expand_expr (arg, subtarget, VOIDmode, 0);
emit_queue ();
start_sequence ();
/* Compute into TARGET. /* Compute into TARGET.
Set TARGET to wherever the result comes back. */ Set TARGET to wherever the result comes back. */
argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))); target = expand_unop (mode, builtin_optab, op0, target, 0);
target = expand_unop (argmode, builtin_optab, op0, target, 0);
/* If we were unable to expand via the builtin, stop the /* If we were unable to expand via the builtin, stop the
sequence (without outputting the insns) and return 0, causing sequence (without outputting the insns) and return 0, causing
...@@ -1824,8 +1833,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) ...@@ -1824,8 +1833,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
rtx op0, op1, insns; rtx op0, op1, insns;
tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
tree arglist = TREE_OPERAND (exp, 1); tree arglist = TREE_OPERAND (exp, 1);
tree arg0, arg1; tree arg0, arg1, temp;
enum machine_mode argmode; enum machine_mode mode;
bool errno_set = true; bool errno_set = true;
bool stable = true; bool stable = true;
...@@ -1835,55 +1844,76 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) ...@@ -1835,55 +1844,76 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
arg0 = TREE_VALUE (arglist); arg0 = TREE_VALUE (arglist);
arg1 = TREE_VALUE (TREE_CHAIN (arglist)); arg1 = TREE_VALUE (TREE_CHAIN (arglist));
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_POW:
case BUILT_IN_POWF:
case BUILT_IN_POWL:
builtin_optab = pow_optab; break;
case BUILT_IN_ATAN2:
case BUILT_IN_ATAN2F:
case BUILT_IN_ATAN2L:
builtin_optab = atan2_optab; break;
default:
abort ();
}
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
target = gen_reg_rtx (mode);
if (! flag_errno_math || ! HONOR_NANS (mode))
errno_set = false;
/* Stabilize the arguments. */ /* Stabilize the arguments. */
if (TREE_CODE (arg0) != VAR_DECL && TREE_CODE (arg0) != PARM_DECL) if (errno_set)
{ {
arg0 = save_expr (arg0); switch (TREE_CODE (arg1))
TREE_VALUE (arglist) = arg0; {
case VAR_DECL:
case PARM_DECL:
case SAVE_EXPR:
case REAL_CST:
temp = TREE_CHAIN (arglist);
break;
default:
stable = false; stable = false;
arg1 = save_expr (arg1);
temp = build_tree_list (NULL_TREE, arg1);
break;
} }
if (TREE_CODE (arg1) != VAR_DECL && TREE_CODE (arg1) != PARM_DECL)
switch (TREE_CODE (arg0))
{ {
arg1 = save_expr (arg1); case VAR_DECL:
TREE_VALUE (TREE_CHAIN (arglist)) = arg1; case PARM_DECL:
case SAVE_EXPR:
case REAL_CST:
if (! stable)
arglist = build_tree_list (temp, arg0);
break;
default:
stable = false; stable = false;
arg0 = save_expr (arg0);
arglist = build_tree_list (temp, arg0);
break;
} }
if (! stable) if (! stable)
{ exp = build_function_call_expr (fndecl, arglist);
exp = copy_node (exp);
arglist = tree_cons (NULL_TREE, arg0,
build_tree_list (NULL_TREE, arg1));
TREE_OPERAND (exp, 1) = arglist;
} }
op0 = expand_expr (arg0, subtarget, VOIDmode, 0); op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
op1 = expand_expr (arg1, 0, VOIDmode, 0); op1 = expand_expr (arg1, 0, VOIDmode, 0);
/* Make a suitable register to place result in. */
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
emit_queue (); emit_queue ();
start_sequence (); start_sequence ();
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_POW:
case BUILT_IN_POWF:
case BUILT_IN_POWL:
builtin_optab = pow_optab; break;
case BUILT_IN_ATAN2:
case BUILT_IN_ATAN2F:
case BUILT_IN_ATAN2L:
builtin_optab = atan2_optab; break;
default:
abort ();
}
/* Compute into TARGET. /* Compute into TARGET.
Set TARGET to wherever the result comes back. */ Set TARGET to wherever the result comes back. */
argmode = TYPE_MODE (TREE_TYPE (arg0)); target = expand_binop (mode, builtin_optab, op0, op1,
target = expand_binop (argmode, builtin_optab, op0, op1,
target, 0, OPTAB_DIRECT); target, 0, OPTAB_DIRECT);
/* If we were unable to expand via the builtin, stop the /* If we were unable to expand via the builtin, stop the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment