summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@gcc.gnu.org>2000-03-14 06:38:52 -0800
committerRichard Henderson <rth@gcc.gnu.org>2000-03-14 06:38:52 -0800
commit1e7f0a48cf6e9c5d1435f3da96990c5d299f4953 (patch)
tree1a629149dede4a23ade805cc2e7cfad2448f3b60 /gcc
parentd5fb67d394088d1574f098923dfe5c09d456738a (diff)
downloadgcc-1e7f0a48cf6e9c5d1435f3da96990c5d299f4953.tar.gz
regmove.c (combine_stack_adjustments): New.
* regmove.c (combine_stack_adjustments): New. (stack_memref_p, single_set_for_csa): New. (free_csa_memlist, record_one_stack_memref): New. (try_apply_stack_adjustment): New. (combine_stack_adjustments_for_block): New. * rtl.h (combine_stack_adjustments): Declare. * toplev.c (rest_of_compilation): Call it. * i386.md: Revert 2000-01-16 change. From-SVN: r32526
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/config/i386/i386.md19
-rw-r--r--gcc/regmove.c333
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/toplev.c16
5 files changed, 359 insertions, 28 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 08c2594d8de..48ea28cdd83 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2000-03-14 Richard Henderson <rth@cygnus.com>
+
+ * regmove.c (combine_stack_adjustments): New.
+ (stack_memref_p, single_set_for_csa): New.
+ (free_csa_memlist, record_one_stack_memref): New.
+ (try_apply_stack_adjustment): New.
+ (combine_stack_adjustments_for_block): New.
+ * rtl.h (combine_stack_adjustments): Declare.
+ * toplev.c (rest_of_compilation): Call it.
+
+ * i386.md: Revert 2000-01-16 change.
+
2000-03-14 Martin v. Löwis <loewis@informatik.hu-berlin.de>
* gccbug.in: Add web category, gcc specific classes.
@@ -370,8 +382,8 @@ Thu Mar 9 20:01:38 2000 Jim Wilson <wilson@cygnus.com>
Thu Mar 9 18:10:02 2000 Jeffrey A Law (law@cygnus.com)
- * config/pa/pa-hpux10.h (LIB_SPEC): Correct typo in !p case.
- (MD_STARTFILE_PREFIX_1): New macro.
+ * config/pa/pa-hpux10.h (LIB_SPEC): Correct typo in !p case.
+ (MD_STARTFILE_PREFIX_1): New macro.
2000-03-09 Robert Lipe <robertl@sco.com>
@@ -1483,7 +1495,7 @@ Mon Feb 28 21:07:59 2000 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
(SET_DEFAULT_TYPE_ATTRIBUTES): Define.
* config/arm/arm.md (call): Call arm_is_longcall_p to decide
- if a long call is needed.
+ if a long call is needed.
(call_value): Ditto.
(call_symbol): Ditto.
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index b55128eac76..be2b035b94d 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -9386,25 +9386,6 @@
[(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))
(clobber (reg:CC 17))])]
"operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));")
-
-;; Merge two successive stack adjusts. The combiner doesn't know how
-;; to do this, and doesn't see all of them.
-;; (reg:SI 7) is %esp.
-(define_peephole2
- [(parallel[
- (set (reg:SI 7)
- (plus:SI (reg:SI 7) (match_operand:SI 0 "const_int_operand" "")))
- (clobber (reg:CC 17))])
- (parallel[
- (set (reg:SI 7)
- (plus:SI (reg:SI 7) (match_operand:SI 1 "const_int_operand" "")))
- (clobber (reg:CC 17))])]
- ""
- [(parallel[
- (set (reg:SI 7)
- (plus:SI (reg:SI 7) (match_dup 2)))
- (clobber (reg:CC 17))])]
- "operands[2] = GEN_INT (INTVAL (operands[0]) + INTVAL (operands[1]));")
;; Call-value patterns last so that the wildcard operand does not
;; disrupt insn-recog's switch tables.
diff --git a/gcc/regmove.c b/gcc/regmove.c
index ba9d2e7d689..fa82f8f95e9 100644
--- a/gcc/regmove.c
+++ b/gcc/regmove.c
@@ -2060,3 +2060,336 @@ stable_and_no_regs_but_for_p (x, src, dst)
return ! rtx_unstable_p (x);
}
}
+
+/* Track stack adjustments and stack memory references. Attempt to
+ reduce the number of stack adjustments by back-propogating across
+ the memory references.
+
+ This is intended primarily for use with targets that do not define
+ ACCUMULATE_OUTGOING_ARGS. It is of significantly more value to
+ targets that define PREFERRED_STACK_BOUNDARY more aligned than
+ STACK_BOUNDARY (e.g. x86), or if not all registers can be pushed
+ (e.g. x86 fp regs) which would ordinarily have to be implemented
+ as a sub/mov pair due to restrictions in calls.c.
+
+ Propogation stops when any of the insns that need adjusting are
+ (a) no longer valid because we've exceeded their range, (b) a
+ non-trivial push instruction, or (c) a call instruction.
+
+ Restriction B is based on the assumption that push instructions
+ are smaller or faster. If a port really wants to remove all
+ pushes, it should have defined ACCUMULATE_OUTGOING_ARGS. The
+ one exception that is made is for an add immediately followed
+ by a push. */
+
+/* This structure records stack memory references between stack adjusting
+ instructions. */
+
+struct csa_memlist
+{
+ HOST_WIDE_INT sp_offset;
+ rtx insn, mem;
+ struct csa_memlist *next;
+};
+
+static int stack_memref_p PARAMS ((rtx));
+static rtx single_set_for_csa PARAMS ((rtx));
+static void free_csa_memlist PARAMS ((struct csa_memlist *));
+static struct csa_memlist *record_one_stack_memref
+ PARAMS ((rtx, rtx, struct csa_memlist *));
+static int try_apply_stack_adjustment
+ PARAMS ((rtx, struct csa_memlist *, HOST_WIDE_INT, HOST_WIDE_INT));
+static void combine_stack_adjustments_for_block PARAMS ((basic_block));
+
+
+/* Main entry point for stack adjustment combination. */
+
+void
+combine_stack_adjustments ()
+{
+ int i;
+
+ for (i = 0; i < n_basic_blocks; ++i)
+ combine_stack_adjustments_for_block (BASIC_BLOCK (i));
+}
+
+/* Recognize a MEM of the form (sp) or (plus sp const). */
+
+static int
+stack_memref_p (mem)
+ rtx mem;
+{
+ return (GET_CODE (mem) == MEM
+ && (XEXP (mem, 0) == stack_pointer_rtx
+ || (GET_CODE (XEXP (mem, 0)) == PLUS
+ && XEXP (XEXP (mem, 0), 0) == stack_pointer_rtx
+ && GET_CODE (XEXP (XEXP (mem, 0), 0)) == CONST_INT)));
+}
+
+/* Recognize either normal single_set or the hack in i386.md for
+ tying fp and sp adjustments. */
+
+static rtx
+single_set_for_csa (insn)
+ rtx insn;
+{
+ int i;
+ rtx tmp = single_set (insn);
+ if (tmp)
+ return tmp;
+
+ if (GET_CODE (insn) != INSN
+ || GET_CODE (PATTERN (insn)) != PARALLEL)
+ return NULL_RTX;
+
+ tmp = PATTERN (insn);
+ if (GET_CODE (XVECEXP (tmp, 0, 0)) != SET)
+ return NULL_RTX;
+
+ for (i = 1; i < XVECLEN (tmp, 0); ++i)
+ {
+ rtx this = XVECEXP (tmp, 0, i);
+
+ /* The special case is allowing a no-op set. */
+ if (GET_CODE (this) == SET
+ && SET_SRC (this) == SET_DEST (this))
+ ;
+ else if (GET_CODE (this) != CLOBBER
+ && GET_CODE (this) != USE)
+ return NULL_RTX;
+ }
+
+ return XVECEXP (tmp, 0, 0);
+}
+
+/* Free the list of csa_memlist nodes. */
+
+static void
+free_csa_memlist (memlist)
+ struct csa_memlist *memlist;
+{
+ struct csa_memlist *next;
+ for (; memlist ; memlist = next)
+ {
+ next = memlist->next;
+ free (memlist);
+ }
+}
+
+/* Create a new csa_memlist node from the given memory reference.
+ It is already known that the memory is stack_memref_p. */
+
+static struct csa_memlist *
+record_one_stack_memref (insn, mem, next_memlist)
+ rtx insn, mem;
+ struct csa_memlist *next_memlist;
+{
+ struct csa_memlist *ml;
+
+ ml = (struct csa_memlist *) xmalloc (sizeof (*ml));
+
+ if (XEXP (mem, 0) == stack_pointer_rtx)
+ ml->sp_offset = 0;
+ else
+ ml->sp_offset = INTVAL (XEXP (XEXP (mem, 0), 1));
+
+ ml->insn = insn;
+ ml->mem = mem;
+ ml->next = next_memlist;
+
+ return ml;
+}
+
+/* Attempt to apply ADJUST to the stack adjusting insn INSN, as well
+ as each of the memories in MEMLIST. Return true on success. */
+
+static int
+try_apply_stack_adjustment (insn, memlist, new_adjust, delta)
+ rtx insn;
+ struct csa_memlist *memlist;
+ HOST_WIDE_INT new_adjust, delta;
+{
+ struct csa_memlist *ml;
+ rtx set;
+
+ /* We know INSN matches single_set_for_csa, because that's what we
+ recognized earlier. However, if INSN is not single_set, it is
+ doing double duty as a barrier for frame pointer memory accesses,
+ which we are not recording. Therefore, an adjust insn that is not
+ single_set may not have a positive delta applied. */
+
+ if (delta > 0 && ! single_set (insn))
+ return 0;
+ set = single_set_for_csa (insn);
+ validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (new_adjust), 1);
+
+ for (ml = memlist; ml ; ml = ml->next)
+ {
+ HOST_WIDE_INT c = ml->sp_offset - delta;
+
+ /* Don't reference memory below the stack pointer. */
+ if (c < 0)
+ {
+ cancel_changes (0);
+ return 0;
+ }
+
+ validate_change (ml->insn, &XEXP (ml->mem, 0),
+ plus_constant (stack_pointer_rtx, c), 1);
+ }
+
+ if (apply_change_group ())
+ {
+ /* Succeeded. Update our knowledge of the memory references. */
+ for (ml = memlist; ml ; ml = ml->next)
+ ml->sp_offset -= delta;
+
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* Subroutine of combine_stack_adjustments, called for each basic block. */
+
+static void
+combine_stack_adjustments_for_block (bb)
+ basic_block bb;
+{
+ HOST_WIDE_INT last_sp_adjust = 0;
+ rtx last_sp_set = NULL_RTX;
+ struct csa_memlist *memlist = NULL;
+ rtx pending_delete;
+ rtx insn, next;
+
+ for (insn = bb->head; ; insn = next)
+ {
+ rtx set;
+
+ pending_delete = NULL_RTX;
+ next = NEXT_INSN (insn);
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ goto processed;
+
+ set = single_set_for_csa (insn);
+ if (set)
+ {
+ rtx dest = SET_DEST (set);
+ rtx src = SET_SRC (set);
+
+ /* Find constant additions to the stack pointer. */
+ if (dest == stack_pointer_rtx
+ && GET_CODE (src) == PLUS
+ && XEXP (src, 0) == stack_pointer_rtx
+ && GET_CODE (XEXP (src, 1)) == CONST_INT)
+ {
+ HOST_WIDE_INT this_adjust = INTVAL (XEXP (src, 1));
+
+ /* If we've not seen an adjustment previously, record
+ it now and continue. */
+ if (! last_sp_set)
+ {
+ last_sp_set = insn;
+ last_sp_adjust = this_adjust;
+ goto processed;
+ }
+
+ /* If not all recorded memrefs can be adjusted, or the
+ adjustment is now too large for a constant addition,
+ we cannot merge the two stack adjustments. */
+ if (! try_apply_stack_adjustment (last_sp_set, memlist,
+ last_sp_adjust + this_adjust,
+ this_adjust))
+ {
+ free_csa_memlist (memlist);
+ memlist = NULL;
+ last_sp_set = insn;
+ last_sp_adjust = this_adjust;
+ goto processed;
+ }
+
+ /* It worked! */
+ pending_delete = insn;
+ last_sp_adjust += this_adjust;
+
+ /* If, by some accident, the adjustments cancel out,
+ delete both insns and start from scratch. */
+ if (last_sp_adjust == 0)
+ {
+ if (last_sp_set == bb->head)
+ bb->head = NEXT_INSN (last_sp_set);
+ flow_delete_insn (last_sp_set);
+
+ free_csa_memlist (memlist);
+ memlist = NULL;
+ last_sp_set = NULL_RTX;
+ }
+
+ goto processed;
+ }
+
+ /* Find loads from stack memory and record them. */
+ if (last_sp_set && stack_memref_p (src))
+ {
+ memlist = record_one_stack_memref (insn, src, memlist);
+ goto processed;
+ }
+
+ /* Find stores to stack memory and record them. */
+ if (last_sp_set && stack_memref_p (dest))
+ {
+ memlist = record_one_stack_memref (insn, dest, memlist);
+ goto processed;
+ }
+
+ /* Find a predecrement of exactly the previous adjustment and
+ turn it into a direct store. Obviously we can't do this if
+ there were any intervening uses of the stack pointer. */
+ if (memlist == NULL
+ && last_sp_adjust == GET_MODE_SIZE (GET_MODE (dest))
+ && GET_CODE (dest) == MEM
+ && GET_CODE (XEXP (dest, 0)) == PRE_DEC
+ && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
+ && validate_change (insn, &SET_DEST (set),
+ change_address (dest, VOIDmode,
+ stack_pointer_rtx), 0))
+ {
+ if (last_sp_set == bb->head)
+ bb->head = NEXT_INSN (last_sp_set);
+ flow_delete_insn (last_sp_set);
+
+ free_csa_memlist (memlist);
+ memlist = NULL;
+ last_sp_set = NULL_RTX;
+ last_sp_adjust = 0;
+ goto processed;
+ }
+ }
+
+ /* Otherwise, we were not able to process the instruction.
+ Do not continue collecting data across such a one. */
+ if (last_sp_set
+ && (GET_CODE (insn) == CALL_INSN
+ || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
+ {
+ free_csa_memlist (memlist);
+ memlist = NULL;
+ last_sp_set = NULL_RTX;
+ last_sp_adjust = 0;
+ }
+
+ processed:
+ if (insn == bb->end)
+ break;
+
+ if (pending_delete)
+ flow_delete_insn (pending_delete);
+ }
+
+ if (pending_delete)
+ {
+ bb->end = PREV_INSN (pending_delete);
+ flow_delete_insn (pending_delete);
+ }
+}
diff --git a/gcc/rtl.h b/gcc/rtl.h
index cdabfdba058..6629667b1ac 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1580,6 +1580,7 @@ extern void delete_null_pointer_checks PARAMS ((rtx));
#ifdef BUFSIZ
extern void regmove_optimize PARAMS ((rtx, int, FILE *));
#endif
+extern void combine_stack_adjustments PARAMS ((void));
/* In reorg.c */
#ifdef BUFSIZ
diff --git a/gcc/toplev.c b/gcc/toplev.c
index aab5c3055bf..fa7494d0e21 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -3547,12 +3547,16 @@ rest_of_compilation (decl)
if (optimize)
{
- TIMEVAR
- (flow2_time,
- {
- cleanup_cfg (insns);
- life_analysis (insns, max_reg_num (), rtl_dump_file, 1);
- });
+ TIMEVAR (flow2_time, { cleanup_cfg (insns); });
+
+#ifndef ACCUMULATE_OUTGOING_ARGS
+ TIMEVAR (flow2_time, { combine_stack_adjustments (); });
+#endif
+
+ TIMEVAR (flow2_time,
+ {
+ life_analysis (insns, max_reg_num (), rtl_dump_file, 1);
+ });
if (ggc_p)
ggc_collect ();