dbgcnt.def (ira_move): New counter.
* dbgcnt.def (ira_move): New counter. * ira-int.h (ira_create_new_reg): Declare function. (first_moveable_pseudo, last_moveable_pseudo): Declare variables. * ira-emit.c (ira_create_new_reg): Renamed from craete_new_reg and no longer static. All callers changed. * ira.c: Include "dbgcnt.h". (rtx_moveable_p, insn_dominated_by_p, find_moveable_pseudos, move_unallocated_pseudos): New static functions. (first_moveable_pseudo, last_moveable_pseudo): New global variables. (pseudo_replaced_reg, pseudo_move_insn): New static variables. (ira): Call find_moveable_pseudos and move_unallocated_pseudos. * ira-costs.c (find_costs_and_classes): Assign a memory cost of zero to the pseudos generated in find_moveable_pseudos. * Makefile.in (ira.o): Add $(DBGCNT_H). From-SVN: r186378
This commit is contained in:
parent
b9b0921497
commit
acf41a74a8
|
@ -1,3 +1,20 @@
|
|||
2012-04-12 Bernd Schmidt <bernds@codesourcery.com>
|
||||
|
||||
* dbgcnt.def (ira_move): New counter.
|
||||
* ira-int.h (ira_create_new_reg): Declare function.
|
||||
(first_moveable_pseudo, last_moveable_pseudo): Declare variables.
|
||||
* ira-emit.c (ira_create_new_reg): Renamed from craete_new_reg and
|
||||
no longer static. All callers changed.
|
||||
* ira.c: Include "dbgcnt.h".
|
||||
(rtx_moveable_p, insn_dominated_by_p, find_moveable_pseudos,
|
||||
move_unallocated_pseudos): New static functions.
|
||||
(first_moveable_pseudo, last_moveable_pseudo): New global variables.
|
||||
(pseudo_replaced_reg, pseudo_move_insn): New static variables.
|
||||
(ira): Call find_moveable_pseudos and move_unallocated_pseudos.
|
||||
* ira-costs.c (find_costs_and_classes): Assign a memory cost of zero
|
||||
to the pseudos generated in find_moveable_pseudos.
|
||||
* Makefile.in (ira.o): Add $(DBGCNT_H).
|
||||
|
||||
2012-04-12 Richard Guenther <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/52943
|
||||
|
|
|
@ -3292,7 +3292,7 @@ ira-lives.o: ira-lives.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
|
|||
$(DF_H) sparseset.h $(IRA_INT_H)
|
||||
ira.o: ira.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
$(TM_H) $(REGS_H) $(RTL_H) $(TM_P_H) $(TARGET_H) $(FLAGS_H) $(OBSTACK_H) \
|
||||
$(BITMAP_H) hard-reg-set.h $(BASIC_BLOCK_H) \
|
||||
$(BITMAP_H) hard-reg-set.h $(BASIC_BLOCK_H) $(DBGCNT_H) \
|
||||
$(EXPR_H) $(RECOG_H) $(PARAMS_H) $(TIMEVAR_H) $(TREE_PASS_H) output.h \
|
||||
$(EXCEPT_H) reload.h toplev.h $(DIAGNOSTIC_CORE_H) $(INTEGRATE_H) $(DF_H) $(GGC_H) $(IRA_INT_H)
|
||||
regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
|
||||
|
|
|
@ -184,3 +184,4 @@ DEBUG_COUNTER (sms_sched_loop)
|
|||
DEBUG_COUNTER (store_motion)
|
||||
DEBUG_COUNTER (split_for_sched2)
|
||||
DEBUG_COUNTER (tail_call)
|
||||
DEBUG_COUNTER (ira_move)
|
||||
|
|
|
@ -1650,6 +1650,8 @@ find_costs_and_classes (FILE *dump_file)
|
|||
COSTS (total_allocno_costs, parent_a_num)->mem_cost
|
||||
+= add_cost;
|
||||
|
||||
if (i >= first_moveable_pseudo && i < last_moveable_pseudo)
|
||||
COSTS (total_allocno_costs, parent_a_num)->mem_cost = 0;
|
||||
}
|
||||
a_costs = COSTS (costs, a_num)->cost;
|
||||
for (k = cost_classes_ptr->num - 1; k >= 0; k--)
|
||||
|
@ -1667,7 +1669,9 @@ find_costs_and_classes (FILE *dump_file)
|
|||
i_mem_cost += add_cost;
|
||||
}
|
||||
}
|
||||
if (equiv_savings < 0)
|
||||
if (i >= first_moveable_pseudo && i < last_moveable_pseudo)
|
||||
i_mem_cost = 0;
|
||||
else if (equiv_savings < 0)
|
||||
i_mem_cost = -equiv_savings;
|
||||
else if (equiv_savings > 0)
|
||||
{
|
||||
|
|
|
@ -330,8 +330,8 @@ add_to_edge_list (edge e, move_t move, bool head_p)
|
|||
|
||||
/* Create and return new pseudo-register with the same attributes as
|
||||
ORIGINAL_REG. */
|
||||
static rtx
|
||||
create_new_reg (rtx original_reg)
|
||||
rtx
|
||||
ira_create_new_reg (rtx original_reg)
|
||||
{
|
||||
rtx new_reg;
|
||||
|
||||
|
@ -625,7 +625,7 @@ change_loop (ira_loop_tree_node_t node)
|
|||
fprintf (ira_dump_file, " %i vs parent %i:",
|
||||
ALLOCNO_HARD_REGNO (allocno),
|
||||
ALLOCNO_HARD_REGNO (parent_allocno));
|
||||
set_allocno_reg (allocno, create_new_reg (original_reg));
|
||||
set_allocno_reg (allocno, ira_create_new_reg (original_reg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -646,7 +646,7 @@ change_loop (ira_loop_tree_node_t node)
|
|||
if (! used_p)
|
||||
continue;
|
||||
bitmap_set_bit (renamed_regno_bitmap, regno);
|
||||
set_allocno_reg (allocno, create_new_reg (allocno_emit_reg (allocno)));
|
||||
set_allocno_reg (allocno, ira_create_new_reg (allocno_emit_reg (allocno)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -852,7 +852,7 @@ modify_move_list (move_t list)
|
|||
ALLOCNO_ASSIGNED_P (new_allocno) = true;
|
||||
ALLOCNO_HARD_REGNO (new_allocno) = -1;
|
||||
ALLOCNO_EMIT_DATA (new_allocno)->reg
|
||||
= create_new_reg (allocno_emit_reg (set_move->to));
|
||||
= ira_create_new_reg (allocno_emit_reg (set_move->to));
|
||||
|
||||
/* Make it possibly conflicting with all earlier
|
||||
created allocnos. Cases where temporary allocnos
|
||||
|
|
|
@ -1416,3 +1416,6 @@ ira_allocate_and_set_or_copy_costs (int **vec, enum reg_class aclass,
|
|||
reg_costs[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
extern rtx ira_create_new_reg (rtx);
|
||||
extern int first_moveable_pseudo, last_moveable_pseudo;
|
||||
|
|
519
gcc/ira.c
519
gcc/ira.c
|
@ -384,7 +384,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "ggc.h"
|
||||
#include "ira-int.h"
|
||||
#include "dce.h"
|
||||
|
||||
#include "dbgcnt.h"
|
||||
|
||||
struct target_ira default_target_ira;
|
||||
struct target_ira_int default_target_ira_int;
|
||||
|
@ -3512,7 +3512,521 @@ build_insn_chain (void)
|
|||
if (dump_file)
|
||||
print_insn_chains (dump_file);
|
||||
}
|
||||
|
||||
/* Examine the rtx found in *LOC, which is read or written to as determined
|
||||
by TYPE. Return false if we find a reason why an insn containing this
|
||||
rtx should not be moved (such as accesses to non-constant memory), true
|
||||
otherwise. */
|
||||
static bool
|
||||
rtx_moveable_p (rtx *loc, enum op_type type)
|
||||
{
|
||||
const char *fmt;
|
||||
rtx x = *loc;
|
||||
enum rtx_code code = GET_CODE (x);
|
||||
int i, j;
|
||||
|
||||
code = GET_CODE (x);
|
||||
switch (code)
|
||||
{
|
||||
case CONST:
|
||||
case CONST_INT:
|
||||
case CONST_DOUBLE:
|
||||
case CONST_FIXED:
|
||||
case CONST_VECTOR:
|
||||
case SYMBOL_REF:
|
||||
case LABEL_REF:
|
||||
return true;
|
||||
|
||||
case PC:
|
||||
return type == OP_IN;
|
||||
|
||||
case CC0:
|
||||
return false;
|
||||
|
||||
case REG:
|
||||
if (x == frame_pointer_rtx)
|
||||
return true;
|
||||
if (HARD_REGISTER_P (x))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case MEM:
|
||||
if (type == OP_IN && MEM_READONLY_P (x))
|
||||
return rtx_moveable_p (&XEXP (x, 0), OP_IN);
|
||||
return false;
|
||||
|
||||
case SET:
|
||||
return (rtx_moveable_p (&SET_SRC (x), OP_IN)
|
||||
&& rtx_moveable_p (&SET_DEST (x), OP_OUT));
|
||||
|
||||
case STRICT_LOW_PART:
|
||||
return rtx_moveable_p (&XEXP (x, 0), OP_OUT);
|
||||
|
||||
case ZERO_EXTRACT:
|
||||
case SIGN_EXTRACT:
|
||||
return (rtx_moveable_p (&XEXP (x, 0), type)
|
||||
&& rtx_moveable_p (&XEXP (x, 1), OP_IN)
|
||||
&& rtx_moveable_p (&XEXP (x, 2), OP_IN));
|
||||
|
||||
case CLOBBER:
|
||||
return rtx_moveable_p (&SET_DEST (x), OP_OUT);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fmt = GET_RTX_FORMAT (code);
|
||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||
{
|
||||
if (fmt[i] == 'e')
|
||||
{
|
||||
if (!rtx_moveable_p (&XEXP (x, i), type))
|
||||
return false;
|
||||
}
|
||||
else if (fmt[i] == 'E')
|
||||
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
||||
{
|
||||
if (!rtx_moveable_p (&XVECEXP (x, i, j), type))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A wrapper around dominated_by_p, which uses the information in UID_LUID
|
||||
to give dominance relationships between two insns I1 and I2. */
|
||||
static bool
|
||||
insn_dominated_by_p (rtx i1, rtx i2, int *uid_luid)
|
||||
{
|
||||
basic_block bb1 = BLOCK_FOR_INSN (i1);
|
||||
basic_block bb2 = BLOCK_FOR_INSN (i2);
|
||||
|
||||
if (bb1 == bb2)
|
||||
return uid_luid[INSN_UID (i2)] < uid_luid[INSN_UID (i1)];
|
||||
return dominated_by_p (CDI_DOMINATORS, bb1, bb2);
|
||||
}
|
||||
|
||||
/* Record the range of register numbers added by find_moveable_pseudos. */
|
||||
int first_moveable_pseudo, last_moveable_pseudo;
|
||||
|
||||
/* These two vectors hold data for every register added by
|
||||
find_movable_pseudos, with index 0 holding data for the
|
||||
first_moveable_pseudo. */
|
||||
/* The original home register. */
|
||||
static VEC (rtx, heap) *pseudo_replaced_reg;
|
||||
/* The move instruction we added to move the value to its original home
|
||||
register. */
|
||||
static VEC (rtx, heap) *pseudo_move_insn;
|
||||
|
||||
/* Look for instances where we have an instruction that is known to increase
|
||||
register pressure, and whose result is not used immediately. If it is
|
||||
possible to move the instruction downwards to just before its first use,
|
||||
split its lifetime into two ranges. We create a new pseudo to compute the
|
||||
value, and emit a move instruction just before the first use. If, after
|
||||
register allocation, the new pseudo remains unallocated, the function
|
||||
move_unallocated_pseudos then deletes the move instruction and places
|
||||
the computation just before the first use.
|
||||
|
||||
Such a move is safe and profitable if all the input registers remain live
|
||||
and unchanged between the original computation and its first use. In such
|
||||
a situation, the computation is known to increase register pressure, and
|
||||
moving it is known to at least not worsen it.
|
||||
|
||||
We restrict moves to only those cases where a register remains unallocated,
|
||||
in order to avoid interfering too much with the instruction schedule. As
|
||||
an exception, we may move insns which only modify their input register
|
||||
(typically induction variables), as this increases the freedom for our
|
||||
intended transformation, and does not limit the second instruction
|
||||
scheduler pass. */
|
||||
|
||||
static void
|
||||
find_moveable_pseudos (void)
|
||||
{
|
||||
unsigned i;
|
||||
int max_regs = max_reg_num ();
|
||||
int max_uid = get_max_uid ();
|
||||
basic_block bb;
|
||||
int *uid_luid = XNEWVEC (int, max_uid);
|
||||
rtx *closest_uses = XNEWVEC (rtx, max_regs);
|
||||
/* A set of registers which are live but not modified throughout a block. */
|
||||
bitmap_head *bb_transp_live = XNEWVEC (bitmap_head, last_basic_block);
|
||||
/* A set of registers which only exist in a given basic block. */
|
||||
bitmap_head *bb_local = XNEWVEC (bitmap_head, last_basic_block);
|
||||
/* A set of registers which are set once, in an instruction that can be
|
||||
moved freely downwards, but are otherwise transparent to a block. */
|
||||
bitmap_head *bb_moveable_reg_sets = XNEWVEC (bitmap_head, last_basic_block);
|
||||
bitmap_head live, used, set, interesting, unusable_as_input;
|
||||
bitmap_iterator bi;
|
||||
bitmap_initialize (&interesting, 0);
|
||||
|
||||
first_moveable_pseudo = max_regs;
|
||||
VEC_free (rtx, heap, pseudo_move_insn);
|
||||
VEC_free (rtx, heap, pseudo_replaced_reg);
|
||||
VEC_safe_grow (rtx, heap, pseudo_move_insn, max_regs);
|
||||
VEC_safe_grow (rtx, heap, pseudo_replaced_reg, max_regs);
|
||||
|
||||
df_analyze ();
|
||||
calculate_dominance_info (CDI_DOMINATORS);
|
||||
|
||||
i = 0;
|
||||
bitmap_initialize (&live, 0);
|
||||
bitmap_initialize (&used, 0);
|
||||
bitmap_initialize (&set, 0);
|
||||
bitmap_initialize (&unusable_as_input, 0);
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
rtx insn;
|
||||
bitmap transp = bb_transp_live + bb->index;
|
||||
bitmap moveable = bb_moveable_reg_sets + bb->index;
|
||||
bitmap local = bb_local + bb->index;
|
||||
|
||||
bitmap_initialize (local, 0);
|
||||
bitmap_initialize (transp, 0);
|
||||
bitmap_initialize (moveable, 0);
|
||||
bitmap_copy (&live, df_get_live_out (bb));
|
||||
bitmap_and_into (&live, df_get_live_in (bb));
|
||||
bitmap_copy (transp, &live);
|
||||
bitmap_clear (moveable);
|
||||
bitmap_clear (&live);
|
||||
bitmap_clear (&used);
|
||||
bitmap_clear (&set);
|
||||
FOR_BB_INSNS (bb, insn)
|
||||
if (NONDEBUG_INSN_P (insn))
|
||||
{
|
||||
df_ref *u_rec, *d_rec;
|
||||
|
||||
uid_luid[INSN_UID (insn)] = i++;
|
||||
|
||||
u_rec = DF_INSN_USES (insn);
|
||||
d_rec = DF_INSN_DEFS (insn);
|
||||
if (d_rec[0] != NULL && d_rec[1] == NULL
|
||||
&& u_rec[0] != NULL && u_rec[1] == NULL
|
||||
&& DF_REF_REGNO (*u_rec) == DF_REF_REGNO (*d_rec)
|
||||
&& !bitmap_bit_p (&set, DF_REF_REGNO (*u_rec))
|
||||
&& rtx_moveable_p (&PATTERN (insn), OP_IN))
|
||||
{
|
||||
unsigned regno = DF_REF_REGNO (*u_rec);
|
||||
bitmap_set_bit (moveable, regno);
|
||||
bitmap_set_bit (&set, regno);
|
||||
bitmap_set_bit (&used, regno);
|
||||
bitmap_clear_bit (transp, regno);
|
||||
continue;
|
||||
}
|
||||
while (*u_rec)
|
||||
{
|
||||
unsigned regno = DF_REF_REGNO (*u_rec);
|
||||
bitmap_set_bit (&used, regno);
|
||||
if (bitmap_clear_bit (moveable, regno))
|
||||
bitmap_clear_bit (transp, regno);
|
||||
u_rec++;
|
||||
}
|
||||
|
||||
while (*d_rec)
|
||||
{
|
||||
unsigned regno = DF_REF_REGNO (*d_rec);
|
||||
bitmap_set_bit (&set, regno);
|
||||
bitmap_clear_bit (transp, regno);
|
||||
bitmap_clear_bit (moveable, regno);
|
||||
d_rec++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitmap_clear (&live);
|
||||
bitmap_clear (&used);
|
||||
bitmap_clear (&set);
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
bitmap local = bb_local + bb->index;
|
||||
rtx insn;
|
||||
|
||||
FOR_BB_INSNS (bb, insn)
|
||||
if (NONDEBUG_INSN_P (insn))
|
||||
{
|
||||
rtx def_insn, closest_use, note;
|
||||
df_ref *def_rec, def, use;
|
||||
unsigned regno;
|
||||
bool all_dominated, all_local;
|
||||
enum machine_mode mode;
|
||||
|
||||
def_rec = DF_INSN_DEFS (insn);
|
||||
/* There must be exactly one def in this insn. */
|
||||
def = *def_rec;
|
||||
if (!def || def_rec[1] || !single_set (insn))
|
||||
continue;
|
||||
/* This must be the only definition of the reg. We also limit
|
||||
which modes we deal with so that we can assume we can generate
|
||||
move instructions. */
|
||||
regno = DF_REF_REGNO (def);
|
||||
mode = GET_MODE (DF_REF_REG (def));
|
||||
if (DF_REG_DEF_COUNT (regno) != 1
|
||||
|| !DF_REF_INSN_INFO (def)
|
||||
|| HARD_REGISTER_NUM_P (regno)
|
||||
|| (!INTEGRAL_MODE_P (mode) && !FLOAT_MODE_P (mode)))
|
||||
continue;
|
||||
def_insn = DF_REF_INSN (def);
|
||||
|
||||
for (note = REG_NOTES (def_insn); note; note = XEXP (note, 1))
|
||||
if (REG_NOTE_KIND (note) == REG_EQUIV && MEM_P (XEXP (note, 0)))
|
||||
break;
|
||||
|
||||
if (note)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Ignoring reg %d, has equiv memory\n",
|
||||
regno);
|
||||
bitmap_set_bit (&unusable_as_input, regno);
|
||||
continue;
|
||||
}
|
||||
|
||||
use = DF_REG_USE_CHAIN (regno);
|
||||
all_dominated = true;
|
||||
all_local = true;
|
||||
closest_use = NULL_RTX;
|
||||
for (; use; use = DF_REF_NEXT_REG (use))
|
||||
{
|
||||
rtx insn;
|
||||
if (!DF_REF_INSN_INFO (use))
|
||||
{
|
||||
all_dominated = false;
|
||||
all_local = false;
|
||||
break;
|
||||
}
|
||||
insn = DF_REF_INSN (use);
|
||||
if (DEBUG_INSN_P (insn))
|
||||
continue;
|
||||
if (BLOCK_FOR_INSN (insn) != BLOCK_FOR_INSN (def_insn))
|
||||
all_local = false;
|
||||
if (!insn_dominated_by_p (insn, def_insn, uid_luid))
|
||||
all_dominated = false;
|
||||
if (closest_use != insn && closest_use != const0_rtx)
|
||||
{
|
||||
if (closest_use == NULL_RTX)
|
||||
closest_use = insn;
|
||||
else if (insn_dominated_by_p (closest_use, insn, uid_luid))
|
||||
closest_use = insn;
|
||||
else if (!insn_dominated_by_p (insn, closest_use, uid_luid))
|
||||
closest_use = const0_rtx;
|
||||
}
|
||||
}
|
||||
if (!all_dominated)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Reg %d not all uses dominated by set\n",
|
||||
regno);
|
||||
continue;
|
||||
}
|
||||
if (all_local)
|
||||
bitmap_set_bit (local, regno);
|
||||
if (closest_use == const0_rtx || closest_use == NULL
|
||||
|| next_nonnote_nondebug_insn (def_insn) == closest_use)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Reg %d uninteresting%s\n", regno,
|
||||
closest_use == const0_rtx || closest_use == NULL
|
||||
? " (no unique first use)" : "");
|
||||
continue;
|
||||
}
|
||||
#ifdef HAVE_cc0
|
||||
if (reg_referenced_p (cc0_rtx, PATTERN (closest_use)))
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Reg %d: closest user uses cc0\n",
|
||||
regno);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
bitmap_set_bit (&interesting, regno);
|
||||
closest_uses[regno] = closest_use;
|
||||
|
||||
if (dump_file && (all_local || all_dominated))
|
||||
{
|
||||
fprintf (dump_file, "Reg %u:", regno);
|
||||
if (all_local)
|
||||
fprintf (dump_file, " local to bb %d", bb->index);
|
||||
if (all_dominated)
|
||||
fprintf (dump_file, " def dominates all uses");
|
||||
if (closest_use != const0_rtx)
|
||||
fprintf (dump_file, " has unique first use");
|
||||
fputs ("\n", dump_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXECUTE_IF_SET_IN_BITMAP (&interesting, 0, i, bi)
|
||||
{
|
||||
df_ref def = DF_REG_DEF_CHAIN (i);
|
||||
rtx def_insn = DF_REF_INSN (def);
|
||||
basic_block def_block = BLOCK_FOR_INSN (def_insn);
|
||||
bitmap def_bb_local = bb_local + def_block->index;
|
||||
bitmap def_bb_moveable = bb_moveable_reg_sets + def_block->index;
|
||||
bitmap def_bb_transp = bb_transp_live + def_block->index;
|
||||
bool local_to_bb_p = bitmap_bit_p (def_bb_local, i);
|
||||
rtx use_insn = closest_uses[i];
|
||||
df_ref *def_insn_use_rec = DF_INSN_USES (def_insn);
|
||||
bool all_ok = true;
|
||||
bool all_transp = true;
|
||||
|
||||
if (!REG_P (DF_REF_REG (def)))
|
||||
continue;
|
||||
|
||||
if (!local_to_bb_p)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Reg %u not local to one basic block\n",
|
||||
i);
|
||||
continue;
|
||||
}
|
||||
if (reg_equiv_init (i) != NULL_RTX)
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Ignoring reg %u with equiv init insn\n",
|
||||
i);
|
||||
continue;
|
||||
}
|
||||
if (!rtx_moveable_p (&PATTERN (def_insn), OP_IN))
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Found def insn %d for %d to be not moveable\n",
|
||||
INSN_UID (def_insn), i);
|
||||
continue;
|
||||
}
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "Examining insn %d, def for %d\n",
|
||||
INSN_UID (def_insn), i);
|
||||
while (*def_insn_use_rec != NULL)
|
||||
{
|
||||
df_ref use = *def_insn_use_rec;
|
||||
unsigned regno = DF_REF_REGNO (use);
|
||||
if (bitmap_bit_p (&unusable_as_input, regno))
|
||||
{
|
||||
all_ok = false;
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " found unusable input reg %u.\n", regno);
|
||||
break;
|
||||
}
|
||||
if (!bitmap_bit_p (def_bb_transp, regno))
|
||||
{
|
||||
if (bitmap_bit_p (def_bb_moveable, regno)
|
||||
&& !control_flow_insn_p (use_insn)
|
||||
#ifdef HAVE_cc0
|
||||
&& !sets_cc0_p (use_insn)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (modified_between_p (DF_REF_REG (use), def_insn, use_insn))
|
||||
{
|
||||
rtx x = NEXT_INSN (def_insn);
|
||||
while (!modified_in_p (DF_REF_REG (use), x))
|
||||
{
|
||||
gcc_assert (x != use_insn);
|
||||
x = NEXT_INSN (x);
|
||||
}
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " input reg %u modified but insn %d moveable\n",
|
||||
regno, INSN_UID (x));
|
||||
emit_insn_after (PATTERN (x), use_insn);
|
||||
set_insn_deleted (x);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " input reg %u modified between def and use\n",
|
||||
regno);
|
||||
all_transp = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
all_transp = false;
|
||||
}
|
||||
|
||||
def_insn_use_rec++;
|
||||
}
|
||||
if (!all_ok)
|
||||
continue;
|
||||
if (!dbg_cnt (ira_move))
|
||||
break;
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " all ok%s\n", all_transp ? " and transp" : "");
|
||||
|
||||
if (all_transp)
|
||||
{
|
||||
rtx def_reg = DF_REF_REG (def);
|
||||
rtx newreg = ira_create_new_reg (def_reg);
|
||||
if (validate_change (def_insn, DF_REF_LOC (def), newreg, 0))
|
||||
{
|
||||
unsigned nregno = REGNO (newreg);
|
||||
rtx move = emit_insn_before (gen_move_insn (def_reg, newreg),
|
||||
use_insn);
|
||||
nregno -= max_regs;
|
||||
VEC_replace (rtx, pseudo_move_insn, nregno, move);
|
||||
VEC_replace (rtx, pseudo_replaced_reg, nregno, def_reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOR_EACH_BB (bb)
|
||||
{
|
||||
bitmap_clear (bb_local + bb->index);
|
||||
bitmap_clear (bb_transp_live + bb->index);
|
||||
bitmap_clear (bb_moveable_reg_sets + bb->index);
|
||||
}
|
||||
bitmap_clear (&interesting);
|
||||
bitmap_clear (&unusable_as_input);
|
||||
free (uid_luid);
|
||||
free (closest_uses);
|
||||
free (bb_local);
|
||||
free (bb_transp_live);
|
||||
free (bb_moveable_reg_sets);
|
||||
|
||||
last_moveable_pseudo = max_reg_num ();
|
||||
|
||||
fix_reg_equiv_init();
|
||||
regstat_free_n_sets_and_refs ();
|
||||
regstat_free_ri ();
|
||||
regstat_init_n_sets_and_refs ();
|
||||
regstat_compute_ri ();
|
||||
free_dominance_info (CDI_DOMINATORS);
|
||||
}
|
||||
|
||||
/* Perform the second half of the transformation started in
|
||||
find_moveable_pseudos. We look for instances where the newly introduced
|
||||
pseudo remains unallocated, and remove it by moving the definition to
|
||||
just before its use, replacing the move instruction generated by
|
||||
find_moveable_pseudos. */
|
||||
static void
|
||||
move_unallocated_pseudos (void)
|
||||
{
|
||||
int i;
|
||||
for (i = first_moveable_pseudo; i < last_moveable_pseudo; i++)
|
||||
if (reg_renumber[i] < 0)
|
||||
{
|
||||
df_ref def = DF_REG_DEF_CHAIN (i);
|
||||
int idx = i - first_moveable_pseudo;
|
||||
rtx other_reg = VEC_index (rtx, pseudo_replaced_reg, idx);
|
||||
rtx def_insn = DF_REF_INSN (def);
|
||||
rtx move_insn = VEC_index (rtx, pseudo_move_insn, idx);
|
||||
rtx set;
|
||||
rtx newinsn = emit_insn_after (PATTERN (def_insn), move_insn);
|
||||
int success;
|
||||
|
||||
if (dump_file)
|
||||
fprintf (dump_file, "moving def of %d (insn %d now) ",
|
||||
REGNO (other_reg), INSN_UID (def_insn));
|
||||
|
||||
set = single_set (newinsn);
|
||||
success = validate_change (newinsn, &SET_DEST (set), other_reg, 0);
|
||||
gcc_assert (success);
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " %d) rather than keep unallocated replacement %d\n",
|
||||
INSN_UID (newinsn), i);
|
||||
delete_insn (move_insn);
|
||||
delete_insn (def_insn);
|
||||
SET_REG_N_REFS (i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* All natural loops. */
|
||||
|
@ -3606,6 +4120,8 @@ ira (FILE *f)
|
|||
}
|
||||
}
|
||||
|
||||
find_moveable_pseudos ();
|
||||
|
||||
max_regno_before_ira = allocated_reg_info_size = max_reg_num ();
|
||||
ira_setup_eliminable_regset ();
|
||||
|
||||
|
@ -3716,6 +4232,7 @@ ira (FILE *f)
|
|||
max_regno * sizeof (struct ira_spilled_reg_stack_slot));
|
||||
}
|
||||
allocate_initial_values (reg_equivs);
|
||||
move_unallocated_pseudos ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue