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: [PATCH] ARM EABI alignment


> The attached patch 

This time with the patch.

Paul

2004-02-23  Paul Brook  <paul@nowt.org>

	* config/arm/arm-protos.h (arm_get_frame_size): Remove prototype.
	(arm_needs_doubleword_align): Add prototype.
	* config/arm/arm.c (arm_get_frame_offsets): New function.
	(use_return_insn, output_return_instruction, arm_output_epilogue,
	arm_output_function_epilogue, arm_compute_initial_elimination_offset,
	arm_expand_prologue): Use it.
	(thumb_get_frame_size): Use local_vars field.
	(arm_get_frame_size): Remove.
	(arm_function_arg): Put doubleword aligned values in even regs.
	(arm_va_arg): Handle all doubleword aligned args.
	(arm_compute_save_reg0_reg12_mask): Fix comment.
	* config/arm/arm.h (TARGET_SWITCHES): Add "aapcs".
	(ARM_DOUBLEWORD_ALIGN): Define.
	(BIGGEST_ALIGNMENT): Use it.
	(PREFERRED_STACK_BOUNDARY): Define.
	(struct arm_stack_offsets): Define.
	(struct machine_function): Add stack_offsets.  Remove frame_size.
	* doc/invoke.texi <ARM>: Document -maapcs.
Index: config/arm/arm-protos.h
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.63
diff -u -p -r1.63 arm-protos.h
--- a/config/arm/arm-protos.h	25 Feb 2004 17:03:26 -0000	1.63
+++ b/config/arm/arm-protos.h	1 Mar 2004 11:24:54 -0000
@@ -31,7 +31,6 @@ extern void arm_finalize_pic (int);
 extern int arm_volatile_func (void);
 extern const char *arm_output_epilogue (rtx);
 extern void arm_expand_prologue (void);
-extern HOST_WIDE_INT arm_get_frame_size	(void);
 extern const char *arm_strip_name_encoding (const char *);
 extern void arm_asm_output_labelref (FILE *, const char *);
 extern unsigned long arm_current_func_type (void);
@@ -157,6 +156,7 @@ extern void arm_init_cumulative_args (CU
 extern rtx arm_va_arg (tree, tree);
 extern int arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *,
 					       enum machine_mode, tree, int);
+extern bool arm_needs_doubleword_align (enum machine_mode, tree);
 #endif
 
 #if defined AOF_ASSEMBLER 
Index: config/arm/arm.c
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.335
diff -u -p -r1.335 arm.c
--- a/config/arm/arm.c	25 Feb 2004 17:03:26 -0000	1.335
+++ b/config/arm/arm.c	3 Mar 2004 10:44:00 -0000
@@ -59,6 +59,7 @@ typedef struct minipool_fixup   Mfix;
 const struct attribute_spec arm_attribute_table[];
 
 /* Forward function declarations.  */
+static arm_stack_offsets *arm_get_frame_offsets (void);
 static void arm_add_gc_roots (void);
 static int arm_gen_constant (enum rtx_code, enum machine_mode, HOST_WIDE_INT,
 			     rtx, rtx, int, int);
@@ -908,14 +909,19 @@ arm_override_options (void)
   
   arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
   
+  /* Override the default structure alignment if AAPCS is specified.  */
+/*  if (TARGET_AAPCS)
+    arm_structure_size_boundary = 8;*/
+
   if (structure_size_string != NULL)
     {
       int size = strtol (structure_size_string, NULL, 0);
       
-      if (size == 8 || size == 32)
+      if (size == 8 || size == 32
+	  || (TARGET_AAPCS && size == 64))
 	arm_structure_size_boundary = size;
       else
-	warning ("structure size boundary can only be set to 8 or 32");
+	warning ("structure size boundary can only be set to 8, 32 or 64");
     }
 
   if (arm_pic_register_string != NULL)
@@ -1109,6 +1115,7 @@ use_return_insn (int iscond, rtx sibling
   unsigned int func_type;
   unsigned long saved_int_regs;
   unsigned HOST_WIDE_INT stack_adjust;
+  arm_stack_offsets *offsets;
 
   /* Never use a return instruction before reload has run.  */
   if (!reload_completed)
@@ -1125,7 +1132,8 @@ use_return_insn (int iscond, rtx sibling
   if (IS_INTERRUPT (func_type) && frame_pointer_needed)
     return 0;
 
-  stack_adjust = arm_get_frame_size () + current_function_outgoing_args_size;
+  offsets = arm_get_frame_offsets ();
+  stack_adjust = offsets->outgoing_args - offsets->saved_regs;
 
   /* As do variadic functions.  */
   if (current_function_pretend_args_size
@@ -2178,6 +2186,17 @@ arm_init_cumulative_args (CUMULATIVE_ARG
     }
 }
 
+
+/* Return true if type need doubleword alignment.  */
+bool
+arm_needs_doubleword_align (enum machine_mode mode, tree type)
+{
+  return (mode == DImode || mode == DFmode
+	  || (mode == BLKmode
+	      && TYPE_ALIGN (type) == ARM_DOUBLEWORD_ALIGN));
+}
+
+
 /* Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
@@ -2193,7 +2212,7 @@ arm_init_cumulative_args (CUMULATIVE_ARG
 
 rtx
 arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
-		  tree type ATTRIBUTE_UNUSED, int named)
+		  tree type, int named)
 {
   if (TARGET_REALLY_IWMMXT)
     {
@@ -2216,9 +2235,15 @@ arm_function_arg (CUMULATIVE_ARGS *pcum,
 	    return NULL_RTX;
 	}
       else if ((mode == DImode || mode == DFmode) && pcum->nregs & 1)
-	pcum->nregs += 1;
+        pcum->nregs += 1;
     }
 
+  /* Put doubleword aligned quantities in even register pairs.  */
+  if (TARGET_AAPCS
+      && pcum->nregs & 1
+      && arm_needs_doubleword_align (mode, type))
+    pcum->nregs++;
+
   if (mode == VOIDmode)
     /* Compute operand 2 of the call insn.  */
     return GEN_INT (pcum->call_cookie);
@@ -2245,6 +2270,8 @@ arm_function_arg_pass_by_reference (CUMU
 rtx
 arm_va_arg (tree valist, tree type)
 {
+  int align;
+
   /* Variable sized types are passed by reference.  */
   if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
     {
@@ -2252,17 +2279,18 @@ arm_va_arg (tree valist, tree type)
       return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));
     }
 
-  if (FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), NULL) == IWMMXT_ALIGNMENT)
+  align = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
+  if (align > PARM_BOUNDARY)
     {
-      tree minus_eight;
+      tree mask;
       tree t;
 
       /* Maintain 64-bit alignment of the valist pointer by
 	 constructing:   valist = ((valist + (8 - 1)) & -8).  */
-      minus_eight = build_int_2 (- (IWMMXT_ALIGNMENT / BITS_PER_UNIT), -1);
-      t = build_int_2 ((IWMMXT_ALIGNMENT / BITS_PER_UNIT) - 1, 0);
+      mask = build_int_2 (- (align / BITS_PER_UNIT), -1);
+      t = build_int_2 ((align / BITS_PER_UNIT) - 1, 0);
       t = build (PLUS_EXPR,    TREE_TYPE (valist), valist, t);
-      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, minus_eight);
+      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, mask);
       t = build (MODIFY_EXPR,  TREE_TYPE (valist), valist, t);
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -8669,8 +8697,7 @@ output_ascii_pseudo_op (FILE *stream, co
 }
 
 /* Compute the register sabe mask for registers 0 through 12
-   inclusive.  This code is used by both arm_compute_save_reg_mask
-   and arm_compute_initial_elimination_offset.  */
+   inclusive.  This code is used by arm_compute_save_reg_mask.  */
 static unsigned long
 arm_compute_save_reg0_reg12_mask (void)
 {
@@ -8816,6 +8843,7 @@ output_return_instruction (rtx operand, 
   int reg;
   unsigned long live_regs_mask;
   unsigned long func_type;
+  arm_stack_offsets *offsets;
 
   func_type = arm_current_func_type ();
 
@@ -8914,9 +8942,10 @@ output_return_instruction (rtx operand, 
 	     points to the base of the saved core registers.  */
 	  if (live_regs_mask & (1 << SP_REGNUM))
 	    {
-	      unsigned HOST_WIDE_INT stack_adjust =
-		arm_get_frame_size () + current_function_outgoing_args_size;
-	      
+	      unsigned HOST_WIDE_INT stack_adjust;
+
+	      offsets = arm_get_frame_offsets ();
+	      stack_adjust = offsets->outgoing_args - offsets->saved_regs;
 	      if (stack_adjust != 0 && stack_adjust != 4)
 		abort ();
 
@@ -9136,6 +9165,7 @@ arm_output_function_prologue (FILE *f, H
   return_used_this_function = 0;  
 }
 
+
 const char *
 arm_output_epilogue (rtx sibling)
 {
@@ -9146,12 +9176,12 @@ arm_output_epilogue (rtx sibling)
      frame that is $fp + 4 for a non-variadic function.  */
   int floats_offset = 0;
   rtx operands[3];
-  int frame_size = arm_get_frame_size ();
   FILE * f = asm_out_file;
   rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
   unsigned int lrm_count = 0;
   int really_return = (sibling == NULL);
   int start_reg;
+  arm_stack_offsets *offsets;
 
   /* If we have already generated the return instruction
      then it is futile to generate anything else.  */
@@ -9182,14 +9212,13 @@ arm_output_epilogue (rtx sibling)
        be doing a return,  so we can't tail-call.  */
     abort ();
   
+  offsets = arm_get_frame_offsets ();
   saved_regs_mask = arm_compute_save_reg_mask ();
 
   if (TARGET_IWMMXT)
     lrm_count = bit_count (saved_regs_mask);
 
-  /* XXX We should adjust floats_offset for any anonymous args, and then
-     re-adjust vfp_offset below to compensate.  */
-
+  floats_offset = offsets->saved_args;
   /* Compute how far away the floats will be.  */
   for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
     if (saved_regs_mask & (1 << reg))
@@ -9198,7 +9227,7 @@ arm_output_epilogue (rtx sibling)
   if (frame_pointer_needed)
     {
       /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
-      int vfp_offset = 4;
+      int vfp_offset = offsets->frame;
 
       if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
 	{
@@ -9350,8 +9379,7 @@ arm_output_epilogue (rtx sibling)
          be reset correctly to the original value, should an interrupt
          occur.  If the stack pointer already points at the right
          place, then omit the subtraction.  */
-      if (((frame_size + current_function_outgoing_args_size + floats_offset)
-	   != 4 * (1 + (int) bit_count (saved_regs_mask)))
+      if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
 	  || current_function_calls_alloca)
 	asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
 		     4 * bit_count (saved_regs_mask));
@@ -9365,11 +9393,10 @@ arm_output_epilogue (rtx sibling)
   else
     {
       /* Restore stack pointer if necessary.  */
-      if (frame_size + current_function_outgoing_args_size != 0)
+      if (offsets->outgoing_args != offsets->saved_regs)
 	{
 	  operands[0] = operands[1] = stack_pointer_rtx;
-	  operands[2] = GEN_INT (frame_size
-				 + current_function_outgoing_args_size);
+	  operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
 	  output_add_immediate (operands);
 	}
 
@@ -9535,8 +9562,10 @@ arm_output_epilogue (rtx sibling)
 
 static void
 arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
-			      HOST_WIDE_INT frame_size)
+			      HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
 {
+  arm_stack_offsets *offsets;
+
   if (TARGET_THUMB)
     {
       /* ??? Probably not safe to set this here, since it assumes that a
@@ -9547,11 +9576,11 @@ arm_output_function_epilogue (FILE *file
   else
     {
       /* We need to take into account any stack-frame rounding.  */
-      frame_size = arm_get_frame_size ();
+      offsets = arm_get_frame_offsets ();
 
       if (use_return_insn (FALSE, NULL)
 	  && return_used_this_function
-	  && (frame_size + current_function_outgoing_args_size) != 0
+	  && offsets->saved_regs != offsets->outgoing_args
 	  && !frame_pointer_needed)
 	abort ();
 
@@ -9781,82 +9810,142 @@ emit_sfm (int base_reg, int count)
 
   The sign of the number returned reflects the direction of stack
   growth, so the values are positive for all eliminations except
-  from the soft frame pointer to the hard frame pointer.  */
-unsigned int
-arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
+  from the soft frame pointer to the hard frame pointer.
+  
+  SFP may point just inside the local variables block to ensure correct
+  alignment.  */
+
+
+/* Calculate stack offsets.  These are used to calculate register elimination
+   offsets and in prologue/epilogue code.  */
+
+static arm_stack_offsets *
+arm_get_frame_offsets (void)
 {
-  unsigned int local_vars    = arm_get_frame_size ();
-  unsigned int outgoing_args = current_function_outgoing_args_size;
-  unsigned int stack_frame;
-  unsigned int call_saved_registers;
+  struct arm_stack_offsets *offsets;
+  unsigned int regno;
   unsigned long func_type;
+  int leaf;
+  bool new_block;
+  HOST_WIDE_INT frame_size;
+
+  offsets = &cfun->machine->stack_offsets;
   
-  func_type = arm_current_func_type ();
+  if (!TARGET_ARM)
+    abort ();
+  
+  /* We need to know if we are a leaf function.  Unfortunately, it
+     is possible to be called after start_sequence has been called,
+     which causes get_insns to return the insns for the sequence,
+     not the function, which will cause leaf_function_p to return
+     the incorrect result.
 
-  /* Volatile functions never return, so there is
-     no need to save call saved registers.  */
-  call_saved_registers = 0;
-  if (! IS_VOLATILE (func_type))
+     To work around this, we cache the computed frame size.  This
+     works because we will only be calling RTL expanders that need
+     to know about leaf functions once reload has completed, and the
+     frame size cannot be changed after that time, so we can safely
+     use the cached value.  */
+
+  if (reload_completed)
+    return offsets;
+
+  /* Initialy this is the size of the local variables.  It will translated
+     into an offset once we have determined the size of preceeding data.  */
+  frame_size = ROUND_UP_WORD (get_frame_size ());
+
+  leaf = leaf_function_p ();
+
+  /* Space for variadic functions.  */
+  offsets->saved_args = current_function_pretend_args_size;
+
+  offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
+
+  /* Saved registers include the stack frame.  */
+  offsets->saved_regs = offsets->saved_args
+			+ bit_count (arm_compute_save_reg_mask ()) * 4;
+
+  /* A leaf function does not need any stack alignment if it has nothing
+     on the stack.  */
+  if (leaf && frame_size == 0)
     {
-      unsigned int reg_mask;
-      unsigned int reg;
-      bool new_block;
+      offsets->soft_frame = offsets->saved_regs;
+      offsets->outgoing_args = offsets->soft_frame;
+      return offsets;
+    }
 
-      /* Make sure that we compute which registers will be saved
-	 on the stack using the same algorithm that is used by
-	 the prologue creation code.  */
-      reg_mask = arm_compute_save_reg_mask ();
-
-      /* Now count the number of bits set in save_reg_mask.
-	 If we have already counted the registers in the stack
-	 frame, do not count them again.  Non call-saved registers
-	 might be saved in the call-save area of the stack, if
-	 doing so will preserve the stack's alignment.  Hence we
-	 must count them here.  For each set bit we need 4 bytes
-	 of stack space.  */
-      if (frame_pointer_needed)
-	reg_mask &= 0x07ff;
-      call_saved_registers += 4 * bit_count (reg_mask);
+  /* We know that SP will be word aligned on entry, and we must
+     preserve that condition at any subroutine call.  We also require the
+     soft frame pointer to be doubleword aligned.  */
 
-      /* If the hard floating point registers are going to be
-	 used then they must be saved on the stack as well.
-         Each register occupies 12 bytes of stack space.  */
-      for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
-	if (regs_ever_live[reg] && ! call_used_regs[reg])
-	  call_saved_registers += 12;
+  if (TARGET_REALLY_IWMMXT)
+    {
+      /* Check for the call-saved iWMMXt registers.  */
+      for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
+	if (regs_ever_live [regno] && ! call_used_regs [regno])
+	  offsets->saved_regs += 8;
+    }
 
-      /* Likewise VFP regs.  */
+  func_type = arm_current_func_type ();
+  if (! IS_VOLATILE (func_type))
+    {
+      /* Space for saved FPA registers.  */
+      for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
+      if (regs_ever_live[regno] && ! call_used_regs[regno])
+	offsets->saved_regs += 12;
+
+      /* Space for saved VFP registers.  */
       if (TARGET_HARD_FLOAT && TARGET_VFP)
 	{
 	  new_block = TRUE;
-	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
+	  for (regno = FIRST_VFP_REGNUM; regno < LAST_VFP_REGNUM; regno += 2)
 	    {
-	      if ((regs_ever_live[reg] && !call_used_regs[reg])
-		  || (regs_ever_live[reg + 1] && !call_used_regs[reg + 1]))
+	      if ((regs_ever_live[regno] && !call_used_regs[regno])
+		  || (regs_ever_live[regno + 1] && !call_used_regs[regno + 1]))
 		{
 		  if (new_block)
 		    {
-		      call_saved_registers += 4;
+		      offsets->saved_regs += 4;
 		      new_block = FALSE;
 		    }
-		  call_saved_registers += 8;
+		  offsets->saved_regs += 8;
 		}
 	      else
 		new_block = TRUE;
 	    }
 	}
+    }
 
-      if (TARGET_REALLY_IWMMXT)
-	/* Check for the call-saved iWMMXt registers.  */
-	for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
-	  if (regs_ever_live[reg] && ! call_used_regs [reg])
-	    call_saved_registers += 8;
+
+  offsets->soft_frame = offsets->saved_regs;
+  /* doubleword align SFP.  */
+  if (TARGET_AAPCS && (offsets->soft_frame & 7))
+    {
+      offsets->soft_frame += 4;
+      frame_size += 4;
+    }
+
+  offsets->outgoing_args = offsets->soft_frame + frame_size
+			   + current_function_outgoing_args_size;
+
+  if (TARGET_ATPCS || TARGET_AAPCS)
+    {
+      /* Ensure SP remains doubleword aligned.  */
+      if (offsets->outgoing_args & 7)
+	offsets->outgoing_args += 4;
+      if (offsets->outgoing_args & 7)
+	abort ();
     }
 
-  /* The stack frame contains 4 registers - the old frame pointer,
-     the old stack pointer, the return address and PC of the start
-     of the function.  */
-  stack_frame = frame_pointer_needed ? 16 : 0;
+  return offsets;
+}
+
+
+unsigned int
+arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
+{
+  arm_stack_offsets *offsets;
+
+  offsets = arm_get_frame_offsets ();
 
   /* OK, now we have enough information to compute the distances.
      There must be an entry in these switch tables for each pair
@@ -9873,24 +9962,22 @@ arm_compute_initial_elimination_offset (
 	case FRAME_POINTER_REGNUM:
 	  /* This is the reverse of the soft frame pointer
 	     to hard frame pointer elimination below.  */
-	  if (call_saved_registers == 0 && stack_frame == 0)
-	    return 0;
-	  return (call_saved_registers + stack_frame - 4);
+	  return offsets->soft_frame - offsets->saved_args;
 
 	case ARM_HARD_FRAME_POINTER_REGNUM:
 	  /* If there is no stack frame then the hard
 	     frame pointer and the arg pointer coincide.  */
-	  if (stack_frame == 0 && call_saved_registers != 0)
+	  if (offsets->frame == offsets->saved_regs)
 	    return 0;
-	  /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
-	  return (frame_pointer_needed
-		  && current_function_needs_context
-		  && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
+          /* FIXME:  Not sure about this.  Maybe we should always return 0 ?  */
+          return (frame_pointer_needed
+                  && current_function_needs_context
+                  && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
 
 	case STACK_POINTER_REGNUM:
 	  /* If nothing has been pushed on the stack at all
 	     then this will return -4.  This *is* correct!  */
-	  return call_saved_registers + stack_frame + local_vars + outgoing_args - 4;
+	  return offsets->outgoing_args - (offsets->saved_args + 4);
 
 	default:
 	  abort ();
@@ -9908,12 +9995,11 @@ arm_compute_initial_elimination_offset (
 	     stack frame.  The soft frame pointer to the bottom entry
 	     in the stack frame.  If there is no stack frame at all,
 	     then they are identical.  */
-	  if (call_saved_registers == 0 && stack_frame == 0)
-	    return 0;
-	  return - (call_saved_registers + stack_frame - 4);
+
+	  return offsets->frame - offsets->soft_frame;
 
 	case STACK_POINTER_REGNUM:
-	  return local_vars + outgoing_args;
+	  return offsets->outgoing_args - offsets->soft_frame;
 
 	default:
 	  abort ();
@@ -9930,107 +10016,6 @@ arm_compute_initial_elimination_offset (
     }
 }
 
-/* Calculate the size of the stack frame, taking into account any
-   padding that is required to ensure stack-alignment.  */
-HOST_WIDE_INT
-arm_get_frame_size (void)
-{
-  int regno;
-
-  int base_size = ROUND_UP_WORD (get_frame_size ());
-  int entry_size = 0;
-  unsigned long func_type = arm_current_func_type ();
-  int leaf;
-  bool new_block;
-
-  if (! TARGET_ARM)
-    abort();
-
-  if (! TARGET_ATPCS)
-    return base_size;
-
-  /* We need to know if we are a leaf function.  Unfortunately, it
-     is possible to be called after start_sequence has been called,
-     which causes get_insns to return the insns for the sequence,
-     not the function, which will cause leaf_function_p to return
-     the incorrect result.
-
-     To work around this, we cache the computed frame size.  This
-     works because we will only be calling RTL expanders that need
-     to know about leaf functions once reload has completed, and the
-     frame size cannot be changed after that time, so we can safely
-     use the cached value.  */
-
-  if (reload_completed)
-    return cfun->machine->frame_size;
-
-  leaf = leaf_function_p ();
-
-  /* A leaf function does not need any stack alignment if it has nothing
-     on the stack.  */
-  if (leaf && base_size == 0)
-    {
-      cfun->machine->frame_size = 0;
-      return 0;
-    }
-
-  /* We know that SP will be word aligned on entry, and we must
-     preserve that condition at any subroutine call.  But those are
-     the only constraints.  */
-
-  /* Space for variadic functions.  */
-  if (current_function_pretend_args_size)
-    entry_size += current_function_pretend_args_size;
-
-  /* Space for saved registers.  */
-  entry_size += bit_count (arm_compute_save_reg_mask ()) * 4;
-
-  if (! IS_VOLATILE (func_type))
-    {
-      /* Space for saved FPA registers.  */
-      for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
-      if (regs_ever_live[regno] && ! call_used_regs[regno])
-	entry_size += 12;
-
-      /* Space for saved VFP registers.  */
-      if (TARGET_HARD_FLOAT && TARGET_VFP)
-	{
-	  new_block = TRUE;
-	  for (regno = FIRST_VFP_REGNUM; regno < LAST_VFP_REGNUM; regno += 2)
-	    {
-	      if ((regs_ever_live[regno] && !call_used_regs[regno])
-		  || (regs_ever_live[regno + 1] && !call_used_regs[regno + 1]))
-		{
-		  if (new_block)
-		    {
-		      entry_size += 4;
-		      new_block = FALSE;
-		    }
-		  entry_size += 8;
-		}
-	      else
-		new_block = TRUE;
-	    }
-	}
-    }
-
-  if (TARGET_REALLY_IWMMXT)
-    {
-      /* Check for the call-saved iWMMXt registers.  */
-      for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
-	if (regs_ever_live [regno] && ! call_used_regs [regno])
-	  entry_size += 8;
-    }
-
-  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
-    base_size += 4;
-  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
-    abort ();
-
-  cfun->machine->frame_size = base_size;
-
-  return base_size;
-}
 
 /* Generate the prologue instructions for entry into an ARM function.  */
 void
@@ -10044,7 +10029,9 @@ arm_expand_prologue (void)
   unsigned long func_type;
   int fp_offset = 0;
   int saved_pretend_args = 0;
+  int saved_regs = 0;
   unsigned int args_to_push;
+  arm_stack_offsets *offsets;
 
   func_type = arm_current_func_type ();
 
@@ -10190,6 +10177,7 @@ arm_expand_prologue (void)
   if (live_regs_mask)
     {
       insn = emit_multi_reg_push (live_regs_mask);
+      saved_regs += bit_count (live_regs_mask) * 4;
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
@@ -10202,6 +10190,7 @@ arm_expand_prologue (void)
 	  insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
 					 gen_rtx_REG (V2SImode, reg)));
 	  RTX_FRAME_RELATED_P (insn) = 1;
+	  saved_regs += 8;
 	}
 
   if (! IS_VOLATILE (func_type))
@@ -10220,6 +10209,7 @@ arm_expand_prologue (void)
 		insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
 					       gen_rtx_REG (XFmode, reg)));
 		RTX_FRAME_RELATED_P (insn) = 1;
+		saved_regs += 12;
 	      }
 	}
       else
@@ -10243,6 +10233,7 @@ arm_expand_prologue (void)
 		    {
 		      insn = emit_sfm (reg + 1, start_reg - reg);
 		      RTX_FRAME_RELATED_P (insn) = 1;
+		      saved_regs += (reg - start_reg) * 12;
 		    }
 		  start_reg = reg - 1;
 		}
@@ -10251,6 +10242,7 @@ arm_expand_prologue (void)
 	  if (start_reg != reg)
 	    {
 	      insn = emit_sfm (reg + 1, start_reg - reg);
+	      saved_regs += (reg - start_reg) * 12;
 	      RTX_FRAME_RELATED_P (insn) = 1;
 	    }
 	}
@@ -10268,6 +10260,7 @@ arm_expand_prologue (void)
 		      insn = vfp_emit_fstmx (start_reg,
 					    (reg - start_reg) / 2);
 		      RTX_FRAME_RELATED_P (insn) = 1;
+		      saved_regs += (start_reg - reg) * 4 + 4;
 		    }
 		  start_reg = reg + 2;
 		}
@@ -10277,6 +10270,7 @@ arm_expand_prologue (void)
 	      insn = vfp_emit_fstmx (start_reg,
 				    (reg - start_reg) / 2);
 	      RTX_FRAME_RELATED_P (insn) = 1;
+	      saved_regs += (start_reg - reg) * 4 + 4;
 	    }
 	}
     }
@@ -10307,14 +10301,16 @@ arm_expand_prologue (void)
 	}
     }
 
-  amount = GEN_INT (-(arm_get_frame_size ()
-		      + current_function_outgoing_args_size));
-
-  if (amount != const0_rtx)
+  offsets = arm_get_frame_offsets ();
+  if (offsets->outgoing_args != offsets->saved_args + saved_regs)
     {
       /* This add can produce multiple insns for a large constant, so we
 	 need to get tricky.  */
       rtx last = get_last_insn ();
+
+      amount = GEN_INT (offsets->saved_args + saved_regs
+			- offsets->outgoing_args);
+
       insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
 				    amount));
       do
@@ -12940,7 +12936,7 @@ thumb_get_frame_size (void)
   if (! TARGET_THUMB)
     abort ();
 
-  if (! TARGET_ATPCS)
+  if (! (TARGET_ATPCS || TARGET_AAPCS))
     return base_size;
 
   /* We need to know if we are a leaf function.  Unfortunately, it
@@ -12956,7 +12952,7 @@ thumb_get_frame_size (void)
      use the cached value.  */
 
   if (reload_completed)
-    return cfun->machine->frame_size;
+    return cfun->machine->stack_offsets.soft_frame;
 
   leaf = leaf_function_p ();
 
@@ -12964,11 +12960,11 @@ thumb_get_frame_size (void)
      on the stack.  */
   if (leaf && base_size == 0)
     {
-      cfun->machine->frame_size = 0;
+      cfun->machine->stack_offsets.soft_frame = 0;
       return 0;
     }
 
-  /* We know that SP will be word aligned on entry, and we must
+  /* We know that SP will be double word aligned on entry, and we must
      preserve that condition at any subroutine call.  But those are
      the only constraints.  */
 
@@ -13008,7 +13004,7 @@ thumb_get_frame_size (void)
   if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
     abort ();
 
-  cfun->machine->frame_size = base_size;
+  cfun->machine->stack_offsets.soft_frame = base_size;
 
   return base_size;
 }
Index: config/arm/arm.h
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.224
diff -u -p -r1.224 arm.h
--- a/config/arm/arm.h	25 Feb 2004 17:03:27 -0000	1.224
+++ b/config/arm/arm.h	3 Mar 2004 09:24:56 -0000
@@ -442,6 +442,10 @@ extern GTY(()) rtx aof_pic_label;
 /* Fix invalid Cirrus instruction combinations by inserting NOPs.  */
 #define CIRRUS_FIX_INVALID_INSNS (1 << 23)
 
+/* Nonzero means to use conform to the Procedure Call Standard for the ARM
+   Architecture (AAPCS).  */
+#define ARM_FLAG_AAPCS		(1 << 24)
+
 #define TARGET_APCS_FRAME		(target_flags & ARM_FLAG_APCS_FRAME)
 #define TARGET_POKE_FUNCTION_NAME	(target_flags & ARM_FLAG_POKE)
 #define TARGET_FPE			(target_flags & ARM_FLAG_FPE)
@@ -450,6 +454,7 @@ extern GTY(()) rtx aof_pic_label;
 #define TARGET_APCS_FLOAT		(target_flags & ARM_FLAG_APCS_FLOAT)
 #define TARGET_APCS_REENT		(target_flags & ARM_FLAG_APCS_REENT)
 #define TARGET_ATPCS			(target_flags & ARM_FLAG_ATPCS)
+#define TARGET_AAPCS			(target_flags & ARM_FLAG_AAPCS)
 #define TARGET_MMU_TRAPS		(target_flags & ARM_FLAG_MMU_TRAPS)
 #define TARGET_SOFT_FLOAT		(arm_float_abi == ARM_FLOAT_ABI_SOFT)
 #define TARGET_SOFT_FLOAT_ABI		(arm_float_abi != ARM_FLOAT_ABI_HARD)
@@ -553,6 +558,9 @@ extern GTY(()) rtx aof_pic_label;
    N_("Thumb: Assume function pointers may go to non-Thumb aware code") }, \
   {"no-caller-super-interworking", -THUMB_FLAG_CALLER_SUPER_INTERWORKING,  \
    "" },								   \
+  {"aapcs",			    ARM_FLAG_AAPCS,			   \
+   N_("Conform to the Procedure Call Standard for the ARM Architecture") },\
+  {"no-aapcs",			    -ARM_FLAG_AAPCS, ""},		   \
   {"cirrus-fix-invalid-insns",      CIRRUS_FIX_INVALID_INSNS,		   \
    N_("Cirrus: Place NOPs to avoid invalid instruction combinations") },   \
   {"no-cirrus-fix-invalid-insns",  -CIRRUS_FIX_INVALID_INSNS,		   \
@@ -818,9 +826,10 @@ extern int arm_is_6_or_7;
 
 #define IWMMXT_ALIGNMENT   64
 
-#define STACK_BOUNDARY  32
+/* The required alignment for doubleword types.  */
+#define ARM_DOUBLEWORD_ALIGN (TARGET_AAPCS ? 64 : 32)
 
-#define PREFERRED_STACK_BOUNDARY (TARGET_ATPCS ? 64 : 32)
+#define STACK_BOUNDARY  ARM_DOUBLEWORD_ALIGN
 
 #define FUNCTION_BOUNDARY  32
 
@@ -831,7 +840,8 @@ extern int arm_is_6_or_7;
 
 #define EMPTY_FIELD_BOUNDARY  32
 
-#define BIGGEST_ALIGNMENT  (TARGET_REALLY_IWMMXT ? 64 : 32)
+#define BIGGEST_ALIGNMENT \
+  (TARGET_REALLY_IWMMXT ? 64 : ARM_DOUBLEWORD_ALIGN)
 
 #define TYPE_NEEDS_IWMMXT_ALIGNMENT(TYPE)	\
  (TARGET_REALLY_IWMMXT				\
@@ -886,7 +896,8 @@ extern int arm_is_6_or_7;
    compact structures.  The command line option -mstructure_size_boundary=<n>
    can be used to change this value.  For compatibility with the ARM SDK
    however the value should be left at 32.  ARM SDT Reference Manual (ARM DUI
-   0020D) page 2-20 says "Structures are aligned on word boundaries".  */
+   0020D) page 2-20 says "Structures are aligned on word boundaries".
+   The AAPCS specifies a value of 8.  */
 #define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary
 extern int arm_structure_size_boundary;
 
@@ -1794,6 +1805,22 @@ enum reg_class
 #define IS_NAKED(t)        	(t & ARM_FT_NAKED)
 #define IS_NESTED(t)       	(t & ARM_FT_NESTED)
 
+
+/* Structure used to hold the function stack frame layout.  Offsets are
+   relative to the stack pointer on function entry.  Positive offsets are
+   in the direction of stack growth.
+   Only soft_frame is used in thumb mode.  */
+
+typedef struct arm_stack_offsets GTY(())
+{
+  int saved_args;	/* ARG_POINTER_REGNUM.  */
+  int frame;		/* ARM_HARD_FRAME_POINTER_REGNUM.  */
+  int saved_regs;
+  int soft_frame;	/* FRAME_POINTER_REGNUM.  */
+  int outgoing_args;	/* STACK_POINTER_REGNUM.  */
+}
+arm_stack_offsets;
+
 /* A C structure for machine-specific, per-function data.
    This is added to the cfun structure.  */
 typedef struct machine_function GTY(())
@@ -1807,7 +1834,7 @@ typedef struct machine_function GTY(())
   /* Records if the save of LR has been eliminated.  */
   int lr_save_eliminated;
   /* The size of the stack frame.  Only valid after reload.  */
-  int frame_size;
+  arm_stack_offsets stack_offsets;
   /* Records the type of the current function.  */
   unsigned long func_type;
   /* Record if the function has a variable argument list.  */
@@ -1895,8 +1922,12 @@ typedef struct
    argument with the specified mode and type.  If it is not defined,
    `PARM_BOUNDARY' is used for all arguments.  */
 #define FUNCTION_ARG_BOUNDARY(MODE,TYPE) \
-  (TARGET_REALLY_IWMMXT && (VALID_IWMMXT_REG_MODE (MODE) || ((MODE) == DFmode)) \
-   ? IWMMXT_ALIGNMENT : PARM_BOUNDARY)
+  ((TARGET_REALLY_IWMMXT \
+    && (VALID_IWMMXT_REG_MODE (MODE) || (MODE) == DFmode)) \
+   ? IWMMXT_ALIGNMENT \
+   : (TARGET_AAPCS && arm_needs_doubleword_align (MODE, TYPE)) \
+   ? ARM_DOUBLEWORD_ALIGN \
+   : PARM_BOUNDARY )
 
 /* 1 if N is a possible register number for function argument passing.
    On the ARM, r0-r3 are used to pass args.  */
Index: doc/invoke.texi
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.418
diff -u -p -r1.418 invoke.texi
--- a/doc/invoke.texi	28 Feb 2004 20:06:01 -0000	1.418
+++ b/doc/invoke.texi	3 Mar 2004 10:35:19 -0000
@@ -368,6 +368,7 @@ in the following sections.
 
 @emph{ARM Options}
 @gccoptlist{-mapcs-frame  -mno-apcs-frame @gol
+-maapcs -mno-aapcs @gol
 -mapcs-26  -mapcs-32 @gol
 -mapcs-stack-check  -mno-apcs-stack-check @gol
 -mapcs-float  -mno-apcs-float @gol
@@ -6396,6 +6397,12 @@ These @samp{-m} options are defined for 
 architectures:
 
 @table @gcctabopt
+@item -maapcs
+@opindex maapcs
+Generate code conforming to the Procedure Call Standard for the ARM
+Architecture (AAPCS).  This mainly effects the alignment of structures and
+doubleword quantities.  The default is @option{-mno-aapcs}.
+
 @item -mapcs-frame
 @opindex mapcs-frame
 Generate a stack frame that is compliant with the ARM Procedure Call

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