/* Integrated Register Allocator (IRA) entry point.
- Copyright (C) 2006-2014 Free Software Foundation, Inc.
+ Copyright (C) 2006-2015 Free Software Foundation, Inc.
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
This file is part of GCC.
calculates its initial (non-accumulated) cost of memory and
each hard-register of its allocno class (file ira-cost.c).
- * IRA creates live ranges of each allocno, calulates register
+ * IRA creates live ranges of each allocno, calculates register
pressure for each pressure class in each region, sets up
conflict hard registers for each allocno and info about calls
the allocno lives through (file ira-lives.c).
hard-register for allocnos conflicting with given allocno.
* Chaitin-Briggs coloring assigns as many pseudos as possible
- to hard registers. After coloringh we try to improve
+ to hard registers. After coloring we try to improve
allocation with cost point of view. We improve the
allocation by spilling some allocnos and assigning the freed
hard registers to other allocnos if it decreases the overall
rebuilding would be, but is much faster.
o After IR flattening, IRA tries to assign hard registers to all
- spilled allocnos. This is impelemented by a simple and fast
+ spilled allocnos. This is implemented by a simple and fast
priority coloring algorithm (see function
ira_reassign_conflict_allocnos::ira-color.c). Here new allocnos
created during the code change pass can be assigned to hard
in places where the pseudo-register lives.
IRA uses a lot of data representing the target processors. These
- data are initilized in file ira.c.
+ data are initialized in file ira.c.
If function has no loops (or the loops are ignored when
-fira-algorithm=CB is used), we have classic Chaitin-Briggs
#include "coretypes.h"
#include "tm.h"
#include "regs.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "tm_p.h"
#include "target.h"
#include "flags.h"
#include "obstack.h"
#include "bitmap.h"
-#include "hard-reg-set.h"
+#include "predict.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
#include "basic-block.h"
#include "df.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
#include "recog.h"
#include "params.h"
#include "except.h"
#include "reload.h"
#include "diagnostic-core.h"
-#include "function.h"
-#include "ggc.h"
#include "ira-int.h"
#include "lra.h"
#include "dce.h"
the allocnos assigned to memory, cost of loads, stores and register
move insns generated for pseudo-register live range splitting (see
ira-emit.c). */
-int ira_overall_cost, overall_cost_before;
-int ira_reg_cost, ira_mem_cost;
-int ira_load_cost, ira_store_cost, ira_shuffle_cost;
+int64_t ira_overall_cost, overall_cost_before;
+int64_t ira_reg_cost, ira_mem_cost;
+int64_t ira_load_cost, ira_store_cost, ira_shuffle_cost;
int ira_move_loops_num, ira_additional_jumps_num;
/* All registers that can be eliminated. */
{
ira_max_memory_move_cost[mode][cl][0]
= ira_memory_move_cost[mode][cl][0]
- = memory_move_cost ((enum machine_mode) mode,
+ = memory_move_cost ((machine_mode) mode,
(reg_class_t) cl, false);
ira_max_memory_move_cost[mode][cl][1]
= ira_memory_move_cost[mode][cl][1]
- = memory_move_cost ((enum machine_mode) mode,
+ = memory_move_cost ((machine_mode) mode,
(reg_class_t) cl, true);
/* Costs for NO_REGS are used in cost calculation on the
1st pass when the preferred register classes are not
ira_prohibited_class_mode_regs[cl][m]);
if (hard_reg_set_empty_p (temp_hard_regset))
continue;
- ira_init_register_move_cost_if_necessary ((enum machine_mode) m);
+ ira_init_register_move_cost_if_necessary ((machine_mode) m);
cost = ira_register_move_cost[m][cl][cl];
if (cost <= ira_max_memory_move_cost[m][cl][1]
|| cost <= ira_max_memory_move_cost[m][cl][0])
IOR_HARD_REG_SET (temp_hard_regset, reg_class_contents[cl]);
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- /* Some targets (like SPARC with ICC reg) have alocatable regs
+ /* Some targets (like SPARC with ICC reg) have allocatable regs
for which no reg class is defined. */
if (REGNO_REG_CLASS (i) == NO_REGS)
SET_HARD_REG_BIT (ignore_hard_regs, i);
for (m = 0; m < NUM_MACHINE_MODES; m++)
if (contains_reg_of_mode[cl][m] && contains_reg_of_mode[cl2][m])
{
- ira_init_register_move_cost_if_necessary ((enum machine_mode) m);
+ ira_init_register_move_cost_if_necessary ((machine_mode) m);
if (ira_register_move_cost[m][cl][cl]
!= ira_register_move_cost[m][cl2][cl2])
break;
/* Set up IRA_ALLOCNO_CLASSES, IRA_ALLOCNO_CLASSES_NUM,
IRA_IMPORTANT_CLASSES, and IRA_IMPORTANT_CLASSES_NUM.
- Target may have many subtargets and not all target hard regiters can
+ Target may have many subtargets and not all target hard registers can
be used for allocation, e.g. x86 port in 32-bit mode can not use
hard registers introduced in x86-64 like r8-r15). Some classes
might have the same allocatable hard registers, e.g. INDEX_REGS
classes[n] = LIM_REG_CLASSES;
/* Set up classes which can be used for allocnos as classes
- conatining non-empty unique sets of allocatable hard
+ containing non-empty unique sets of allocatable hard
registers. */
ira_allocno_classes_num = 0;
for (i = 0; (cl = classes[i]) != LIM_REG_CLASSES; i++)
if (important_class_p[cl3]
&& hard_reg_set_subset_p (temp_hard_regset, union_set))
{
- /* CL3 allocatbale hard register set is inside of
+ /* CL3 allocatable hard register set is inside of
union of allocatable hard register sets of CL1
and CL2. */
COPY_HARD_REG_SET
}
}
-/* Output all unifrom and important classes into file F. */
+/* Output all uniform and important classes into file F. */
static void
print_unform_and_important_classes (FILE *f)
{
for (cl = 0; cl < N_REG_CLASSES; cl++)
ira_reg_class_max_nregs[cl][m]
= ira_reg_class_min_nregs[cl][m]
- = targetm.class_max_nregs ((reg_class_t) cl, (enum machine_mode) m);
+ = targetm.class_max_nregs ((reg_class_t) cl, (machine_mode) m);
for (cl = 0; cl < N_REG_CLASSES; cl++)
for (i = 0;
(cl2 = alloc_reg_class_subclasses[cl][i]) != LIM_REG_CLASSES;
for (k = ira_class_hard_regs_num[cl] - 1; k >= 0; k--)
{
hard_regno = ira_class_hard_regs[cl][k];
- if (! HARD_REGNO_MODE_OK (hard_regno, (enum machine_mode) j))
+ if (! HARD_REGNO_MODE_OK (hard_regno, (machine_mode) j))
SET_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
hard_regno);
else if (in_hard_reg_set_p (temp_hard_regset,
- (enum machine_mode) j, hard_regno))
+ (machine_mode) j, hard_regno))
{
last_hard_regno = hard_regno;
count++;
if (!TEST_HARD_REG_BIT (ira_prohibited_class_mode_regs[cl][j],
hard_regno))
add_to_hard_reg_set (&ira_useful_class_mode_regs[cl][j],
- (enum machine_mode) j, hard_regno);
+ (machine_mode) j, hard_regno);
}
}
}
/* Allocate and initialize IRA_REGISTER_MOVE_COST, IRA_MAY_MOVE_IN_COST
and IRA_MAY_MOVE_OUT_COST for MODE. */
void
-ira_init_register_move_cost (enum machine_mode mode)
+ira_init_register_move_cost (machine_mode mode)
{
static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES];
bool all_match = true;
if (ira_prohibited_mode_move_regs_initialized_p)
return;
ira_prohibited_mode_move_regs_initialized_p = true;
- test_reg1 = gen_rtx_REG (VOIDmode, 0);
- test_reg2 = gen_rtx_REG (VOIDmode, 0);
- move_pat = gen_rtx_SET (VOIDmode, test_reg1, test_reg2);
+ test_reg1 = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
+ test_reg2 = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 2);
+ move_pat = gen_rtx_SET (test_reg1, test_reg2);
move_insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, move_pat, 0, -1, 0);
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
SET_HARD_REG_SET (ira_prohibited_mode_move_regs[i]);
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
{
- if (! HARD_REGNO_MODE_OK (j, (enum machine_mode) i))
+ if (! HARD_REGNO_MODE_OK (j, (machine_mode) i))
continue;
- SET_REGNO_RAW (test_reg1, j);
- PUT_MODE (test_reg1, (enum machine_mode) i);
- SET_REGNO_RAW (test_reg2, j);
- PUT_MODE (test_reg2, (enum machine_mode) i);
+ set_mode_and_regno (test_reg1, (machine_mode) i, j);
+ set_mode_and_regno (test_reg2, (machine_mode) i, j);
INSN_CODE (move_insn) = -1;
recog_memoized (move_insn);
if (INSN_CODE (move_insn) < 0)
continue;
extract_insn (move_insn);
- if (! constrain_operands (1))
+ /* We don't know whether the move will be in code that is optimized
+ for size or speed, so consider all enabled alternatives. */
+ if (! constrain_operands (1, get_enabled_alternatives (move_insn)))
continue;
CLEAR_HARD_REG_BIT (ira_prohibited_mode_move_regs[i], j);
}
int nop, nalt;
bool curr_swapped;
const char *p;
- rtx op;
int commutative = -1;
extract_insn (insn);
+ alternative_mask preferred = get_preferred_alternatives (insn);
CLEAR_HARD_REG_SET (alts);
insn_constraints.release ();
insn_constraints.safe_grow_cleared (recog_data.n_operands
}
for (nalt = 0; nalt < recog_data.n_alternatives; nalt++)
{
- if (!TEST_BIT (recog_data.enabled_alternatives, nalt)
+ if (!TEST_BIT (preferred, nalt)
|| TEST_HARD_REG_BIT (alts, nalt))
continue;
{
int c, len;
- op = recog_data.operand[nop];
+ rtx op = recog_data.operand[nop];
p = insn_constraints[nop * recog_data.n_alternatives + nalt];
if (*p == 0 || *p == ',')
continue;
break;
if (curr_swapped)
break;
- op = recog_data.operand[commutative];
- recog_data.operand[commutative] = recog_data.operand[commutative + 1];
- recog_data.operand[commutative + 1] = op;
-
+ std::swap (recog_data.operand[commutative],
+ recog_data.operand[commutative + 1]);
}
}
{
basic_block bb;
rtx_insn *insn;
- rtx set, src, dest, dest_death, q, note;
- rtx_insn *p;
+ rtx set, src, dest, dest_death, note;
+ rtx_insn *p, *q;
int sregno, dregno;
if (! flag_expensive_optimizations)
else
df_set_regs_ever_live (eliminables[i].from, true);
}
-#if !HARD_FRAME_POINTER_IS_FRAME_POINTER
- if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM))
+ if (!HARD_FRAME_POINTER_IS_FRAME_POINTER)
{
- SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
- if (frame_pointer_needed)
- SET_HARD_REG_BIT (ira_no_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+ if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM))
+ {
+ SET_HARD_REG_BIT (eliminable_regset, HARD_FRAME_POINTER_REGNUM);
+ if (frame_pointer_needed)
+ SET_HARD_REG_BIT (ira_no_alloc_regs, HARD_FRAME_POINTER_REGNUM);
+ }
+ else if (frame_pointer_needed)
+ error ("%s cannot be used in asm here",
+ reg_names[HARD_FRAME_POINTER_REGNUM]);
+ else
+ df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM, true);
}
- else if (frame_pointer_needed)
- error ("%s cannot be used in asm here",
- reg_names[HARD_FRAME_POINTER_REGNUM]);
- else
- df_set_regs_ever_live (HARD_FRAME_POINTER_REGNUM, true);
-#endif
#else
if (!TEST_HARD_REG_BIT (crtl->asm_clobbers, HARD_FRAME_POINTER_REGNUM))
if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL)
{
fprintf (ira_dump_file,
- "+++Costs: overall %d, reg %d, mem %d, ld %d, st %d, move %d\n",
+ "+++Costs: overall %" PRId64
+ ", reg %" PRId64
+ ", mem %" PRId64
+ ", ld %" PRId64
+ ", st %" PRId64
+ ", move %" PRId64,
ira_overall_cost, ira_reg_cost, ira_mem_cost,
ira_load_cost, ira_store_cost, ira_shuffle_cost);
- fprintf (ira_dump_file, "+++ move loops %d, new jumps %d\n",
+ fprintf (ira_dump_file, "\n+++ move loops %d, new jumps %d\n",
ira_move_loops_num, ira_additional_jumps_num);
}
{
int max_regno = max_reg_num ();
int i, new_regno, max;
- rtx x, prev, next, insn, set;
+ rtx set;
+ rtx_insn_list *x, *next, *prev;
+ rtx_insn *insn;
if (max_regno_before_ira < max_regno)
{
max = vec_safe_length (reg_equivs);
grow_reg_equivs ();
for (i = FIRST_PSEUDO_REGISTER; i < max; i++)
- for (prev = NULL_RTX, x = reg_equiv_init (i);
+ for (prev = NULL, x = reg_equiv_init (i);
x != NULL_RTX;
x = next)
{
- next = XEXP (x, 1);
- insn = XEXP (x, 0);
- set = single_set (as_a <rtx_insn *> (insn));
+ next = x->next ();
+ insn = x->insn ();
+ set = single_set (insn);
ira_assert (set != NULL_RTX
&& (REG_P (SET_DEST (set)) || REG_P (SET_SRC (set))));
if (REG_P (SET_DEST (set))
}
\f
-/* The number of entries allocated in teg_info. */
+/* The number of entries allocated in reg_info. */
static int allocated_reg_info_size;
/* Regional allocation can create new pseudo-registers. This function
init_alias_analysis ();
/* Scan insns and set pdx_subregs[regno] if the reg is used in a
- paradoxical subreg. Don't set such reg sequivalent to a mem,
+ paradoxical subreg. Don't set such reg equivalent to a mem,
because lra will not substitute such equiv memory in order to
prevent access beyond allocated memory for paradoxical memory subreg. */
FOR_EACH_BB_FN (bb, cfun)
}
else if (function_invariant_p (x))
{
- enum machine_mode mode;
+ machine_mode mode;
mode = GET_MODE (SET_DEST (set));
if (GET_CODE (x) == PLUS
case CLOBBER:
return rtx_moveable_p (&SET_DEST (x), OP_OUT);
+ case UNSPEC_VOLATILE:
+ /* It is a bad idea to consider insns with with such rtl
+ as moveable ones. The insn scheduler also considers them as barrier
+ for a reason. */
+ return false;
+
default:
break;
}
df_ref def, use;
unsigned regno;
bool all_dominated, all_local;
- enum machine_mode mode;
+ machine_mode mode;
def = df_single_def (insn_info);
/* There must be exactly one def in this insn. */
? " (no unique first use)" : "");
continue;
}
-#ifdef HAVE_cc0
- if (reg_referenced_p (cc0_rtx, PATTERN (closest_use)))
+ if (HAVE_cc0 && 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);
/* If we get here, we know closest_use is a non-NULL insn
(as opposed to const_0_rtx). */
{
if (bitmap_bit_p (def_bb_moveable, regno)
&& !control_flow_insn_p (use_insn)
-#ifdef HAVE_cc0
- && !sets_cc0_p (use_insn)
-#endif
- )
+ && (!HAVE_cc0 || !sets_cc0_p (use_insn)))
{
if (modified_between_p (DF_REF_REG (use), def_insn, use_insn))
{
return dest;
}
-/* If insn is interesting for parameter range-splitting shring-wrapping
+/* If insn is interesting for parameter range-splitting shrink-wrapping
preparation, i.e. it is a single set from a hard register to a pseudo, which
is live at CALL_DOM (if non-NULL, otherwise this check is omitted), or a
parallel statement with only one such statement, return the destination.
if (newreg)
{
- rtx new_move = gen_move_insn (newreg, dest);
+ rtx_insn *new_move = gen_move_insn (newreg, dest);
emit_insn_after (new_move, bb_note (call_dom));
if (dump_file)
{
ira_allocno_iterator ai;
FOR_EACH_ALLOCNO (a, ai)
- ALLOCNO_REGNO (a) = REGNO (ALLOCNO_EMIT_DATA (a)->reg);
+ {
+ int old_regno = ALLOCNO_REGNO (a);
+ int new_regno = REGNO (ALLOCNO_EMIT_DATA (a)->reg);
+
+ ALLOCNO_REGNO (a) = new_regno;
+
+ if (old_regno != new_regno)
+ setup_reg_classes (new_regno, reg_preferred_class (old_regno),
+ reg_alternate_class (old_regno),
+ reg_allocno_class (old_regno));
+ }
+
}
else
{
if (internal_flag_ira_verbose > 0 && ira_dump_file != NULL
&& overall_cost_before != ira_overall_cost)
- fprintf (ira_dump_file, "+++Overall after reload %d\n", ira_overall_cost);
+ fprintf (ira_dump_file, "+++Overall after reload %" PRId64 "\n",
+ ira_overall_cost);
flag_ira_share_spill_slots = saved_flag_ira_share_spill_slots;
{}
/* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return !targetm.no_register_allocation;
+ }
virtual unsigned int execute (function *)
{
ira (dump_file);
{}
/* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return !targetm.no_register_allocation;
+ }
virtual unsigned int execute (function *)
{
do_reload ();