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  <ebotca...@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);
> 


Reply via email to