/* 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 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* This module looks for cases where matching constraints would force
#include "except.h"
#include "toplev.h"
#include "reload.h"
+#include "timevar.h"
+#include "tree-pass.h"
/* Turn STACK_GROWS_DOWNWARD into a boolean. */
static int try_auto_increment (rtx, rtx, rtx, rtx, HOST_WIDE_INT, int);
static int find_matches (rtx, struct match *);
static void replace_in_call_usage (rtx *, unsigned int, rtx, rtx);
-static int fixup_match_1 (rtx, rtx, rtx, rtx, rtx, int, int, int, FILE *);
+static int fixup_match_1 (rtx, rtx, rtx, rtx, rtx, int, int, int);
static int reg_is_remote_constant_p (rtx, rtx, rtx);
static int stable_and_no_regs_but_for_p (rtx, rtx, rtx);
static int regclass_compatible_p (int, int);
static int replacement_quality (rtx);
-static int fixup_match_2 (rtx, rtx, rtx, rtx, FILE *);
+static int fixup_match_2 (rtx, rtx, rtx, rtx);
/* Return nonzero if registers with CLASS1 and CLASS2 can be merged without
causing too much register allocation problems. */
/* If there is a REG_DEAD note on this insn, we must
change this not to REG_UNUSED meaning that the register
is set, but the value is dead. Failure to do so will
- result in a sched1 abort -- when it recomputes lifetime
+ result in a sched1 dieing -- when it recomputes lifetime
information, the number of REG_DEAD notes will have
changed. */
rtx note = find_reg_note (insn, REG_DEAD, reg);
{
int i;
for (i = 0; i < flags_nregs; ++i)
- live |= REGNO_REG_SET_P (block->global_live_at_start,
+ live |= REGNO_REG_SET_P (block->il.rtl->global_live_at_start,
flags_regno + i);
}
#endif
if (REGNO_LAST_UID (src_regno) == insn_uid)
REGNO_LAST_UID (src_regno) = move_uid;
-
- if (REGNO_LAST_NOTE_UID (src_regno) == insn_uid)
- REGNO_LAST_NOTE_UID (src_regno) = move_uid;
}
}
return 0;
/* Look for the set. */
- for (p = LOG_LINKS (insn); p; p = XEXP (p, 1))
+ for (p = BB_HEAD (BLOCK_FOR_INSN (insn)); p != insn; p = NEXT_INSN (p))
{
rtx s;
- if (REG_NOTE_KIND (p) != 0)
+ if (!INSN_P (p))
continue;
- s = single_set (XEXP (p, 0));
+ s = single_set (p);
if (s != 0
&& REG_P (SET_DEST (s))
&& REGNO (SET_DEST (s)) == REGNO (reg))
hard register as ultimate source, like the frame pointer. */
static int
-fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset, FILE *regmove_dump_file)
+fixup_match_2 (rtx insn, rtx dst, rtx src, rtx offset)
{
rtx p, dst_death = 0;
int length, num_calls = 0;
REG_N_CALLS_CROSSED (REGNO (dst)) += num_calls;
}
- if (regmove_dump_file)
- fprintf (regmove_dump_file,
+ if (dump_file)
+ fprintf (dump_file,
"Fixed operand of insn %d.\n",
INSN_UID (insn));
REGMOVE_DUMP_FILE is a stream for output of a trace of actions taken
(or 0 if none should be output). */
-void
-regmove_optimize (rtx f, int nregs, FILE *regmove_dump_file)
+static void
+regmove_optimize (rtx f, int nregs)
{
int old_max_uid = get_max_uid ();
rtx insn;
can suppress some optimizations in those zones. */
mark_flags_life_zones (discover_flags_reg ());
- regno_src_regno = xmalloc (sizeof *regno_src_regno * nregs);
+ regno_src_regno = XNEWVEC (int, nregs);
for (i = nregs; --i >= 0; ) regno_src_regno[i] = -1;
- regmove_bb_head = xmalloc (sizeof (int) * (old_max_uid + 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;
if (! flag_regmove && pass >= flag_expensive_optimizations)
goto done;
- if (regmove_dump_file)
- fprintf (regmove_dump_file, "Starting %s pass...\n",
+ if (dump_file)
+ fprintf (dump_file, "Starting %s pass...\n",
pass ? "backward" : "forward");
for (insn = pass ? get_last_insn () : f; insn;
&& GET_MODE_SIZE (GET_MODE (dst))
>= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst))))
{
- src_subreg
- = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)),
- src, SUBREG_BYTE (dst));
dst = SUBREG_REG (dst);
+ src_subreg = lowpart_subreg (GET_MODE (dst),
+ src, GET_MODE (src));
+ if (!src_subreg)
+ continue;
}
if (!REG_P (dst)
|| REGNO (dst) < FIRST_PSEUDO_REGISTER)
continue;
if (fixup_match_1 (insn, set, src, src_subreg, dst, pass,
- op_no, match_no,
- regmove_dump_file))
+ op_no, match_no))
break;
}
}
/* A backward pass. Replace input operands with output operands. */
- if (regmove_dump_file)
- fprintf (regmove_dump_file, "Starting backward pass...\n");
+ if (dump_file)
+ fprintf (dump_file, "Starting backward pass...\n");
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
&& GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
&& XEXP (SET_SRC (set), 0) == src
&& fixup_match_2 (insn, dst, src,
- XEXP (SET_SRC (set), 1),
- regmove_dump_file))
+ XEXP (SET_SRC (set), 1)))
break;
continue;
}
}
- if (regmove_dump_file)
- fprintf (regmove_dump_file,
+ if (dump_file)
+ fprintf (dump_file,
"Could fix operand %d of insn %d matching operand %d.\n",
op_no, INSN_UID (insn), match_no);
REG_LIVE_LENGTH (srcno) = 2;
}
- if (regmove_dump_file)
- fprintf (regmove_dump_file,
+ if (dump_file)
+ fprintf (dump_file,
"Fixed operand %d of insn %d matching operand %d.\n",
op_no, INSN_UID (insn), match_no);
static int
fixup_match_1 (rtx insn, rtx set, rtx src, rtx src_subreg, rtx dst,
- int backward, int operand_number, int match_number,
- FILE *regmove_dump_file)
+ int backward, int operand_number, int match_number)
{
rtx p;
rtx post_inc = 0, post_inc_set = 0, search_end = 0;
code = NOTE;
}
- if (regmove_dump_file)
- fprintf (regmove_dump_file,
+ if (dump_file)
+ fprintf (dump_file,
"Could fix operand %d of insn %d matching operand %d.\n",
operand_number, INSN_UID (insn), match_number);
if (REG_LIVE_LENGTH (REGNO (dst)) < 2)
REG_LIVE_LENGTH (REGNO (dst)) = 2;
}
- if (regmove_dump_file)
- fprintf (regmove_dump_file,
+ if (dump_file)
+ fprintf (dump_file,
"Fixed operand %d of insn %d matching operand %d.\n",
operand_number, INSN_UID (insn), match_number);
return 1;
/* Main entry point for stack adjustment combination. */
-void
+static void
combine_stack_adjustments (void)
{
basic_block bb;
{
struct csa_memlist *ml;
- ml = xmalloc (sizeof (*ml));
+ ml = XNEW (struct csa_memlist);
if (XEXP (*mem, 0) == stack_pointer_rtx)
ml->sp_offset = 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;
+}
+
+struct tree_opt_pass pass_regmove =
+{
+ "regmove", /* name */
+ gate_handle_regmove, /* gate */
+ rest_of_handle_regmove, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_REGMOVE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 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 */
+};
+