Fix nested function support for the ARM
authorNick Clifton <nickc@redhat.com>
Thu, 16 Nov 2000 19:23:15 +0000 (19:23 +0000)
committerNick Clifton <nickc@gcc.gnu.org>
Thu, 16 Nov 2000 19:23:15 +0000 (19:23 +0000)
From-SVN: r37503

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.h

index 7f1cea548edb59e856c724fbeb75bdbc8594b75d..9866dc4cc7935acd24233c1de409c08637720588 100644 (file)
@@ -1,3 +1,15 @@
+2000-11-16  Nick Clifton  <nickc@redhat.com>
+
+       * config/arm/arm.c (output_arm_prologue): Note nested functions.
+       (arm_expand_prologue): For nested functions preserve the
+       static chain register during stack frame creation.
+
+       * config/arm/arm.h (STATIC_CHAIN_REGNUM): Change to 12.
+       (ARM_INITIAL_FRAME_ELIMINATION_OFFSET): For a nested function
+       with a stack frame there is a 4 byte gap between the arg
+       pointer and the hard frame pointer (used to preserve the
+       static chain register during stack frame creation).
+
 2000-11-16  DJ Delorie  <dj@redhat.com>
 
        * rtl.c (read_rtx): Provide suitable names for unnamed
index 7a04dd78ca9781a6d9442c9270de187d1d274542..3bb55227ff13e2e7c40ff6004576bd8853fd7902 100644 (file)
@@ -6776,6 +6776,9 @@ output_arm_prologue (f, frame_size)
   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;
 
@@ -7318,6 +7321,9 @@ arm_expand_prologue ()
      the call-saved regs.  */
   int volatile_func = arm_volatile_func ();
   rtx insn;
+  rtx ip_rtx;
+  int fp_offset = 0;
+      
 
   /* Naked functions don't have prologues.  */
   if (arm_naked_function_p (current_function_decl))
@@ -7345,11 +7351,59 @@ arm_expand_prologue ()
        live_regs_mask |= 1 << LR_REGNUM;
     }
 
+  ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
+  
   if (frame_pointer_needed)
     {
+      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;
+             fp_offset = 4;
+           }
+         else
+           /* FIXME - the way to handle this situation is to allow
+              the pretend args to be dumped onto the stack, then
+              reuse r3 to save IP.  This would involve moving the
+              copying os SP into IP until after the pretend args
+              have been dumped, but this is not too hard.  */
+           error ("Unable to find a temporary location for static chanin register");
+       }
+
       live_regs_mask |= 0xD800;
-      insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
-                                  stack_pointer_rtx));
+
+      if (fp_offset)
+       {
+         insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
+         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;
     }
 
@@ -7426,11 +7480,29 @@ arm_expand_prologue ()
 
   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));
+      insn = GEN_INT (-(4 + current_function_pretend_args_size + fp_offset));
+      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)
index 3078a03f49f3692849e3639b1c8cbbb0a644e431..f9d5cd8baabc9017e0a291bfcd598754729f6acc 100644 (file)
@@ -891,7 +891,7 @@ extern const char * structure_size_string;
 /* The native (Norcroft) Pascal compiler for the ARM passes the static chain
    as an invisible last argument (possible since varargs don't exist in
    Pascal), so the following is not true.  */
-#define STATIC_CHAIN_REGNUM    (TARGET_ARM ? 8 : 9)
+#define STATIC_CHAIN_REGNUM    (TARGET_ARM ? 12 : 9)
 
 /* Define this to be where the real frame pointer is if it is not possible to
    work out the offset between the frame pointer and the automatic variables
@@ -1600,7 +1600,12 @@ typedef struct
 {                                                                      \
   int volatile_func = arm_volatile_func ();                            \
   if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\
-    (OFFSET) = 0;                                                      \
+    {                                                                  \
+      if (! current_function_needs_context || ! frame_pointer_needed)  \
+        (OFFSET) = 0;                                                  \
+      else                                                             \
+        (OFFSET) = 4;                                                  \
+    }                                                                  \
   else if ((FROM) == FRAME_POINTER_REGNUM                              \
           && (TO) == STACK_POINTER_REGNUM)                             \
     (OFFSET) = current_function_outgoing_args_size                     \