/* 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);
+ {
+ PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
+ df_insn_rescan (q);
+ }
if (CALL_P (q))
{
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;
-
- 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;
- }
+ 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;
+ }
}
+
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;
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 */