This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [ARM] Fix register r3 wrongly used to save ip in nested APCS frame


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);
> 



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]