diff options
author | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-11-13 09:55:11 +0000 |
---|---|---|
committer | ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-11-13 09:55:11 +0000 |
commit | aadbaa4023fe0e7b1ee073f33ca0a6cccd5c2e55 (patch) | |
tree | 19b659552e41d64e2cf5e934a33e7119dada4c08 /gcc/calls.c | |
parent | 16de8065baf08ed0e7bec8a7bc488e8d037d912b (diff) | |
download | gcc-aadbaa4023fe0e7b1ee073f33ca0a6cccd5c2e55.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@106860 138bc75d-0d04-0410-961f-82ee72b054a4
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 920c81575e0..2cc15fc2e81 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) { |