flow.c: Update comment.
* flow.c: Update comment. (notice_stack_pointer_modification): New static function. (record_volatile_insns): Use it. (mark_regs_live_at_end): Mark the stack pointer as alive at the end of the function if current_function_sp_is_unchanging is set. (life_analysis_1): Set current_function_sp_is_unchanging. * function.c: Define it. (init_function_start): Initialize it. * output.h: Declare it. * reorg.c (fill_simple_delay_slots, dbr_schedule): Mark the stack pointer as alive at the end of the function if current_function_sp_is_unchanging is set. * i386.c (ix86_epilogue): Optimize the restoring of the stack pointer. From-SVN: r23009
This commit is contained in:
parent
3babe36c37
commit
fdb8a883a4
@ -1,3 +1,21 @@
|
||||
Sun Oct 11 16:49:15 EDT 1998 John Wehle (john@feith.com)
|
||||
|
||||
* flow.c: Update comment.
|
||||
(notice_stack_pointer_modification): New static function.
|
||||
(record_volatile_insns): Use it.
|
||||
(mark_regs_live_at_end): Mark the stack pointer as alive
|
||||
at the end of the function if current_function_sp_is_unchanging
|
||||
is set.
|
||||
(life_analysis_1): Set current_function_sp_is_unchanging.
|
||||
* function.c: Define it.
|
||||
(init_function_start): Initialize it.
|
||||
* output.h: Declare it.
|
||||
* reorg.c (fill_simple_delay_slots, dbr_schedule): Mark
|
||||
the stack pointer as alive at the end of the function if
|
||||
current_function_sp_is_unchanging is set.
|
||||
* i386.c (ix86_epilogue): Optimize the restoring
|
||||
of the stack pointer.
|
||||
|
||||
Mon Oct 12 02:03:25 1998 Jason Merrill <jason@yorick.cygnus.com>
|
||||
|
||||
* i386/t-cygwin32 (TARGET_LIBGCC2_CFLAGS): Define.
|
||||
|
@ -2294,6 +2294,7 @@ ix86_epilogue (do_rtl)
|
||||
rtx xops[3];
|
||||
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|
||||
|| current_function_uses_const_pool);
|
||||
int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
|
||||
long tsize = get_frame_size ();
|
||||
|
||||
/* Compute the number of registers to pop */
|
||||
@ -2307,12 +2308,7 @@ ix86_epilogue (do_rtl)
|
||||
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
|
||||
nregs++;
|
||||
|
||||
/* sp is often unreliable so we must go off the frame pointer.
|
||||
|
||||
In reality, we may not care if sp is unreliable, because we can restore
|
||||
the register relative to the frame pointer. In theory, since each move
|
||||
is the same speed as a pop, and we don't need the leal, this is faster.
|
||||
For now restore multiple registers the old way. */
|
||||
/* sp is often unreliable so we may have to go off the frame pointer. */
|
||||
|
||||
offset = - tsize - (nregs * UNITS_PER_WORD);
|
||||
|
||||
@ -2329,9 +2325,14 @@ ix86_epilogue (do_rtl)
|
||||
if (flag_pic || profile_flag || profile_block_flag)
|
||||
emit_insn (gen_blockage ());
|
||||
|
||||
if (nregs > 1 || ! frame_pointer_needed)
|
||||
/* If we're only restoring one register and sp is not valid then
|
||||
using a move instruction to restore the register since it's
|
||||
less work than reloading sp and popping the register. Otherwise,
|
||||
restore sp (if necessary) and pop the registers. */
|
||||
|
||||
if (nregs > 1 || sp_valid)
|
||||
{
|
||||
if (frame_pointer_needed)
|
||||
if ( !sp_valid )
|
||||
{
|
||||
xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
|
||||
if (do_rtl)
|
||||
|
40
gcc/flow.c
40
gcc/flow.c
@ -106,7 +106,10 @@ Boston, MA 02111-1307, USA. */
|
||||
|
||||
life_analysis fills in certain vectors containing information about
|
||||
register usage: reg_n_refs, reg_n_deaths, reg_n_sets, reg_live_length,
|
||||
reg_n_calls_crosses and reg_basic_block. */
|
||||
reg_n_calls_crosses and reg_basic_block.
|
||||
|
||||
life_analysis sets current_function_sp_is_unchanging if the function
|
||||
doesn't modify the stack pointer. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
@ -289,6 +292,7 @@ static void init_regset_vector PROTO ((regset *, int,
|
||||
static void count_reg_sets_1 PROTO ((rtx));
|
||||
static void count_reg_sets PROTO ((rtx));
|
||||
static void count_reg_references PROTO ((rtx));
|
||||
static void notice_stack_pointer_modification PROTO ((rtx, rtx));
|
||||
|
||||
/* Find basic blocks of the current function.
|
||||
F is the first insn of the function and NREGS the number of register numbers
|
||||
@ -1221,9 +1225,28 @@ noop_move_p (insn)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
notice_stack_pointer_modification (x, pat)
|
||||
rtx x;
|
||||
rtx pat ATTRIBUTE_UNUSED;
|
||||
{
|
||||
if (x == stack_pointer_rtx
|
||||
/* The stack pointer is only modified indirectly as the result
|
||||
of a push until later in flow. See the comments in rtl.texi
|
||||
regarding Embedded Side-Effects on Addresses. */
|
||||
|| (GET_CODE (x) == MEM
|
||||
&& (GET_CODE (XEXP (x, 0)) == PRE_DEC
|
||||
|| GET_CODE (XEXP (x, 0)) == PRE_INC
|
||||
|| GET_CODE (XEXP (x, 0)) == POST_DEC
|
||||
|| GET_CODE (XEXP (x, 0)) == POST_INC)
|
||||
&& XEXP (XEXP (x, 0), 0) == stack_pointer_rtx))
|
||||
current_function_sp_is_unchanging = 0;
|
||||
}
|
||||
|
||||
/* Record which insns refer to any volatile memory
|
||||
or for any reason can't be deleted just because they are dead stores.
|
||||
Also, delete any insns that copy a register to itself. */
|
||||
Also, delete any insns that copy a register to itself.
|
||||
And see if the stack pointer is modified. */
|
||||
static void
|
||||
record_volatile_insns (f)
|
||||
rtx f;
|
||||
@ -1264,6 +1287,11 @@ record_volatile_insns (f)
|
||||
NOTE_SOURCE_FILE (insn) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if insn modifies the stack pointer. */
|
||||
if ( current_function_sp_is_unchanging
|
||||
&& GET_RTX_CLASS (GET_CODE (insn)) == 'i')
|
||||
note_stores (PATTERN (insn), notice_stack_pointer_modification);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1279,7 +1307,8 @@ mark_regs_live_at_end (set)
|
||||
if (! EXIT_IGNORE_STACK
|
||||
|| (! FRAME_POINTER_REQUIRED
|
||||
&& ! current_function_calls_alloca
|
||||
&& flag_omit_frame_pointer))
|
||||
&& flag_omit_frame_pointer)
|
||||
|| current_function_sp_is_unchanging)
|
||||
#endif
|
||||
/* If exiting needs the right stack value,
|
||||
consider the stack pointer live at the end of the function. */
|
||||
@ -1376,6 +1405,11 @@ life_analysis_1 (f, nregs)
|
||||
= (regset *) alloca (n_basic_blocks * sizeof (regset));
|
||||
init_regset_vector (basic_block_significant, n_basic_blocks, &flow_obstack);
|
||||
|
||||
/* Assume that the stack pointer is unchanging if alloca hasn't been used.
|
||||
This will be cleared by record_volatile_insns if it encounters an insn
|
||||
which modifies the stack pointer. */
|
||||
current_function_sp_is_unchanging = !current_function_calls_alloca;
|
||||
|
||||
record_volatile_insns (f);
|
||||
|
||||
if (n_basic_blocks > 0)
|
||||
|
@ -138,6 +138,12 @@ int current_function_has_computed_jump;
|
||||
|
||||
int current_function_contains_functions;
|
||||
|
||||
/* Nonzero if function being compiled doesn't modify the stack pointer
|
||||
(ignoring the prologue and epilogue). This is only valid after
|
||||
life_analysis has run. */
|
||||
|
||||
int current_function_sp_is_unchanging;
|
||||
|
||||
/* Nonzero if the current function is a thunk (a lightweight function that
|
||||
just adjusts one of its arguments and forwards to another function), so
|
||||
we should try to cut corners where we can. */
|
||||
@ -5426,6 +5432,7 @@ init_function_start (subr, filename, line)
|
||||
current_function_has_nonlocal_label = 0;
|
||||
current_function_has_nonlocal_goto = 0;
|
||||
current_function_contains_functions = 0;
|
||||
current_function_sp_is_unchanging = 0;
|
||||
current_function_is_thunk = 0;
|
||||
|
||||
current_function_returns_pcc_struct = 0;
|
||||
|
@ -380,6 +380,12 @@ extern int current_function_has_nonlocal_label;
|
||||
|
||||
extern int current_function_contains_functions;
|
||||
|
||||
/* Nonzero if function being compiled doesn't modify the stack pointer
|
||||
(ignoring the prologue and epilogue). This is only valid after
|
||||
life_analysis has run. */
|
||||
|
||||
extern int current_function_sp_is_unchanging;
|
||||
|
||||
/* Nonzero if the current function returns a pointer type */
|
||||
|
||||
extern int current_function_returns_pointer;
|
||||
|
@ -3452,7 +3452,8 @@ fill_simple_delay_slots (non_jumps_p)
|
||||
SET_HARD_REG_BIT (needed.regs, HARD_FRAME_POINTER_REGNUM);
|
||||
#endif
|
||||
#ifdef EXIT_IGNORE_STACK
|
||||
if (! EXIT_IGNORE_STACK)
|
||||
if (! EXIT_IGNORE_STACK
|
||||
|| current_function_sp_is_unchanging)
|
||||
#endif
|
||||
SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
|
||||
}
|
||||
@ -4602,7 +4603,8 @@ dbr_schedule (first, file)
|
||||
SET_HARD_REG_BIT (end_of_function_needs.regs, HARD_FRAME_POINTER_REGNUM);
|
||||
#endif
|
||||
#ifdef EXIT_IGNORE_STACK
|
||||
if (! EXIT_IGNORE_STACK)
|
||||
if (! EXIT_IGNORE_STACK
|
||||
|| current_function_sp_is_unchanging)
|
||||
#endif
|
||||
SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user