This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [ARM] Fix register r3 wrongly used to save ip in nested APCS frame
- From: Richard Earnshaw <rearnsha at arm dot com>
- To: Eric Botcazou <ebotcazou at adacore dot com>
- Cc: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 05 Sep 2013 15:41:24 +0100
- Subject: Re: [ARM] Fix register r3 wrongly used to save ip in nested APCS frame
- Authentication-results: sourceware.org; auth=none
- References: <2528794 dot 36Q92I15i4 at polaris>
On 05/09/13 15:07, Eric Botcazou wrote:
> Hi,
>
> in case the ip register needs to be saved before establishing an APCS frame,
> i.e. when it is used as the static chain register, the prologue tries various
> tricks in the following order:
>
> 1. The last argument register r3.
> 2. A slot on the stack above the frame. (This only
> works if the function is not a varargs function).
> 3. Register r3 again, after pushing the argument registers
> onto the stack.
>
> #3 doesn't really work since its implementation reads:
>
> {
> /* Store the args on the stack. */
> if (cfun->machine->uses_anonymous_args)
> insn = emit_multi_reg_push
> ((0xf0 >> (args_to_push / 4)) & 0xf);
> else
> insn = emit_insn
> (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
> GEN_INT (- args_to_push)));
>
> RTX_FRAME_RELATED_P (insn) = 1;
>
> saved_pretend_args = 1;
> fp_offset = args_to_push;
> args_to_push = 0;
>
> /* Now reuse r3 to preserve IP. */
> emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
> }
>
> It works only if cfun->machine->uses_anonymous_args is true, because in this
> case r3 is pushed onto the stack as part of the multi-reg push. Otherwise,
> the contents of r3 are simply overwritten by the last line.
>
> Fixed by saving ip on the stack in this latter case, using one of the slots to
> be used by the pushed arguments. This eliminates the last ACATS failures on
> ARM/VxWorks. OK for the mainline?
>
>
> 2013-09-05 Eric Botcazou <ebotcazou@adacore.com>
>
> * config/arm/arm.c (arm_expand_prologue): In a nested APCS frame with
> arguments to push onto the stack and no varargs, save ip into a stack
> slot if r3 isn't available on entry.
>
>
This is all fragile code, so a testcase would be very much appreciated.
R.
>
> p.diff
>
>
> Index: config/arm/arm.c
> ===================================================================
> --- config/arm/arm.c (revision 202160)
> +++ config/arm/arm.c (working copy)
> @@ -18209,11 +18209,13 @@ arm_expand_prologue (void)
> whilst the frame is being created. We try the following
> places in order:
>
> - 1. The last argument register r3.
> - 2. A slot on the stack above the frame. (This only
> - works if the function is not a varargs function).
> + 1. The last argument register r3 if it is available.
> + 2. A slot on the stack above the frame if there are no
> + arguments to push onto the stack.
> 3. Register r3 again, after pushing the argument registers
> - onto the stack.
> + onto the stack, if this is a varargs function.
> + 4. A slot on the stack created for the arguments to push,
> + if this isn't a varargs function.
>
> Note - we only need to tell the dwarf2 backend about the SP
> adjustment in the second variant; the static chain register
> @@ -18244,21 +18246,25 @@ arm_expand_prologue (void)
> {
> /* Store the args on the stack. */
> if (cfun->machine->uses_anonymous_args)
> - insn = emit_multi_reg_push
> - ((0xf0 >> (args_to_push / 4)) & 0xf);
> + {
> + insn
> + = emit_multi_reg_push ((0xf0 >> (args_to_push / 4)) & 0xf);
> + emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
> + saved_pretend_args = 1;
> + }
> else
> - insn = emit_insn
> - (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
> - GEN_INT (- args_to_push)));
> + {
> + rtx x = plus_constant (Pmode, stack_pointer_rtx,
> + args_to_push - 4);
> + insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
> + stack_pointer_rtx,
> + GEN_INT (- args_to_push)));
> + emit_set_insn (gen_frame_mem (SImode, x), ip_rtx);
> + }
>
> RTX_FRAME_RELATED_P (insn) = 1;
> -
> - saved_pretend_args = 1;
> fp_offset = args_to_push;
> args_to_push = 0;
> -
> - /* Now reuse r3 to preserve IP. */
> - emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
> }
> }
>
> @@ -18363,7 +18369,7 @@ arm_expand_prologue (void)
> /* Recover the static chain register. */
> if (!arm_r3_live_at_start_p () || saved_pretend_args)
> insn = gen_rtx_REG (SImode, 3);
> - else /* if (crtl->args.pretend_args_size == 0) */
> + else
> {
> insn = plus_constant (Pmode, hard_frame_pointer_rtx, 4);
> insn = gen_frame_mem (SImode, insn);
>