diff options
author | ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-05-27 13:25:01 +0000 |
---|---|---|
committer | ktkachov <ktkachov@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-05-27 13:25:01 +0000 |
commit | a95e57762d0418d031feae89c90762758500c36e (patch) | |
tree | 1f87b9fb46c70610a2b5ca644213e39984ef9d6a /gcc/calls.c | |
parent | 3c9ef6293e6307d288aa213a2cb2047649d9b0c3 (diff) | |
download | gcc-a95e57762d0418d031feae89c90762758500c36e.tar.gz |
[expr.c] PR target/65358 Avoid clobbering partial argument during sibcall
PR target/65358
* expr.c (memory_load_overlap): New function.
(emit_push_insn): When pushing partial args to the stack would
clobber the register part load the overlapping part into a pseudo
and put it into the hard reg after pushing. Change return type
to bool. Add bool argument.
* expr.h (emit_push_insn): Change return type to bool.
Add bool argument.
* calls.c (expand_call): Cancel sibcall optimization when encountering
partial argument on targets with ARGS_GROW_DOWNWARD and
!STACK_GROWS_DOWNWARD.
(emit_library_call_value_1): Update callsite of emit_push_insn.
(store_one_arg): Likewise.
PR target/65358
* gcc.dg/pr65358.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@223753 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index afe61f47d87..2158ebad0b4 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -3234,6 +3234,15 @@ expand_call (tree exp, rtx target, int ignore) { rtx_insn *before_arg = get_last_insn (); + /* On targets with weird calling conventions (e.g. PA) it's + hard to ensure that all cases of argument overlap between + stack and registers work. Play it safe and bail out. */ + if (ARGS_GROW_DOWNWARD && !STACK_GROWS_DOWNWARD) + { + sibcall_failure = 1; + break; + } + if (store_one_arg (&args[i], argblock, flags, adjusted_args_size.var != 0, reg_parm_stack_space) @@ -4276,7 +4285,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, partial, reg, 0, argblock, GEN_INT (argvec[argnum].locate.offset.constant), reg_parm_stack_space, - ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad)); + ARGS_SIZE_RTX (argvec[argnum].locate.alignment_pad), false); /* Now mark the segment we just used. */ if (ACCUMULATE_OUTGOING_ARGS) @@ -4886,10 +4895,11 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, /* This isn't already where we want it on the stack, so put it there. This can either be done with push or copy insns. */ - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, + if (!emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, parm_align, partial, reg, used - size, argblock, ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, - ARGS_SIZE_RTX (arg->locate.alignment_pad)); + ARGS_SIZE_RTX (arg->locate.alignment_pad), true)) + sibcall_failure = 1; /* Unless this is a partially-in-register argument, the argument is now in the stack. */ @@ -4994,7 +5004,7 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx, parm_align, partial, reg, excess, argblock, ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, - ARGS_SIZE_RTX (arg->locate.alignment_pad)); + ARGS_SIZE_RTX (arg->locate.alignment_pad), false); /* Unless this is a partially-in-register argument, the argument is now in the stack. |