diff options
author | Roger Sayle <roger@eyesopen.com> | 2003-06-19 19:30:34 +0000 |
---|---|---|
committer | Roger Sayle <sayle@gcc.gnu.org> | 2003-06-19 19:30:34 +0000 |
commit | 6dab8d4cdf065d4045132d01e9c2556bdcab4195 (patch) | |
tree | 7af02d8fec3c643ce7d7d78668269c6d7cfb822d /gcc/builtins.c | |
parent | cf8e4b78762b282387140a4cf54c880bbc87acd4 (diff) | |
download | gcc-6dab8d4cdf065d4045132d01e9c2556bdcab4195.zip gcc-6dab8d4cdf065d4045132d01e9c2556bdcab4195.tar.gz gcc-6dab8d4cdf065d4045132d01e9c2556bdcab4195.tar.bz2 |
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
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 200 |
1 files changed, 115 insertions, 85 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 0a53e3c..8f278aa 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -1653,38 +1653,35 @@ mathfn_built_in (tree type, enum built_in_function fn) static void 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 - the argument was not in the domain. */ - emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target), - 0, lab); + /* Test the result; if it is NaN, set errno=EDOM because + the argument was not in the domain. */ + emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target), + 0, lab); #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 - rtx errno_rtx = GEN_ERRNO_RTX; + rtx errno_rtx = GEN_ERRNO_RTX; #else - rtx errno_rtx + rtx errno_rtx = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno")); #endif - - emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM)); - } -#else - /* We can't set errno=EDOM directly; let the library call do it. - Pop the arguments right away in case the call gets deleted. */ - NO_DEFER_POP; - expand_call (exp, target, 0); - OK_DEFER_POP; -#endif - + emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM)); emit_label (lab); + return; } +#endif + + /* We can't set errno=EDOM directly; let the library call do it. + Pop the arguments right away in case the call gets deleted. */ + NO_DEFER_POP; + expand_call (exp, target, 0); + OK_DEFER_POP; + emit_label (lab); } @@ -1701,35 +1698,14 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) rtx op0, insns; tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); tree arglist = TREE_OPERAND (exp, 1); - enum machine_mode argmode; + enum machine_mode mode; bool errno_set = false; + tree arg; if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE)) return 0; - /* Stabilize and compute the argument. */ - 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 (); + arg = TREE_VALUE (arglist); switch (DECL_FUNCTION_CODE (fndecl)) { @@ -1744,7 +1720,9 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) case BUILT_IN_SQRT: case BUILT_IN_SQRTF: 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_EXPF: case BUILT_IN_EXPL: @@ -1785,10 +1763,41 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget) 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. Set TARGET to wherever the result comes back. */ - argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))); - target = expand_unop (argmode, builtin_optab, op0, target, 0); + target = expand_unop (mode, builtin_optab, op0, target, 0); /* If we were unable to expand via the builtin, stop the sequence (without outputting the insns) and return 0, causing @@ -1824,8 +1833,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) rtx op0, op1, insns; tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); tree arglist = TREE_OPERAND (exp, 1); - tree arg0, arg1; - enum machine_mode argmode; + tree arg0, arg1, temp; + enum machine_mode mode; bool errno_set = true; bool stable = true; @@ -1835,37 +1844,6 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) arg0 = TREE_VALUE (arglist); arg1 = TREE_VALUE (TREE_CHAIN (arglist)); - /* Stabilize the arguments. */ - if (TREE_CODE (arg0) != VAR_DECL && TREE_CODE (arg0) != PARM_DECL) - { - arg0 = save_expr (arg0); - TREE_VALUE (arglist) = arg0; - stable = false; - } - if (TREE_CODE (arg1) != VAR_DECL && TREE_CODE (arg1) != PARM_DECL) - { - arg1 = save_expr (arg1); - TREE_VALUE (TREE_CHAIN (arglist)) = arg1; - stable = false; - } - - if (! stable) - { - 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); - 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 (); - start_sequence (); - switch (DECL_FUNCTION_CODE (fndecl)) { case BUILT_IN_POW: @@ -1880,10 +1858,62 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget) 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. */ + if (errno_set) + { + switch (TREE_CODE (arg1)) + { + case VAR_DECL: + case PARM_DECL: + case SAVE_EXPR: + case REAL_CST: + temp = TREE_CHAIN (arglist); + break; + + default: + stable = false; + arg1 = save_expr (arg1); + temp = build_tree_list (NULL_TREE, arg1); + break; + } + + switch (TREE_CODE (arg0)) + { + case VAR_DECL: + case PARM_DECL: + case SAVE_EXPR: + case REAL_CST: + if (! stable) + arglist = build_tree_list (temp, arg0); + break; + + default: + stable = false; + arg0 = save_expr (arg0); + arglist = build_tree_list (temp, arg0); + break; + } + + if (! stable) + exp = build_function_call_expr (fndecl, arglist); + } + + op0 = expand_expr (arg0, subtarget, VOIDmode, 0); + op1 = expand_expr (arg1, 0, VOIDmode, 0); + + emit_queue (); + start_sequence (); + /* Compute into TARGET. Set TARGET to wherever the result comes back. */ - argmode = TYPE_MODE (TREE_TYPE (arg0)); - target = expand_binop (argmode, builtin_optab, op0, op1, + target = expand_binop (mode, builtin_optab, op0, op1, target, 0, OPTAB_DIRECT); /* If we were unable to expand via the builtin, stop the |