diff options
author | Kyrylo Tkachov <ktkachov@gcc.gnu.org> | 2015-05-27 13:25:01 +0000 |
---|---|---|
committer | Kyrylo Tkachov <ktkachov@gcc.gnu.org> | 2015-05-27 13:25:01 +0000 |
commit | 99206968a8da4e5342b498f264eb365e11a499c8 (patch) | |
tree | 1f87b9fb46c70610a2b5ca644213e39984ef9d6a /gcc/calls.c | |
parent | 66371f94f55df849da15ffa9334868de99ac1f8c (diff) | |
download | gcc-99206968a8da4e5342b498f264eb365e11a499c8.zip gcc-99206968a8da4e5342b498f264eb365e11a499c8.tar.gz gcc-99206968a8da4e5342b498f264eb365e11a499c8.tar.bz2 |
[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.
From-SVN: r223753
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 afe61f4..2158eba 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. |