/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GCC.
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
#include "rtl.h" /* stdio.h must precede rtl.h for FFS. */
#include "tm_p.h"
#include "insn-config.h"
static int replacement_quality PARAMS ((rtx));
static int fixup_match_2 PARAMS ((rtx, rtx, rtx, rtx, FILE *));
-/* Return non-zero if registers with CLASS1 and CLASS2 can be merged without
+/* Return nonzero if registers with CLASS1 and CLASS2 can be merged without
causing too much register allocation problems. */
static int
regclass_compatible_p (class0, class1)
/* Can't use the size of SET_SRC, we might have something like
(sign_extend:SI (mem:QI ... */
rtx use = find_use_as_address (pset, reg, 0);
- if (use != 0 && use != (rtx) 1)
+ if (use != 0 && use != (rtx) (size_t) 1)
{
int size = GET_MODE_SIZE (GET_MODE (use));
if (0
{
int flags_regno;
int flags_nregs;
- int block;
+ basic_block block;
#ifdef HAVE_cc0
/* If we found a flags register on a cc0 host, bail. */
{
enum machine_mode mode = (flags ? HImode : VOIDmode);
rtx insn;
- for (insn = get_insns(); insn; insn = NEXT_INSN (insn))
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
PUT_MODE (insn, mode);
return;
}
flags_set_1_rtx = flags;
/* Process each basic block. */
- for (block = n_basic_blocks - 1; block >= 0; block--)
+ FOR_EACH_BB_REVERSE (block)
{
rtx insn, end;
int live;
- insn = BLOCK_HEAD (block);
- end = BLOCK_END (block);
+ insn = block->head;
+ end = block->end;
/* Look out for the (unlikely) case of flags being live across
basic block boundaries. */
{
int i;
for (i = 0; i < flags_nregs; ++i)
- live |= REGNO_REG_SET_P (BASIC_BLOCK (block)->global_live_at_start,
+ live |= REGNO_REG_SET_P (block->global_live_at_start,
flags_regno + i);
}
#endif
a candidate for tying to a hard register, since the output might in
turn be a candidate to be tied to a different hard register. */
static int
-replacement_quality(reg)
+replacement_quality (reg)
rtx reg;
{
int src_regno;
}
/* 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 encorporate the zero/sign extension
+ it from memory. If so, try to incorporate the zero/sign extension
into the memory read, change SRC to the mode of DEST, and alter
the remaining accesses to use the appropriate SUBREG. This allows
SRC and DEST to be tied later. */
if (src_no < FIRST_PSEUDO_REGISTER
|| dst_no < FIRST_PSEUDO_REGISTER
|| ! find_reg_note (insn, REG_DEAD, src_reg)
+ || REG_N_DEATHS (src_no) != 1
|| REG_N_SETS (src_no) != 1)
return;
for (p = PREV_INSN (insn); p && ! reg_set_p (src_reg, p); p = PREV_INSN (p))
|| SET_DEST (set) != src_reg)
return;
- /* Be conserative: although this optimization is also valid for
+ /* Be conservative: although this optimization is also valid for
volatile memory references, that could cause trouble in later passes. */
if (MEM_VOLATILE_P (SET_SRC (set)))
return;
/* Generate the src->dest move. */
start_sequence ();
emit_move_insn (dest, src);
- seq = gen_sequence ();
+ seq = get_insns ();
end_sequence ();
/* If this sequence uses new registers, we may not use it. */
if (old_num_regs != reg_rtx_no
p_move_notes = ®_NOTES (move_insn);
p_insn_notes = ®_NOTES (insn);
- /* Move any notes mentioning src to the move instruction */
+ /* Move any notes mentioning src to the move instruction. */
for (link = REG_NOTES (insn); link != NULL_RTX; link = next)
{
next = XEXP (link, 1);
*p_move_notes = NULL_RTX;
*p_insn_notes = NULL_RTX;
- /* Is the insn the head of a basic block? If so extend it */
+ /* 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)
(set (reg100) (plus reg100 offset2-offset1)) */
/* ??? What does this comment mean? */
-/* cse disrupts preincrement / postdecrement squences when it finds a
+/* cse disrupts preincrement / postdecrement sequences when it finds a
hard register as ultimate source, like the frame pointer. */
static int
if (perhaps_ends_bb_p (p))
break;
else if (! INSN_P (p))
- continue;
+ continue;
if (find_regno_note (p, REG_DEAD, REGNO (dst)))
dst_death = p;
&& GET_CODE (SET_SRC (pset)) == PLUS
&& XEXP (SET_SRC (pset), 0) == src
&& GET_CODE (XEXP (SET_SRC (pset), 1)) == CONST_INT)
- {
+ {
HOST_WIDE_INT newconst
= INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
rtx add = gen_add3_insn (dst, dst, GEN_INT (newconst));
#endif
return 1;
}
- }
+ }
if (reg_set_p (dst, PATTERN (p)))
- break;
+ break;
/* If we have passed a call instruction, and the
pseudo-reg SRC is not already live across a call,
hard regs are clobbered. Thus, we only use it for src for
non-call insns. */
if (GET_CODE (p) == CALL_INSN)
- {
+ {
if (! dst_death)
num_calls++;
- if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
- break;
+ if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
+ break;
if (call_used_regs [REGNO (dst)]
|| find_reg_fusage (p, CLOBBER, dst))
break;
- }
+ }
else if (reg_set_p (src, PATTERN (p)))
- break;
+ break;
}
return 0;
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. */
return;
/* Find out where a potential flags register is live, and so that we
- can supress some optimizations in those zones. */
+ can suppress some optimizations in those zones. */
mark_flags_life_zones (discover_flags_reg ());
regno_src_regno = (int *) xmalloc (sizeof *regno_src_regno * nregs);
regmove_bb_head = (int *) xmalloc (sizeof (int) * (old_max_uid + 1));
for (i = old_max_uid; i >= 0; i--) regmove_bb_head[i] = -1;
- for (i = 0; i < n_basic_blocks; i++)
- regmove_bb_head[INSN_UID (BLOCK_HEAD (i))] = i;
+ FOR_EACH_BB (bb)
+ regmove_bb_head[INSN_UID (bb->head)] = bb->index;
/* A forward/backward pass. Replace output operands with input operands. */
&& (GET_CODE (SET_SRC (set)) == SIGN_EXTEND
|| GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
&& GET_CODE (XEXP (SET_SRC (set), 0)) == REG
- && GET_CODE (SET_DEST(set)) == REG)
+ && GET_CODE (SET_DEST (set)) == REG)
optimize_reg_copy_3 (insn, SET_DEST (set), SET_SRC (set));
if (flag_expensive_optimizations && ! pass
&& GET_CODE (SET_SRC (set)) == REG
- && GET_CODE (SET_DEST(set)) == REG)
+ && GET_CODE (SET_DEST (set)) == REG)
{
/* If this is a register-register copy where SRC is not dead,
see if we can optimize it. If this optimization succeeds,
if (regno_src_regno[REGNO (SET_DEST (set))] < 0
&& SET_SRC (set) != SET_DEST (set))
{
- int srcregno = REGNO (SET_SRC(set));
+ int srcregno = REGNO (SET_SRC (set));
if (regno_src_regno[srcregno] >= 0)
srcregno = regno_src_regno[srcregno];
regno_src_regno[REGNO (SET_DEST (set))] = srcregno;
}
}
}
- if (! flag_regmove)
- continue;
+ if (! flag_regmove)
+ continue;
if (! find_matches (insn, &match))
continue;
}
src_class = reg_preferred_class (REGNO (src));
dst_class = reg_preferred_class (REGNO (dst));
- if (! regclass_compatible_p (src_class, dst_class))
+
+ if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
{
- if (!copy_src)
- {
- copy_src = src;
- copy_dst = dst;
- }
+ /* We used to force the copy here like in other cases, but
+ it produces worse code, as it eliminates no copy
+ instructions and the copy emitted will be produced by
+ reload anyway. On patterns with multiple alternatives,
+ there may be better solution available.
+
+ In particular this change produced slower code for numeric
+ i387 programs. */
+
continue;
}
- /* Can not modify an earlier insn to set dst if this insn
- uses an old value in the source. */
- if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
+ if (! regclass_compatible_p (src_class, dst_class))
{
if (!copy_src)
{
continue;
}
- if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
+ /* Can not modify an earlier insn to set dst if this insn
+ uses an old value in the source. */
+ if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
{
if (!copy_src)
{
continue;
}
-
/* If src is set once in a different basic block,
and is set equal to a constant, then do not use
it for this optimization, as this would make it
no longer equivalent to a constant. */
- if (reg_is_remote_constant_p (src, insn, f))
+ if (reg_is_remote_constant_p (src, insn, f))
{
if (!copy_src)
{
}
/* If we weren't able to replace any of the alternatives, try an
- alternative appoach of copying the source to the destination. */
+ 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);
/* In fixup_match_1, some insns may have been inserted after basic block
ends. Fix that here. */
- for (i = 0; i < n_basic_blocks; i++)
+ FOR_EACH_BB (bb)
{
- rtx end = BLOCK_END (i);
+ rtx end = bb->end;
rtx new = end;
rtx next = NEXT_INSN (new);
while (next != 0 && INSN_UID (next) >= old_max_uid
- && (i == n_basic_blocks - 1 || BLOCK_HEAD (i + 1) != next))
+ && (bb->next_bb == EXIT_BLOCK_PTR || bb->next_bb->head != next))
new = next, next = NEXT_INSN (new);
- BLOCK_END (i) = new;
+ bb->end = new;
}
done:
if (*p == ',')
i++;
- while ((c = *p++) != '\0' && c != ',')
- switch (c)
- {
- case '=':
- break;
- case '+':
- break;
- case '&':
- matchp->early_clobber[op_no] = 1;
- break;
- case '%':
- matchp->commutative[op_no] = op_no + 1;
- matchp->commutative[op_no + 1] = op_no;
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
+ while ((c = *p) != '\0' && c != ',')
+ {
+ switch (c)
{
- char *end;
- unsigned long match = strtoul (p - 1, &end, 10);
- p = end;
+ case '=':
+ break;
+ case '+':
+ break;
+ case '&':
+ matchp->early_clobber[op_no] = 1;
+ break;
+ case '%':
+ matchp->commutative[op_no] = op_no + 1;
+ matchp->commutative[op_no + 1] = op_no;
+ break;
- if (match < op_no && likely_spilled[match])
- break;
- matchp->with[op_no] = match;
- any_matches = 1;
- if (matchp->commutative[op_no] >= 0)
- matchp->with[matchp->commutative[op_no]] = match;
- }
- break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ {
+ char *end;
+ unsigned long match_ul = strtoul (p, &end, 10);
+ int match = match_ul;
+
+ p = end;
+
+ if (match < op_no && likely_spilled[match])
+ continue;
+ matchp->with[op_no] = match;
+ any_matches = 1;
+ if (matchp->commutative[op_no] >= 0)
+ matchp->with[matchp->commutative[op_no]] = match;
+ }
+ continue;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
case 'C': case 'D': case 'W': case 'Y': case 'Z':
- if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_LETTER ((unsigned char)c)))
+ if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p) ))
likely_spilled[op_no] = 1;
break;
}
+ p += CONSTRAINT_LEN (c, p);
+ }
}
return any_matches;
}
int success = 0;
int num_calls = 0, s_num_calls = 0;
enum rtx_code code = NOTE;
- HOST_WIDE_INT insn_const = 0, newconst;
+ HOST_WIDE_INT insn_const = 0, newconst = 0;
rtx overlap = 0; /* need to move insn ? */
rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note = NULL_RTX;
int length, s_length;
if (note && CONSTANT_P (XEXP (note, 0)))
{
- for (q = PREV_INSN (insn); q; q = PREV_INSN(q))
+ for (q = PREV_INSN (insn); q; q = PREV_INSN (q))
{
/* ??? We can't scan past the end of a basic block without
updating the register lifetime info
void
combine_stack_adjustments ()
{
- int i;
+ basic_block bb;
- for (i = 0; i < n_basic_blocks; ++i)
- combine_stack_adjustments_for_block (BASIC_BLOCK (i));
+ FOR_EACH_BB (bb)
+ combine_stack_adjustments_for_block (bb);
}
/* Recognize a MEM of the form (sp) or (plus sp const). */
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 explict clobber in an asm statement will
+ In particular, an explicit clobber in an asm statement will
result in a QImode clober. */
if (REGNO (x) == STACK_POINTER_REGNUM)
return 1;
HOST_WIDE_INT last_sp_adjust = 0;
rtx last_sp_set = NULL_RTX;
struct csa_memlist *memlist = NULL;
- rtx pending_delete;
- rtx insn, next;
+ rtx insn, next, set;
struct record_stack_memrefs_data data;
+ bool end_of_block = false;
- for (insn = bb->head; ; insn = next)
+ for (insn = bb->head; !end_of_block ; insn = next)
{
- rtx set;
-
- pending_delete = NULL_RTX;
+ end_of_block = insn == bb->end;
next = NEXT_INSN (insn);
if (! INSN_P (insn))
- goto processed;
+ continue;
set = single_set_for_csa (insn);
if (set)
{
last_sp_set = insn;
last_sp_adjust = this_adjust;
- goto processed;
+ 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 carefull to not move stack pointer
+ 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
this_adjust))
{
/* It worked! */
- pending_delete = insn;
+ delete_insn (insn);
last_sp_adjust += this_adjust;
- goto processed;
+ continue;
}
}
last_sp_adjust += this_adjust;
free_csa_memlist (memlist);
memlist = NULL;
- goto processed;
+ continue;
}
}
- /* Combination failed. Restart processing from here. */
+ /* 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;
- goto processed;
+ continue;
}
/* Find a predecrement of exactly the previous adjustment and
stack_pointer_rtx),
0))
{
- if (last_sp_set == bb->head)
- bb->head = NEXT_INSN (last_sp_set);
delete_insn (last_sp_set);
-
free_csa_memlist (memlist);
memlist = NULL;
last_sp_set = NULL_RTX;
last_sp_adjust = 0;
- goto processed;
+ continue;
}
}
&& !for_each_rtx (&PATTERN (insn), record_stack_memrefs, &data))
{
memlist = data.memlist;
- goto processed;
+ continue;
}
memlist = data.memlist;
&& (GET_CODE (insn) == CALL_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;
}
-
- processed:
- if (insn == bb->end)
- break;
-
- if (pending_delete)
- delete_insn (pending_delete);
}
- if (pending_delete)
- delete_insn (pending_delete);
+ if (last_sp_set && last_sp_adjust == 0)
+ delete_insn (last_sp_set);
}