aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJohn Wehle <john@feith.com>1998-10-12 10:06:49 +0000
committerJeff Law <law@gcc.gnu.org>1998-10-12 04:06:49 -0600
commitfdb8a883a4f3415aec0434737c9446f80d0133f0 (patch)
tree3dfd3a630883b77a0b6ce45c2d90fe9452e85a15 /gcc
parent3babe36c375f475103415e2ab33b32681b25e8b7 (diff)
downloadgcc-fdb8a883a4f3415aec0434737c9446f80d0133f0.zip
gcc-fdb8a883a4f3415aec0434737c9446f80d0133f0.tar.gz
gcc-fdb8a883a4f3415aec0434737c9446f80d0133f0.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/config/i386/i386.c17
-rw-r--r--gcc/flow.c40
-rw-r--r--gcc/function.c7
-rw-r--r--gcc/output.h6
-rw-r--r--gcc/reorg.c6
6 files changed, 81 insertions, 13 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ef57f79..2cb1e09 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index fc8edbd..70cfcdc 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -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)
diff --git a/gcc/flow.c b/gcc/flow.c
index 30618a4..0161d94 100644
--- a/gcc/flow.c
+++ b/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)
diff --git a/gcc/function.c b/gcc/function.c
index 4645f5a..48018cf 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -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;
diff --git a/gcc/output.h b/gcc/output.h
index 06d5204..83ec167 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -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;
diff --git a/gcc/reorg.c b/gcc/reorg.c
index 007d92e..d4c7778 100644
--- a/gcc/reorg.c
+++ b/gcc/reorg.c
@@ -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);
}