Commit 35596784 by Andrew Jenner Committed by Andrew Jenner

arm.c (arm_compute_static_chain_stack_bytes): New function.

	* config/arm/arm.c (arm_compute_static_chain_stack_bytes): New
	function.
	(arm_compute_initial_elimination_offset): Use it.
	(arm_compute_save_reg_mask): Include static chain save slot when
	calculating alignment.
	(arm_get_frame_offsets): Ditto.
	(thumb1_compute_save_reg_mask): Ensure we have a low register saved
	that we can use to decrement the stack when the stack decrement
	could be too big for an immediate value in a single insn.
	(thumb1_expand_prologue): Avoid using r12 for stack decrement.

From-SVN: r138327
parent 5cc6fa41
2008-07-30 Andrew Jenner <andrew@codesourcery.com>
* config/arm/arm.c (arm_compute_static_chain_stack_bytes): New
function.
(arm_compute_initial_elimination_offset): Use it.
(arm_compute_save_reg_mask): Include static chain save slot when
calculating alignment.
(arm_get_frame_offsets): Ditto.
(thumb1_compute_save_reg_mask): Ensure we have a low register saved
that we can use to decrement the stack when the stack decrement
could be too big for an immediate value in a single insn.
(thumb1_expand_prologue): Avoid using r12 for stack decrement.
2008-07-30 Richard Guenther <rguenther@suse.de> 2008-07-30 Richard Guenther <rguenther@suse.de>
PR tree-optimization/36967 PR tree-optimization/36967
......
...@@ -62,6 +62,7 @@ const struct attribute_spec arm_attribute_table[]; ...@@ -62,6 +62,7 @@ const struct attribute_spec arm_attribute_table[];
void (*arm_lang_output_object_attributes_hook)(void); void (*arm_lang_output_object_attributes_hook)(void);
/* Forward function declarations. */ /* Forward function declarations. */
static int arm_compute_static_chain_stack_bytes (void);
static arm_stack_offsets *arm_get_frame_offsets (void); 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, rtx, static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx,
...@@ -10792,6 +10793,24 @@ arm_compute_save_reg0_reg12_mask (void) ...@@ -10792,6 +10793,24 @@ arm_compute_save_reg0_reg12_mask (void)
} }
/* Compute the number of bytes used to store the static chain register on the
stack, above the stack frame. We need to know this accurately to get the
alignment of the rest of the stack frame correct. */
static int arm_compute_static_chain_stack_bytes (void)
{
unsigned long func_type = arm_current_func_type ();
int static_chain_stack_bytes = 0;
if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM &&
IS_NESTED (func_type) &&
df_regs_ever_live_p (3) && crtl->args.pretend_args_size == 0)
static_chain_stack_bytes = 4;
return static_chain_stack_bytes;
}
/* Compute a bit mask of which registers need to be /* Compute a bit mask of which registers need to be
saved on the stack for the current function. saved on the stack for the current function.
This is used by arm_get_frame_offsets, which may add extra registers. */ This is used by arm_get_frame_offsets, which may add extra registers. */
...@@ -10844,7 +10863,9 @@ arm_compute_save_reg_mask (void) ...@@ -10844,7 +10863,9 @@ arm_compute_save_reg_mask (void)
if (TARGET_REALLY_IWMMXT if (TARGET_REALLY_IWMMXT
&& ((bit_count (save_reg_mask) && ((bit_count (save_reg_mask)
+ ARM_NUM_INTS (crtl->args.pretend_args_size)) % 2) != 0) + ARM_NUM_INTS (crtl->args.pretend_args_size +
arm_compute_static_chain_stack_bytes())
) % 2) != 0)
{ {
/* The total number of registers that are going to be pushed /* The total number of registers that are going to be pushed
onto the stack is odd. We need to ensure that the stack onto the stack is odd. We need to ensure that the stack
...@@ -10929,6 +10950,26 @@ thumb1_compute_save_reg_mask (void) ...@@ -10929,6 +10950,26 @@ thumb1_compute_save_reg_mask (void)
mask |= 1 << reg; mask |= 1 << reg;
} }
/* The 504 below is 8 bytes less than 512 because there are two possible
alignment words. We can't tell here if they will be present or not so we
have to play it safe and assume that they are. */
if ((CALLER_INTERWORKING_SLOT_SIZE +
ROUND_UP_WORD (get_frame_size ()) +
crtl->outgoing_args_size) >= 504)
{
/* This is the same as the code in thumb1_expand_prologue() which
determines which register to use for stack decrement. */
for (reg = LAST_ARG_REGNUM + 1; reg <= LAST_LO_REGNUM; reg++)
if (mask & (1 << reg))
break;
if (reg > LAST_LO_REGNUM)
{
/* Make sure we have a register available for stack decrement. */
mask |= 1 << LAST_LO_REGNUM;
}
}
return mask; return mask;
} }
...@@ -12064,7 +12105,8 @@ arm_get_frame_offsets (void) ...@@ -12064,7 +12105,8 @@ arm_get_frame_offsets (void)
offsets->saved_args = crtl->args.pretend_args_size; offsets->saved_args = crtl->args.pretend_args_size;
/* In Thumb mode this is incorrect, but never used. */ /* In Thumb mode this is incorrect, but never used. */
offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0); offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0) +
arm_compute_static_chain_stack_bytes();
if (TARGET_32BIT) if (TARGET_32BIT)
{ {
...@@ -12111,7 +12153,8 @@ arm_get_frame_offsets (void) ...@@ -12111,7 +12153,8 @@ arm_get_frame_offsets (void)
} }
/* Saved registers include the stack frame. */ /* Saved registers include the stack frame. */
offsets->saved_regs = offsets->saved_args + saved; offsets->saved_regs = offsets->saved_args + saved +
arm_compute_static_chain_stack_bytes();
offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE; offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
/* A leaf function does not need any stack alignment if it has nothing /* A leaf function does not need any stack alignment if it has nothing
on the stack. */ on the stack. */
...@@ -12203,14 +12246,9 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to) ...@@ -12203,14 +12246,9 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
return offsets->soft_frame - offsets->saved_args; return offsets->soft_frame - offsets->saved_args;
case ARM_HARD_FRAME_POINTER_REGNUM: case ARM_HARD_FRAME_POINTER_REGNUM:
/* If there is no stack frame then the hard /* This is only non-zero in the case where the static chain register
frame pointer and the arg pointer coincide. */ is stored above the frame. */
if (offsets->frame == offsets->saved_regs) return offsets->frame - offsets->saved_args - 4;
return 0;
/* FIXME: Not sure about this. Maybe we should always return 0 ? */
return (frame_pointer_needed
&& cfun->static_chain_decl != NULL
&& ! cfun->machine->uses_anonymous_args) ? 4 : 0;
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
...@@ -12498,6 +12536,9 @@ arm_expand_prologue (void) ...@@ -12498,6 +12536,9 @@ arm_expand_prologue (void)
insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx); insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
else if (args_to_push == 0) else if (args_to_push == 0)
{ {
gcc_assert(arm_compute_static_chain_stack_bytes() == 4);
saved_regs += 4;
rtx dwarf; rtx dwarf;
insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx); insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
...@@ -17008,62 +17049,25 @@ thumb1_expand_prologue (void) ...@@ -17008,62 +17049,25 @@ thumb1_expand_prologue (void)
been pushed at the start of the prologue and so we can corrupt been pushed at the start of the prologue and so we can corrupt
it now. */ it now. */
for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++) for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
if (live_regs_mask & (1 << regno) if (live_regs_mask & (1 << regno))
&& !(frame_pointer_needed
&& (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
break; break;
if (regno > LAST_LO_REGNUM) /* Very unlikely. */ gcc_assert(regno <= LAST_LO_REGNUM);
{
rtx spare = gen_rtx_REG (SImode, IP_REGNUM);
/* Choose an arbitrary, non-argument low register. */
reg = gen_rtx_REG (SImode, LAST_LO_REGNUM);
/* Save it by copying it into a high, scratch register. */
emit_insn (gen_movsi (spare, reg));
/* Add a USE to stop propagate_one_insn() from barfing. */
emit_insn (gen_prologue_use (spare));
/* Decrement the stack. */ reg = gen_rtx_REG (SImode, regno);
emit_insn (gen_movsi (reg, GEN_INT (- amount)));
insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx, reg));
RTX_FRAME_RELATED_P (insn) = 1;
dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
plus_constant (stack_pointer_rtx,
-amount));
RTX_FRAME_RELATED_P (dwarf) = 1;
REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
REG_NOTES (insn));
/* Restore the low register's original value. */
emit_insn (gen_movsi (reg, spare));
/* Emit a USE of the restored scratch register, so that flow
analysis will not consider the restore redundant. The
register won't be used again in this function and isn't
restored by the epilogue. */
emit_insn (gen_prologue_use (reg));
}
else
{
reg = gen_rtx_REG (SImode, regno);
emit_insn (gen_movsi (reg, GEN_INT (- amount))); emit_insn (gen_movsi (reg, GEN_INT (- amount)));
insn = emit_insn (gen_addsi3 (stack_pointer_rtx, insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx, reg)); stack_pointer_rtx, reg));
RTX_FRAME_RELATED_P (insn) = 1; RTX_FRAME_RELATED_P (insn) = 1;
dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx, dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
plus_constant (stack_pointer_rtx, plus_constant (stack_pointer_rtx,
-amount)); -amount));
RTX_FRAME_RELATED_P (dwarf) = 1; RTX_FRAME_RELATED_P (dwarf) = 1;
REG_NOTES (insn) REG_NOTES (insn)
= gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
REG_NOTES (insn)); REG_NOTES (insn));
}
} }
} }
......
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