diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2005-11-13 09:55:11 +0000 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2005-11-13 09:55:11 +0000 |
commit | 51caaefe17ece564e44fdf6c98dba20569c95663 (patch) | |
tree | 19b659552e41d64e2cf5e934a33e7119dada4c08 /gcc/calls.c | |
parent | 5d723e5434e83d9de5271f6d1c24a694826450a8 (diff) | |
download | gcc-51caaefe17ece564e44fdf6c98dba20569c95663.zip gcc-51caaefe17ece564e44fdf6c98dba20569c95663.tar.gz gcc-51caaefe17ece564e44fdf6c98dba20569c95663.tar.bz2 |
re PR middle-end/24003 (17 ACATS regressions (fixed point or decimal artihmetic))
PR middle-end/24003
* calls.c (expand_call): If TARGET is a MEM and some part of the
argument area has been saved, force TARGET to a register.
Co-Authored-By: Ian Lance Taylor <ian@airs.com>
From-SVN: r106860
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index 920c8157..2cc15fc 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -2857,6 +2857,8 @@ expand_call (tree exp, rtx target, int ignore) && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)) && GET_MODE (target) == GET_MODE (valreg)) { + bool may_overlap = false; + /* We have to copy a return value in a CLASS_LIKELY_SPILLED hard reg to a plain register. */ if (REG_P (valreg) @@ -2865,19 +2867,40 @@ expand_call (tree exp, rtx target, int ignore) && !(REG_P (target) && !HARD_REGISTER_P (target))) valreg = copy_to_reg (valreg); - /* TARGET and VALREG cannot be equal at this point because the - latter would not have REG_FUNCTION_VALUE_P true, while the - former would if it were referring to the same register. - - If they refer to the same register, this move will be a no-op, - except when function inlining is being done. */ - emit_move_insn (target, valreg); + /* If TARGET is a MEM in the argument area, and we have + saved part of the argument area, then we can't store + directly into TARGET as it may get overwritten when we + restore the argument save area below. Don't work too + hard though and simply force TARGET to a register if it + is a MEM; the optimizer is quite likely to sort it out. */ + if (ACCUMULATE_OUTGOING_ARGS && pass && MEM_P (target)) + for (i = 0; i < num_actuals; i++) + if (args[i].save_area) + { + may_overlap = true; + break; + } - /* If we are setting a MEM, this code must be executed. Since it is - emitted after the call insn, sibcall optimization cannot be - performed in that case. */ - if (MEM_P (target)) - sibcall_failure = 1; + if (may_overlap) + target = copy_to_reg (valreg); + else + { + /* TARGET and VALREG cannot be equal at this point + because the latter would not have + REG_FUNCTION_VALUE_P true, while the former would if + it were referring to the same register. + + If they refer to the same register, this move will be + a no-op, except when function inlining is being + done. */ + emit_move_insn (target, valreg); + + /* If we are setting a MEM, this code must be executed. + Since it is emitted after the call insn, sibcall + optimization cannot be performed in that case. */ + if (MEM_P (target)) + sibcall_failure = 1; + } } else if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode) { |