/* Move registers around to reduce number of move instructions needed.
- Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GCC.
#include "reload.h"
#include "timevar.h"
#include "tree-pass.h"
-
-
-/* Turn STACK_GROWS_DOWNWARD into a boolean. */
-#ifdef STACK_GROWS_DOWNWARD
-#undef STACK_GROWS_DOWNWARD
-#define STACK_GROWS_DOWNWARD 1
-#else
-#define STACK_GROWS_DOWNWARD 0
-#endif
+#include "df.h"
static int perhaps_ends_bb_p (rtx);
static int optimize_reg_copy_1 (rtx, rtx, rtx);
static void optimize_reg_copy_2 (rtx, rtx, rtx);
static void optimize_reg_copy_3 (rtx, rtx, rtx);
-static void copy_src_to_dest (rtx, rtx, rtx, int);
-static int *regmove_bb_head;
+static void copy_src_to_dest (rtx, rtx, rtx);
struct match {
int with[MAX_RECOG_OPERANDS];
&& ! CLASS_LIKELY_SPILLED_P (class1)));
}
+/* Find the place in the rtx X where REG is used as a memory address.
+ Return the MEM rtx that so uses it.
+ If PLUSCONST is nonzero, search instead for a memory address equivalent to
+ (plus REG (const_int PLUSCONST)).
+
+ If such an address does not appear, return 0.
+ If REG appears more than once, or is used other than in such an address,
+ return (rtx) 1. */
+
+static rtx
+find_use_as_address (rtx x, rtx reg, HOST_WIDE_INT plusconst)
+{
+ enum rtx_code code = GET_CODE (x);
+ const char * const fmt = GET_RTX_FORMAT (code);
+ int i;
+ rtx value = 0;
+ rtx tem;
+
+ if (code == MEM && XEXP (x, 0) == reg && plusconst == 0)
+ return x;
+
+ if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS
+ && XEXP (XEXP (x, 0), 0) == reg
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && INTVAL (XEXP (XEXP (x, 0), 1)) == plusconst)
+ return x;
+
+ if (code == SIGN_EXTRACT || code == ZERO_EXTRACT)
+ {
+ /* If REG occurs inside a MEM used in a bit-field reference,
+ that is unacceptable. */
+ if (find_use_as_address (XEXP (x, 0), reg, 0) != 0)
+ return (rtx) (size_t) 1;
+ }
+
+ if (x == reg)
+ return (rtx) (size_t) 1;
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ tem = find_use_as_address (XEXP (x, i), reg, plusconst);
+ if (value == 0)
+ value = tem;
+ else if (tem != 0)
+ return (rtx) (size_t) 1;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ {
+ tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst);
+ if (value == 0)
+ value = tem;
+ else if (tem != 0)
+ return (rtx) (size_t) 1;
+ }
+ }
+ }
+
+ return value;
+}
+
+
/* INC_INSN is an instruction that adds INCREMENT to REG.
Try to fold INC_INSN as a post/pre in/decrement into INSN.
Iff INC_INSN_SET is nonzero, inc_insn has a destination different from src.
{
int i;
for (i = 0; i < flags_nregs; ++i)
- live |= REGNO_REG_SET_P (block->il.rtl->global_live_at_start,
- flags_regno + i);
+ live |= REGNO_REG_SET_P (df_get_live_in (block), flags_regno + i);
}
#endif
if (INSN_P (q))
{
if (reg_mentioned_p (dest, PATTERN (q)))
- PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
-
-
- if (CALL_P (q))
- {
- REG_N_CALLS_CROSSED (dregno)--;
- REG_N_CALLS_CROSSED (sregno)++;
- }
+ {
+ PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
+ df_insn_rescan (q);
+ }
+
+ if (CALL_P (q))
+ {
+ REG_N_CALLS_CROSSED (dregno)--;
+ REG_N_CALLS_CROSSED (sregno)++;
+ }
}
remove_note (p, find_reg_note (p, REG_DEAD, dest));
break;
}
}
+
/* INSN is a ZERO_EXTEND or SIGN_EXTEND of SRC to DEST.
Look if SRC dies there, and if it is only set once, by loading
it from memory. If so, try to incorporate the zero/sign extension
instead moving the value to dest directly before the operation. */
static void
-copy_src_to_dest (rtx insn, rtx src, rtx dest, int old_max_uid)
+copy_src_to_dest (rtx insn, rtx src, rtx dest)
{
rtx seq;
rtx link;
rtx *p_move_notes;
int src_regno;
int dest_regno;
- int bb;
int insn_uid;
int move_uid;
*p_move_notes = NULL_RTX;
*p_insn_notes = NULL_RTX;
- /* Is the insn the head of a basic block? If so extend it. */
insn_uid = INSN_UID (insn);
move_uid = INSN_UID (move_insn);
- if (insn_uid < old_max_uid)
- {
- bb = regmove_bb_head[insn_uid];
- if (bb >= 0)
- {
- BB_HEAD (BASIC_BLOCK (bb)) = move_insn;
- regmove_bb_head[insn_uid] = -1;
- }
- }
/* Update the various register tables. */
dest_regno = REGNO (dest);
- REG_N_SETS (dest_regno) ++;
+ INC_REG_N_SETS (dest_regno, 1);
REG_LIVE_LENGTH (dest_regno)++;
- if (REGNO_FIRST_UID (dest_regno) == insn_uid)
- REGNO_FIRST_UID (dest_regno) = move_uid;
-
src_regno = REGNO (src);
if (! find_reg_note (move_insn, REG_DEAD, src))
REG_LIVE_LENGTH (src_regno)++;
-
- if (REGNO_FIRST_UID (src_regno) == insn_uid)
- REGNO_FIRST_UID (src_regno) = move_uid;
-
- if (REGNO_LAST_UID (src_regno) == insn_uid)
- REGNO_LAST_UID (src_regno) = move_uid;
}
}
may increase register pressure and make reload harder. If REG is
set in the same basic block as INSN, we don't worry about it,
because we'll probably need a register anyhow (??? but what if REG
- is used in a different basic block as well as this one?). FIRST is
- the first insn in the function. */
+ is used in a different basic block as well as this one?). */
static bool
reg_is_remote_constant_p (rtx reg, rtx insn)
reg_set_in_bb = xcalloc (max, sizeof (*reg_set_in_bb));
FOR_EACH_BB (bb)
- for (p = BB_HEAD (bb); p != NEXT_INSN (BB_END (bb));
- p = NEXT_INSN (p))
- {
- rtx s;
+ FOR_BB_INSNS (bb, p)
+ {
+ rtx s;
- if (!INSN_P (p))
- continue;
- s = single_set (p);
- /* This is the instruction which sets REG. If there is a
- REG_EQUAL note, then REG is equivalent to a constant. */
- if (s != 0
- && REG_P (SET_DEST (s))
- && REG_N_SETS (REGNO (SET_DEST (s))) == 1
- && find_reg_note (p, REG_EQUAL, NULL_RTX))
- reg_set_in_bb[REGNO (SET_DEST (s))] = bb;
- }
+ if (!INSN_P (p))
+ continue;
+ s = single_set (p);
+ /* This is the instruction which sets REG. If there is a
+ REG_EQUAL note, then REG is equivalent to a constant. */
+ if (s != 0
+ && REG_P (SET_DEST (s))
+ && REG_N_SETS (REGNO (SET_DEST (s))) == 1
+ && find_reg_note (p, REG_EQUAL, NULL_RTX))
+ reg_set_in_bb[REGNO (SET_DEST (s))] = bb;
+ }
}
+
gcc_assert (REGNO (reg) < max_reg_computed);
if (reg_set_in_bb[REGNO (reg)] == NULL)
return false;
- if (reg_set_in_bb[REGNO (reg)] != BLOCK_FOR_INSN (insn))
- return true;
- /* Look for the set. */
- for (p = BB_HEAD (BLOCK_FOR_INSN (insn)); p != insn; p = NEXT_INSN (p))
- {
- rtx s;
-
- if (!INSN_P (p))
- continue;
- s = single_set (p);
- if (s != 0
- && REG_P (SET_DEST (s)) && REGNO (SET_DEST (s)) == REGNO (reg))
- {
- /* The register is set in the same basic block. */
- return false;
- }
- }
- return true;
+ return (reg_set_in_bb[REGNO (reg)] != BLOCK_FOR_INSN (insn));
}
/* INSN is adding a CONST_INT to a REG. We search backwards looking for
static void
regmove_optimize (rtx f, int nregs)
{
- int old_max_uid = get_max_uid ();
rtx insn;
struct match match;
int pass;
int i;
rtx copy_src, copy_dst;
- basic_block bb;
/* ??? Hack. Regmove doesn't examine the CFG, and gets mightily
confused by non-call exceptions ending blocks. */
if (flag_non_call_exceptions)
return;
+ df_note_add_problem ();
+ df_analyze ();
+
+ regstat_init_n_sets_and_refs ();
+ regstat_compute_ri ();
+
/* Find out where a potential flags register is live, and so that we
can suppress some optimizations in those zones. */
mark_flags_life_zones (discover_flags_reg ());
regno_src_regno = XNEWVEC (int, nregs);
- for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1;
-
- regmove_bb_head = XNEWVEC (int, old_max_uid + 1);
- for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1;
- FOR_EACH_BB (bb)
- regmove_bb_head[INSN_UID (BB_HEAD (bb))] = bb->index;
+ for (i = nregs; --i >= 0; )
+ regno_src_regno[i] = -1;
/* A forward/backward pass. Replace output operands with input operands. */
dstno = REGNO (dst);
srcno = REGNO (src);
- REG_N_SETS (dstno)++;
- REG_N_SETS (srcno)--;
+ INC_REG_N_SETS (dstno, 1);
+ INC_REG_N_SETS (srcno, -1);
REG_N_CALLS_CROSSED (dstno) += num_calls;
REG_N_CALLS_CROSSED (srcno) -= num_calls;
/* If we weren't able to replace any of the alternatives, try an
alternative approach of copying the source to the destination. */
if (!success && copy_src != NULL_RTX)
- copy_src_to_dest (insn, copy_src, copy_dst, old_max_uid);
-
+ copy_src_to_dest (insn, copy_src, copy_dst);
}
}
- /* In fixup_match_1, some insns may have been inserted after basic block
- ends. Fix that here. */
- FOR_EACH_BB (bb)
- {
- rtx end = BB_END (bb);
- rtx new = end;
- rtx next = NEXT_INSN (new);
- while (next != 0 && INSN_UID (next) >= old_max_uid
- && (bb->next_bb == EXIT_BLOCK_PTR || BB_HEAD (bb->next_bb) != next))
- new = next, next = NEXT_INSN (new);
- BB_END (bb) = new;
- }
-
done:
/* Clean up. */
free (regno_src_regno);
- free (regmove_bb_head);
if (reg_set_in_bb)
{
free (reg_set_in_bb);
reg_set_in_bb = NULL;
}
+ regstat_free_n_sets_and_refs ();
+ regstat_free_ri ();
}
/* Returns nonzero if INSN's pattern has matching constraints for any operand.
&& try_auto_increment (search_end, post_inc, 0, src, newconst, 1))
post_inc = 0;
validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (insn_const), 0);
- REG_N_SETS (REGNO (src))++;
+ INC_REG_N_SETS (REGNO (src), 1);
REG_LIVE_LENGTH (REGNO (src))++;
}
if (overlap)
p = emit_insn_after_setloc (pat, PREV_INSN (p), INSN_LOCATOR (insn));
delete_insn (insn);
REG_NOTES (p) = notes;
+ df_notes_rescan (p);
}
}
/* Sometimes we'd generate src = const; src += n;
&& validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
{
delete_insn (q);
- REG_N_SETS (REGNO (src))--;
+ INC_REG_N_SETS (REGNO (src), -1);
REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2;
REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
insn_const = 0;
REG_N_CALLS_CROSSED (REGNO (src)) += s_num_calls;
}
- REG_N_SETS (REGNO (src))++;
- REG_N_SETS (REGNO (dst))--;
+ INC_REG_N_SETS (REGNO (src), 1);
+ INC_REG_N_SETS (REGNO (dst), -1);
REG_N_CALLS_CROSSED (REGNO (dst)) -= num_calls;
}
}
\f
-/* Track stack adjustments and stack memory references. Attempt to
- reduce the number of stack adjustments by back-propagating 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.
-
- Propagation 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 (rtx);
-static rtx single_set_for_csa (rtx);
-static void free_csa_memlist (struct csa_memlist *);
-static struct csa_memlist *record_one_stack_memref (rtx, rtx *,
- struct csa_memlist *);
-static int try_apply_stack_adjustment (rtx, struct csa_memlist *,
- HOST_WIDE_INT, HOST_WIDE_INT);
-static void combine_stack_adjustments_for_block (basic_block);
-static int record_stack_memrefs (rtx *, void *);
-
-
-/* Main entry point for stack adjustment combination. */
-
-static void
-combine_stack_adjustments (void)
-{
- basic_block bb;
-
- FOR_EACH_BB (bb)
- combine_stack_adjustments_for_block (bb);
-}
-
-/* Recognize a MEM of the form (sp) or (plus sp const). */
-
-static int
-stack_memref_p (rtx x)
-{
- if (!MEM_P (x))
- return 0;
- x = XEXP (x, 0);
-
- if (x == stack_pointer_rtx)
- return 1;
- if (GET_CODE (x) == PLUS
- && XEXP (x, 0) == stack_pointer_rtx
- && GET_CODE (XEXP (x, 1)) == CONST_INT)
- return 1;
-
- return 0;
-}
-
-/* Recognize either normal single_set or the hack in i386.md for
- tying fp and sp adjustments. */
-
-static rtx
-single_set_for_csa (rtx insn)
-{
- int i;
- rtx tmp = single_set (insn);
- if (tmp)
- return tmp;
-
- if (!NONJUMP_INSN_P (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 (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 (rtx insn, rtx *mem, struct csa_memlist *next_memlist)
-{
- struct csa_memlist *ml;
- ml = XNEW (struct csa_memlist);
-
- 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 (rtx insn, struct csa_memlist *memlist, HOST_WIDE_INT new_adjust,
- HOST_WIDE_INT delta)
-{
- struct csa_memlist *ml;
- rtx set;
-
- 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)
- validate_change
- (ml->insn, ml->mem,
- replace_equiv_address_nv (*ml->mem,
- plus_constant (stack_pointer_rtx,
- ml->sp_offset - delta)), 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;
-}
-
-/* Called via for_each_rtx and used to record all stack memory references in
- the insn and discard all other stack pointer references. */
-struct record_stack_memrefs_data
-{
- rtx insn;
- struct csa_memlist *memlist;
-};
-
-static int
-record_stack_memrefs (rtx *xp, void *data)
-{
- rtx x = *xp;
- struct record_stack_memrefs_data *d =
- (struct record_stack_memrefs_data *) data;
- if (!x)
- return 0;
- switch (GET_CODE (x))
- {
- case MEM:
- if (!reg_mentioned_p (stack_pointer_rtx, x))
- return -1;
- /* We are not able to handle correctly all possible memrefs containing
- stack pointer, so this check is necessary. */
- if (stack_memref_p (x))
- {
- d->memlist = record_one_stack_memref (d->insn, xp, d->memlist);
- return -1;
- }
- return 1;
- case REG:
- /* ??? We want be able to handle non-memory stack pointer
- references later. For now just discard all insns referring to
- stack pointer outside mem expressions. We would probably
- want to teach validate_replace to simplify expressions first.
-
- We can't just compare with STACK_POINTER_RTX because the
- reference to the stack pointer might be in some other mode.
- In particular, an explicit clobber in an asm statement will
- result in a QImode clobber. */
- if (REGNO (x) == STACK_POINTER_REGNUM)
- return 1;
- break;
- default:
- break;
- }
- return 0;
-}
-
-/* Subroutine of combine_stack_adjustments, called for each basic block. */
-
-static void
-combine_stack_adjustments_for_block (basic_block bb)
-{
- HOST_WIDE_INT last_sp_adjust = 0;
- rtx last_sp_set = NULL_RTX;
- struct csa_memlist *memlist = NULL;
- rtx insn, next, set;
- struct record_stack_memrefs_data data;
- bool end_of_block = false;
-
- for (insn = BB_HEAD (bb); !end_of_block ; insn = next)
- {
- end_of_block = insn == BB_END (bb);
- next = NEXT_INSN (insn);
-
- if (! INSN_P (insn))
- continue;
-
- 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;
- continue;
- }
-
- /* 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.
-
- Also we need to be careful to not move stack pointer
- such that we create stack accesses outside the allocated
- area. We can combine an allocation into the first insn,
- or a deallocation into the second insn. We can not
- combine an allocation followed by a deallocation.
-
- The only somewhat frequent occurrence of the later is when
- a function allocates a stack frame but does not use it.
- For this case, we would need to analyze rtl stream to be
- sure that allocated area is really unused. This means not
- only checking the memory references, but also all registers
- or global memory references possibly containing a stack
- frame address.
-
- Perhaps the best way to address this problem is to teach
- gcc not to allocate stack for objects never used. */
-
- /* Combine an allocation into the first instruction. */
- if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0)
- {
- if (try_apply_stack_adjustment (last_sp_set, memlist,
- last_sp_adjust + this_adjust,
- this_adjust))
- {
- /* It worked! */
- delete_insn (insn);
- last_sp_adjust += this_adjust;
- continue;
- }
- }
-
- /* Otherwise we have a deallocation. Do not combine with
- a previous allocation. Combine into the second insn. */
- else if (STACK_GROWS_DOWNWARD
- ? last_sp_adjust >= 0 : last_sp_adjust <= 0)
- {
- if (try_apply_stack_adjustment (insn, memlist,
- last_sp_adjust + this_adjust,
- -last_sp_adjust))
- {
- /* It worked! */
- delete_insn (last_sp_set);
- last_sp_set = insn;
- last_sp_adjust += this_adjust;
- free_csa_memlist (memlist);
- memlist = NULL;
- continue;
- }
- }
-
- /* Combination failed. Restart processing from here. If
- deallocation+allocation conspired to cancel, we can
- delete the old deallocation insn. */
- if (last_sp_set && last_sp_adjust == 0)
- delete_insn (insn);
- free_csa_memlist (memlist);
- memlist = NULL;
- last_sp_set = insn;
- last_sp_adjust = this_adjust;
- continue;
- }
-
- /* 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
- && MEM_P (dest)
- && ((GET_CODE (XEXP (dest, 0)) == PRE_DEC
- && (last_sp_adjust
- == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (dest))))
- || (GET_CODE (XEXP (dest, 0)) == PRE_MODIFY
- && GET_CODE (XEXP (XEXP (dest, 0), 1)) == PLUS
- && XEXP (XEXP (XEXP (dest, 0), 1), 0) == stack_pointer_rtx
- && (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
- == CONST_INT)
- && (INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1))
- == -last_sp_adjust)))
- && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx
- && ! reg_mentioned_p (stack_pointer_rtx, src)
- && memory_address_p (GET_MODE (dest), stack_pointer_rtx)
- && validate_change (insn, &SET_DEST (set),
- replace_equiv_address (dest,
- stack_pointer_rtx),
- 0))
- {
- delete_insn (last_sp_set);
- free_csa_memlist (memlist);
- memlist = NULL;
- last_sp_set = NULL_RTX;
- last_sp_adjust = 0;
- continue;
- }
- }
-
- data.insn = insn;
- data.memlist = memlist;
- if (!CALL_P (insn) && last_sp_set
- && !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data))
- {
- memlist = data.memlist;
- continue;
- }
- memlist = data.memlist;
-
- /* Otherwise, we were not able to process the instruction.
- Do not continue collecting data across such a one. */
- if (last_sp_set
- && (CALL_P (insn)
- || reg_mentioned_p (stack_pointer_rtx, PATTERN (insn))))
- {
- if (last_sp_set && last_sp_adjust == 0)
- delete_insn (last_sp_set);
- free_csa_memlist (memlist);
- memlist = NULL;
- last_sp_set = NULL_RTX;
- last_sp_adjust = 0;
- }
- }
-
- if (last_sp_set && last_sp_adjust == 0)
- delete_insn (last_sp_set);
-
- if (memlist)
- free_csa_memlist (memlist);
-}
-\f
static bool
gate_handle_regmove (void)
{
return (optimize > 0 && flag_regmove);
}
-
/* Register allocation pre-pass, to reduce number of moves necessary
for two-address machines. */
static unsigned int
rest_of_handle_regmove (void)
{
regmove_optimize (get_insns (), max_reg_num ());
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE);
return 0;
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
+ TODO_df_finish |
TODO_dump_func |
TODO_ggc_collect, /* todo_flags_finish */
'N' /* letter */
};
-
-static bool
-gate_handle_stack_adjustments (void)
-{
- return (optimize > 0);
-}
-
-static unsigned int
-rest_of_handle_stack_adjustments (void)
-{
- life_analysis (PROP_POSTRELOAD);
- cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE
- | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0));
-
- /* This is kind of a heuristic. We need to run combine_stack_adjustments
- even for machines with possibly nonzero RETURN_POPS_ARGS
- and ACCUMULATE_OUTGOING_ARGS. We expect that only ports having
- push instructions will have popping returns. */
-#ifndef PUSH_ROUNDING
- if (!ACCUMULATE_OUTGOING_ARGS)
-#endif
- combine_stack_adjustments ();
- return 0;
-}
-
-struct tree_opt_pass pass_stack_adjustments =
-{
- "csa", /* name */
- gate_handle_stack_adjustments, /* gate */
- rest_of_handle_stack_adjustments, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- 0, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func |
- TODO_ggc_collect, /* todo_flags_finish */
- 0 /* letter */
-};
-