Nested functions on ARM (mk II)

Nick Clifton nickc@redhat.com
Tue Nov 14 17:41:00 GMT 2000


Hi Guys,

  OK, here is a revised patch to fix nested functions for the ARM.

  This patch uses the same solution as the previous version (changing
  the static chain register from the call-saved register r8 to the
  call-clobbered r12).  This time however, if r12 is going to be
  clobbered by stack frame creation the code attempts to find a viable
  alternative place to store the static chain (either an unused
  argument register, or an *allocated* slot on the stack).  If no
  slot can be found, an error message is emitted, rather than silently
  producing bad code.  This should only happen with nested functions
  that use varargs.

  The patch still does not address the corruption of r12 by the PIC
  support code, but if this turns out to be a real issue, it should be
  simple enough to duplicate the solution in this case.

  Here are a couple of example code sequences to show the patch in
  action.  Firstly using a spare argument register:

	mov	r3, ip
	mov	ip, sp
	stmfd	sp!, {fp, ip, lr, pc}
	sub	fp, ip, #4
	sub	sp, sp, #4
	mov	ip, r3

  Secondly using a spare stack slot:

	str	ip, [sp, #-4]!
	add	ip, sp, #4
	stmfd	sp!, {r4, fp, ip, lr, pc}
	sub	fp, ip, #4
	ldr	ip, [fp, #4]

  Any objections to my applying this version ?

Cheers
	Nick

PS.  I was unable to reproduce the problem I saw of stack slots being
used before they were allocated due to the scheduling of instructions
into the prologue.


2000-11-14  Nick Clifton  <nickc@redhat.com>

	* config/arm/arm.c (arm_expand_prologue): IF the static chain
	register is needed and going to be corrupted by stack frame
	creation, attempt to find a place to preserve it.  If none can
	be found, issue an error message.

Index: gcc/config/arm/arm.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/arm/arm.c,v
retrieving revision 1.113
diff -p -r1.113 arm.c
*** arm.c	2000/11/10 16:01:21	1.113
--- arm.c	2000/11/15 01:35:34
*************** output_arm_prologue (f, frame_size)
*** 6776,6781 ****
--- 6776,6784 ----
    if (volatile_func)
      asm_fprintf (f, "\t%@ Volatile function.\n");
  
+   if (current_function_needs_context)
+     asm_fprintf (f, "\t%@ Nested function.\n");
+ 
    if (current_function_anonymous_args && current_function_pretend_args_size)
      store_arg_regs = 1;
  
*************** arm_expand_prologue ()
*** 7318,7323 ****
--- 7321,7327 ----
       the call-saved regs.  */
    int volatile_func = arm_volatile_func ();
    rtx insn;
+   rtx ip_rtx;
  
    /* Naked functions don't have prologues.  */
    if (arm_naked_function_p (current_function_decl))
*************** arm_expand_prologue ()
*** 7345,7355 ****
  	live_regs_mask |= 1 << LR_REGNUM;
      }
  
    if (frame_pointer_needed)
      {
        live_regs_mask |= 0xD800;
!       insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
! 				   stack_pointer_rtx));
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
--- 7349,7404 ----
  	live_regs_mask |= 1 << LR_REGNUM;
      }
  
+   ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
+   
    if (frame_pointer_needed)
      {
+       int offset = 0;
+       
+       if (current_function_needs_context)
+ 	{
+ 	  /* The Static chain register is the same as the IP register
+ 	     used as a scratch register during stack frame creation.
+ 	     To get around this need to find somewhere to store IP
+ 	     whilst the frame is being created.  We try the following
+ 	     places in order:
+ 	     
+ 	       1. An unused argument register.
+ 	       2. A slot on the stack above the frame.  (This only
+ 	          works if the function is not a varargs function).
+ 		  
+ 	     If neither of these places is available, we abort (for now).  */
+ 	  if (regs_ever_live[3] == 0)
+ 	    {
+ 	      insn = gen_rtx_REG (SImode, 3);
+ 	      insn = gen_rtx_SET (SImode, insn, ip_rtx);
+ 	      insn = emit_insn (insn);
+ 	      RTX_FRAME_RELATED_P (insn) = 1;	  
+ 	    }
+ 	  else if (current_function_pretend_args_size == 0)
+ 	    {
+ 	      insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
+ 	      insn = gen_rtx_MEM (SImode, insn);
+ 	      insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
+ 	      insn = emit_insn (insn);
+ 	      RTX_FRAME_RELATED_P (insn) = 1;
+ 	      offset = 4;
+ 	    }
+ 	  else
+ 	    error ("Unable to find a temporary location for static chanin register");
+ 	}
+ 
        live_regs_mask |= 0xD800;
! 
!       if (offset)
! 	{
! 	  insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (4));
! 	  insn = gen_rtx_SET  (SImode, ip_rtx, insn);
! 	}
!       else
! 	insn = gen_movsi (ip_rtx, stack_pointer_rtx);
!       
!       insn = emit_insn (insn);
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
*************** arm_expand_prologue ()
*** 7427,7436 ****
    if (frame_pointer_needed)
      {
        insn = GEN_INT (-(4 + current_function_pretend_args_size));
!       insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
! 				    gen_rtx_REG (SImode, IP_REGNUM),
! 				    insn));
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
    if (amount != const0_rtx)
--- 7476,7503 ----
    if (frame_pointer_needed)
      {
        insn = GEN_INT (-(4 + current_function_pretend_args_size));
!       insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
        RTX_FRAME_RELATED_P (insn) = 1;
+       
+       if (current_function_needs_context)
+ 	{
+ 	  /* Recover the static chain register.  */
+ 	  if (regs_ever_live [3] == 0)
+ 	    {
+ 	      insn = gen_rtx_REG (SImode, 3);
+ 	      insn = gen_rtx_SET (SImode, ip_rtx, insn);
+ 	      insn = emit_insn (insn);
+ 	      RTX_FRAME_RELATED_P (insn) = 1;	  
+ 	    }
+ 	  else /* if (current_function_pretend_args_size == 0) */
+ 	    {
+ 	      insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
+ 	      insn = gen_rtx_MEM (SImode, insn);
+ 	      insn = gen_rtx_SET (SImode, ip_rtx, insn);
+ 	      insn = emit_insn (insn);
+ 	      RTX_FRAME_RELATED_P (insn) = 1;	  
+ 	    }
+ 	}
      }
  
    if (amount != const0_rtx)


More information about the Gcc-bugs mailing list