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]

ARM EABI #2


Attached is a second attempt at making gcc generate code conforming to the ARM 
EABI.

Hopefully if addresses all the issues raised with the previous patch. Major 
changes relative to that are:
- Added -mabi=<foo> to select abi.
- Caught a load of thumb changes I missed last time.
- The use of the iwmmxt ABI is now controlled by the selected abi, not the cpu 
target. It is implemented as aapcs+extensions. The actual ABI should be 
unchanged.
- FIxed a related bug with split arguments.

Tested with cross-compiler to arm-none-elf using both apcs and aapcs.
Ok for mainline and csl-arm-branch?

Paul

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

	* config.gcc <arm>: Add --with-abi=
	* config/arm/arm-protos.h (arm_get_frame_size, thumb_get_frame_size,
	thumb_far_jump_used): Remove prototypes.
	(arm_needs_doubleword_align): Add prototype.
	(thumb_compute_initial_elimination_offset): Ditto.
	* 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, thumb_expand_epilogue): Use it.
	(arm_abi, target_abi_name, all_arm_abis): New variables.
	(arm_override_options): Set them.  Set structure padding for AAPCS.
	(arm_return_in_memory): Update ABI check.
	(arm_init_cumulative_args): Initialize can_split.
	(arm_needs_doubleword_align): New function.
	(arm_function_arg): Don't split args after pushing to stack. Handle
	doubleword/even reg alignment.
	(arm_va_arg): Handle all doubleword aligned args.
	(add_minpoolforward ref, dump_minpool, push_minpool_fix): Align based
	on ABI, not CPU.
	(arm_compute_save_reg0_reg12_mask): Fix comment.
	(thumb_get_frame_size, thumb_get_frame_size): Remove.
	(thumb_jump_far_used_p): Remove superfluous argument.  Return save
	value for alignment.
	(thumb_unexpanded_epilogue, thumb_output_function_prologue): Change
	to match.
	(thumb_compute_initial_elimination_offset): New function.
	(thumb_expand_prologue): Use arm_get_frame_offsets.  Remove
	unneccessary rounding.
	* config/arm/arm.h (target_abi_name): Declare.
	(ARM_DOUBLEWORD_ALIGN, DOUBLEWORD_ALIGNMENT, TARGET_IWMMXT_ABI,
	arm_abi_type, ARM_DEFAULT_ABI): Define.
	(ARM_FLAG_ATPCS): Remove.
	(TARGET_OPTIONS, OPTION_DEFAULT_SPECS): Add -mabi=.
	(BIGGEST_ALIGNMENT, PREFERRED_STACK_BOUNDARY, STACK_BOUNDARY): Use it.
	(ADJUST_FIELD_ALIGN, DATA_ALIGNMENT, LOCAL_ALIGNMENT,
	TYPE_NEEDS_IWMMXT_ALIGNMENT): Remove.
	(LIBCALL_VALUE, FUNCTION_VALUE_REGNO_P, FUNCTION_ARG_REGNO_P):
	Contitionalize on ABI, not CPU.
	(struct arm_stack_offsets): Define.
	(struct machine_function): Add stack_offsets.  Remove frame_size.
	(FUNCTION_ARG_PARTIAL_NREGS): Don't split if previous args have been
	pushed.
	(FUNCTION_ARG_ADVANCE, FUNCTION_ARG_BOUNDARY): Handle general
	doubleword alignment.
	(THUMB_INITIAL_ELIMINATION_OFFSET,
	ARM_INITIAL_ELIMINATION_OFFSET): Remove.
	(INITIAL_ELIMINATION_OFFSET): Call functions directly.
	* config/arm/arm.md (align_8): Enable for all targets.
	* config/arm/netbsd-elf.h (TARGET_DEFAULT): Remove TARGET_ATPCS.
	(ARM_DEFAULT_ABI): Define.
	* doc/invoke.texi <ARM>: Document -mabi=. Update documentation for
	-mstructure-size-boundary.
Index: gcc/config.gcc
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config.gcc,v
retrieving revision 1.440
diff -c -p -r1.440 config.gcc
*** a/gcc/config.gcc	10 Mar 2004 17:23:33 -0000	1.440
--- b/gcc/config.gcc	11 Mar 2004 17:59:25 -0000
*************** fi
*** 2227,2233 ****
  		;;
  
  	arm*-*-*)
! 		supported_defaults="arch cpu float tune fpu"
  		for which in cpu tune; do
  			eval "val=\$with_$which"
  			case "$val" in
--- 2227,2233 ----
  		;;
  
  	arm*-*-*)
! 		supported_defaults="arch cpu float tune fpu abi"
  		for which in cpu tune; do
  			eval "val=\$with_$which"
  			case "$val" in
*************** fi
*** 2281,2293 ****
  			# OK
  			;;
  		*)
! 			echo "Unknown fpu used in --with-fpu=$fpu" 2>&1
  			exit 1
  			;;
  		esac
  
  		if test "x$with_arch" != x && test "x$with_cpu" != x; then
! 			echo "Warning: --with-arch overrides --with-cpu" 1>&2
  		fi
  		;;
  
--- 2281,2304 ----
  			# OK
  			;;
  		*)
! 			echo "Unknown fpu used in --with-fpu=$with_fpu" 2>&1
! 			exit 1
! 			;;
! 		esac
! 
! 		case "$with_abi" in
! 		"" \
! 		| apcs | atpcs | aapcs | iwmmxt )
! 			#OK
! 			;;
! 		*)
! 			echo "Unknown ABI used in --with-abi=$with_abi"
  			exit 1
  			;;
  		esac
  
  		if test "x$with_arch" != x && test "x$with_cpu" != x; then
! 			echo "Warning: --with-arch overrides --with-cpu=$with_cpu" 1>&2
  		fi
  		;;
  
Index: gcc/config/arm/arm-protos.h
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm-protos.h,v
retrieving revision 1.63
diff -c -p -r1.63 arm-protos.h
*** a/gcc/config/arm/arm-protos.h	25 Feb 2004 17:03:26 -0000	1.63
--- b/gcc/config/arm/arm-protos.h	21 Mar 2004 21:35:17 -0000
*************** extern void arm_finalize_pic (int);
*** 31,42 ****
  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);
  extern unsigned int arm_compute_initial_elimination_offset (unsigned int,
  							    unsigned int);
  
  #ifdef TREE_CODE
  extern int arm_return_in_memory (tree);
--- 31,43 ----
  extern int arm_volatile_func (void);
  extern const char *arm_output_epilogue (rtx);
  extern void arm_expand_prologue (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);
  extern unsigned int arm_compute_initial_elimination_offset (unsigned int,
  							    unsigned int);
+ extern HOST_WIDE_INT thumb_compute_initial_elimination_offset (unsigned int,
+ 							       unsigned int);
  
  #ifdef TREE_CODE
  extern int arm_return_in_memory (tree);
*************** extern void arm_init_cumulative_args (CU
*** 157,162 ****
--- 158,164 ----
  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 
*************** extern int arm_float_words_big_endian (v
*** 175,183 ****
  
  /* Thumb functions.  */
  extern void arm_init_expanders (void);
- extern int thumb_far_jump_used_p (int);
  extern const char *thumb_unexpanded_epilogue (void);
- extern HOST_WIDE_INT thumb_get_frame_size (void);
  extern void thumb_expand_prologue (void);
  extern void thumb_expand_epilogue (void);
  #ifdef TREE_CODE
--- 177,183 ----
Index: gcc/config/arm/arm.c
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.c,v
retrieving revision 1.336
diff -c -p -r1.336 arm.c
*** a/gcc/config/arm/arm.c	3 Mar 2004 08:34:43 -0000	1.336
--- b/gcc/config/arm/arm.c	23 Mar 2004 12:34:15 -0000
*************** typedef struct minipool_fixup   Mfix;
*** 59,64 ****
--- 59,65 ----
  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);
*************** static int arm_address_register_rtx_p (r
*** 67,72 ****
--- 68,74 ----
  static int arm_legitimate_index_p (enum machine_mode, rtx, int);
  static int thumb_base_register_rtx_p (rtx, enum machine_mode, int);
  inline static int thumb_index_register_rtx_p (rtx, int);
+ static int thumb_far_jump_used_p (void);
  static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
  static rtx emit_multi_reg_push (int);
  static rtx emit_sfm (int, int);
*************** enum fputype arm_fpu_tune;
*** 284,289 ****
--- 286,294 ----
  /* Whether to use floating point hardware.  */
  enum float_abi_type arm_float_abi;
  
+ /* Which ABI to use.  */
+ enum arm_abi_type arm_abi;
+ 
  /* What program mode is the cpu running in? 26-bit mode or 32-bit mode.  */
  enum prog_mode_type arm_prgmode;
  
*************** const char * target_fpe_name = NULL;
*** 296,301 ****
--- 301,309 ----
  /* Set by the -mfloat-abi=... option.  */
  const char * target_float_abi_name = NULL;
  
+ /* Set by the -mabi=... option.  */
+ const char * target_abi_name = NULL;
+ 
  /* Used to parse -mstructure_size_boundary command line option.  */
  const char * structure_size_string = NULL;
  int    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
*************** static const struct float_abi all_float_
*** 510,515 ****
--- 518,540 ----
  };
  
  
+ struct abi_name
+ {
+   const char *name;
+   enum arm_abi_type abi_type;
+ };
+ 
+ 
+ /* Available values for -mabi=.  */
+ 
+ static const struct abi_name arm_all_abis[] =
+ {
+   {"apcs",    ARM_ABI_APCS},
+   {"atpcs",   ARM_ABI_ATPCS},
+   {"aapcs",   ARM_ABI_AAPCS},
+   {"iwmmxt",  ARM_ABI_IWMMXT}
+ };
+ 
  /* Return the number of bits set in VALUE.  */
  static unsigned
  bit_count (unsigned long value)
*************** arm_override_options (void)
*** 814,821 ****
    arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
    arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
  
!   if (TARGET_IWMMXT && (! TARGET_ATPCS))
!     target_flags |= ARM_FLAG_ATPCS;    
  
    arm_fp_model = ARM_FP_MODEL_UNKNOWN;
    if (target_fpu_name == NULL && target_fpe_name != NULL)
--- 839,865 ----
    arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
    arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
  
!   if (target_abi_name)
!     {
!       for (i = 0; i < ARRAY_SIZE (arm_all_abis); i++)
! 	{
! 	  if (streq (arm_all_abis[i].name, target_abi_name))
! 	    {
! 	      arm_abi = arm_all_abis[i].abi_type;
! 	      break;
! 	    }
! 	}
!       if (i == ARRAY_SIZE (arm_all_abis))
! 	error ("invalid ABI option: -mabi=%s", target_abi_name);
!     }
!   else
!     arm_abi = ARM_DEFAULT_ABI;
! 
!   if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
!     error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
! 
!   if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
!     error ("iwmmxt abi requires an iwmmxt capable cpu");
  
    arm_fp_model = ARM_FP_MODEL_UNKNOWN;
    if (target_fpu_name == NULL && target_fpe_name != NULL)
*************** arm_override_options (void)
*** 908,921 ****
    
    arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
    
    if (structure_size_string != NULL)
      {
        int size = strtol (structure_size_string, NULL, 0);
!       
!       if (size == 8 || size == 32)
  	arm_structure_size_boundary = size;
        else
! 	warning ("structure size boundary can only be set to 8 or 32");
      }
  
    if (arm_pic_register_string != NULL)
--- 952,971 ----
    
    arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26;
    
+   /* Override the default structure alignment for AAPCS ABI.  */
+   if (arm_abi == ARM_ABI_AAPCS)
+     arm_structure_size_boundary = 8;
+ 
    if (structure_size_string != NULL)
      {
        int size = strtol (structure_size_string, NULL, 0);
! 
!       if (size == 8 || size == 32
! 	  || (ARM_DOUBLEWORD_ALIGN && size == 64))
  	arm_structure_size_boundary = size;
        else
! 	warning ("structure size boundary can only be set to %s",
! 		 ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
      }
  
    if (arm_pic_register_string != NULL)
*************** use_return_insn (int iscond, rtx sibling
*** 1109,1114 ****
--- 1159,1165 ----
    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)
*************** use_return_insn (int iscond, rtx sibling
*** 1125,1131 ****
    if (IS_INTERRUPT (func_type) && frame_pointer_needed)
      return 0;
  
!   stack_adjust = arm_get_frame_size () + current_function_outgoing_args_size;
  
    /* As do variadic functions.  */
    if (current_function_pretend_args_size
--- 1176,1183 ----
    if (IS_INTERRUPT (func_type) && frame_pointer_needed)
      return 0;
  
!   offsets = arm_get_frame_offsets ();
!   stack_adjust = offsets->outgoing_args - offsets->saved_regs;
  
    /* As do variadic functions.  */
    if (current_function_pretend_args_size
*************** arm_return_in_memory (tree type)
*** 2018,2026 ****
  
    size = int_size_in_bytes (type);
  
!   if (TARGET_ATPCS)
      {
!       /* ATPCS returns aggregate types in memory only if they are
  	 larger than a word (or are variable size).  */
        return (size < 0 || size > UNITS_PER_WORD);
      }
--- 2070,2078 ----
  
    size = int_size_in_bytes (type);
  
!   if (arm_abi != ARM_ABI_APCS)
      {
!       /* ATPCS and later return aggregate types in memory only if they are
  	 larger than a word (or are variable size).  */
        return (size < 0 || size > UNITS_PER_WORD);
      }
*************** arm_init_cumulative_args (CUMULATIVE_ARG
*** 2143,2148 ****
--- 2195,2201 ----
    /* On the ARM, the offset starts at 0.  */
    pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype), fntype)) ? 1 : 0);
    pcum->iwmmxt_nregs = 0;
+   pcum->can_split = true;
    
    pcum->call_cookie = CALL_NORMAL;
  
*************** arm_init_cumulative_args (CUMULATIVE_ARG
*** 2178,2183 ****
--- 2231,2249 ----
      }
  }
  
+ 
+ /* Return true if mode/type need doubleword alignment.  */
+ bool
+ arm_needs_doubleword_align (enum machine_mode mode, tree type)
+ {
+   return (mode == DImode
+ 	  || mode == DFmode
+ 	  || VECTOR_MODE_SUPPORTED_P (mode)
+ 	  || (mode == BLKmode
+ 	      && TYPE_ALIGN (type) > PARM_BOUNDARY));
+ }
+ 
+ 
  /* 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.
*************** arm_init_cumulative_args (CUMULATIVE_ARG
*** 2193,2229 ****
  
  rtx
  arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
! 		  tree type ATTRIBUTE_UNUSED, int named)
  {
!   if (TARGET_REALLY_IWMMXT)
      {
!       if (VECTOR_MODE_SUPPORTED_P (mode))
  	{
! 	  /* varargs vectors are treated the same as long long.
! 	     named_count avoids having to change the way arm handles 'named' */
! 	  if (pcum->named_count <= pcum->nargs + 1)
! 	    {
! 	      if (pcum->nregs == 1)
! 		pcum->nregs += 1;
! 	      if (pcum->nregs <= 2)
! 		return gen_rtx_REG (mode, pcum->nregs);
! 	      else
! 		return NULL_RTX;
! 	    }
! 	  else if (pcum->iwmmxt_nregs <= 9)
! 	    return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
! 	  else
! 	    return NULL_RTX;
  	}
-       else if ((mode == DImode || mode == DFmode) && pcum->nregs & 1)
- 	pcum->nregs += 1;
      }
  
    if (mode == VOIDmode)
      /* Compute operand 2 of the call insn.  */
      return GEN_INT (pcum->call_cookie);
!   
!   if (!named || pcum->nregs >= NUM_ARG_REGS)
      return NULL_RTX;
    
    return gen_rtx_REG (mode, pcum->nregs);
--- 2259,2302 ----
  
  rtx
  arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
! 		  tree type, int named)
  {
!   int nregs;
! 
!   /* Varargs vectors are treated the same as long long.
!      named_count avoids having to change the way arm handles 'named' */
!   if (TARGET_IWMMXT_ABI
!       && VECTOR_MODE_SUPPORTED_P (mode)
!       && pcum->named_count > pcum->nargs + 1)
      {
!       if (pcum->iwmmxt_nregs <= 9)
! 	return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
!       else
  	{
! 	  pcum->can_split = false;
! 	  return NULL_RTX;
  	}
      }
  
+   /* Put doubleword aligned quantities in even register pairs.  */
+   if (pcum->nregs & 1
+       && ARM_DOUBLEWORD_ALIGN
+       && arm_needs_doubleword_align (mode, type))
+     pcum->nregs++;
+ 
    if (mode == VOIDmode)
      /* Compute operand 2 of the call insn.  */
      return GEN_INT (pcum->call_cookie);
! 
!   /* Only allow splitting an arg between regs and memory if all preceeding
!      args were allocated to regs.  For args passed by reference we only count
!      the reference pointer.  */
!   if (pcum->can_split)
!     nregs = 1;
!   else
!     nregs = ARM_NUM_REGS2 (mode, type);
! 
!   if (!named || pcum->nregs + nregs > NUM_ARG_REGS)
      return NULL_RTX;
    
    return gen_rtx_REG (mode, pcum->nregs);
*************** arm_function_arg_pass_by_reference (CUMU
*** 2245,2250 ****
--- 2318,2325 ----
  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)
      {
*************** arm_va_arg (tree valist, tree type)
*** 2252,2268 ****
        return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));
      }
  
!   if (FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), NULL) == IWMMXT_ALIGNMENT)
      {
!       tree minus_eight;
        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);
        t = build (PLUS_EXPR,    TREE_TYPE (valist), valist, t);
!       t = build (BIT_AND_EXPR, TREE_TYPE (t), t, minus_eight);
        t = build (MODIFY_EXPR,  TREE_TYPE (valist), valist, t);
        TREE_SIDE_EFFECTS (t) = 1;
        expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
--- 2327,2344 ----
        return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));
      }
  
!   align = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
!   if (align > PARM_BOUNDARY)
      {
!       tree mask;
        tree t;
  
        /* Maintain 64-bit alignment of the valist pointer by
  	 constructing:   valist = ((valist + (8 - 1)) & -8).  */
!       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, mask);
        t = build (MODIFY_EXPR,  TREE_TYPE (valist), valist, t);
        TREE_SIDE_EFFECTS (t) = 1;
        expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
*************** add_minipool_forward_ref (Mfix *fix)
*** 6861,6867 ****
  	 we have not already found an insertion point, then
  	 make sure that all such 8-byte aligned quantities are
  	 placed at the start of the pool.  */
!       if (TARGET_REALLY_IWMMXT
  	  && max_mp == NULL
  	  && fix->fix_size == 8
  	  && mp->fix_size != 8)
--- 6937,6943 ----
  	 we have not already found an insertion point, then
  	 make sure that all such 8-byte aligned quantities are
  	 placed at the start of the pool.  */
!       if (ARM_DOUBLEWORD_ALIGN
  	  && max_mp == NULL
  	  && fix->fix_size == 8
  	  && mp->fix_size != 8)
*************** add_minipool_backward_ref (Mfix *fix)
*** 7045,7051 ****
  	    {
  	      /* For now, we do not allow the insertion of 8-byte alignment
  		 requiring nodes anywhere but at the start of the pool.  */
! 	      if (TARGET_REALLY_IWMMXT && fix->fix_size == 8 && mp->fix_size != 8)
  		return NULL;
  	      else
  		min_mp = mp;
--- 7121,7128 ----
  	    {
  	      /* For now, we do not allow the insertion of 8-byte alignment
  		 requiring nodes anywhere but at the start of the pool.  */
! 	      if (ARM_DOUBLEWORD_ALIGN
! 		  && fix->fix_size == 8 && mp->fix_size != 8)
  		return NULL;
  	      else
  		min_mp = mp;
*************** add_minipool_backward_ref (Mfix *fix)
*** 7064,7070 ****
  	     we have not already found an insertion point, then
  	     make sure that all such 8-byte aligned quantities are
  	     placed at the start of the pool.  */
! 	  else if (TARGET_REALLY_IWMMXT
  		   && min_mp == NULL
  		   && fix->fix_size == 8
  		   && mp->fix_size < 8)
--- 7141,7147 ----
  	     we have not already found an insertion point, then
  	     make sure that all such 8-byte aligned quantities are
  	     placed at the start of the pool.  */
! 	  else if (ARM_DOUBLEWORD_ALIGN
  		   && min_mp == NULL
  		   && fix->fix_size == 8
  		   && mp->fix_size < 8)
*************** dump_minipool (rtx scan)
*** 7162,7168 ****
    Mnode * nmp;
    int align64 = 0;
  
!   if (TARGET_REALLY_IWMMXT)
      for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
        if (mp->refcount > 0 && mp->fix_size == 8)
  	{
--- 7239,7245 ----
    Mnode * nmp;
    int align64 = 0;
  
!   if (ARM_DOUBLEWORD_ALIGN)
      for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
        if (mp->refcount > 0 && mp->fix_size == 8)
  	{
*************** push_minipool_fix (rtx insn, HOST_WIDE_I
*** 7404,7414 ****
    if (fix->forwards == 0 && fix->backwards == 0)
      abort ();
  
!   /* With iWMMXt enabled, the pool is aligned to an 8-byte boundary.
       So there might be an empty word before the start of the pool.
       Hence we reduce the forward range by 4 to allow for this
       possibility.  */
!   if (TARGET_REALLY_IWMMXT && fix->fix_size == 8)
      fix->forwards -= 4;
  
    if (dump_file)
--- 7481,7491 ----
    if (fix->forwards == 0 && fix->backwards == 0)
      abort ();
  
!   /* With AAPCS/iWMMXt enabled, the pool is aligned to an 8-byte boundary.
       So there might be an empty word before the start of the pool.
       Hence we reduce the forward range by 4 to allow for this
       possibility.  */
!   if (ARM_DOUBLEWORD_ALIGN && fix->fix_size == 8)
      fix->forwards -= 4;
  
    if (dump_file)
*************** output_ascii_pseudo_op (FILE *stream, co
*** 8666,8673 ****
  }
  
  /* 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.  */
  static unsigned long
  arm_compute_save_reg0_reg12_mask (void)
  {
--- 8743,8749 ----
  }
  
  /* Compute the register sabe mask for registers 0 through 12
!    inclusive.  This code is used by arm_compute_save_reg_mask.  */
  static unsigned long
  arm_compute_save_reg0_reg12_mask (void)
  {
*************** output_return_instruction (rtx operand, 
*** 8813,8818 ****
--- 8889,8895 ----
    int reg;
    unsigned long live_regs_mask;
    unsigned long func_type;
+   arm_stack_offsets *offsets;
  
    func_type = arm_current_func_type ();
  
*************** output_return_instruction (rtx operand, 
*** 8911,8919 ****
  	     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;
! 	      
  	      if (stack_adjust != 0 && stack_adjust != 4)
  		abort ();
  
--- 8988,8997 ----
  	     points to the base of the saved core registers.  */
  	  if (live_regs_mask & (1 << SP_REGNUM))
  	    {
! 	      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 ();
  
*************** arm_output_epilogue (rtx sibling)
*** 9143,9154 ****
       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;
  
    /* If we have already generated the return instruction
       then it is futile to generate anything else.  */
--- 9221,9232 ----
       frame that is $fp + 4 for a non-variadic function.  */
    int floats_offset = 0;
    rtx operands[3];
    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.  */
*************** arm_output_epilogue (rtx sibling)
*** 9179,9192 ****
         be doing a return,  so we can't tail-call.  */
      abort ();
    
    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.  */
! 
    /* Compute how far away the floats will be.  */
    for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
      if (saved_regs_mask & (1 << reg))
--- 9257,9269 ----
         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);
  
!   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))
*************** arm_output_epilogue (rtx sibling)
*** 9195,9201 ****
    if (frame_pointer_needed)
      {
        /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
!       int vfp_offset = 4;
  
        if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
  	{
--- 9272,9278 ----
    if (frame_pointer_needed)
      {
        /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
!       int vfp_offset = offsets->frame;
  
        if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
  	{
*************** arm_output_epilogue (rtx sibling)
*** 9347,9354 ****
           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)))
  	  || current_function_calls_alloca)
  	asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
  		     4 * bit_count (saved_regs_mask));
--- 9424,9430 ----
           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 (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));
*************** arm_output_epilogue (rtx sibling)
*** 9362,9372 ****
    else
      {
        /* Restore stack pointer if necessary.  */
!       if (frame_size + current_function_outgoing_args_size != 0)
  	{
  	  operands[0] = operands[1] = stack_pointer_rtx;
! 	  operands[2] = GEN_INT (frame_size
! 				 + current_function_outgoing_args_size);
  	  output_add_immediate (operands);
  	}
  
--- 9438,9447 ----
    else
      {
        /* Restore stack pointer if necessary.  */
!       if (offsets->outgoing_args != offsets->saved_regs)
  	{
  	  operands[0] = operands[1] = stack_pointer_rtx;
! 	  operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
  	  output_add_immediate (operands);
  	}
  
*************** arm_output_epilogue (rtx sibling)
*** 9532,9539 ****
  
  static void
  arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
! 			      HOST_WIDE_INT frame_size)
  {
    if (TARGET_THUMB)
      {
        /* ??? Probably not safe to set this here, since it assumes that a
--- 9607,9616 ----
  
  static void
  arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
! 			      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
*************** arm_output_function_epilogue (FILE *file
*** 9544,9554 ****
    else
      {
        /* We need to take into account any stack-frame rounding.  */
!       frame_size = arm_get_frame_size ();
  
        if (use_return_insn (FALSE, NULL)
  	  && return_used_this_function
! 	  && (frame_size + current_function_outgoing_args_size) != 0
  	  && !frame_pointer_needed)
  	abort ();
  
--- 9621,9631 ----
    else
      {
        /* We need to take into account any stack-frame rounding.  */
!       offsets = arm_get_frame_offsets ();
  
        if (use_return_insn (FALSE, NULL)
  	  && return_used_this_function
! 	  && offsets->saved_regs != offsets->outgoing_args
  	  && !frame_pointer_needed)
  	abort ();
  
*************** emit_sfm (int base_reg, int count)
*** 9778,9859 ****
  
    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)
  {
!   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;
    unsigned long func_type;
    
!   func_type = arm_current_func_type ();
  
!   /* Volatile functions never return, so there is
!      no need to save call saved registers.  */
!   call_saved_registers = 0;
!   if (! IS_VOLATILE (func_type))
      {
!       unsigned int reg_mask;
!       unsigned int reg;
!       bool new_block;
  
!       /* 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);
  
!       /* 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;
  
!       /* Likewise VFP regs.  */
!       if (TARGET_HARD_FLOAT && TARGET_VFP)
  	{
! 	  new_block = TRUE;
! 	  for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
  	    {
! 	      if ((regs_ever_live[reg] && !call_used_regs[reg])
! 		  || (regs_ever_live[reg + 1] && !call_used_regs[reg + 1]))
  		{
! 		  if (new_block)
  		    {
! 		      call_saved_registers += 4;
! 		      new_block = FALSE;
  		    }
! 		  call_saved_registers += 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;
      }
  
!   /* 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;
  
    /* OK, now we have enough information to compute the distances.
       There must be an entry in these switch tables for each pair
--- 9855,10027 ----
  
    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.
! 
!   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)
  {
!   struct arm_stack_offsets *offsets;
    unsigned long func_type;
+   int leaf;
+   bool new_block;
+   int saved;
+   HOST_WIDE_INT frame_size;
+ 
+   offsets = &cfun->machine->stack_offsets;
    
!   /* 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 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);
! 
!   if (TARGET_ARM)
      {
!       unsigned int regno;
  
!       saved = bit_count (arm_compute_save_reg_mask ()) * 4;
  
!       /* We know that SP will be doubleword 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 (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])
! 	      saved += 8;
! 	}
! 
!       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])
! 	    saved += 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)
! 			{
! 			  saved += 4;
! 			  new_block = FALSE;
! 			}
! 		      saved += 8;
  		    }
! 		  else
! 		    new_block = TRUE;
  		}
  	    }
  	}
+     }
+   else /* TARGET_THUMB */
+     {
+       int reg;
+       int count_regs;
+ 
+       saved = 0;
+       count_regs = 0;
+       for (reg = 8; reg < 13; reg ++)
+ 	if (THUMB_REG_PUSHED_P (reg))
+ 	  count_regs ++;
+       if (count_regs)
+ 	saved += 4 * count_regs;
+       count_regs = 0;
+       for (reg = 0; reg <= LAST_LO_REGNUM; reg ++)
+ 	if (THUMB_REG_PUSHED_P (reg))
+ 	  count_regs ++;
+       if (count_regs || ! leaf_function_p ()
+ 	  || thumb_far_jump_used_p ())
+ 	saved += 4 * (count_regs + 1);
+       if (TARGET_BACKTRACE)
+ 	{
+ 	  if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0))
+ 	    saved += 20;
+ 	  else
+ 	    saved += 16;
+ 	}
+     }
  
!   /* Saved registers include the stack frame.  */
!   offsets->saved_regs = offsets->saved_args + saved;
!   offsets->soft_frame = offsets->saved_regs;
!   /* A leaf function does not need any stack alignment if it has nothing
!      on the stack.  */
!   if (leaf && frame_size == 0)
!     {
!       offsets->outgoing_args = offsets->soft_frame;
!       return offsets;
!     }
! 
!   /* Ensure SFP has the correct alignment.  */
!   if (ARM_DOUBLEWORD_ALIGN
!       && (offsets->soft_frame & 7))
!     offsets->soft_frame += 4;
! 
!   offsets->outgoing_args = offsets->soft_frame + frame_size
! 			   + current_function_outgoing_args_size;
! 
!   if (ARM_DOUBLEWORD_ALIGN)
!     {
!       /* Ensure SP remains doubleword aligned.  */
!       if (offsets->outgoing_args & 7)
! 	offsets->outgoing_args += 4;
!       if (offsets->outgoing_args & 7)
! 	abort ();
      }
  
!   return offsets;
! }
! 
! 
! /* Calculate the realative offsets for the different stack pointers.  Positive
!    offsets are in the direction of stack growth.  */
! 
! 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
*************** arm_compute_initial_elimination_offset (
*** 9870,9893 ****
  	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);
  
  	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)
  	    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;
  
  	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;
  
  	default:
  	  abort ();
--- 10038,10059 ----
  	case FRAME_POINTER_REGNUM:
  	  /* This is the reverse of the soft frame pointer
  	     to hard frame pointer elimination below.  */
! 	  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 (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;
  
  	case STACK_POINTER_REGNUM:
  	  /* If nothing has been pushed on the stack at all
  	     then this will return -4.  This *is* correct!  */
! 	  return offsets->outgoing_args - (offsets->saved_args + 4);
  
  	default:
  	  abort ();
*************** arm_compute_initial_elimination_offset (
*** 9905,9916 ****
  	     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);
  
  	case STACK_POINTER_REGNUM:
! 	  return local_vars + outgoing_args;
  
  	default:
  	  abort ();
--- 10071,10081 ----
  	     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.  */
! 
! 	  return offsets->frame - offsets->soft_frame;
  
  	case STACK_POINTER_REGNUM:
! 	  return offsets->outgoing_args - offsets->soft_frame;
  
  	default:
  	  abort ();
*************** arm_compute_initial_elimination_offset (
*** 9927,10033 ****
      }
  }
  
- /* 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
--- 10092,10097 ----
*************** arm_expand_prologue (void)
*** 10041,10047 ****
--- 10105,10113 ----
    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 ();
  
*************** arm_expand_prologue (void)
*** 10187,10192 ****
--- 10253,10259 ----
    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;
      }
  
*************** arm_expand_prologue (void)
*** 10199,10204 ****
--- 10266,10272 ----
  	  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))
*************** arm_expand_prologue (void)
*** 10217,10222 ****
--- 10285,10291 ----
  		insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
  					       gen_rtx_REG (XFmode, reg)));
  		RTX_FRAME_RELATED_P (insn) = 1;
+ 		saved_regs += 12;
  	      }
  	}
        else
*************** arm_expand_prologue (void)
*** 10240,10245 ****
--- 10309,10315 ----
  		    {
  		      insn = emit_sfm (reg + 1, start_reg - reg);
  		      RTX_FRAME_RELATED_P (insn) = 1;
+ 		      saved_regs += (reg - start_reg) * 12;
  		    }
  		  start_reg = reg - 1;
  		}
*************** arm_expand_prologue (void)
*** 10248,10253 ****
--- 10318,10324 ----
  	  if (start_reg != reg)
  	    {
  	      insn = emit_sfm (reg + 1, start_reg - reg);
+ 	      saved_regs += (reg - start_reg) * 12;
  	      RTX_FRAME_RELATED_P (insn) = 1;
  	    }
  	}
*************** arm_expand_prologue (void)
*** 10265,10270 ****
--- 10336,10342 ----
  		      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;
  		}
*************** arm_expand_prologue (void)
*** 10274,10279 ****
--- 10346,10352 ----
  	      insn = vfp_emit_fstmx (start_reg,
  				    (reg - start_reg) / 2);
  	      RTX_FRAME_RELATED_P (insn) = 1;
+ 	      saved_regs += (start_reg - reg) * 4 + 4;
  	    }
  	}
      }
*************** arm_expand_prologue (void)
*** 10304,10317 ****
  	}
      }
  
!   amount = GEN_INT (-(arm_get_frame_size ()
! 		      + current_function_outgoing_args_size));
! 
!   if (amount != const0_rtx)
      {
        /* This add can produce multiple insns for a large constant, so we
  	 need to get tricky.  */
        rtx last = get_last_insn ();
        insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
  				    amount));
        do
--- 10377,10392 ----
  	}
      }
  
!   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
*************** thumb_shiftable_const (unsigned HOST_WID
*** 12629,12636 ****
  
  /* Returns nonzero if the current function contains,
     or might contain a far jump.  */
! int
! thumb_far_jump_used_p (int in_prologue)
  {
    rtx insn;
  
--- 12704,12711 ----
  
  /* Returns nonzero if the current function contains,
     or might contain a far jump.  */
! static int
! thumb_far_jump_used_p (void)
  {
    rtx insn;
  
*************** thumb_far_jump_used_p (int in_prologue)
*** 12648,12654 ****
    /* If this function is not being called from the prologue/epilogue
       generation code then it must be being called from the
       INITIAL_ELIMINATION_OFFSET macro.  */
!   if (!in_prologue)
      {
        /* In this case we know that we are being asked about the elimination
  	 of the arg pointer register.  If that register is not being used,
--- 12723,12729 ----
    /* If this function is not being called from the prologue/epilogue
       generation code then it must be being called from the
       INITIAL_ELIMINATION_OFFSET macro.  */
!   if (!(ARM_DOUBLEWORD_ALIGN || reload_completed))
      {
        /* In this case we know that we are being asked about the elimination
  	 of the arg pointer register.  If that register is not being used,
*************** thumb_far_jump_used_p (int in_prologue)
*** 12667,12673 ****
  
  	 A false negative will not result in bad code being generated, but it
  	 will result in a needless push and pop of the link register.  We
! 	 hope that this does not occur too often.  */
        if (regs_ever_live [ARG_POINTER_REGNUM])
  	cfun->machine->arg_pointer_live = 1;
        else if (!cfun->machine->arg_pointer_live)
--- 12742,12751 ----
  
  	 A false negative will not result in bad code being generated, but it
  	 will result in a needless push and pop of the link register.  We
! 	 hope that this does not occur too often.
! 
! 	 If we need doubleword stack alignment this could affect the other
! 	 elimination offsets so we can't risk getting it wrong.  */
        if (regs_ever_live [ARG_POINTER_REGNUM])
  	cfun->machine->arg_pointer_live = 1;
        else if (!cfun->machine->arg_pointer_live)
*************** thumb_unexpanded_epilogue (void)
*** 12818,12824 ****
      }
  
    had_to_push_lr = (live_regs_mask || !leaf_function
! 		    || thumb_far_jump_used_p (1));
    
    if (TARGET_BACKTRACE
        && ((live_regs_mask & 0xFF) == 0)
--- 12896,12902 ----
      }
  
    had_to_push_lr = (live_regs_mask || !leaf_function
! 		    || thumb_far_jump_used_p ());
    
    if (TARGET_BACKTRACE
        && ((live_regs_mask & 0xFF) == 0)
*************** arm_init_expanders (void)
*** 12924,13023 ****
    init_machine_status = arm_init_machine_status;
  }
  
- HOST_WIDE_INT
- thumb_get_frame_size (void)
- {
-   int regno;
- 
-   int base_size = ROUND_UP_WORD (get_frame_size ());
-   int count_regs = 0;
-   int entry_size = 0;
-   int leaf;
- 
-   if (! TARGET_THUMB)
-     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 pushed lo registers.  */
!   for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
!     if (THUMB_REG_PUSHED_P (regno))
!       count_regs++;
  
!   /* Space for backtrace structure.  */
!   if (TARGET_BACKTRACE)
      {
!       if (count_regs == 0 && regs_ever_live[LAST_ARG_REGNUM] != 0)
! 	entry_size += 20;
!       else
! 	entry_size += 16;
!     }
  
!   if (count_regs || !leaf || thumb_far_jump_used_p (1))
!     count_regs++;	/* LR */
  
!   entry_size += count_regs * 4;
!   count_regs = 0;
  
!   /* Space for pushed hi regs.  */
!   for (regno = 8; regno < 13; regno++)
!     if (THUMB_REG_PUSHED_P (regno))
!       count_regs++;
  
!   entry_size += count_regs * 4;
  
!   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 rest of a function's prologue.  */
  void
  thumb_expand_prologue (void)
  {
    rtx insn, dwarf;
  
!   HOST_WIDE_INT amount = (thumb_get_frame_size ()
! 			  + current_function_outgoing_args_size);
    unsigned long func_type;
  
    func_type = arm_current_func_type ();
--- 13002,13067 ----
    init_machine_status = arm_init_machine_status;
  }
  
  
! /* Like arm_compute_initial_elimination offset.  Simpler because
!    THUMB_HARD_FRAME_POINTER isn't actually the ABI specified frame pointer.  */
  
! HOST_WIDE_INT
! thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
! {
!   arm_stack_offsets *offsets;
! 
!   offsets = arm_get_frame_offsets ();
  
!   switch (from)
      {
!     case ARG_POINTER_REGNUM:
!       switch (to)
! 	{
! 	case STACK_POINTER_REGNUM:
! 	  return offsets->outgoing_args - offsets->saved_args;
  
! 	case FRAME_POINTER_REGNUM:
! 	  return offsets->soft_frame - offsets->saved_args;
  
! 	case THUMB_HARD_FRAME_POINTER_REGNUM:
! 	case ARM_HARD_FRAME_POINTER_REGNUM:
! 	  return offsets->saved_regs - offsets->saved_args;
  
! 	default:
! 	  abort();
! 	}
!       break;
  
!     case FRAME_POINTER_REGNUM:
!       switch (to)
! 	{
! 	case STACK_POINTER_REGNUM:
! 	  return offsets->outgoing_args - offsets->soft_frame;
  
! 	case THUMB_HARD_FRAME_POINTER_REGNUM:
! 	case ARM_HARD_FRAME_POINTER_REGNUM:
! 	  return offsets->saved_regs - offsets->soft_frame;
  
! 	default:
! 	  abort();
! 	}
!       break;
  
!     default:
!       abort ();
!     }
  }
  
+ 
  /* Generate the rest of a function's prologue.  */
  void
  thumb_expand_prologue (void)
  {
    rtx insn, dwarf;
  
!   HOST_WIDE_INT amount;
!   arm_stack_offsets *offsets;
    unsigned long func_type;
  
    func_type = arm_current_func_type ();
*************** thumb_expand_prologue (void)
*** 13032,13047 ****
        return;
      }
  
    if (frame_pointer_needed)
      {
!       insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
    if (amount)
      {
-       amount = ROUND_UP_WORD (amount);
-       
        if (amount < 512)
  	{
  	  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
--- 13076,13093 ----
        return;
      }
  
+   offsets = arm_get_frame_offsets ();
+ 
    if (frame_pointer_needed)
      {
!       insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
! 				   stack_pointer_rtx));
        RTX_FRAME_RELATED_P (insn) = 1;
      }
  
+   amount = offsets->outgoing_args - offsets->saved_regs;
    if (amount)
      {
        if (amount < 512)
  	{
  	  insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
*************** thumb_expand_prologue (void)
*** 13134,13153 ****
  void
  thumb_expand_epilogue (void)
  {
!   HOST_WIDE_INT amount = (thumb_get_frame_size ()
! 			  + current_function_outgoing_args_size);
    int regno;
  
    /* Naked functions don't have prologues.  */
    if (IS_NAKED (arm_current_func_type ()))
      return;
  
    if (frame_pointer_needed)
      emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
    else if (amount)
      {
-       amount = ROUND_UP_WORD (amount);
-       
        if (amount < 512)
  	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
  			       GEN_INT (amount)));
--- 13186,13206 ----
  void
  thumb_expand_epilogue (void)
  {
!   HOST_WIDE_INT amount;
!   arm_stack_offsets *offsets;
    int regno;
  
    /* Naked functions don't have prologues.  */
    if (IS_NAKED (arm_current_func_type ()))
      return;
  
+   offsets = arm_get_frame_offsets ();
+   amount = offsets->outgoing_args - offsets->saved_regs;
+ 
    if (frame_pointer_needed)
      emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
    else if (amount)
      {
        if (amount < 512)
  	emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
  			       GEN_INT (amount)));
*************** thumb_output_function_prologue (FILE *f,
*** 13262,13268 ****
      if (THUMB_REG_PUSHED_P (regno))
        live_regs_mask |= 1 << regno;
  
!   if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1))
      live_regs_mask |= 1 << LR_REGNUM;
  
    if (TARGET_BACKTRACE)
--- 13316,13322 ----
      if (THUMB_REG_PUSHED_P (regno))
        live_regs_mask |= 1 << regno;
  
!   if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p ())
      live_regs_mask |= 1 << LR_REGNUM;
  
    if (TARGET_BACKTRACE)
Index: gcc/config/arm/arm.h
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.h,v
retrieving revision 1.225
diff -c -p -r1.225 arm.h
*** a/gcc/config/arm/arm.h	5 Mar 2004 16:59:53 -0000	1.225
--- b/gcc/config/arm/arm.h	17 Mar 2004 18:17:06 -0000
*************** extern const char *target_fpu_name;
*** 140,145 ****
--- 140,147 ----
  extern const char *target_fpe_name;
  /* Whether to use floating point hardware.  */
  extern const char *target_float_abi_name;
+ /* Which ABI to use.  */
+ extern const char *target_abi_name;
  /* Define the information needed to generate branch insns.  This is
     stored from the compare operation.  */
  extern GTY(()) rtx arm_compare_op0;
*************** extern GTY(()) rtx aof_pic_label;
*** 433,443 ****
     destination is non-Thumb aware.  */
  #define THUMB_FLAG_CALLER_SUPER_INTERWORKING	(1 << 20)
  
- /* Nonzero means to use ARM/Thumb Procedure Call Standard conventions.  */
- #define ARM_FLAG_ATPCS		(1 << 21)
- 
  /* Fix invalid Cirrus instruction combinations by inserting NOPs.  */
! #define CIRRUS_FIX_INVALID_INSNS (1 << 22)
  
  #define TARGET_APCS_FRAME		(target_flags & ARM_FLAG_APCS_FRAME)
  #define TARGET_POKE_FUNCTION_NAME	(target_flags & ARM_FLAG_POKE)
--- 435,442 ----
     destination is non-Thumb aware.  */
  #define THUMB_FLAG_CALLER_SUPER_INTERWORKING	(1 << 20)
  
  /* Fix invalid Cirrus instruction combinations by inserting NOPs.  */
! #define CIRRUS_FIX_INVALID_INSNS (1 << 21)
  
  #define TARGET_APCS_FRAME		(target_flags & ARM_FLAG_APCS_FRAME)
  #define TARGET_POKE_FUNCTION_NAME	(target_flags & ARM_FLAG_POKE)
*************** extern GTY(()) rtx aof_pic_label;
*** 446,452 ****
  #define TARGET_APCS_STACK		(target_flags & ARM_FLAG_APCS_STACK)
  #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_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)
--- 445,450 ----
*************** extern GTY(()) rtx aof_pic_label;
*** 456,461 ****
--- 454,460 ----
  #define TARGET_VFP			(arm_fp_model == ARM_FP_MODEL_VFP)
  #define TARGET_IWMMXT			(arm_arch_iwmmxt)
  #define TARGET_REALLY_IWMMXT		(TARGET_IWMMXT && TARGET_ARM)
+ #define TARGET_IWMMXT_ABI (TARGET_ARM && arm_abi == ARM_ABI_IWMMXT)
  #define TARGET_BIG_END			(target_flags & ARM_FLAG_BIG_END)
  #define TARGET_INTERWORK		(target_flags & ARM_FLAG_INTERWORK)
  #define TARGET_LITTLE_WORDS		(target_flags & ARM_FLAG_LITTLE_WORDS)
*************** extern GTY(()) rtx aof_pic_label;
*** 574,580 ****
    {"structure-size-boundary=", & structure_size_string,			\
     N_("Specify the minimum bit alignment of structures"), 0},		\
    {"pic-register=", & arm_pic_register_string,				\
!    N_("Specify the register to be used for PIC addressing"), 0}		\
  }
  
  /* Support for a compile-time default CPU, et cetera.  The rules are:
--- 573,580 ----
    {"structure-size-boundary=", & structure_size_string,			\
     N_("Specify the minimum bit alignment of structures"), 0},		\
    {"pic-register=", & arm_pic_register_string,				\
!    N_("Specify the register to be used for PIC addressing"), 0},	\
!   {"abi=", &target_abi_name, N_("Specify an ABI"), 0}			\
  }
  
  /* Support for a compile-time default CPU, et cetera.  The rules are:
*************** extern GTY(()) rtx aof_pic_label;
*** 585,598 ****
       by -march).
     --with-float is ignored if -mhard-float, -msoft-float or -mfloat-abi are
     specified.
!    --with-fpu is ignored if -mfpu is specified.  */
  #define OPTION_DEFAULT_SPECS \
    {"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \
    {"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
    {"tune", "%{!mcpu=*:%{!mtune=*:-mtune=%(VALUE)}}" }, \
    {"float", \
      "%{!msoft-float:%{!mhard-float:%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}}}" }, \
!   {"fpu", "%{!mfpu=*:-mfpu=%(VALUE)}"},
  
  struct arm_cpu_select
  {
--- 585,600 ----
       by -march).
     --with-float is ignored if -mhard-float, -msoft-float or -mfloat-abi are
     specified.
!    --with-fpu is ignored if -mfpu is specified.
!    --with-abi is ignored is -mabi is specified.  */
  #define OPTION_DEFAULT_SPECS \
    {"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \
    {"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
    {"tune", "%{!mcpu=*:%{!mtune=*:-mtune=%(VALUE)}}" }, \
    {"float", \
      "%{!msoft-float:%{!mhard-float:%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}}}" }, \
!   {"fpu", "%{!mfpu=*:-mfpu=%(VALUE)}"}, \
!   {"abi", "%{!mabi=*:-mabi=%(VALUE)}"},
  
  struct arm_cpu_select
  {
*************** extern enum float_abi_type arm_float_abi
*** 682,687 ****
--- 684,704 ----
  #define FPUTYPE_DEFAULT FPUTYPE_MAVERICK
  #endif
  
+ /* Which ABI to use.  */
+ enum arm_abi_type
+ {
+   ARM_ABI_APCS,
+   ARM_ABI_ATPCS,
+   ARM_ABI_AAPCS,
+   ARM_ABI_IWMMXT
+ };
+ 
+ extern enum arm_abi_type arm_abi;
+ 
+ #ifndef ARM_DEFAULT_ABI
+ #define ARM_DEFAULT_ABI ARM_ABI_APCS
+ #endif
+ 
  /* Nonzero if this chip supports the ARM Architecture 3M extensions.  */
  extern int arm_arch3m;
  
*************** extern int arm_is_6_or_7;
*** 811,823 ****
  
  #define UNITS_PER_WORD	4
  
! #define PARM_BOUNDARY  	32
  
! #define IWMMXT_ALIGNMENT   64
  
! #define STACK_BOUNDARY  32
  
! #define PREFERRED_STACK_BOUNDARY (TARGET_ATPCS ? 64 : 32)
  
  #define FUNCTION_BOUNDARY  32
  
--- 828,844 ----
  
  #define UNITS_PER_WORD	4
  
! /* True if natural alignment is used for doubleword types.  */
! #define ARM_DOUBLEWORD_ALIGN \
!     (arm_abi == ARM_ABI_AAPCS || arm_abi == ARM_ABI_IWMMXT)
! #define DOUBLEWORD_ALIGNMENT 64
  
! #define PARM_BOUNDARY  	32
  
! #define STACK_BOUNDARY  (ARM_DOUBLEWORD_ALIGN ? DOUBLEWORD_ALIGNMENT : 32)
  
! #define PREFERRED_STACK_BOUNDARY \
!     (arm_abi == ARM_ABI_ATPCS ? 64 : STACK_BOUNDARY)
  
  #define FUNCTION_BOUNDARY  32
  
*************** extern int arm_is_6_or_7;
*** 828,889 ****
  
  #define EMPTY_FIELD_BOUNDARY  32
  
! #define BIGGEST_ALIGNMENT  (TARGET_REALLY_IWMMXT ? 64 : 32)
! 
! #define TYPE_NEEDS_IWMMXT_ALIGNMENT(TYPE)	\
!  (TARGET_REALLY_IWMMXT				\
!    && ((TREE_CODE (TYPE) == VECTOR_TYPE) || (TYPE_MODE (TYPE) == DImode) || (TYPE_MODE (TYPE) == DFmode)))
  
  /* XXX Blah -- this macro is used directly by libobjc.  Since it
     supports no vector modes, cut out the complexity and fall back
     on BIGGEST_FIELD_ALIGNMENT.  */
  #ifdef IN_TARGET_LIBS
  #define BIGGEST_FIELD_ALIGNMENT 64
! #else
! /* An expression for the alignment of a structure field FIELD if the
!    alignment computed in the usual way is COMPUTED.  GCC uses this
!    value instead of the value in `BIGGEST_ALIGNMENT' or
!    `BIGGEST_FIELD_ALIGNMENT', if defined, for structure fields only.  */
! #define ADJUST_FIELD_ALIGN(FIELD, COMPUTED)		\
!   (TYPE_NEEDS_IWMMXT_ALIGNMENT (TREE_TYPE (FIELD))	\
!    ? IWMMXT_ALIGNMENT					\
!    : (COMPUTED))
! #endif
! 
! /* If defined, a C expression to compute the alignment for a static variable.
!    TYPE is the data type, and ALIGN is the alignment that the object
!    would ordinarily have.  The value of this macro is used instead of that
!    alignment to align the object.
! 
!    If this macro is not defined, then ALIGN is used.  */
! #define DATA_ALIGNMENT(TYPE, ALIGN) \
!   (TYPE_NEEDS_IWMMXT_ALIGNMENT (TYPE) ? IWMMXT_ALIGNMENT : ALIGN)
! 
! /* If defined, a C expression to compute the alignment for a
!    variables in the local store.  TYPE is the data type, and
!    BASIC-ALIGN is the alignment that the object would ordinarily
!    have.  The value of this macro is used instead of that alignment
!    to align the object.
! 
!    If this macro is not defined, then BASIC-ALIGN is used.  */
! #define LOCAL_ALIGNMENT(TYPE, ALIGN) \
!   (TYPE_NEEDS_IWMMXT_ALIGNMENT (TYPE) ? IWMMXT_ALIGNMENT : ALIGN)
  
  /* Make strings word-aligned so strcpy from constants will be faster.  */
  #define CONSTANT_ALIGNMENT_FACTOR (TARGET_THUMB || ! arm_tune_xscale ? 1 : 2)
      
  #define CONSTANT_ALIGNMENT(EXP, ALIGN)				\
!   ((TARGET_REALLY_IWMMXT && TREE_CODE (EXP) == VECTOR_TYPE) ? IWMMXT_ALIGNMENT : \
!    (TREE_CODE (EXP) == STRING_CST				\
!     && (ALIGN) < BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR)	\
!    ? BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR : (ALIGN))
  
  /* Setting STRUCTURE_SIZE_BOUNDARY to 32 produces more efficient code, but the
     value set in previous versions of this toolchain was 8, which produces more
     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".  */
  #define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary
  extern int arm_structure_size_boundary;
  
--- 849,878 ----
  
  #define EMPTY_FIELD_BOUNDARY  32
  
! #define BIGGEST_ALIGNMENT (ARM_DOUBLEWORD_ALIGN ? DOUBLEWORD_ALIGNMENT : 32)
  
  /* XXX Blah -- this macro is used directly by libobjc.  Since it
     supports no vector modes, cut out the complexity and fall back
     on BIGGEST_FIELD_ALIGNMENT.  */
  #ifdef IN_TARGET_LIBS
  #define BIGGEST_FIELD_ALIGNMENT 64
! #endif
  
  /* Make strings word-aligned so strcpy from constants will be faster.  */
  #define CONSTANT_ALIGNMENT_FACTOR (TARGET_THUMB || ! arm_tune_xscale ? 1 : 2)
      
  #define CONSTANT_ALIGNMENT(EXP, ALIGN)				\
!    ((TREE_CODE (EXP) == STRING_CST				\
!      && (ALIGN) < BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR)	\
!     ? BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR : (ALIGN))
  
  /* Setting STRUCTURE_SIZE_BOUNDARY to 32 produces more efficient code, but the
     value set in previous versions of this toolchain was 8, which produces more
     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".
!    The AAPCS specifies a value of 8.  */
  #define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary
  extern int arm_structure_size_boundary;
  
*************** enum reg_class
*** 1719,1725 ****
     : TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK			\
       && GET_MODE_CLASS (MODE) == MODE_FLOAT				\
     ? gen_rtx_REG (MODE, FIRST_CIRRUS_FP_REGNUM) 			\
!    : TARGET_REALLY_IWMMXT && VECTOR_MODE_SUPPORTED_P (MODE)		\
     ? gen_rtx_REG (MODE, FIRST_IWMMXT_REGNUM) 				\
     : gen_rtx_REG (MODE, ARG_REGISTER (1)))
  
--- 1708,1714 ----
     : TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK			\
       && GET_MODE_CLASS (MODE) == MODE_FLOAT				\
     ? gen_rtx_REG (MODE, FIRST_CIRRUS_FP_REGNUM) 			\
!    : TARGET_IWMMXT_ABI && VECTOR_MODE_SUPPORTED_P (MODE)	\
     ? gen_rtx_REG (MODE, FIRST_IWMMXT_REGNUM) 				\
     : gen_rtx_REG (MODE, ARG_REGISTER (1)))
  
*************** enum reg_class
*** 1737,1743 ****
    ((REGNO) == ARG_REGISTER (1) \
     || (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM)		\
         && TARGET_HARD_FLOAT && TARGET_MAVERICK)				\
!    || (TARGET_ARM && ((REGNO) == FIRST_IWMMXT_REGNUM) && TARGET_IWMMXT) \
     || (TARGET_ARM && ((REGNO) == FIRST_FPA_REGNUM)			\
         && TARGET_HARD_FLOAT && TARGET_FPA))
  
--- 1726,1732 ----
    ((REGNO) == ARG_REGISTER (1) \
     || (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM)		\
         && TARGET_HARD_FLOAT && TARGET_MAVERICK)				\
!    || ((REGNO) == FIRST_IWMMXT_REGNUM && TARGET_IWMMXT_ABI) \
     || (TARGET_ARM && ((REGNO) == FIRST_FPA_REGNUM)			\
         && TARGET_HARD_FLOAT && TARGET_FPA))
  
*************** enum reg_class
*** 1791,1796 ****
--- 1780,1801 ----
  #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(())
*************** typedef struct machine_function GTY(())
*** 1804,1810 ****
    /* 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;
    /* Records the type of the current function.  */
    unsigned long func_type;
    /* Record if the function has a variable argument list.  */
--- 1809,1815 ----
    /* Records if the save of LR has been eliminated.  */
    int lr_save_eliminated;
    /* The size of the stack frame.  Only valid after reload.  */
!   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.  */
*************** typedef struct
*** 1828,1833 ****
--- 1833,1839 ----
    int nargs;
    /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT.  */
    int call_cookie;
+   int can_split;
  } CUMULATIVE_ARGS;
  
  /* Define where to put the arguments to a function.
*************** typedef struct
*** 1857,1863 ****
  #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED)	\
    (VECTOR_MODE_SUPPORTED_P (MODE) ? 0 :				\
         NUM_ARG_REGS > (CUM).nregs				\
!    && (NUM_ARG_REGS < ((CUM).nregs + ARM_NUM_REGS2 (MODE, TYPE)))	\
     ?   NUM_ARG_REGS - (CUM).nregs : 0)
  
  /* A C expression that indicates when an argument must be passed by
--- 1863,1870 ----
  #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED)	\
    (VECTOR_MODE_SUPPORTED_P (MODE) ? 0 :				\
         NUM_ARG_REGS > (CUM).nregs				\
!    && (NUM_ARG_REGS < ((CUM).nregs + ARM_NUM_REGS2 (MODE, TYPE))	\
!    && (CUM).can_split)						\
     ?   NUM_ARG_REGS - (CUM).nregs : 0)
  
  /* A C expression that indicates when an argument must be passed by
*************** typedef struct
*** 1880,1905 ****
     (TYPE is null for libcalls where that information may not be available.)  */
  #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)	\
    (CUM).nargs += 1;					\
!   if (VECTOR_MODE_SUPPORTED_P (MODE))			\
!      if ((CUM).named_count <= (CUM).nargs)		\
!         (CUM).nregs += 2;				\
!      else						\
!         (CUM).iwmmxt_nregs += 1;			\
    else							\
!   (CUM).nregs += ARM_NUM_REGS2 (MODE, TYPE)
  
  /* If defined, a C expression that gives the alignment boundary, in bits, of an
     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)
  
  /* 1 if N is a possible register number for function argument passing.
     On the ARM, r0-r3 are used to pass args.  */
  #define FUNCTION_ARG_REGNO_P(REGNO)	\
     (IN_RANGE ((REGNO), 0, 3)		\
!     || (TARGET_REALLY_IWMMXT && IN_RANGE ((REGNO), FIRST_IWMMXT_REGNUM, FIRST_IWMMXT_REGNUM + 9)))
  
  /* Implement `va_arg'.  */
  #define EXPAND_BUILTIN_VA_ARG(valist, type) \
--- 1887,1912 ----
     (TYPE is null for libcalls where that information may not be available.)  */
  #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)	\
    (CUM).nargs += 1;					\
!   if (VECTOR_MODE_SUPPORTED_P (MODE)			\
!       && (CUM).named_count > (CUM).nargs)		\
!     (CUM).iwmmxt_nregs += 1;				\
    else							\
!     (CUM).nregs += ARM_NUM_REGS2 (MODE, TYPE)
  
  /* If defined, a C expression that gives the alignment boundary, in bits, of an
     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) \
!    ((ARM_DOUBLEWORD_ALIGN && arm_needs_doubleword_align (MODE, TYPE)) \
!    ? DOUBLEWORD_ALIGNMENT \
!    : PARM_BOUNDARY )
  
  /* 1 if N is a possible register number for function argument passing.
     On the ARM, r0-r3 are used to pass args.  */
  #define FUNCTION_ARG_REGNO_P(REGNO)	\
     (IN_RANGE ((REGNO), 0, 3)		\
!     || (TARGET_IWMMXT_ABI		\
! 	&& IN_RANGE ((REGNO), FIRST_IWMMXT_REGNUM, FIRST_IWMMXT_REGNUM + 9)))
  
  /* Implement `va_arg'.  */
  #define EXPAND_BUILTIN_VA_ARG(valist, type) \
*************** typedef struct
*** 2021,2073 ****
       
  /* Define the offset between two registers, one to be eliminated, and the
     other its replacement, at the start of a routine.  */
- #define ARM_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)		\
-   do									\
-     {									\
-       (OFFSET) = arm_compute_initial_elimination_offset (FROM, TO);	\
-     }									\
-   while (0)
- 
- /* Note:  This macro must match the code in thumb_function_prologue().  */
- #define THUMB_INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)		\
- {									\
-   (OFFSET) = 0;								\
-   if ((FROM) == ARG_POINTER_REGNUM)					\
-     {									\
-       int count_regs = 0;						\
-       int regno;							\
-       for (regno = 8; regno < 13; regno ++)				\
-         if (THUMB_REG_PUSHED_P (regno))					\
-           count_regs ++;						\
-       if (count_regs)							\
- 	(OFFSET) += 4 * count_regs;					\
-       count_regs = 0;							\
-       for (regno = 0; regno <= LAST_LO_REGNUM; regno ++)		\
-         if (THUMB_REG_PUSHED_P (regno))					\
- 	  count_regs ++;						\
-       if (count_regs || ! leaf_function_p () || thumb_far_jump_used_p (0))\
- 	(OFFSET) += 4 * (count_regs + 1);				\
-       if (TARGET_BACKTRACE)						\
-         {								\
- 	  if ((count_regs & 0xFF) == 0 && (regs_ever_live[3] != 0))	\
- 	    (OFFSET) += 20;						\
- 	  else								\
- 	    (OFFSET) += 16;						\
-         }								\
-     }									\
-   if ((TO) == STACK_POINTER_REGNUM)					\
-     {									\
-       (OFFSET) += current_function_outgoing_args_size;			\
-       (OFFSET) += thumb_get_frame_size ();				\
-      }									\
- }
- 
  #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
    if (TARGET_ARM)							\
!     ARM_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET);			\
    else									\
!     THUMB_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET)
!      
  /* Special case handling of the location of arguments passed on the stack.  */
  #define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr)
       
--- 2028,2039 ----
       
  /* Define the offset between two registers, one to be eliminated, and the
     other its replacement, at the start of a routine.  */
  #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)			\
    if (TARGET_ARM)							\
!     (OFFSET) = arm_compute_initial_elimination_offset (FROM, TO);	\
    else									\
!     (OFFSET) = thumb_compute_initial_elimination_offset (FROM, TO)
! 
  /* Special case handling of the location of arguments passed on the stack.  */
  #define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr)
       
Index: gcc/config/arm/arm.md
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/arm.md,v
retrieving revision 1.160
diff -c -p -r1.160 arm.md
*** a/gcc/config/arm/arm.md	11 Mar 2004 13:02:32 -0000	1.160
--- b/gcc/config/arm/arm.md	11 Mar 2004 17:59:37 -0000
***************
*** 10193,10199 ****
  
  (define_insn "align_8"
    [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
!   "TARGET_REALLY_IWMMXT"
    "*
    assemble_align (64);
    return \"\";
--- 10193,10199 ----
  
  (define_insn "align_8"
    [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
!   "TARGET_EITHER"
    "*
    assemble_align (64);
    return \"\";
Index: gcc/config/arm/netbsd-elf.h
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/config/arm/netbsd-elf.h,v
retrieving revision 1.9
diff -c -p -r1.9 netbsd-elf.h
*** a/gcc/config/arm/netbsd-elf.h	5 Mar 2004 16:59:54 -0000	1.9
--- b/gcc/config/arm/netbsd-elf.h	8 Mar 2004 11:57:31 -0000
***************
*** 38,47 ****
    (ARM_FLAG_APCS_32			\
     | ARM_FLAG_SOFT_FLOAT		\
     | ARM_FLAG_APCS_FRAME		\
-    | ARM_FLAG_ATPCS			\
     | ARM_FLAG_MMU_TRAPS			\
     | TARGET_ENDIAN_DEFAULT)
  
  #define TARGET_OS_CPP_BUILTINS()	\
    do					\
      {					\
--- 38,49 ----
    (ARM_FLAG_APCS_32			\
     | ARM_FLAG_SOFT_FLOAT		\
     | ARM_FLAG_APCS_FRAME		\
     | ARM_FLAG_MMU_TRAPS			\
     | TARGET_ENDIAN_DEFAULT)
  
+ #undef ARM_DEFAULT_ABI
+ #define ARM_DEFAULT_ABI ARM_ABI_ATPCS
+ 
  #define TARGET_OS_CPP_BUILTINS()	\
    do					\
      {					\
Index: gcc/doc/invoke.texi
===================================================================
RCS file: /var/cvsroot/gcc-cvs/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.426
diff -c -p -r1.426 invoke.texi
*** a/gcc/doc/invoke.texi	10 Mar 2004 21:43:35 -0000	1.426
--- b/gcc/doc/invoke.texi	12 Mar 2004 16:05:04 -0000
*************** in the following sections.
*** 368,373 ****
--- 368,374 ----
  
  @emph{ARM Options}
  @gccoptlist{-mapcs-frame  -mno-apcs-frame @gol
+ -mabi=@var{name} @gol
  -mapcs-26  -mapcs-32 @gol
  -mapcs-stack-check  -mno-apcs-stack-check @gol
  -mapcs-float  -mno-apcs-float @gol
*************** These @samp{-m} options are defined for 
*** 6404,6409 ****
--- 6405,6415 ----
  architectures:
  
  @table @gcctabopt
+ @item -mabi=@var{name}
+ @opindex mabi
+ Generate code for the specified ABI.  Permissible values are: @samp{apcs},
+ @samp{atpcs}, @samp{aapcs} and @samp{iwmmxt}.
+ 
  @item -mapcs-frame
  @opindex mapcs-frame
  Generate a stack frame that is compliant with the ARM Procedure Call
*************** floating point values.
*** 6626,6639 ****
  @item -mstructure-size-boundary=@var{n}
  @opindex mstructure-size-boundary
  The size of all structures and unions will be rounded up to a multiple
! of the number of bits set by this option.  Permissible values are 8 and
! 32.  The default value varies for different toolchains.  For the COFF
! targeted toolchain the default value is 8.  Specifying the larger number
! can produce faster, more efficient code, but can also increase the size
! of the program.  The two values are potentially incompatible.  Code
! compiled with one value cannot necessarily expect to work with code or
! libraries compiled with the other value, if they exchange information
! using structures or unions.
  
  @item -mabort-on-noreturn
  @opindex mabort-on-noreturn
--- 6632,6647 ----
  @item -mstructure-size-boundary=@var{n}
  @opindex mstructure-size-boundary
  The size of all structures and unions will be rounded up to a multiple
! of the number of bits set by this option.  Permissible values are 8, 32
! and 64.  The default value varies for different toolchains.  For the COFF
! targeted toolchain the default value is 8.  A value of 64 is only allowed
! if the underlying ABI supports it.
! 
! Specifying the larger number can produce faster, more efficient code, but
! can also increase the size of the program.  Different values are potentially
! incompatible.  Code compiled with one value cannot necessarily expect to
! work with code or libraries compiled with annother value, if they exchange
! information using structures or unions.
  
  @item -mabort-on-noreturn
  @opindex mabort-on-noreturn

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