Commit 5848830f by Paul Brook Committed by Paul Brook

config.gcc: Add --with-abi=

	* 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.

From-SVN: r79921
parent b4a76c01
2004-03-24 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.
2004-03-24 Nathanael Nerode <neroden@gcc.gnu.org> 2004-03-24 Nathanael Nerode <neroden@gcc.gnu.org>
* configure.ac: Check for -Wno-variadic-macros; don't use * configure.ac: Check for -Wno-variadic-macros; don't use
......
...@@ -2226,7 +2226,7 @@ fi ...@@ -2226,7 +2226,7 @@ fi
;; ;;
arm*-*-*) arm*-*-*)
supported_defaults="arch cpu float tune fpu" supported_defaults="arch cpu float tune fpu abi"
for which in cpu tune; do for which in cpu tune; do
eval "val=\$with_$which" eval "val=\$with_$which"
case "$val" in case "$val" in
...@@ -2280,13 +2280,24 @@ fi ...@@ -2280,13 +2280,24 @@ fi
# OK # OK
;; ;;
*) *)
echo "Unknown fpu used in --with-fpu=$fpu" 2>&1 echo "Unknown fpu used in --with-fpu=$with_fpu" 2>&1
exit 1
;;
esac
case "$with_abi" in
"" \
| apcs-gnu | atpcs | aapcs | iwmmxt )
#OK
;;
*)
echo "Unknown ABI used in --with-abi=$with_abi"
exit 1 exit 1
;; ;;
esac esac
if test "x$with_arch" != x && test "x$with_cpu" != x; then if test "x$with_arch" != x && test "x$with_cpu" != x; then
echo "Warning: --with-arch overrides --with-cpu" 1>&2 echo "Warning: --with-arch overrides --with-cpu=$with_cpu" 1>&2
fi fi
;; ;;
......
...@@ -31,12 +31,13 @@ extern void arm_finalize_pic (int); ...@@ -31,12 +31,13 @@ extern void arm_finalize_pic (int);
extern int arm_volatile_func (void); extern int arm_volatile_func (void);
extern const char *arm_output_epilogue (rtx); extern const char *arm_output_epilogue (rtx);
extern void arm_expand_prologue (void); 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 const char *arm_strip_name_encoding (const char *);
extern void arm_asm_output_labelref (FILE *, const char *); extern void arm_asm_output_labelref (FILE *, const char *);
extern unsigned long arm_current_func_type (void); extern unsigned long arm_current_func_type (void);
extern unsigned int arm_compute_initial_elimination_offset (unsigned int, extern unsigned int arm_compute_initial_elimination_offset (unsigned int,
unsigned int); unsigned int);
extern HOST_WIDE_INT thumb_compute_initial_elimination_offset (unsigned int,
unsigned int);
#ifdef TREE_CODE #ifdef TREE_CODE
extern int arm_return_in_memory (tree); extern int arm_return_in_memory (tree);
...@@ -157,6 +158,7 @@ extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree); ...@@ -157,6 +158,7 @@ extern void arm_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
extern rtx arm_va_arg (tree, tree); extern rtx arm_va_arg (tree, tree);
extern int arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *, extern int arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *,
enum machine_mode, tree, int); enum machine_mode, tree, int);
extern bool arm_needs_doubleword_align (enum machine_mode, tree);
#endif #endif
#if defined AOF_ASSEMBLER #if defined AOF_ASSEMBLER
...@@ -175,9 +177,7 @@ extern int arm_float_words_big_endian (void); ...@@ -175,9 +177,7 @@ extern int arm_float_words_big_endian (void);
/* Thumb functions. */ /* Thumb functions. */
extern void arm_init_expanders (void); extern void arm_init_expanders (void);
extern int thumb_far_jump_used_p (int);
extern const char *thumb_unexpanded_epilogue (void); 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_prologue (void);
extern void thumb_expand_epilogue (void); extern void thumb_expand_epilogue (void);
#ifdef TREE_CODE #ifdef TREE_CODE
......
...@@ -59,6 +59,7 @@ typedef struct minipool_fixup Mfix; ...@@ -59,6 +59,7 @@ typedef struct minipool_fixup Mfix;
const struct attribute_spec arm_attribute_table[]; const struct attribute_spec arm_attribute_table[];
/* Forward function declarations. */ /* Forward function declarations. */
static arm_stack_offsets *arm_get_frame_offsets (void);
static void arm_add_gc_roots (void); static void arm_add_gc_roots (void);
static int arm_gen_constant (enum rtx_code, enum machine_mode, HOST_WIDE_INT, static int arm_gen_constant (enum rtx_code, enum machine_mode, HOST_WIDE_INT,
rtx, rtx, int, int); rtx, rtx, int, int);
...@@ -67,6 +68,7 @@ static int arm_address_register_rtx_p (rtx, int); ...@@ -67,6 +68,7 @@ static int arm_address_register_rtx_p (rtx, int);
static int arm_legitimate_index_p (enum machine_mode, rtx, RTX_CODE, int); static int arm_legitimate_index_p (enum machine_mode, rtx, RTX_CODE, int);
static int thumb_base_register_rtx_p (rtx, enum machine_mode, int); static int thumb_base_register_rtx_p (rtx, enum machine_mode, int);
inline static int thumb_index_register_rtx_p (rtx, 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 int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
static rtx emit_multi_reg_push (int); static rtx emit_multi_reg_push (int);
static rtx emit_sfm (int, int); static rtx emit_sfm (int, int);
...@@ -284,6 +286,9 @@ enum fputype arm_fpu_tune; ...@@ -284,6 +286,9 @@ enum fputype arm_fpu_tune;
/* Whether to use floating point hardware. */ /* Whether to use floating point hardware. */
enum float_abi_type arm_float_abi; 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. */ /* What program mode is the cpu running in? 26-bit mode or 32-bit mode. */
enum prog_mode_type arm_prgmode; enum prog_mode_type arm_prgmode;
...@@ -296,6 +301,9 @@ const char * target_fpe_name = NULL; ...@@ -296,6 +301,9 @@ const char * target_fpe_name = NULL;
/* Set by the -mfloat-abi=... option. */ /* Set by the -mfloat-abi=... option. */
const char * target_float_abi_name = NULL; 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. */ /* Used to parse -mstructure_size_boundary command line option. */
const char * structure_size_string = NULL; const char * structure_size_string = NULL;
int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY; int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
...@@ -510,6 +518,23 @@ static const struct float_abi all_float_abis[] = ...@@ -510,6 +518,23 @@ static const struct float_abi all_float_abis[] =
}; };
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-gnu", ARM_ABI_APCS},
{"atpcs", ARM_ABI_ATPCS},
{"aapcs", ARM_ABI_AAPCS},
{"iwmmxt", ARM_ABI_IWMMXT}
};
/* Return the number of bits set in VALUE. */ /* Return the number of bits set in VALUE. */
static unsigned static unsigned
bit_count (unsigned long value) bit_count (unsigned long value)
...@@ -814,8 +839,27 @@ arm_override_options (void) ...@@ -814,8 +839,27 @@ arm_override_options (void)
arm_tune_xscale = (tune_flags & FL_XSCALE) != 0; arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0; arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
if (TARGET_IWMMXT && (! TARGET_ATPCS)) if (target_abi_name)
target_flags |= ARM_FLAG_ATPCS; {
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; arm_fp_model = ARM_FP_MODEL_UNKNOWN;
if (target_fpu_name == NULL && target_fpe_name != NULL) if (target_fpu_name == NULL && target_fpe_name != NULL)
...@@ -908,14 +952,20 @@ arm_override_options (void) ...@@ -908,14 +952,20 @@ arm_override_options (void)
arm_prgmode = TARGET_APCS_32 ? PROG_MODE_PROG32 : PROG_MODE_PROG26; 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) if (structure_size_string != NULL)
{ {
int size = strtol (structure_size_string, NULL, 0); int size = strtol (structure_size_string, NULL, 0);
if (size == 8 || size == 32) if (size == 8 || size == 32
|| (ARM_DOUBLEWORD_ALIGN && size == 64))
arm_structure_size_boundary = size; arm_structure_size_boundary = size;
else else
warning ("structure size boundary can only be set to 8 or 32"); 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) if (arm_pic_register_string != NULL)
...@@ -1109,6 +1159,7 @@ use_return_insn (int iscond, rtx sibling) ...@@ -1109,6 +1159,7 @@ use_return_insn (int iscond, rtx sibling)
unsigned int func_type; unsigned int func_type;
unsigned long saved_int_regs; unsigned long saved_int_regs;
unsigned HOST_WIDE_INT stack_adjust; unsigned HOST_WIDE_INT stack_adjust;
arm_stack_offsets *offsets;
/* Never use a return instruction before reload has run. */ /* Never use a return instruction before reload has run. */
if (!reload_completed) if (!reload_completed)
...@@ -1125,7 +1176,8 @@ use_return_insn (int iscond, rtx sibling) ...@@ -1125,7 +1176,8 @@ use_return_insn (int iscond, rtx sibling)
if (IS_INTERRUPT (func_type) && frame_pointer_needed) if (IS_INTERRUPT (func_type) && frame_pointer_needed)
return 0; 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. */ /* As do variadic functions. */
if (current_function_pretend_args_size if (current_function_pretend_args_size
...@@ -2018,9 +2070,9 @@ arm_return_in_memory (tree type) ...@@ -2018,9 +2070,9 @@ arm_return_in_memory (tree type)
size = int_size_in_bytes (type); size = int_size_in_bytes (type);
if (TARGET_ATPCS) if (arm_abi != ARM_ABI_APCS)
{ {
/* ATPCS returns aggregate types in memory only if they are /* ATPCS and later return aggregate types in memory only if they are
larger than a word (or are variable size). */ larger than a word (or are variable size). */
return (size < 0 || size > UNITS_PER_WORD); return (size < 0 || size > UNITS_PER_WORD);
} }
...@@ -2143,6 +2195,7 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype, ...@@ -2143,6 +2195,7 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
/* On the ARM, the offset starts at 0. */ /* On the ARM, the offset starts at 0. */
pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype), fntype)) ? 1 : 0); pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype), fntype)) ? 1 : 0);
pcum->iwmmxt_nregs = 0; pcum->iwmmxt_nregs = 0;
pcum->can_split = true;
pcum->call_cookie = CALL_NORMAL; pcum->call_cookie = CALL_NORMAL;
...@@ -2178,6 +2231,19 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype, ...@@ -2178,6 +2231,19 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
} }
} }
/* 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. /* Determine where to put an argument to a function.
Value is zero to push the argument on the stack, Value is zero to push the argument on the stack,
or a hard register in which to store the argument. or a hard register in which to store the argument.
...@@ -2193,37 +2259,44 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype, ...@@ -2193,37 +2259,44 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
rtx rtx
arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode, arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
tree type ATTRIBUTE_UNUSED, int named) tree type, int named)
{ {
if (TARGET_REALLY_IWMMXT) int nregs;
{
if (VECTOR_MODE_SUPPORTED_P (mode)) /* Varargs vectors are treated the same as long long.
{
/* varargs vectors are treated the same as long long.
named_count avoids having to change the way arm handles 'named' */ named_count avoids having to change the way arm handles 'named' */
if (pcum->named_count <= pcum->nargs + 1) if (TARGET_IWMMXT_ABI
&& VECTOR_MODE_SUPPORTED_P (mode)
&& pcum->named_count > pcum->nargs + 1)
{ {
if (pcum->nregs == 1) if (pcum->iwmmxt_nregs <= 9)
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); return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
else else
{
pcum->can_split = false;
return NULL_RTX; return NULL_RTX;
} }
else if ((mode == DImode || mode == DFmode) && pcum->nregs & 1)
pcum->nregs += 1;
} }
/* 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) if (mode == VOIDmode)
/* Compute operand 2 of the call insn. */ /* Compute operand 2 of the call insn. */
return GEN_INT (pcum->call_cookie); return GEN_INT (pcum->call_cookie);
if (!named || pcum->nregs >= NUM_ARG_REGS) /* 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 NULL_RTX;
return gen_rtx_REG (mode, pcum->nregs); return gen_rtx_REG (mode, pcum->nregs);
...@@ -2245,6 +2318,8 @@ arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, ...@@ -2245,6 +2318,8 @@ arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
rtx rtx
arm_va_arg (tree valist, tree type) arm_va_arg (tree valist, tree type)
{ {
int align;
/* Variable sized types are passed by reference. */ /* Variable sized types are passed by reference. */
if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
{ {
...@@ -2252,17 +2327,18 @@ arm_va_arg (tree valist, tree type) ...@@ -2252,17 +2327,18 @@ arm_va_arg (tree valist, tree type)
return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr)); 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; tree t;
/* Maintain 64-bit alignment of the valist pointer by /* Maintain 64-bit alignment of the valist pointer by
constructing: valist = ((valist + (8 - 1)) & -8). */ constructing: valist = ((valist + (8 - 1)) & -8). */
minus_eight = build_int_2 (- (IWMMXT_ALIGNMENT / BITS_PER_UNIT), -1); mask = build_int_2 (- (align / BITS_PER_UNIT), -1);
t = build_int_2 ((IWMMXT_ALIGNMENT / BITS_PER_UNIT) - 1, 0); t = build_int_2 ((align / BITS_PER_UNIT) - 1, 0);
t = build (PLUS_EXPR, TREE_TYPE (valist), valist, t); 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); t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
TREE_SIDE_EFFECTS (t) = 1; TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
...@@ -6846,7 +6922,7 @@ add_minipool_forward_ref (Mfix *fix) ...@@ -6846,7 +6922,7 @@ add_minipool_forward_ref (Mfix *fix)
we have not already found an insertion point, then we have not already found an insertion point, then
make sure that all such 8-byte aligned quantities are make sure that all such 8-byte aligned quantities are
placed at the start of the pool. */ placed at the start of the pool. */
if (TARGET_REALLY_IWMMXT if (ARM_DOUBLEWORD_ALIGN
&& max_mp == NULL && max_mp == NULL
&& fix->fix_size == 8 && fix->fix_size == 8
&& mp->fix_size != 8) && mp->fix_size != 8)
...@@ -7030,7 +7106,8 @@ add_minipool_backward_ref (Mfix *fix) ...@@ -7030,7 +7106,8 @@ add_minipool_backward_ref (Mfix *fix)
{ {
/* For now, we do not allow the insertion of 8-byte alignment /* For now, we do not allow the insertion of 8-byte alignment
requiring nodes anywhere but at the start of the pool. */ requiring nodes anywhere but at the start of the pool. */
if (TARGET_REALLY_IWMMXT && fix->fix_size == 8 && mp->fix_size != 8) if (ARM_DOUBLEWORD_ALIGN
&& fix->fix_size == 8 && mp->fix_size != 8)
return NULL; return NULL;
else else
min_mp = mp; min_mp = mp;
...@@ -7049,7 +7126,7 @@ add_minipool_backward_ref (Mfix *fix) ...@@ -7049,7 +7126,7 @@ add_minipool_backward_ref (Mfix *fix)
we have not already found an insertion point, then we have not already found an insertion point, then
make sure that all such 8-byte aligned quantities are make sure that all such 8-byte aligned quantities are
placed at the start of the pool. */ placed at the start of the pool. */
else if (TARGET_REALLY_IWMMXT else if (ARM_DOUBLEWORD_ALIGN
&& min_mp == NULL && min_mp == NULL
&& fix->fix_size == 8 && fix->fix_size == 8
&& mp->fix_size < 8) && mp->fix_size < 8)
...@@ -7147,7 +7224,7 @@ dump_minipool (rtx scan) ...@@ -7147,7 +7224,7 @@ dump_minipool (rtx scan)
Mnode * nmp; Mnode * nmp;
int align64 = 0; int align64 = 0;
if (TARGET_REALLY_IWMMXT) if (ARM_DOUBLEWORD_ALIGN)
for (mp = minipool_vector_head; mp != NULL; mp = mp->next) for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
if (mp->refcount > 0 && mp->fix_size == 8) if (mp->refcount > 0 && mp->fix_size == 8)
{ {
...@@ -7389,11 +7466,11 @@ push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc, ...@@ -7389,11 +7466,11 @@ push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
if (fix->forwards == 0 && fix->backwards == 0) if (fix->forwards == 0 && fix->backwards == 0)
abort (); abort ();
/* With iWMMXt enabled, the pool is aligned to an 8-byte boundary. /* 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. 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 Hence we reduce the forward range by 4 to allow for this
possibility. */ possibility. */
if (TARGET_REALLY_IWMMXT && fix->fix_size == 8) if (ARM_DOUBLEWORD_ALIGN && fix->fix_size == 8)
fix->forwards -= 4; fix->forwards -= 4;
if (dump_file) if (dump_file)
...@@ -8651,8 +8728,7 @@ output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len) ...@@ -8651,8 +8728,7 @@ output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
} }
/* Compute the register sabe mask for registers 0 through 12 /* Compute the register sabe mask for registers 0 through 12
inclusive. This code is used by both arm_compute_save_reg_mask inclusive. This code is used by arm_compute_save_reg_mask. */
and arm_compute_initial_elimination_offset. */
static unsigned long static unsigned long
arm_compute_save_reg0_reg12_mask (void) arm_compute_save_reg0_reg12_mask (void)
{ {
...@@ -8798,6 +8874,7 @@ output_return_instruction (rtx operand, int really_return, int reverse) ...@@ -8798,6 +8874,7 @@ output_return_instruction (rtx operand, int really_return, int reverse)
int reg; int reg;
unsigned long live_regs_mask; unsigned long live_regs_mask;
unsigned long func_type; unsigned long func_type;
arm_stack_offsets *offsets;
func_type = arm_current_func_type (); func_type = arm_current_func_type ();
...@@ -8896,9 +8973,10 @@ output_return_instruction (rtx operand, int really_return, int reverse) ...@@ -8896,9 +8973,10 @@ output_return_instruction (rtx operand, int really_return, int reverse)
points to the base of the saved core registers. */ points to the base of the saved core registers. */
if (live_regs_mask & (1 << SP_REGNUM)) if (live_regs_mask & (1 << SP_REGNUM))
{ {
unsigned HOST_WIDE_INT stack_adjust = unsigned HOST_WIDE_INT stack_adjust;
arm_get_frame_size () + current_function_outgoing_args_size;
offsets = arm_get_frame_offsets ();
stack_adjust = offsets->outgoing_args - offsets->saved_regs;
if (stack_adjust != 0 && stack_adjust != 4) if (stack_adjust != 0 && stack_adjust != 4)
abort (); abort ();
...@@ -9128,12 +9206,12 @@ arm_output_epilogue (rtx sibling) ...@@ -9128,12 +9206,12 @@ arm_output_epilogue (rtx sibling)
frame that is $fp + 4 for a non-variadic function. */ frame that is $fp + 4 for a non-variadic function. */
int floats_offset = 0; int floats_offset = 0;
rtx operands[3]; rtx operands[3];
int frame_size = arm_get_frame_size ();
FILE * f = asm_out_file; FILE * f = asm_out_file;
rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs; rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
unsigned int lrm_count = 0; unsigned int lrm_count = 0;
int really_return = (sibling == NULL); int really_return = (sibling == NULL);
int start_reg; int start_reg;
arm_stack_offsets *offsets;
/* If we have already generated the return instruction /* If we have already generated the return instruction
then it is futile to generate anything else. */ then it is futile to generate anything else. */
...@@ -9164,14 +9242,13 @@ arm_output_epilogue (rtx sibling) ...@@ -9164,14 +9242,13 @@ arm_output_epilogue (rtx sibling)
be doing a return, so we can't tail-call. */ be doing a return, so we can't tail-call. */
abort (); abort ();
offsets = arm_get_frame_offsets ();
saved_regs_mask = arm_compute_save_reg_mask (); saved_regs_mask = arm_compute_save_reg_mask ();
if (TARGET_IWMMXT) if (TARGET_IWMMXT)
lrm_count = bit_count (saved_regs_mask); lrm_count = bit_count (saved_regs_mask);
/* XXX We should adjust floats_offset for any anonymous args, and then floats_offset = offsets->saved_args;
re-adjust vfp_offset below to compensate. */
/* Compute how far away the floats will be. */ /* Compute how far away the floats will be. */
for (reg = 0; reg <= LAST_ARM_REGNUM; reg++) for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
if (saved_regs_mask & (1 << reg)) if (saved_regs_mask & (1 << reg))
...@@ -9180,7 +9257,7 @@ arm_output_epilogue (rtx sibling) ...@@ -9180,7 +9257,7 @@ arm_output_epilogue (rtx sibling)
if (frame_pointer_needed) if (frame_pointer_needed)
{ {
/* This variable is for the Virtual Frame Pointer, not VFP regs. */ /* 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) if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
{ {
...@@ -9332,8 +9409,7 @@ arm_output_epilogue (rtx sibling) ...@@ -9332,8 +9409,7 @@ arm_output_epilogue (rtx sibling)
be reset correctly to the original value, should an interrupt be reset correctly to the original value, should an interrupt
occur. If the stack pointer already points at the right occur. If the stack pointer already points at the right
place, then omit the subtraction. */ place, then omit the subtraction. */
if (((frame_size + current_function_outgoing_args_size + floats_offset) if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
!= 4 * (1 + (int) bit_count (saved_regs_mask)))
|| current_function_calls_alloca) || current_function_calls_alloca)
asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM, asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
4 * bit_count (saved_regs_mask)); 4 * bit_count (saved_regs_mask));
...@@ -9347,11 +9423,10 @@ arm_output_epilogue (rtx sibling) ...@@ -9347,11 +9423,10 @@ arm_output_epilogue (rtx sibling)
else else
{ {
/* Restore stack pointer if necessary. */ /* 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[0] = operands[1] = stack_pointer_rtx;
operands[2] = GEN_INT (frame_size operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
+ current_function_outgoing_args_size);
output_add_immediate (operands); output_add_immediate (operands);
} }
...@@ -9517,8 +9592,10 @@ arm_output_epilogue (rtx sibling) ...@@ -9517,8 +9592,10 @@ arm_output_epilogue (rtx sibling)
static void static void
arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, 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) if (TARGET_THUMB)
{ {
/* ??? Probably not safe to set this here, since it assumes that a /* ??? Probably not safe to set this here, since it assumes that a
...@@ -9529,11 +9606,11 @@ arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, ...@@ -9529,11 +9606,11 @@ arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
else else
{ {
/* We need to take into account any stack-frame rounding. */ /* 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) if (use_return_insn (FALSE, NULL)
&& return_used_this_function && return_used_this_function
&& (frame_size + current_function_outgoing_args_size) != 0 && offsets->saved_regs != offsets->outgoing_args
&& !frame_pointer_needed) && !frame_pointer_needed)
abort (); abort ();
...@@ -9763,82 +9840,173 @@ emit_sfm (int base_reg, int count) ...@@ -9763,82 +9840,173 @@ emit_sfm (int base_reg, int count)
The sign of the number returned reflects the direction of stack The sign of the number returned reflects the direction of stack
growth, so the values are positive for all eliminations except growth, so the values are positive for all eliminations except
from the soft frame pointer to the hard frame pointer. */ from the soft frame pointer to the hard frame pointer.
unsigned int
arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) 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 (); struct arm_stack_offsets *offsets;
unsigned int outgoing_args = current_function_outgoing_args_size;
unsigned int stack_frame;
unsigned int call_saved_registers;
unsigned long func_type; unsigned long func_type;
int leaf;
bool new_block;
int saved;
HOST_WIDE_INT frame_size;
func_type = arm_current_func_type (); offsets = &cfun->machine->stack_offsets;
/* Volatile functions never return, so there is /* We need to know if we are a leaf function. Unfortunately, it
no need to save call saved registers. */ is possible to be called after start_sequence has been called,
call_saved_registers = 0; which causes get_insns to return the insns for the sequence,
if (! IS_VOLATILE (func_type)) 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 reg_mask; unsigned int regno;
unsigned int reg;
bool new_block;
/* Make sure that we compute which registers will be saved saved = bit_count (arm_compute_save_reg_mask ()) * 4;
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 /* We know that SP will be doubleword aligned on entry, and we must
used then they must be saved on the stack as well. preserve that condition at any subroutine call. We also require the
Each register occupies 12 bytes of stack space. */ soft frame pointer to be doubleword aligned. */
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_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) if (TARGET_HARD_FLOAT && TARGET_VFP)
{ {
new_block = TRUE; 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]) if ((regs_ever_live[regno] && !call_used_regs[regno])
|| (regs_ever_live[reg + 1] && !call_used_regs[reg + 1])) || (regs_ever_live[regno + 1]
&& !call_used_regs[regno + 1]))
{ {
if (new_block) if (new_block)
{ {
call_saved_registers += 4; saved += 4;
new_block = FALSE; new_block = FALSE;
} }
call_saved_registers += 8; saved += 8;
} }
else else
new_block = TRUE; new_block = TRUE;
} }
} }
}
}
else /* TARGET_THUMB */
{
int reg;
int count_regs;
if (TARGET_REALLY_IWMMXT) saved = 0;
/* Check for the call-saved iWMMXt registers. */ count_regs = 0;
for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++) for (reg = 8; reg < 13; reg ++)
if (regs_ever_live[reg] && ! call_used_regs [reg]) if (THUMB_REG_PUSHED_P (reg))
call_saved_registers += 8; 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 ();
} }
/* The stack frame contains 4 registers - the old frame pointer, return offsets;
the old stack pointer, the return address and PC of the start }
of the function. */
stack_frame = frame_pointer_needed ? 16 : 0;
/* 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. /* OK, now we have enough information to compute the distances.
There must be an entry in these switch tables for each pair There must be an entry in these switch tables for each pair
...@@ -9855,14 +10023,12 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) ...@@ -9855,14 +10023,12 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
case FRAME_POINTER_REGNUM: case FRAME_POINTER_REGNUM:
/* This is the reverse of the soft frame pointer /* This is the reverse of the soft frame pointer
to hard frame pointer elimination below. */ to hard frame pointer elimination below. */
if (call_saved_registers == 0 && stack_frame == 0) return offsets->soft_frame - offsets->saved_args;
return 0;
return (call_saved_registers + stack_frame - 4);
case ARM_HARD_FRAME_POINTER_REGNUM: case ARM_HARD_FRAME_POINTER_REGNUM:
/* If there is no stack frame then the hard /* If there is no stack frame then the hard
frame pointer and the arg pointer coincide. */ frame pointer and the arg pointer coincide. */
if (stack_frame == 0 && call_saved_registers != 0) if (offsets->frame == offsets->saved_regs)
return 0; return 0;
/* FIXME: Not sure about this. Maybe we should always return 0 ? */ /* FIXME: Not sure about this. Maybe we should always return 0 ? */
return (frame_pointer_needed return (frame_pointer_needed
...@@ -9872,7 +10038,7 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) ...@@ -9872,7 +10038,7 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
case STACK_POINTER_REGNUM: case STACK_POINTER_REGNUM:
/* If nothing has been pushed on the stack at all /* If nothing has been pushed on the stack at all
then this will return -4. This *is* correct! */ 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: default:
abort (); abort ();
...@@ -9890,12 +10056,11 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) ...@@ -9890,12 +10056,11 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
stack frame. The soft frame pointer to the bottom entry stack frame. The soft frame pointer to the bottom entry
in the stack frame. If there is no stack frame at all, in the stack frame. If there is no stack frame at all,
then they are identical. */ then they are identical. */
if (call_saved_registers == 0 && stack_frame == 0)
return 0; return offsets->frame - offsets->soft_frame;
return - (call_saved_registers + stack_frame - 4);
case STACK_POINTER_REGNUM: case STACK_POINTER_REGNUM:
return local_vars + outgoing_args; return offsets->outgoing_args - offsets->soft_frame;
default: default:
abort (); abort ();
...@@ -9912,107 +10077,6 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) ...@@ -9912,107 +10077,6 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
} }
} }
/* 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. */ /* Generate the prologue instructions for entry into an ARM function. */
void void
...@@ -10026,7 +10090,9 @@ arm_expand_prologue (void) ...@@ -10026,7 +10090,9 @@ arm_expand_prologue (void)
unsigned long func_type; unsigned long func_type;
int fp_offset = 0; int fp_offset = 0;
int saved_pretend_args = 0; int saved_pretend_args = 0;
int saved_regs = 0;
unsigned int args_to_push; unsigned int args_to_push;
arm_stack_offsets *offsets;
func_type = arm_current_func_type (); func_type = arm_current_func_type ();
...@@ -10172,6 +10238,7 @@ arm_expand_prologue (void) ...@@ -10172,6 +10238,7 @@ arm_expand_prologue (void)
if (live_regs_mask) if (live_regs_mask)
{ {
insn = emit_multi_reg_push (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; RTX_FRAME_RELATED_P (insn) = 1;
} }
...@@ -10184,6 +10251,7 @@ arm_expand_prologue (void) ...@@ -10184,6 +10251,7 @@ arm_expand_prologue (void)
insn = emit_insn (gen_rtx_SET (VOIDmode, insn, insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
gen_rtx_REG (V2SImode, reg))); gen_rtx_REG (V2SImode, reg)));
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
saved_regs += 8;
} }
if (! IS_VOLATILE (func_type)) if (! IS_VOLATILE (func_type))
...@@ -10202,6 +10270,7 @@ arm_expand_prologue (void) ...@@ -10202,6 +10270,7 @@ arm_expand_prologue (void)
insn = emit_insn (gen_rtx_SET (VOIDmode, insn, insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
gen_rtx_REG (XFmode, reg))); gen_rtx_REG (XFmode, reg)));
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
saved_regs += 12;
} }
} }
else else
...@@ -10225,6 +10294,7 @@ arm_expand_prologue (void) ...@@ -10225,6 +10294,7 @@ arm_expand_prologue (void)
{ {
insn = emit_sfm (reg + 1, start_reg - reg); insn = emit_sfm (reg + 1, start_reg - reg);
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
saved_regs += (reg - start_reg) * 12;
} }
start_reg = reg - 1; start_reg = reg - 1;
} }
...@@ -10233,6 +10303,7 @@ arm_expand_prologue (void) ...@@ -10233,6 +10303,7 @@ arm_expand_prologue (void)
if (start_reg != reg) if (start_reg != reg)
{ {
insn = emit_sfm (reg + 1, start_reg - reg); insn = emit_sfm (reg + 1, start_reg - reg);
saved_regs += (reg - start_reg) * 12;
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
} }
} }
...@@ -10250,6 +10321,7 @@ arm_expand_prologue (void) ...@@ -10250,6 +10321,7 @@ arm_expand_prologue (void)
insn = vfp_emit_fstmx (start_reg, insn = vfp_emit_fstmx (start_reg,
(reg - start_reg) / 2); (reg - start_reg) / 2);
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
saved_regs += (start_reg - reg) * 4 + 4;
} }
start_reg = reg + 2; start_reg = reg + 2;
} }
...@@ -10259,6 +10331,7 @@ arm_expand_prologue (void) ...@@ -10259,6 +10331,7 @@ arm_expand_prologue (void)
insn = vfp_emit_fstmx (start_reg, insn = vfp_emit_fstmx (start_reg,
(reg - start_reg) / 2); (reg - start_reg) / 2);
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
saved_regs += (start_reg - reg) * 4 + 4;
} }
} }
} }
...@@ -10289,14 +10362,16 @@ arm_expand_prologue (void) ...@@ -10289,14 +10362,16 @@ arm_expand_prologue (void)
} }
} }
amount = GEN_INT (-(arm_get_frame_size () offsets = arm_get_frame_offsets ();
+ current_function_outgoing_args_size)); if (offsets->outgoing_args != offsets->saved_args + saved_regs)
if (amount != const0_rtx)
{ {
/* This add can produce multiple insns for a large constant, so we /* This add can produce multiple insns for a large constant, so we
need to get tricky. */ need to get tricky. */
rtx last = get_last_insn (); 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, insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
amount)); amount));
do do
...@@ -12618,8 +12693,8 @@ thumb_shiftable_const (unsigned HOST_WIDE_INT val) ...@@ -12618,8 +12693,8 @@ thumb_shiftable_const (unsigned HOST_WIDE_INT val)
/* Returns nonzero if the current function contains, /* Returns nonzero if the current function contains,
or might contain a far jump. */ or might contain a far jump. */
int static int
thumb_far_jump_used_p (int in_prologue) thumb_far_jump_used_p (void)
{ {
rtx insn; rtx insn;
...@@ -12637,7 +12712,7 @@ thumb_far_jump_used_p (int in_prologue) ...@@ -12637,7 +12712,7 @@ thumb_far_jump_used_p (int in_prologue)
/* If this function is not being called from the prologue/epilogue /* If this function is not being called from the prologue/epilogue
generation code then it must be being called from the generation code then it must be being called from the
INITIAL_ELIMINATION_OFFSET macro. */ INITIAL_ELIMINATION_OFFSET macro. */
if (!in_prologue) if (!(ARM_DOUBLEWORD_ALIGN || reload_completed))
{ {
/* In this case we know that we are being asked about the elimination /* 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, of the arg pointer register. If that register is not being used,
...@@ -12656,7 +12731,10 @@ thumb_far_jump_used_p (int in_prologue) ...@@ -12656,7 +12731,10 @@ thumb_far_jump_used_p (int in_prologue)
A false negative will not result in bad code being generated, but it 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 will result in a needless push and pop of the link register. We
hope that this does not occur too often. */ 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]) if (regs_ever_live [ARG_POINTER_REGNUM])
cfun->machine->arg_pointer_live = 1; cfun->machine->arg_pointer_live = 1;
else if (!cfun->machine->arg_pointer_live) else if (!cfun->machine->arg_pointer_live)
...@@ -12807,7 +12885,7 @@ thumb_unexpanded_epilogue (void) ...@@ -12807,7 +12885,7 @@ thumb_unexpanded_epilogue (void)
} }
had_to_push_lr = (live_regs_mask || !leaf_function had_to_push_lr = (live_regs_mask || !leaf_function
|| thumb_far_jump_used_p (1)); || thumb_far_jump_used_p ());
if (TARGET_BACKTRACE if (TARGET_BACKTRACE
&& ((live_regs_mask & 0xFF) == 0) && ((live_regs_mask & 0xFF) == 0)
...@@ -12913,100 +12991,66 @@ arm_init_expanders (void) ...@@ -12913,100 +12991,66 @@ arm_init_expanders (void)
init_machine_status = arm_init_machine_status; 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 /* Like arm_compute_initial_elimination offset. Simpler because
is possible to be called after start_sequence has been called, THUMB_HARD_FRAME_POINTER isn't actually the ABI specified frame pointer. */
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 HOST_WIDE_INT
works because we will only be calling RTL expanders that need thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
to know about leaf functions once reload has completed, and the {
frame size cannot be changed after that time, so we can safely arm_stack_offsets *offsets;
use the cached value. */
if (reload_completed)
return cfun->machine->frame_size;
leaf = leaf_function_p (); offsets = arm_get_frame_offsets ();
/* A leaf function does not need any stack alignment if it has nothing switch (from)
on the stack. */
if (leaf && base_size == 0)
{ {
cfun->machine->frame_size = 0; case ARG_POINTER_REGNUM:
return 0; switch (to)
} {
case STACK_POINTER_REGNUM:
/* We know that SP will be word aligned on entry, and we must return offsets->outgoing_args - offsets->saved_args;
preserve that condition at any subroutine call. But those are
the only constraints. */
/* Space for variadic functions. */ case FRAME_POINTER_REGNUM:
if (current_function_pretend_args_size) return offsets->soft_frame - offsets->saved_args;
entry_size += current_function_pretend_args_size;
/* Space for pushed lo registers. */ case THUMB_HARD_FRAME_POINTER_REGNUM:
for (regno = 0; regno <= LAST_LO_REGNUM; regno++) case ARM_HARD_FRAME_POINTER_REGNUM:
if (THUMB_REG_PUSHED_P (regno)) return offsets->saved_regs - offsets->saved_args;
count_regs++;
/* Space for backtrace structure. */ default:
if (TARGET_BACKTRACE) abort();
{
if (count_regs == 0 && regs_ever_live[LAST_ARG_REGNUM] != 0)
entry_size += 20;
else
entry_size += 16;
} }
break;
if (count_regs || !leaf || thumb_far_jump_used_p (1)) case FRAME_POINTER_REGNUM:
count_regs++; /* LR */ switch (to)
{
entry_size += count_regs * 4; case STACK_POINTER_REGNUM:
count_regs = 0; return offsets->outgoing_args - offsets->soft_frame;
/* Space for pushed hi regs. */ case THUMB_HARD_FRAME_POINTER_REGNUM:
for (regno = 8; regno < 13; regno++) case ARM_HARD_FRAME_POINTER_REGNUM:
if (THUMB_REG_PUSHED_P (regno)) return offsets->saved_regs - offsets->soft_frame;
count_regs++;
entry_size += count_regs * 4; default:
abort();
}
break;
if ((entry_size + base_size + current_function_outgoing_args_size) & 7) default:
base_size += 4;
if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
abort (); abort ();
}
cfun->machine->frame_size = base_size;
return base_size;
} }
/* Generate the rest of a function's prologue. */ /* Generate the rest of a function's prologue. */
void void
thumb_expand_prologue (void) thumb_expand_prologue (void)
{ {
rtx insn, dwarf; rtx insn, dwarf;
HOST_WIDE_INT amount = (thumb_get_frame_size () HOST_WIDE_INT amount;
+ current_function_outgoing_args_size); arm_stack_offsets *offsets;
unsigned long func_type; unsigned long func_type;
func_type = arm_current_func_type (); func_type = arm_current_func_type ();
...@@ -13021,16 +13065,18 @@ thumb_expand_prologue (void) ...@@ -13021,16 +13065,18 @@ thumb_expand_prologue (void)
return; return;
} }
offsets = arm_get_frame_offsets ();
if (frame_pointer_needed) if (frame_pointer_needed)
{ {
insn = emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx)); insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
stack_pointer_rtx));
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
} }
amount = offsets->outgoing_args - offsets->saved_regs;
if (amount) if (amount)
{ {
amount = ROUND_UP_WORD (amount);
if (amount < 512) if (amount < 512)
{ {
insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
...@@ -13129,20 +13175,21 @@ thumb_expand_prologue (void) ...@@ -13129,20 +13175,21 @@ thumb_expand_prologue (void)
void void
thumb_expand_epilogue (void) thumb_expand_epilogue (void)
{ {
HOST_WIDE_INT amount = (thumb_get_frame_size () HOST_WIDE_INT amount;
+ current_function_outgoing_args_size); arm_stack_offsets *offsets;
int regno; int regno;
/* Naked functions don't have prologues. */ /* Naked functions don't have prologues. */
if (IS_NAKED (arm_current_func_type ())) if (IS_NAKED (arm_current_func_type ()))
return; return;
offsets = arm_get_frame_offsets ();
amount = offsets->outgoing_args - offsets->saved_regs;
if (frame_pointer_needed) if (frame_pointer_needed)
emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx)); emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
else if (amount) else if (amount)
{ {
amount = ROUND_UP_WORD (amount);
if (amount < 512) if (amount < 512)
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
GEN_INT (amount))); GEN_INT (amount)));
...@@ -13257,7 +13304,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ...@@ -13257,7 +13304,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
if (THUMB_REG_PUSHED_P (regno)) if (THUMB_REG_PUSHED_P (regno))
live_regs_mask |= 1 << regno; live_regs_mask |= 1 << regno;
if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1)) if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p ())
live_regs_mask |= 1 << LR_REGNUM; live_regs_mask |= 1 << LR_REGNUM;
if (TARGET_BACKTRACE) if (TARGET_BACKTRACE)
......
...@@ -140,6 +140,8 @@ extern const char *target_fpu_name; ...@@ -140,6 +140,8 @@ extern const char *target_fpu_name;
extern const char *target_fpe_name; extern const char *target_fpe_name;
/* Whether to use floating point hardware. */ /* Whether to use floating point hardware. */
extern const char *target_float_abi_name; 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 /* Define the information needed to generate branch insns. This is
stored from the compare operation. */ stored from the compare operation. */
extern GTY(()) rtx arm_compare_op0; extern GTY(()) rtx arm_compare_op0;
...@@ -433,11 +435,8 @@ extern GTY(()) rtx aof_pic_label; ...@@ -433,11 +435,8 @@ extern GTY(()) rtx aof_pic_label;
destination is non-Thumb aware. */ destination is non-Thumb aware. */
#define THUMB_FLAG_CALLER_SUPER_INTERWORKING (1 << 20) #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. */ /* Fix invalid Cirrus instruction combinations by inserting NOPs. */
#define CIRRUS_FIX_INVALID_INSNS (1 << 22) #define CIRRUS_FIX_INVALID_INSNS (1 << 21)
#define TARGET_APCS_FRAME (target_flags & ARM_FLAG_APCS_FRAME) #define TARGET_APCS_FRAME (target_flags & ARM_FLAG_APCS_FRAME)
#define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE) #define TARGET_POKE_FUNCTION_NAME (target_flags & ARM_FLAG_POKE)
...@@ -446,7 +445,6 @@ extern GTY(()) rtx aof_pic_label; ...@@ -446,7 +445,6 @@ extern GTY(()) rtx aof_pic_label;
#define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK) #define TARGET_APCS_STACK (target_flags & ARM_FLAG_APCS_STACK)
#define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT) #define TARGET_APCS_FLOAT (target_flags & ARM_FLAG_APCS_FLOAT)
#define TARGET_APCS_REENT (target_flags & ARM_FLAG_APCS_REENT) #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_MMU_TRAPS (target_flags & ARM_FLAG_MMU_TRAPS)
#define TARGET_SOFT_FLOAT (arm_float_abi == ARM_FLOAT_ABI_SOFT) #define TARGET_SOFT_FLOAT (arm_float_abi == ARM_FLOAT_ABI_SOFT)
#define TARGET_SOFT_FLOAT_ABI (arm_float_abi != ARM_FLOAT_ABI_HARD) #define TARGET_SOFT_FLOAT_ABI (arm_float_abi != ARM_FLOAT_ABI_HARD)
...@@ -456,6 +454,7 @@ extern GTY(()) rtx aof_pic_label; ...@@ -456,6 +454,7 @@ extern GTY(()) rtx aof_pic_label;
#define TARGET_VFP (arm_fp_model == ARM_FP_MODEL_VFP) #define TARGET_VFP (arm_fp_model == ARM_FP_MODEL_VFP)
#define TARGET_IWMMXT (arm_arch_iwmmxt) #define TARGET_IWMMXT (arm_arch_iwmmxt)
#define TARGET_REALLY_IWMMXT (TARGET_IWMMXT && TARGET_ARM) #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_BIG_END (target_flags & ARM_FLAG_BIG_END)
#define TARGET_INTERWORK (target_flags & ARM_FLAG_INTERWORK) #define TARGET_INTERWORK (target_flags & ARM_FLAG_INTERWORK)
#define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS) #define TARGET_LITTLE_WORDS (target_flags & ARM_FLAG_LITTLE_WORDS)
...@@ -574,7 +573,8 @@ extern GTY(()) rtx aof_pic_label; ...@@ -574,7 +573,8 @@ extern GTY(()) rtx aof_pic_label;
{"structure-size-boundary=", & structure_size_string, \ {"structure-size-boundary=", & structure_size_string, \
N_("Specify the minimum bit alignment of structures"), 0}, \ N_("Specify the minimum bit alignment of structures"), 0}, \
{"pic-register=", & arm_pic_register_string, \ {"pic-register=", & arm_pic_register_string, \
N_("Specify the register to be used for PIC addressing"), 0} \ 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: /* Support for a compile-time default CPU, et cetera. The rules are:
...@@ -585,14 +585,16 @@ extern GTY(()) rtx aof_pic_label; ...@@ -585,14 +585,16 @@ extern GTY(()) rtx aof_pic_label;
by -march). by -march).
--with-float is ignored if -mhard-float, -msoft-float or -mfloat-abi are --with-float is ignored if -mhard-float, -msoft-float or -mfloat-abi are
specified. specified.
--with-fpu is ignored if -mfpu is specified. */ --with-fpu is ignored if -mfpu is specified.
--with-abi is ignored is -mabi is specified. */
#define OPTION_DEFAULT_SPECS \ #define OPTION_DEFAULT_SPECS \
{"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \ {"arch", "%{!march=*:%{!mcpu=*:-march=%(VALUE)}}" }, \
{"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \ {"cpu", "%{!march=*:%{!mcpu=*:-mcpu=%(VALUE)}}" }, \
{"tune", "%{!mcpu=*:%{!mtune=*:-mtune=%(VALUE)}}" }, \ {"tune", "%{!mcpu=*:%{!mtune=*:-mtune=%(VALUE)}}" }, \
{"float", \ {"float", \
"%{!msoft-float:%{!mhard-float:%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}}}" }, \ "%{!msoft-float:%{!mhard-float:%{!mfloat-abi=*:-mfloat-abi=%(VALUE)}}}" }, \
{"fpu", "%{!mfpu=*:-mfpu=%(VALUE)}"}, {"fpu", "%{!mfpu=*:-mfpu=%(VALUE)}"}, \
{"abi", "%{!mabi=*:-mabi=%(VALUE)}"},
struct arm_cpu_select struct arm_cpu_select
{ {
...@@ -682,6 +684,21 @@ extern enum float_abi_type arm_float_abi; ...@@ -682,6 +684,21 @@ extern enum float_abi_type arm_float_abi;
#define FPUTYPE_DEFAULT FPUTYPE_MAVERICK #define FPUTYPE_DEFAULT FPUTYPE_MAVERICK
#endif #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. */ /* Nonzero if this chip supports the ARM Architecture 3M extensions. */
extern int arm_arch3m; extern int arm_arch3m;
...@@ -811,13 +828,17 @@ extern int arm_is_6_or_7; ...@@ -811,13 +828,17 @@ extern int arm_is_6_or_7;
#define UNITS_PER_WORD 4 #define UNITS_PER_WORD 4
#define PARM_BOUNDARY 32 /* 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 IWMMXT_ALIGNMENT 64 #define PARM_BOUNDARY 32
#define STACK_BOUNDARY 32 #define STACK_BOUNDARY (ARM_DOUBLEWORD_ALIGN ? DOUBLEWORD_ALIGNMENT : 32)
#define PREFERRED_STACK_BOUNDARY (TARGET_ATPCS ? 64 : 32) #define PREFERRED_STACK_BOUNDARY \
(arm_abi == ARM_ABI_ATPCS ? 64 : STACK_BOUNDARY)
#define FUNCTION_BOUNDARY 32 #define FUNCTION_BOUNDARY 32
...@@ -828,53 +849,20 @@ extern int arm_is_6_or_7; ...@@ -828,53 +849,20 @@ extern int arm_is_6_or_7;
#define EMPTY_FIELD_BOUNDARY 32 #define EMPTY_FIELD_BOUNDARY 32
#define BIGGEST_ALIGNMENT (TARGET_REALLY_IWMMXT ? 64 : 32) #define BIGGEST_ALIGNMENT (ARM_DOUBLEWORD_ALIGN ? DOUBLEWORD_ALIGNMENT : 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 /* XXX Blah -- this macro is used directly by libobjc. Since it
supports no vector modes, cut out the complexity and fall back supports no vector modes, cut out the complexity and fall back
on BIGGEST_FIELD_ALIGNMENT. */ on BIGGEST_FIELD_ALIGNMENT. */
#ifdef IN_TARGET_LIBS #ifdef IN_TARGET_LIBS
#define BIGGEST_FIELD_ALIGNMENT 64 #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 #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. */ /* 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_FACTOR (TARGET_THUMB || ! arm_tune_xscale ? 1 : 2)
#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ #define CONSTANT_ALIGNMENT(EXP, ALIGN) \
((TARGET_REALLY_IWMMXT && TREE_CODE (EXP) == VECTOR_TYPE) ? IWMMXT_ALIGNMENT : \ ((TREE_CODE (EXP) == STRING_CST \
(TREE_CODE (EXP) == STRING_CST \
&& (ALIGN) < BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR) \ && (ALIGN) < BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR) \
? BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR : (ALIGN)) ? BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR : (ALIGN))
...@@ -883,7 +871,8 @@ extern int arm_is_6_or_7; ...@@ -883,7 +871,8 @@ extern int arm_is_6_or_7;
compact structures. The command line option -mstructure_size_boundary=<n> compact structures. The command line option -mstructure_size_boundary=<n>
can be used to change this value. For compatibility with the ARM SDK 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 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 #define STRUCTURE_SIZE_BOUNDARY arm_structure_size_boundary
extern int arm_structure_size_boundary; extern int arm_structure_size_boundary;
...@@ -1728,7 +1717,7 @@ enum reg_class ...@@ -1728,7 +1717,7 @@ enum reg_class
: TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK \ : TARGET_ARM && TARGET_HARD_FLOAT && TARGET_MAVERICK \
&& GET_MODE_CLASS (MODE) == MODE_FLOAT \ && GET_MODE_CLASS (MODE) == MODE_FLOAT \
? gen_rtx_REG (MODE, FIRST_CIRRUS_FP_REGNUM) \ ? gen_rtx_REG (MODE, FIRST_CIRRUS_FP_REGNUM) \
: TARGET_REALLY_IWMMXT && VECTOR_MODE_SUPPORTED_P (MODE) \ : TARGET_IWMMXT_ABI && VECTOR_MODE_SUPPORTED_P (MODE) \
? gen_rtx_REG (MODE, FIRST_IWMMXT_REGNUM) \ ? gen_rtx_REG (MODE, FIRST_IWMMXT_REGNUM) \
: gen_rtx_REG (MODE, ARG_REGISTER (1))) : gen_rtx_REG (MODE, ARG_REGISTER (1)))
...@@ -1746,7 +1735,7 @@ enum reg_class ...@@ -1746,7 +1735,7 @@ enum reg_class
((REGNO) == ARG_REGISTER (1) \ ((REGNO) == ARG_REGISTER (1) \
|| (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) \ || (TARGET_ARM && ((REGNO) == FIRST_CIRRUS_FP_REGNUM) \
&& TARGET_HARD_FLOAT && TARGET_MAVERICK) \ && TARGET_HARD_FLOAT && TARGET_MAVERICK) \
|| (TARGET_ARM && ((REGNO) == FIRST_IWMMXT_REGNUM) && TARGET_IWMMXT) \ || ((REGNO) == FIRST_IWMMXT_REGNUM && TARGET_IWMMXT_ABI) \
|| (TARGET_ARM && ((REGNO) == FIRST_FPA_REGNUM) \ || (TARGET_ARM && ((REGNO) == FIRST_FPA_REGNUM) \
&& TARGET_HARD_FLOAT && TARGET_FPA)) && TARGET_HARD_FLOAT && TARGET_FPA))
...@@ -1800,6 +1789,22 @@ enum reg_class ...@@ -1800,6 +1789,22 @@ enum reg_class
#define IS_NAKED(t) (t & ARM_FT_NAKED) #define IS_NAKED(t) (t & ARM_FT_NAKED)
#define IS_NESTED(t) (t & ARM_FT_NESTED) #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. /* A C structure for machine-specific, per-function data.
This is added to the cfun structure. */ This is added to the cfun structure. */
typedef struct machine_function GTY(()) typedef struct machine_function GTY(())
...@@ -1813,7 +1818,7 @@ typedef struct machine_function GTY(()) ...@@ -1813,7 +1818,7 @@ typedef struct machine_function GTY(())
/* Records if the save of LR has been eliminated. */ /* Records if the save of LR has been eliminated. */
int lr_save_eliminated; int lr_save_eliminated;
/* The size of the stack frame. Only valid after reload. */ /* 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. */ /* Records the type of the current function. */
unsigned long func_type; unsigned long func_type;
/* Record if the function has a variable argument list. */ /* Record if the function has a variable argument list. */
...@@ -1837,6 +1842,7 @@ typedef struct ...@@ -1837,6 +1842,7 @@ typedef struct
int nargs; int nargs;
/* One of CALL_NORMAL, CALL_LONG or CALL_SHORT. */ /* One of CALL_NORMAL, CALL_LONG or CALL_SHORT. */
int call_cookie; int call_cookie;
int can_split;
} CUMULATIVE_ARGS; } CUMULATIVE_ARGS;
/* Define where to put the arguments to a function. /* Define where to put the arguments to a function.
...@@ -1866,7 +1872,8 @@ typedef struct ...@@ -1866,7 +1872,8 @@ typedef struct
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ #define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
(VECTOR_MODE_SUPPORTED_P (MODE) ? 0 : \ (VECTOR_MODE_SUPPORTED_P (MODE) ? 0 : \
NUM_ARG_REGS > (CUM).nregs \ NUM_ARG_REGS > (CUM).nregs \
&& (NUM_ARG_REGS < ((CUM).nregs + ARM_NUM_REGS2 (MODE, TYPE))) \ && (NUM_ARG_REGS < ((CUM).nregs + ARM_NUM_REGS2 (MODE, TYPE)) \
&& (CUM).can_split) \
? NUM_ARG_REGS - (CUM).nregs : 0) ? NUM_ARG_REGS - (CUM).nregs : 0)
/* A C expression that indicates when an argument must be passed by /* A C expression that indicates when an argument must be passed by
...@@ -1889,10 +1896,8 @@ typedef struct ...@@ -1889,10 +1896,8 @@ typedef struct
(TYPE is null for libcalls where that information may not be available.) */ (TYPE is null for libcalls where that information may not be available.) */
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ #define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
(CUM).nargs += 1; \ (CUM).nargs += 1; \
if (VECTOR_MODE_SUPPORTED_P (MODE)) \ if (VECTOR_MODE_SUPPORTED_P (MODE) \
if ((CUM).named_count <= (CUM).nargs) \ && (CUM).named_count > (CUM).nargs) \
(CUM).nregs += 2; \
else \
(CUM).iwmmxt_nregs += 1; \ (CUM).iwmmxt_nregs += 1; \
else \ else \
(CUM).nregs += ARM_NUM_REGS2 (MODE, TYPE) (CUM).nregs += ARM_NUM_REGS2 (MODE, TYPE)
...@@ -1901,14 +1906,16 @@ typedef struct ...@@ -1901,14 +1906,16 @@ typedef struct
argument with the specified mode and type. If it is not defined, argument with the specified mode and type. If it is not defined,
`PARM_BOUNDARY' is used for all arguments. */ `PARM_BOUNDARY' is used for all arguments. */
#define FUNCTION_ARG_BOUNDARY(MODE,TYPE) \ #define FUNCTION_ARG_BOUNDARY(MODE,TYPE) \
(TARGET_REALLY_IWMMXT && (VALID_IWMMXT_REG_MODE (MODE) || ((MODE) == DFmode)) \ ((ARM_DOUBLEWORD_ALIGN && arm_needs_doubleword_align (MODE, TYPE)) \
? IWMMXT_ALIGNMENT : PARM_BOUNDARY) ? DOUBLEWORD_ALIGNMENT \
: PARM_BOUNDARY )
/* 1 if N is a possible register number for function argument passing. /* 1 if N is a possible register number for function argument passing.
On the ARM, r0-r3 are used to pass args. */ On the ARM, r0-r3 are used to pass args. */
#define FUNCTION_ARG_REGNO_P(REGNO) \ #define FUNCTION_ARG_REGNO_P(REGNO) \
(IN_RANGE ((REGNO), 0, 3) \ (IN_RANGE ((REGNO), 0, 3) \
|| (TARGET_REALLY_IWMMXT && IN_RANGE ((REGNO), FIRST_IWMMXT_REGNUM, FIRST_IWMMXT_REGNUM + 9))) || (TARGET_IWMMXT_ABI \
&& IN_RANGE ((REGNO), FIRST_IWMMXT_REGNUM, FIRST_IWMMXT_REGNUM + 9)))
/* Implement `va_arg'. */ /* Implement `va_arg'. */
#define EXPAND_BUILTIN_VA_ARG(valist, type) \ #define EXPAND_BUILTIN_VA_ARG(valist, type) \
...@@ -2030,52 +2037,11 @@ typedef struct ...@@ -2030,52 +2037,11 @@ typedef struct
/* Define the offset between two registers, one to be eliminated, and the /* Define the offset between two registers, one to be eliminated, and the
other its replacement, at the start of a routine. */ 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) \ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
if (TARGET_ARM) \ if (TARGET_ARM) \
ARM_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET); \ (OFFSET) = arm_compute_initial_elimination_offset (FROM, TO); \
else \ else \
THUMB_INITIAL_ELIMINATION_OFFSET (FROM, TO, OFFSET) (OFFSET) = thumb_compute_initial_elimination_offset (FROM, TO)
/* Special case handling of the location of arguments passed on the stack. */ /* 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) #define DEBUGGER_ARG_OFFSET(value, addr) value ? value : arm_debugger_arg_offset (value, addr)
......
...@@ -10102,7 +10102,7 @@ ...@@ -10102,7 +10102,7 @@
(define_insn "align_8" (define_insn "align_8"
[(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)] [(unspec_volatile [(const_int 0)] VUNSPEC_ALIGN8)]
"TARGET_REALLY_IWMMXT" "TARGET_EITHER"
"* "*
assemble_align (64); assemble_align (64);
return \"\"; return \"\";
......
...@@ -38,10 +38,12 @@ ...@@ -38,10 +38,12 @@
(ARM_FLAG_APCS_32 \ (ARM_FLAG_APCS_32 \
| ARM_FLAG_SOFT_FLOAT \ | ARM_FLAG_SOFT_FLOAT \
| ARM_FLAG_APCS_FRAME \ | ARM_FLAG_APCS_FRAME \
| ARM_FLAG_ATPCS \
| ARM_FLAG_MMU_TRAPS \ | ARM_FLAG_MMU_TRAPS \
| TARGET_ENDIAN_DEFAULT) | TARGET_ENDIAN_DEFAULT)
#undef ARM_DEFAULT_ABI
#define ARM_DEFAULT_ABI ARM_ABI_ATPCS
#define TARGET_OS_CPP_BUILTINS() \ #define TARGET_OS_CPP_BUILTINS() \
do \ do \
{ \ { \
......
...@@ -368,6 +368,7 @@ in the following sections. ...@@ -368,6 +368,7 @@ in the following sections.
@emph{ARM Options} @emph{ARM Options}
@gccoptlist{-mapcs-frame -mno-apcs-frame @gol @gccoptlist{-mapcs-frame -mno-apcs-frame @gol
-mabi=@var{name} @gol
-mapcs-26 -mapcs-32 @gol -mapcs-26 -mapcs-32 @gol
-mapcs-stack-check -mno-apcs-stack-check @gol -mapcs-stack-check -mno-apcs-stack-check @gol
-mapcs-float -mno-apcs-float @gol -mapcs-float -mno-apcs-float @gol
...@@ -6413,6 +6414,11 @@ These @samp{-m} options are defined for Advanced RISC Machines (ARM) ...@@ -6413,6 +6414,11 @@ These @samp{-m} options are defined for Advanced RISC Machines (ARM)
architectures: architectures:
@table @gcctabopt @table @gcctabopt
@item -mabi=@var{name}
@opindex mabi
Generate code for the specified ABI. Permissible values are: @samp{apcs-gnu},
@samp{atpcs}, @samp{aapcs} and @samp{iwmmxt}.
@item -mapcs-frame @item -mapcs-frame
@opindex mapcs-frame @opindex mapcs-frame
Generate a stack frame that is compliant with the ARM Procedure Call Generate a stack frame that is compliant with the ARM Procedure Call
...@@ -6635,14 +6641,16 @@ floating point values. ...@@ -6635,14 +6641,16 @@ floating point values.
@item -mstructure-size-boundary=@var{n} @item -mstructure-size-boundary=@var{n}
@opindex mstructure-size-boundary @opindex mstructure-size-boundary
The size of all structures and unions will be rounded up to a multiple 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 of the number of bits set by this option. Permissible values are 8, 32
32. The default value varies for different toolchains. For the COFF and 64. The default value varies for different toolchains. For the COFF
targeted toolchain the default value is 8. Specifying the larger number targeted toolchain the default value is 8. A value of 64 is only allowed
can produce faster, more efficient code, but can also increase the size if the underlying ABI supports it.
of the program. The two values are potentially incompatible. Code
compiled with one value cannot necessarily expect to work with code or Specifying the larger number can produce faster, more efficient code, but
libraries compiled with the other value, if they exchange information can also increase the size of the program. Different values are potentially
using structures or unions. 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 @item -mabort-on-noreturn
@opindex mabort-on-noreturn @opindex mabort-on-noreturn
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment