[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [avr-gcc-list] the framepointer
From: |
Andy H |
Subject: |
Re: [avr-gcc-list] the framepointer |
Date: |
Sat, 19 Apr 2008 08:27:55 -0400 |
User-agent: |
Thunderbird 2.0.0.12 (Windows/20080213) |
Hi Ruud
the source you refer to has assembler prolog/epilog. ie its old. The
latest is written in RTL and does much better job of minimizing the
code. (I have attached below)
The frame pointer should only be used if it is needed. It will be
omitted otherwise with fomit_frame_pointer.
If stack space is needed for variables, then it will not be omitted.
R28/29 is used as frame_pointer. It can also be used for other purposes.
This register must be preserved by function. If function does not need
frame but calls another function, R28/29 will be saved.
In most causes you want to use -fomit_frame_pointer.
There are still situation we need to fix. One is that gcc will not
readily use R28/R29 - if it is not needed by frame. Also, it does not
factor the "free usage" of R28/R29 when it tries to figure out if frame
pointer is needed or not (obviously R28/29 can be used to hold 16 bit value)
best regards
Andy
/* Output function prologue. */
void
expand_prologue (void)
{
int live_seq;
HARD_REG_SET set;
int minimize;
HOST_WIDE_INT size = get_frame_size();
/* Define templates for push instructions. */
rtx pushbyte = gen_rtx_MEM (QImode,
gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
rtx pushword = gen_rtx_MEM (HImode,
gen_rtx_POST_DEC (HImode, stack_pointer_rtx));
rtx insn;
last_insn_address = 0;
/* Init cfun->machine. */
cfun->machine->is_naked = avr_naked_function_p (current_function_decl);
cfun->machine->is_interrupt = interrupt_function_p
(current_function_decl);
cfun->machine->is_signal = signal_function_p (current_function_decl);
cfun->machine->is_OS_task = avr_OS_task_function_p
(current_function_decl);
/* Prologue: naked. */
if (cfun->machine->is_naked)
{
return;
}
avr_regs_to_save (&set);
live_seq = sequent_regs_live ();
minimize = (TARGET_CALL_PROLOGUES
&& !cfun->machine->is_interrupt
&& !cfun->machine->is_signal
&& !cfun->machine->is_OS_task
&& live_seq);
if (cfun->machine->is_interrupt || cfun->machine->is_signal)
{
if (cfun->machine->is_interrupt)
{
/* Enable interrupts. */
insn = emit_insn (gen_enable_interrupt ());
RTX_FRAME_RELATED_P (insn) = 1;
}
/* Push zero reg. */
insn = emit_move_insn (pushbyte, zero_reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
/* Push tmp reg. */
insn = emit_move_insn (pushbyte, tmp_reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
/* Push SREG. */
insn = emit_move_insn (tmp_reg_rtx,
gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn (pushbyte, tmp_reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
/* Push RAMPZ. */
if(AVR_HAVE_RAMPZ
&& (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set,
REG_Z + 1)))
{
insn = emit_move_insn (tmp_reg_rtx,
gen_rtx_MEM (QImode, GEN_INT
(RAMPZ_ADDR)));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn (pushbyte, tmp_reg_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
/* Clear zero reg. */
insn = emit_move_insn (zero_reg_rtx, const0_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
/* Prevent any attempt to delete the setting of ZERO_REG! */
emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx));
}
if (minimize && (frame_pointer_needed || live_seq > 6))
{
insn = emit_move_insn (gen_rtx_REG (HImode, REG_X),
gen_int_mode (size, HImode));
RTX_FRAME_RELATED_P (insn) = 1;
insn =
emit_insn (gen_call_prologue_saves (gen_int_mode (live_seq, HImode),
gen_int_mode (size + live_seq, HImode)));
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
int reg;
for (reg = 0; reg < 32; ++reg)
{
if (TEST_HARD_REG_BIT (set, reg))
{
/* Emit push of register to save. */
insn=emit_move_insn (pushbyte, gen_rtx_REG (QImode, reg));
RTX_FRAME_RELATED_P (insn) = 1;
}
}
if (frame_pointer_needed)
{
if(!cfun->machine->is_OS_task)
{
/* Push frame pointer. */
insn = emit_move_insn (pushword, frame_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
if (!size)
{
insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
/* Creating a frame can be done by direct manipulation of the
stack or via the frame pointer. These two methods are:
fp=sp
fp-=size
sp=fp
OR
sp-=size
fp=sp
the optimum method depends on function type, stack and
frame size.
To avoid a complex logic, both methods are tested and shortest
is selected. */
rtx myfp;
/* First method. */
if (TARGET_TINY_STACK)
{
if (size < -63 || size > 63)
warning (0, "large frame pointer change (%d) with
-mtiny-stack", size);
/* The high byte (r29) doesn't change - prefer 'subi'
(1 cycle)
over 'sbiw' (2 cycles, same size). */
myfp = gen_rtx_REG (QImode, REGNO (frame_pointer_rtx));
}
else
{
/* Normal sized addition. */
myfp = frame_pointer_rtx;
}
/* Calculate length. */
int method1_length;
method1_length =
get_attr_length (gen_move_insn (frame_pointer_rtx,
stack_pointer_rtx));
method1_length +=
get_attr_length (gen_move_insn (myfp,
gen_rtx_PLUS
(GET_MODE(myfp), myfp,
gen_int_mode (-size,
GET_MODE(myfp)))));
method1_length +=
get_attr_length (gen_move_insn (stack_pointer_rtx,
frame_pointer_rtx));
/* Method 2-Adjust Stack pointer. */
int sp_plus_length = 0;
if (size <= 6)
{
sp_plus_length =
get_attr_length (gen_move_insn (stack_pointer_rtx,
gen_rtx_PLUS
(HImode, stack_pointer_rtx,
gen_int_mode (-size,
HImode))));
sp_plus_length +=
get_attr_length (gen_move_insn (frame_pointer_rtx,
stack_pointer_rtx));
}
/* Use shortest method. */
if (size <= 6 && (sp_plus_length < method1_length))
{
insn = emit_move_insn (stack_pointer_rtx,
gen_rtx_PLUS (HImode,
stack_pointer_rtx,
gen_int_mode
(-size, HImode)));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
insn = emit_move_insn (frame_pointer_rtx,
stack_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn (myfp,
gen_rtx_PLUS (GET_MODE(myfp),
myfp,
gen_int_mode
(-size, GET_MODE(myfp))));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn ( stack_pointer_rtx,
frame_pointer_rtx);
RTX_FRAME_RELATED_P (insn) = 1;
}
}
}
}
}