/* 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 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)
{
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. */
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
}
/* 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. */
}
}
}
- if (! flag_regmove)
- continue;
+ if (! flag_regmove)
+ continue;
if (! find_matches (insn, &match))
continue;
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 sollution availble.
+ there may be better solution available.
In particular this change produced slower code for numeric
i387 programs. */
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_ul = strtoul (p - 1, &end, 10);
- int match = match_ul;
+ 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;
- p = end;
+ 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;
- 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;
+ 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;
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);
}