/* IRA hard register and memory cost calculation for allocnos or pseudos.
- Copyright (C) 2006, 2007, 2008, 2009
- 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.
#include "tm.h"
#include "hard-reg-set.h"
#include "rtl.h"
+#include "symtab.h"
+#include "function.h"
+#include "flags.h"
+#include "alias.h"
+#include "tree.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 "tm_p.h"
-#include "flags.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
#include "basic-block.h"
#include "regs.h"
#include "addresses.h"
-#include "insn-config.h"
#include "recog.h"
#include "reload.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
#include "target.h"
#include "params.h"
#include "ira-int.h"
/* TRUE if we work with allocnos. Otherwise we work with pseudos. */
static bool allocno_p;
-/* Number of elements in arrays `in_inc_dec' and `costs'. */
+/* Number of elements in array `costs'. */
static int cost_elements_num;
-#ifdef FORBIDDEN_INC_DEC_CLASSES
-/* Indexed by n, is TRUE if allocno or pseudo with number N is used in
- an auto-inc or auto-dec context. */
-static bool *in_inc_dec;
-#endif
-
/* The `costs' struct records the cost of using hard registers of each
class considered for the calculation and of using memory for each
allocno or pseudo. */
{
int mem_cost;
/* Costs for register classes start here. We process only some
- register classes (cover classes on the 1st cost calculation
- iteration and important classes on the 2nd iteration). */
+ allocno classes. */
int cost[1];
};
-/* Initialized once. It is a maximal possible size of the allocated
- struct costs. */
-static int max_struct_costs_size;
-
-/* Allocated and initialized once, and used to initialize cost values
- for each insn. */
-static struct costs *init_cost;
-
-/* Allocated once, and used for temporary purposes. */
-static struct costs *temp_costs;
-
-/* Allocated once, and used for the cost calculation. */
-static struct costs *op_costs[MAX_RECOG_OPERANDS];
-static struct costs *this_op_costs[MAX_RECOG_OPERANDS];
+#define max_struct_costs_size \
+ (this_target_ira_int->x_max_struct_costs_size)
+#define init_cost \
+ (this_target_ira_int->x_init_cost)
+#define temp_costs \
+ (this_target_ira_int->x_temp_costs)
+#define op_costs \
+ (this_target_ira_int->x_op_costs)
+#define this_op_costs \
+ (this_target_ira_int->x_this_op_costs)
/* Costs of each class for each allocno or pseudo. */
static struct costs *costs;
/* Accumulated costs of each class for each allocno. */
static struct costs *total_allocno_costs;
-/* Classes used for cost calculation. They may be different on
- different iterations of the cost calculations or in different
- optimization modes. */
-static enum reg_class *cost_classes;
-
-/* The size of the previous array. */
-static int cost_classes_num;
-
-/* Map: cost class -> order number (they start with 0) of the cost
- class. The order number is negative for non-cost classes. */
-static int cost_class_nums[N_REG_CLASSES];
-
/* It is the current size of struct costs. */
static int struct_costs_size;
((struct costs *) ((char *) (arr) + (num) * struct_costs_size))
/* Return index in COSTS when processing reg with REGNO. */
-#define COST_INDEX(regno) (allocno_p \
- ? ALLOCNO_NUM (ira_curr_regno_allocno_map[regno]) \
+#define COST_INDEX(regno) (allocno_p \
+ ? ALLOCNO_NUM (ira_curr_regno_allocno_map[regno]) \
: (int) regno)
/* Record register class preferences of each allocno or pseudo. Null
/* Allocated buffers for pref. */
static enum reg_class *pref_buffer;
-/* Record cover register class of each allocno with the same regno. */
-static enum reg_class *regno_cover_class;
+/* Record allocno class of each allocno with the same regno. */
+static enum reg_class *regno_aclass;
/* Record cost gains for not allocating a register with an invariant
equivalence. */
\f
+/* Info about reg classes whose costs are calculated for a pseudo. */
+struct cost_classes
+{
+ /* Number of the cost classes in the subsequent array. */
+ int num;
+ /* Container of the cost classes. */
+ enum reg_class classes[N_REG_CLASSES];
+ /* Map reg class -> index of the reg class in the previous array.
+ -1 if it is not a cost class. */
+ int index[N_REG_CLASSES];
+ /* Map hard regno index of first class in array CLASSES containing
+ the hard regno, -1 otherwise. */
+ int hard_regno_index[FIRST_PSEUDO_REGISTER];
+};
+
+/* Types of pointers to the structure above. */
+typedef struct cost_classes *cost_classes_t;
+typedef const struct cost_classes *const_cost_classes_t;
+
+/* Info about cost classes for each pseudo. */
+static cost_classes_t *regno_cost_classes;
+
+/* Helper for cost_classes hashing. */
+
+struct cost_classes_hasher : pointer_hash <cost_classes>
+{
+ static inline hashval_t hash (const cost_classes *);
+ static inline bool equal (const cost_classes *, const cost_classes *);
+ static inline void remove (cost_classes *);
+};
+
+/* Returns hash value for cost classes info HV. */
+inline hashval_t
+cost_classes_hasher::hash (const cost_classes *hv)
+{
+ return iterative_hash (&hv->classes, sizeof (enum reg_class) * hv->num, 0);
+}
+
+/* Compares cost classes info HV1 and HV2. */
+inline bool
+cost_classes_hasher::equal (const cost_classes *hv1, const cost_classes *hv2)
+{
+ return (hv1->num == hv2->num
+ && memcmp (hv1->classes, hv2->classes,
+ sizeof (enum reg_class) * hv1->num) == 0);
+}
+
+/* Delete cost classes info V from the hash table. */
+inline void
+cost_classes_hasher::remove (cost_classes *v)
+{
+ ira_free (v);
+}
+
+/* Hash table of unique cost classes. */
+static hash_table<cost_classes_hasher> *cost_classes_htab;
+
+/* Map allocno class -> cost classes for pseudo of given allocno
+ class. */
+static cost_classes_t cost_classes_aclass_cache[N_REG_CLASSES];
+
+/* Map mode -> cost classes for pseudo of give mode. */
+static cost_classes_t cost_classes_mode_cache[MAX_MACHINE_MODE];
+
+/* Cost classes that include all classes in ira_important_classes. */
+static cost_classes all_cost_classes;
+
+/* Use the array of classes in CLASSES_PTR to fill out the rest of
+ the structure. */
+static void
+complete_cost_classes (cost_classes_t classes_ptr)
+{
+ for (int i = 0; i < N_REG_CLASSES; i++)
+ classes_ptr->index[i] = -1;
+ for (int i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ classes_ptr->hard_regno_index[i] = -1;
+ for (int i = 0; i < classes_ptr->num; i++)
+ {
+ enum reg_class cl = classes_ptr->classes[i];
+ classes_ptr->index[cl] = i;
+ for (int j = ira_class_hard_regs_num[cl] - 1; j >= 0; j--)
+ {
+ unsigned int hard_regno = ira_class_hard_regs[cl][j];
+ if (classes_ptr->hard_regno_index[hard_regno] < 0)
+ classes_ptr->hard_regno_index[hard_regno] = i;
+ }
+ }
+}
+
+/* Initialize info about the cost classes for each pseudo. */
+static void
+initiate_regno_cost_classes (void)
+{
+ int size = sizeof (cost_classes_t) * max_reg_num ();
+
+ regno_cost_classes = (cost_classes_t *) ira_allocate (size);
+ memset (regno_cost_classes, 0, size);
+ memset (cost_classes_aclass_cache, 0,
+ sizeof (cost_classes_t) * N_REG_CLASSES);
+ memset (cost_classes_mode_cache, 0,
+ sizeof (cost_classes_t) * MAX_MACHINE_MODE);
+ cost_classes_htab = new hash_table<cost_classes_hasher> (200);
+ all_cost_classes.num = ira_important_classes_num;
+ for (int i = 0; i < ira_important_classes_num; i++)
+ all_cost_classes.classes[i] = ira_important_classes[i];
+ complete_cost_classes (&all_cost_classes);
+}
+
+/* Create new cost classes from cost classes FROM and set up members
+ index and hard_regno_index. Return the new classes. The function
+ implements some common code of two functions
+ setup_regno_cost_classes_by_aclass and
+ setup_regno_cost_classes_by_mode. */
+static cost_classes_t
+setup_cost_classes (cost_classes_t from)
+{
+ cost_classes_t classes_ptr;
+
+ classes_ptr = (cost_classes_t) ira_allocate (sizeof (struct cost_classes));
+ classes_ptr->num = from->num;
+ for (int i = 0; i < from->num; i++)
+ classes_ptr->classes[i] = from->classes[i];
+ complete_cost_classes (classes_ptr);
+ return classes_ptr;
+}
+
+/* Return a version of FULL that only considers registers in REGS that are
+ valid for mode MODE. Both FULL and the returned class are globally
+ allocated. */
+static cost_classes_t
+restrict_cost_classes (cost_classes_t full, machine_mode mode,
+ const HARD_REG_SET ®s)
+{
+ static struct cost_classes narrow;
+ int map[N_REG_CLASSES];
+ narrow.num = 0;
+ for (int i = 0; i < full->num; i++)
+ {
+ /* Assume that we'll drop the class. */
+ map[i] = -1;
+
+ /* Ignore classes that are too small for the mode. */
+ enum reg_class cl = full->classes[i];
+ if (!contains_reg_of_mode[cl][mode])
+ continue;
+
+ /* Calculate the set of registers in CL that belong to REGS and
+ are valid for MODE. */
+ HARD_REG_SET valid_for_cl;
+ COPY_HARD_REG_SET (valid_for_cl, reg_class_contents[cl]);
+ AND_HARD_REG_SET (valid_for_cl, regs);
+ AND_COMPL_HARD_REG_SET (valid_for_cl,
+ ira_prohibited_class_mode_regs[cl][mode]);
+ AND_COMPL_HARD_REG_SET (valid_for_cl, ira_no_alloc_regs);
+ if (hard_reg_set_empty_p (valid_for_cl))
+ continue;
+
+ /* Don't use this class if the set of valid registers is a subset
+ of an existing class. For example, suppose we have two classes
+ GR_REGS and FR_REGS and a union class GR_AND_FR_REGS. Suppose
+ that the mode changes allowed by FR_REGS are not as general as
+ the mode changes allowed by GR_REGS.
+
+ In this situation, the mode changes for GR_AND_FR_REGS could
+ either be seen as the union or the intersection of the mode
+ changes allowed by the two subclasses. The justification for
+ the union-based definition would be that, if you want a mode
+ change that's only allowed by GR_REGS, you can pick a register
+ from the GR_REGS subclass. The justification for the
+ intersection-based definition would be that every register
+ from the class would allow the mode change.
+
+ However, if we have a register that needs to be in GR_REGS,
+ using GR_AND_FR_REGS with the intersection-based definition
+ would be too pessimistic, since it would bring in restrictions
+ that only apply to FR_REGS. Conversely, if we have a register
+ that needs to be in FR_REGS, using GR_AND_FR_REGS with the
+ union-based definition would lose the extra restrictions
+ placed on FR_REGS. GR_AND_FR_REGS is therefore only useful
+ for cases where GR_REGS and FP_REGS are both valid. */
+ int pos;
+ for (pos = 0; pos < narrow.num; ++pos)
+ {
+ enum reg_class cl2 = narrow.classes[pos];
+ if (hard_reg_set_subset_p (valid_for_cl, reg_class_contents[cl2]))
+ break;
+ }
+ map[i] = pos;
+ if (pos == narrow.num)
+ {
+ /* If several classes are equivalent, prefer to use the one
+ that was chosen as the allocno class. */
+ enum reg_class cl2 = ira_allocno_class_translate[cl];
+ if (ira_class_hard_regs_num[cl] == ira_class_hard_regs_num[cl2])
+ cl = cl2;
+ narrow.classes[narrow.num++] = cl;
+ }
+ }
+ if (narrow.num == full->num)
+ return full;
+
+ cost_classes **slot = cost_classes_htab->find_slot (&narrow, INSERT);
+ if (*slot == NULL)
+ {
+ cost_classes_t classes = setup_cost_classes (&narrow);
+ /* Map equivalent classes to the representative that we chose above. */
+ for (int i = 0; i < ira_important_classes_num; i++)
+ {
+ enum reg_class cl = ira_important_classes[i];
+ int index = full->index[cl];
+ if (index >= 0)
+ classes->index[cl] = map[index];
+ }
+ *slot = classes;
+ }
+ return *slot;
+}
+
+/* Setup cost classes for pseudo REGNO whose allocno class is ACLASS.
+ This function is used when we know an initial approximation of
+ allocno class of the pseudo already, e.g. on the second iteration
+ of class cost calculation or after class cost calculation in
+ register-pressure sensitive insn scheduling or register-pressure
+ sensitive loop-invariant motion. */
+static void
+setup_regno_cost_classes_by_aclass (int regno, enum reg_class aclass)
+{
+ static struct cost_classes classes;
+ cost_classes_t classes_ptr;
+ enum reg_class cl;
+ int i;
+ cost_classes **slot;
+ HARD_REG_SET temp, temp2;
+ bool exclude_p;
+
+ if ((classes_ptr = cost_classes_aclass_cache[aclass]) == NULL)
+ {
+ COPY_HARD_REG_SET (temp, reg_class_contents[aclass]);
+ AND_COMPL_HARD_REG_SET (temp, ira_no_alloc_regs);
+ /* We exclude classes from consideration which are subsets of
+ ACLASS only if ACLASS is an uniform class. */
+ exclude_p = ira_uniform_class_p[aclass];
+ classes.num = 0;
+ for (i = 0; i < ira_important_classes_num; i++)
+ {
+ cl = ira_important_classes[i];
+ if (exclude_p)
+ {
+ /* Exclude non-uniform classes which are subsets of
+ ACLASS. */
+ COPY_HARD_REG_SET (temp2, reg_class_contents[cl]);
+ AND_COMPL_HARD_REG_SET (temp2, ira_no_alloc_regs);
+ if (hard_reg_set_subset_p (temp2, temp) && cl != aclass)
+ continue;
+ }
+ classes.classes[classes.num++] = cl;
+ }
+ slot = cost_classes_htab->find_slot (&classes, INSERT);
+ if (*slot == NULL)
+ {
+ classes_ptr = setup_cost_classes (&classes);
+ *slot = classes_ptr;
+ }
+ classes_ptr = cost_classes_aclass_cache[aclass] = (cost_classes_t) *slot;
+ }
+ if (regno_reg_rtx[regno] != NULL_RTX)
+ {
+ /* Restrict the classes to those that are valid for REGNO's mode
+ (which might for example exclude singleton classes if the mode
+ requires two registers). Also restrict the classes to those that
+ are valid for subregs of REGNO. */
+ const HARD_REG_SET *valid_regs = valid_mode_changes_for_regno (regno);
+ if (!valid_regs)
+ valid_regs = ®_class_contents[ALL_REGS];
+ classes_ptr = restrict_cost_classes (classes_ptr,
+ PSEUDO_REGNO_MODE (regno),
+ *valid_regs);
+ }
+ regno_cost_classes[regno] = classes_ptr;
+}
+
+/* Setup cost classes for pseudo REGNO with MODE. Usage of MODE can
+ decrease number of cost classes for the pseudo, if hard registers
+ of some important classes can not hold a value of MODE. So the
+ pseudo can not get hard register of some important classes and cost
+ calculation for such important classes is only wasting CPU
+ time. */
+static void
+setup_regno_cost_classes_by_mode (int regno, machine_mode mode)
+{
+ if (const HARD_REG_SET *valid_regs = valid_mode_changes_for_regno (regno))
+ regno_cost_classes[regno] = restrict_cost_classes (&all_cost_classes,
+ mode, *valid_regs);
+ else
+ {
+ if (cost_classes_mode_cache[mode] == NULL)
+ cost_classes_mode_cache[mode]
+ = restrict_cost_classes (&all_cost_classes, mode,
+ reg_class_contents[ALL_REGS]);
+ regno_cost_classes[regno] = cost_classes_mode_cache[mode];
+ }
+}
+
+/* Finalize info about the cost classes for each pseudo. */
+static void
+finish_regno_cost_classes (void)
+{
+ ira_free (regno_cost_classes);
+ delete cost_classes_htab;
+ cost_classes_htab = NULL;
+}
+
+\f
+
/* Compute the cost of loading X into (if TO_P is TRUE) or from (if
TO_P is FALSE) a register of class RCLASS in mode MODE. X must not
be a pseudo register. */
static int
-copy_cost (rtx x, enum machine_mode mode, enum reg_class rclass, bool to_p,
+copy_cost (rtx x, machine_mode mode, reg_class_t rclass, bool to_p,
secondary_reload_info *prev_sri)
{
secondary_reload_info sri;
- enum reg_class secondary_class = NO_REGS;
+ reg_class_t secondary_class = NO_REGS;
/* If X is a SCRATCH, there is actually nothing to move since we are
assuming optimal allocation. */
return 0;
/* Get the class we will actually use for a reload. */
- rclass = PREFERRED_RELOAD_CLASS (x, rclass);
+ rclass = targetm.preferred_reload_class (x, rclass);
/* If we need a secondary reload for an intermediate, the cost is
that to load the input into the intermediate register, then to
if (secondary_class != NO_REGS)
{
- if (!move_cost[mode])
- init_move_cost (mode);
- return (move_cost[mode][secondary_class][rclass] + sri.extra_cost
+ ira_init_register_move_cost_if_necessary (mode);
+ return (ira_register_move_cost[mode][(int) secondary_class][(int) rclass]
+ + sri.extra_cost
+ copy_cost (x, mode, secondary_class, to_p, &sri));
}
the cost to move between the register classes, and use 2 for
everything else (constants). */
if (MEM_P (x) || rclass == NO_REGS)
- return sri.extra_cost + ira_memory_move_cost[mode][rclass][to_p != 0];
+ return sri.extra_cost
+ + ira_memory_move_cost[mode][(int) rclass][to_p != 0];
else if (REG_P (x))
{
- if (!move_cost[mode])
- init_move_cost (mode);
- return (sri.extra_cost + move_cost[mode][REGNO_REG_CLASS (REGNO (x))][rclass]);
+ reg_class_t x_class = REGNO_REG_CLASS (REGNO (x));
+
+ ira_init_register_move_cost_if_necessary (mode);
+ return (sri.extra_cost
+ + ira_register_move_cost[mode][(int) x_class][(int) rclass]);
}
else
/* If this is a constant, we may eventually want to call rtx_cost
the alternatives. */
static void
record_reg_classes (int n_alts, int n_ops, rtx *ops,
- enum machine_mode *modes, const char **constraints,
- rtx insn, struct costs **op_costs,
- enum reg_class *pref)
+ machine_mode *modes, const char **constraints,
+ rtx_insn *insn, enum reg_class *pref)
{
int alt;
int i, j, k;
- rtx set;
int insn_allows_mem[MAX_RECOG_OPERANDS];
+ move_table *move_in_cost, *move_out_cost;
+ short (*mem_cost)[2];
for (i = 0; i < n_ops; i++)
insn_allows_mem[i] = 0;
/* Process each alternative, each time minimizing an operand's cost
with the cost for each operand in that alternative. */
+ alternative_mask preferred = get_preferred_alternatives (insn);
for (alt = 0; alt < n_alts; alt++)
{
enum reg_class classes[MAX_RECOG_OPERANDS];
int alt_fail = 0;
int alt_cost = 0, op_cost_add;
- if (!recog_data.alternative_enabled_p[alt])
+ if (!TEST_BIT (preferred, alt))
{
for (i = 0; i < recog_data.n_operands; i++)
constraints[i] = skip_alternative (constraints[i]);
unsigned char c;
const char *p = constraints[i];
rtx op = ops[i];
- enum machine_mode mode = modes[i];
+ machine_mode mode = modes[i];
int allows_addr = 0;
int win = 0;
while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
p++;
- if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
+ if (p[0] >= '0' && p[0] <= '0' + i)
{
/* Copy class and whether memory is allowed from the
matching alternative. Then perform any needed cost
Moreover, if we cannot tie them, this alternative
needs to do a copy, which is one insn. */
struct costs *pp = this_op_costs[i];
-
- for (k = 0; k < cost_classes_num; k++)
+ int *pp_costs = pp->cost;
+ cost_classes_t cost_classes_ptr
+ = regno_cost_classes[REGNO (op)];
+ enum reg_class *cost_classes = cost_classes_ptr->classes;
+ bool in_p = recog_data.operand_type[i] != OP_OUT;
+ bool out_p = recog_data.operand_type[i] != OP_IN;
+ enum reg_class op_class = classes[i];
+
+ ira_init_register_move_cost_if_necessary (mode);
+ if (! in_p)
{
- rclass = cost_classes[k];
- pp->cost[k]
- = (((recog_data.operand_type[i] != OP_OUT
- ? ira_get_may_move_cost (mode, rclass,
- classes[i], true) : 0)
- + (recog_data.operand_type[i] != OP_IN
- ? ira_get_may_move_cost (mode, classes[i],
- rclass, false) : 0))
- * frequency);
+ ira_assert (out_p);
+ if (op_class == NO_REGS)
+ {
+ mem_cost = ira_memory_move_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = mem_cost[rclass][0] * frequency;
+ }
+ }
+ else
+ {
+ move_out_cost = ira_may_move_out_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k]
+ = move_out_cost[op_class][rclass] * frequency;
+ }
+ }
+ }
+ else if (! out_p)
+ {
+ ira_assert (in_p);
+ if (op_class == NO_REGS)
+ {
+ mem_cost = ira_memory_move_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = mem_cost[rclass][1] * frequency;
+ }
+ }
+ else
+ {
+ move_in_cost = ira_may_move_in_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k]
+ = move_in_cost[rclass][op_class] * frequency;
+ }
+ }
+ }
+ else
+ {
+ if (op_class == NO_REGS)
+ {
+ mem_cost = ira_memory_move_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = ((mem_cost[rclass][0]
+ + mem_cost[rclass][1])
+ * frequency);
+ }
+ }
+ else
+ {
+ move_in_cost = ira_may_move_in_cost[mode];
+ move_out_cost = ira_may_move_out_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = ((move_in_cost[rclass][op_class]
+ + move_out_cost[op_class][rclass])
+ * frequency);
+ }
+ }
}
/* If the alternative actually allows memory, make
things a bit cheaper since we won't need an extra
insn to load it. */
pp->mem_cost
- = ((recog_data.operand_type[i] != OP_IN
- ? ira_memory_move_cost[mode][classes[i]][0] : 0)
- + (recog_data.operand_type[i] != OP_OUT
- ? ira_memory_move_cost[mode][classes[i]][1] : 0)
+ = ((out_p ? ira_memory_move_cost[mode][op_class][0] : 0)
+ + (in_p ? ira_memory_move_cost[mode][op_class][1] : 0)
- allows_mem[i]) * frequency;
- /* If we have assigned a class to this allocno in our
- first pass, add a cost to this alternative
- corresponding to what we would add if this allocno
- were not in the appropriate class. We could use
- cover class here but it is less accurate
- approximation. */
+ /* If we have assigned a class to this allocno in
+ our first pass, add a cost to this alternative
+ corresponding to what we would add if this
+ allocno were not in the appropriate class. */
if (pref)
{
enum reg_class pref_class = pref[COST_INDEX (REGNO (op))];
if (pref_class == NO_REGS)
alt_cost
- += ((recog_data.operand_type[i] != OP_IN
- ? ira_memory_move_cost[mode][classes[i]][0]
- : 0)
- + (recog_data.operand_type[i] != OP_OUT
- ? ira_memory_move_cost[mode][classes[i]][1]
+ += ((out_p
+ ? ira_memory_move_cost[mode][op_class][0] : 0)
+ + (in_p
+ ? ira_memory_move_cost[mode][op_class][1]
: 0));
else if (ira_reg_class_intersect
- [pref_class][classes[i]] == NO_REGS)
- alt_cost += ira_get_register_move_cost (mode,
- pref_class,
- classes[i]);
+ [pref_class][op_class] == NO_REGS)
+ alt_cost
+ += ira_register_move_cost[mode][pref_class][op_class];
}
if (REGNO (ops[i]) != REGNO (ops[j])
&& ! find_reg_note (insn, REG_DEAD, op))
alt_cost += 2;
- /* This is in place of ordinary cost computation for
- this operand, so skip to the end of the
- alternative (should be just one character). */
- while (*p && *p++ != ',')
- ;
-
- constraints[i] = p;
- continue;
+ p++;
}
}
{
switch (c)
{
- case ',':
- break;
case '*':
/* Ignore the next letter for this pass. */
c = *++p;
break;
- case '?':
+ case '^':
alt_cost += 2;
- case '!': case '#': case '&':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- break;
-
- case 'p':
- allows_addr = 1;
- win = address_operand (op, GET_MODE (op));
- /* We know this operand is an address, so we want it
- to be allocated to a register that can be the
- base of an address, i.e. BASE_REG_CLASS. */
- classes[i]
- = ira_reg_class_union[classes[i]]
- [base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
- break;
-
- case 'm': case 'o': case 'V':
- /* It doesn't seem worth distinguishing between
- offsettable and non-offsettable addresses
- here. */
- insn_allows_mem[i] = allows_mem[i] = 1;
- if (MEM_P (op))
- win = 1;
- break;
-
- case '<':
- if (MEM_P (op)
- && (GET_CODE (XEXP (op, 0)) == PRE_DEC
- || GET_CODE (XEXP (op, 0)) == POST_DEC))
- win = 1;
break;
- case '>':
- if (MEM_P (op)
- && (GET_CODE (XEXP (op, 0)) == PRE_INC
- || GET_CODE (XEXP (op, 0)) == POST_INC))
- win = 1;
- break;
-
- case 'E':
- case 'F':
- if (GET_CODE (op) == CONST_DOUBLE
- || (GET_CODE (op) == CONST_VECTOR
- && (GET_MODE_CLASS (GET_MODE (op))
- == MODE_VECTOR_FLOAT)))
- win = 1;
- break;
-
- case 'G':
- case 'H':
- if (GET_CODE (op) == CONST_DOUBLE
- && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
- win = 1;
- break;
-
- case 's':
- if (CONST_INT_P (op)
- || (GET_CODE (op) == CONST_DOUBLE
- && GET_MODE (op) == VOIDmode))
- break;
-
- case 'i':
- if (CONSTANT_P (op)
- && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)))
- win = 1;
- break;
-
- case 'n':
- if (CONST_INT_P (op)
- || (GET_CODE (op) == CONST_DOUBLE
- && GET_MODE (op) == VOIDmode))
- win = 1;
- break;
-
- case 'I':
- case 'J':
- case 'K':
- case 'L':
- case 'M':
- case 'N':
- case 'O':
- case 'P':
- if (CONST_INT_P (op)
- && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
- win = 1;
- break;
-
- case 'X':
- win = 1;
+ case '?':
+ alt_cost += 2;
break;
case 'g':
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))))
win = 1;
insn_allows_mem[i] = allows_mem[i] = 1;
- case 'r':
- classes[i] = ira_reg_class_union[classes[i]][GENERAL_REGS];
+ classes[i] = ira_reg_class_subunion[classes[i]][GENERAL_REGS];
break;
default:
- if (REG_CLASS_FROM_CONSTRAINT (c, p) != NO_REGS)
- classes[i] = ira_reg_class_union[classes[i]]
- [REG_CLASS_FROM_CONSTRAINT (c, p)];
-#ifdef EXTRA_CONSTRAINT_STR
- else if (EXTRA_CONSTRAINT_STR (op, c, p))
- win = 1;
-
- if (EXTRA_MEMORY_CONSTRAINT (c, p))
+ enum constraint_num cn = lookup_constraint (p);
+ enum reg_class cl;
+ switch (get_constraint_type (cn))
{
+ case CT_REGISTER:
+ cl = reg_class_for_constraint (cn);
+ if (cl != NO_REGS)
+ classes[i] = ira_reg_class_subunion[classes[i]][cl];
+ break;
+
+ case CT_CONST_INT:
+ if (CONST_INT_P (op)
+ && insn_const_int_ok_for_constraint (INTVAL (op), cn))
+ win = 1;
+ break;
+
+ case CT_MEMORY:
/* Every MEM can be reloaded to fit. */
insn_allows_mem[i] = allows_mem[i] = 1;
if (MEM_P (op))
win = 1;
- }
- if (EXTRA_ADDRESS_CONSTRAINT (c, p))
- {
+ break;
+
+ case CT_ADDRESS:
/* Every address can be reloaded to fit. */
allows_addr = 1;
- if (address_operand (op, GET_MODE (op)))
+ if (address_operand (op, GET_MODE (op))
+ || constraint_satisfied_p (op, cn))
win = 1;
/* We know this operand is an address, so we
want it to be allocated to a hard register
that can be the base of an address,
i.e. BASE_REG_CLASS. */
classes[i]
- = ira_reg_class_union[classes[i]]
- [base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
+ = ira_reg_class_subunion[classes[i]]
+ [base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+ ADDRESS, SCRATCH)];
+ break;
+
+ case CT_FIXED_FORM:
+ if (constraint_satisfied_p (op, cn))
+ win = 1;
+ break;
}
-#endif
break;
}
p += CONSTRAINT_LEN (c, p);
into that class. */
if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
{
- if (classes[i] == NO_REGS)
+ if (classes[i] == NO_REGS && ! allows_mem[i])
{
/* We must always fail if the operand is a REG, but
- we did not find a suitable class.
+ we did not find a suitable class and memory is
+ not allowed.
Otherwise we may perform an uninitialized read
from this_op_costs after the `continue' statement
}
else
{
+ unsigned int regno = REGNO (op);
struct costs *pp = this_op_costs[i];
-
- for (k = 0; k < cost_classes_num; k++)
+ int *pp_costs = pp->cost;
+ cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
+ enum reg_class *cost_classes = cost_classes_ptr->classes;
+ bool in_p = recog_data.operand_type[i] != OP_OUT;
+ bool out_p = recog_data.operand_type[i] != OP_IN;
+ enum reg_class op_class = classes[i];
+
+ ira_init_register_move_cost_if_necessary (mode);
+ if (! in_p)
{
- rclass = cost_classes[k];
- pp->cost[k]
- = (((recog_data.operand_type[i] != OP_OUT
- ? ira_get_may_move_cost (mode, rclass,
- classes[i], true) : 0)
- + (recog_data.operand_type[i] != OP_IN
- ? ira_get_may_move_cost (mode, classes[i],
- rclass, false) : 0))
- * frequency);
+ ira_assert (out_p);
+ if (op_class == NO_REGS)
+ {
+ mem_cost = ira_memory_move_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = mem_cost[rclass][0] * frequency;
+ }
+ }
+ else
+ {
+ move_out_cost = ira_may_move_out_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k]
+ = move_out_cost[op_class][rclass] * frequency;
+ }
+ }
+ }
+ else if (! out_p)
+ {
+ ira_assert (in_p);
+ if (op_class == NO_REGS)
+ {
+ mem_cost = ira_memory_move_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = mem_cost[rclass][1] * frequency;
+ }
+ }
+ else
+ {
+ move_in_cost = ira_may_move_in_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k]
+ = move_in_cost[rclass][op_class] * frequency;
+ }
+ }
+ }
+ else
+ {
+ if (op_class == NO_REGS)
+ {
+ mem_cost = ira_memory_move_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = ((mem_cost[rclass][0]
+ + mem_cost[rclass][1])
+ * frequency);
+ }
+ }
+ else
+ {
+ move_in_cost = ira_may_move_in_cost[mode];
+ move_out_cost = ira_may_move_out_cost[mode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ pp_costs[k] = ((move_in_cost[rclass][op_class]
+ + move_out_cost[op_class][rclass])
+ * frequency);
+ }
+ }
}
- /* If the alternative actually allows memory, make
- things a bit cheaper since we won't need an extra
- insn to load it. */
- pp->mem_cost
- = ((recog_data.operand_type[i] != OP_IN
- ? ira_memory_move_cost[mode][classes[i]][0] : 0)
- + (recog_data.operand_type[i] != OP_OUT
- ? ira_memory_move_cost[mode][classes[i]][1] : 0)
- - allows_mem[i]) * frequency;
- /* If we have assigned a class to this allocno in our
- first pass, add a cost to this alternative
- corresponding to what we would add if this allocno
- were not in the appropriate class. We could use
- cover class here but it is less accurate
- approximation. */
+ if (op_class == NO_REGS)
+ /* Although we don't need insn to reload from
+ memory, still accessing memory is usually more
+ expensive than a register. */
+ pp->mem_cost = frequency;
+ else
+ /* If the alternative actually allows memory, make
+ things a bit cheaper since we won't need an
+ extra insn to load it. */
+ pp->mem_cost
+ = ((out_p ? ira_memory_move_cost[mode][op_class][0] : 0)
+ + (in_p ? ira_memory_move_cost[mode][op_class][1] : 0)
+ - allows_mem[i]) * frequency;
+ /* If we have assigned a class to this allocno in
+ our first pass, add a cost to this alternative
+ corresponding to what we would add if this
+ allocno were not in the appropriate class. */
if (pref)
{
enum reg_class pref_class = pref[COST_INDEX (REGNO (op))];
if (pref_class == NO_REGS)
+ {
+ if (op_class != NO_REGS)
+ alt_cost
+ += ((out_p
+ ? ira_memory_move_cost[mode][op_class][0]
+ : 0)
+ + (in_p
+ ? ira_memory_move_cost[mode][op_class][1]
+ : 0));
+ }
+ else if (op_class == NO_REGS)
alt_cost
- += ((recog_data.operand_type[i] != OP_IN
- ? ira_memory_move_cost[mode][classes[i]][0]
+ += ((out_p
+ ? ira_memory_move_cost[mode][pref_class][1]
: 0)
- + (recog_data.operand_type[i] != OP_OUT
- ? ira_memory_move_cost[mode][classes[i]][1]
+ + (in_p
+ ? ira_memory_move_cost[mode][pref_class][0]
: 0));
- else if (ira_reg_class_intersect[pref_class][classes[i]]
+ else if (ira_reg_class_intersect[pref_class][op_class]
== NO_REGS)
- alt_cost += ira_get_register_move_cost (mode,
- pref_class,
- classes[i]);
+ alt_cost += (ira_register_move_cost
+ [mode][pref_class][op_class]);
}
}
}
if (REG_P (ops[i]) && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
{
struct costs *pp = op_costs[i], *qq = this_op_costs[i];
+ int *pp_costs = pp->cost, *qq_costs = qq->cost;
int scale = 1 + (recog_data.operand_type[i] == OP_INOUT);
+ cost_classes_t cost_classes_ptr
+ = regno_cost_classes[REGNO (ops[i])];
pp->mem_cost = MIN (pp->mem_cost,
(qq->mem_cost + op_cost_add) * scale);
- for (k = 0; k < cost_classes_num; k++)
- pp->cost[k]
- = MIN (pp->cost[k], (qq->cost[k] + op_cost_add) * scale);
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ pp_costs[k]
+ = MIN (pp_costs[k], (qq_costs[k] + op_cost_add) * scale);
}
}
ALLOCNO_BAD_SPILL_P (a) = true;
}
- /* If this insn is a single set copying operand 1 to operand 0 and
- one operand is an allocno with the other a hard reg or an allocno
- that prefers a hard register that is in its own register class
- then we may want to adjust the cost of that register class to -1.
-
- Avoid the adjustment if the source does not die to avoid
- stressing of register allocator by preferrencing two colliding
- registers into single class.
-
- Also avoid the adjustment if a copy between hard registers of the
- class is expensive (ten times the cost of a default copy is
- considered arbitrarily expensive). This avoids losing when the
- preferred class is very expensive as the source of a copy
- instruction. */
- if ((set = single_set (insn)) != 0
- && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set)
- && REG_P (ops[0]) && REG_P (ops[1])
- && find_regno_note (insn, REG_DEAD, REGNO (ops[1])))
- for (i = 0; i <= 1; i++)
- if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
- {
- unsigned int regno = REGNO (ops[!i]);
- enum machine_mode mode = GET_MODE (ops[!i]);
- enum reg_class rclass;
- unsigned int nr;
-
- if (regno < FIRST_PSEUDO_REGISTER)
- for (k = 0; k < cost_classes_num; k++)
- {
- rclass = cost_classes[k];
- if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno)
- && (reg_class_size[rclass]
- == (unsigned) CLASS_MAX_NREGS (rclass, mode)))
- {
- if (reg_class_size[rclass] == 1)
- op_costs[i]->cost[k] = -frequency;
- else
- {
- for (nr = 0;
- nr < (unsigned) hard_regno_nregs[regno][mode];
- nr++)
- if (! TEST_HARD_REG_BIT (reg_class_contents[rclass],
- regno + nr))
- break;
-
- if (nr == (unsigned) hard_regno_nregs[regno][mode])
- op_costs[i]->cost[k] = -frequency;
- }
- }
- }
- }
}
\f
pseudo-registers should count as OK. Arguments as for
regno_ok_for_base_p. */
static inline bool
-ok_for_base_p_nonstrict (rtx reg, enum machine_mode mode,
+ok_for_base_p_nonstrict (rtx reg, machine_mode mode, addr_space_t as,
enum rtx_code outer_code, enum rtx_code index_code)
{
unsigned regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER)
return true;
- return ok_for_base_p_1 (regno, mode, outer_code, index_code);
+ return ok_for_base_p_1 (regno, mode, as, outer_code, index_code);
}
/* Record the pseudo registers we must reload into hard registers in a
If CONTEXT is 0, we are looking at the base part of an address,
otherwise we are looking at the index part.
- MODE is the mode of the memory reference; OUTER_CODE and INDEX_CODE
- give the context that the rtx appears in. These three arguments
- are passed down to base_reg_class.
+ MODE and AS are the mode and address space of the memory reference;
+ OUTER_CODE and INDEX_CODE give the context that the rtx appears in.
+ These four arguments are passed down to base_reg_class.
SCALE is twice the amount to multiply the cost by (it is twice so
we can represent half-cost adjustments). */
static void
-record_address_regs (enum machine_mode mode, rtx x, int context,
- enum rtx_code outer_code, enum rtx_code index_code,
- int scale)
+record_address_regs (machine_mode mode, addr_space_t as, rtx x,
+ int context, enum rtx_code outer_code,
+ enum rtx_code index_code, int scale)
{
enum rtx_code code = GET_CODE (x);
enum reg_class rclass;
if (context == 1)
rclass = INDEX_REG_CLASS;
else
- rclass = base_reg_class (mode, outer_code, index_code);
+ rclass = base_reg_class (mode, as, outer_code, index_code);
switch (code)
{
/* If this machine only allows one register per address, it
must be in the first operand. */
if (MAX_REGS_PER_ADDRESS == 1)
- record_address_regs (mode, arg0, 0, PLUS, code1, scale);
+ record_address_regs (mode, as, arg0, 0, PLUS, code1, scale);
/* If index and base registers are the same on this machine,
just record registers in any non-constant operands. We
assume here, as well as in the tests below, that all
addresses are in canonical form. */
- else if (INDEX_REG_CLASS == base_reg_class (VOIDmode, PLUS, SCRATCH))
+ else if (INDEX_REG_CLASS
+ == base_reg_class (VOIDmode, as, PLUS, SCRATCH))
{
- record_address_regs (mode, arg0, context, PLUS, code1, scale);
+ record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
if (! CONSTANT_P (arg1))
- record_address_regs (mode, arg1, context, PLUS, code0, scale);
+ record_address_regs (mode, as, arg1, context, PLUS, code0, scale);
}
/* If the second operand is a constant integer, it doesn't
change what class the first operand must be. */
- else if (code1 == CONST_INT || code1 == CONST_DOUBLE)
- record_address_regs (mode, arg0, context, PLUS, code1, scale);
+ else if (CONST_SCALAR_INT_P (arg1))
+ record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
/* If the second operand is a symbolic constant, the first
operand must be an index register. */
else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
- record_address_regs (mode, arg0, 1, PLUS, code1, scale);
+ record_address_regs (mode, as, arg0, 1, PLUS, code1, scale);
/* If both operands are registers but one is already a hard
register of index or reg-base class, give the other the
class that the hard register is not. */
else if (code0 == REG && code1 == REG
&& REGNO (arg0) < FIRST_PSEUDO_REGISTER
- && (ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
+ && (ok_for_base_p_nonstrict (arg0, mode, as, PLUS, REG)
|| ok_for_index_p_nonstrict (arg0)))
- record_address_regs (mode, arg1,
- ok_for_base_p_nonstrict (arg0, mode, PLUS, REG)
- ? 1 : 0,
+ record_address_regs (mode, as, arg1,
+ ok_for_base_p_nonstrict (arg0, mode, as,
+ PLUS, REG) ? 1 : 0,
PLUS, REG, scale);
else if (code0 == REG && code1 == REG
&& REGNO (arg1) < FIRST_PSEUDO_REGISTER
- && (ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
+ && (ok_for_base_p_nonstrict (arg1, mode, as, PLUS, REG)
|| ok_for_index_p_nonstrict (arg1)))
- record_address_regs (mode, arg0,
- ok_for_base_p_nonstrict (arg1, mode, PLUS, REG)
- ? 1 : 0,
+ record_address_regs (mode, as, arg0,
+ ok_for_base_p_nonstrict (arg1, mode, as,
+ PLUS, REG) ? 1 : 0,
PLUS, REG, scale);
/* If one operand is known to be a pointer, it must be the
base with the other operand the index. Likewise if the
other operand is a MULT. */
else if ((code0 == REG && REG_POINTER (arg0)) || code1 == MULT)
{
- record_address_regs (mode, arg0, 0, PLUS, code1, scale);
- record_address_regs (mode, arg1, 1, PLUS, code0, scale);
+ record_address_regs (mode, as, arg0, 0, PLUS, code1, scale);
+ record_address_regs (mode, as, arg1, 1, PLUS, code0, scale);
}
else if ((code1 == REG && REG_POINTER (arg1)) || code0 == MULT)
{
- record_address_regs (mode, arg0, 1, PLUS, code1, scale);
- record_address_regs (mode, arg1, 0, PLUS, code0, scale);
+ record_address_regs (mode, as, arg0, 1, PLUS, code1, scale);
+ record_address_regs (mode, as, arg1, 0, PLUS, code0, scale);
}
/* Otherwise, count equal chances that each might be a base or
index register. This case should be rare. */
else
{
- record_address_regs (mode, arg0, 0, PLUS, code1, scale / 2);
- record_address_regs (mode, arg0, 1, PLUS, code1, scale / 2);
- record_address_regs (mode, arg1, 0, PLUS, code0, scale / 2);
- record_address_regs (mode, arg1, 1, PLUS, code0, scale / 2);
+ record_address_regs (mode, as, arg0, 0, PLUS, code1, scale / 2);
+ record_address_regs (mode, as, arg0, 1, PLUS, code1, scale / 2);
+ record_address_regs (mode, as, arg1, 0, PLUS, code0, scale / 2);
+ record_address_regs (mode, as, arg1, 1, PLUS, code0, scale / 2);
}
}
break;
up in the wrong place. */
case POST_MODIFY:
case PRE_MODIFY:
- record_address_regs (mode, XEXP (x, 0), 0, code,
+ record_address_regs (mode, as, XEXP (x, 0), 0, code,
GET_CODE (XEXP (XEXP (x, 1), 1)), 2 * scale);
if (REG_P (XEXP (XEXP (x, 1), 1)))
- record_address_regs (mode, XEXP (XEXP (x, 1), 1), 1, code, REG,
+ record_address_regs (mode, as, XEXP (XEXP (x, 1), 1), 1, code, REG,
2 * scale);
break;
case PRE_DEC:
/* Double the importance of an allocno that is incremented or
decremented, since it would take two extra insns if it ends
- up in the wrong place. If the operand is a pseudo-register,
- show it is being used in an INC_DEC context. */
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- if (REG_P (XEXP (x, 0))
- && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER)
- in_inc_dec[COST_INDEX (REGNO (XEXP (x, 0)))] = true;
-#endif
- record_address_regs (mode, XEXP (x, 0), 0, code, SCRATCH, 2 * scale);
+ up in the wrong place. */
+ record_address_regs (mode, as, XEXP (x, 0), 0, code, SCRATCH, 2 * scale);
break;
case REG:
{
struct costs *pp;
+ int *pp_costs;
enum reg_class i;
- int k;
+ int k, regno, add_cost;
+ cost_classes_t cost_classes_ptr;
+ enum reg_class *cost_classes;
+ move_table *move_in_cost;
if (REGNO (x) < FIRST_PSEUDO_REGISTER)
break;
+ regno = REGNO (x);
if (allocno_p)
- ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[REGNO (x)]) = true;
- pp = COSTS (costs, COST_INDEX (REGNO (x)));
- pp->mem_cost += (ira_memory_move_cost[Pmode][rclass][1] * scale) / 2;
- for (k = 0; k < cost_classes_num; k++)
+ ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[regno]) = true;
+ pp = COSTS (costs, COST_INDEX (regno));
+ add_cost = (ira_memory_move_cost[Pmode][rclass][1] * scale) / 2;
+ if (INT_MAX - add_cost < pp->mem_cost)
+ pp->mem_cost = INT_MAX;
+ else
+ pp->mem_cost += add_cost;
+ cost_classes_ptr = regno_cost_classes[regno];
+ cost_classes = cost_classes_ptr->classes;
+ pp_costs = pp->cost;
+ ira_init_register_move_cost_if_necessary (Pmode);
+ move_in_cost = ira_may_move_in_cost[Pmode];
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
{
i = cost_classes[k];
- pp->cost[k]
- += (ira_get_may_move_cost (Pmode, i, rclass, true) * scale) / 2;
+ add_cost = (move_in_cost[i][rclass] * scale) / 2;
+ if (INT_MAX - add_cost < pp_costs[k])
+ pp_costs[k] = INT_MAX;
+ else
+ pp_costs[k] += add_cost;
}
}
break;
int i;
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
- record_address_regs (mode, XEXP (x, i), context, code, SCRATCH,
+ record_address_regs (mode, as, XEXP (x, i), context, code, SCRATCH,
scale);
}
}
/* Calculate the costs of insn operands. */
static void
-record_operand_costs (rtx insn, struct costs **op_costs, enum reg_class *pref)
+record_operand_costs (rtx_insn *insn, enum reg_class *pref)
{
const char *constraints[MAX_RECOG_OPERANDS];
- enum machine_mode modes[MAX_RECOG_OPERANDS];
+ machine_mode modes[MAX_RECOG_OPERANDS];
+ rtx ops[MAX_RECOG_OPERANDS];
+ rtx set;
int i;
for (i = 0; i < recog_data.n_operands; i++)
{
memcpy (op_costs[i], init_cost, struct_costs_size);
+ ops[i] = recog_data.operand[i];
if (GET_CODE (recog_data.operand[i]) == SUBREG)
recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
if (MEM_P (recog_data.operand[i]))
record_address_regs (GET_MODE (recog_data.operand[i]),
+ MEM_ADDR_SPACE (recog_data.operand[i]),
XEXP (recog_data.operand[i], 0),
0, MEM, SCRATCH, frequency * 2);
else if (constraints[i][0] == 'p'
- || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0],
- constraints[i]))
- record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS,
- SCRATCH, frequency * 2);
+ || (insn_extra_address_constraint
+ (lookup_constraint (constraints[i]))))
+ record_address_regs (VOIDmode, ADDR_SPACE_GENERIC,
+ recog_data.operand[i], 0, ADDRESS, SCRATCH,
+ frequency * 2);
}
-
+
/* Check for commutative in a separate loop so everything will have
been initialized. We must do this even if one operand is a
constant--see addsi3 in m68k.md. */
xconstraints[i+1] = constraints[i];
record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
recog_data.operand, modes,
- xconstraints, insn, op_costs, pref);
+ xconstraints, insn, pref);
}
record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
recog_data.operand, modes,
- constraints, insn, op_costs, pref);
+ constraints, insn, pref);
+
+ /* If this insn is a single set copying operand 1 to operand 0 and
+ one operand is an allocno with the other a hard reg or an allocno
+ that prefers a hard register that is in its own register class
+ then we may want to adjust the cost of that register class to -1.
+
+ Avoid the adjustment if the source does not die to avoid
+ stressing of register allocator by preferencing two colliding
+ registers into single class.
+
+ Also avoid the adjustment if a copy between hard registers of the
+ class is expensive (ten times the cost of a default copy is
+ considered arbitrarily expensive). This avoids losing when the
+ preferred class is very expensive as the source of a copy
+ instruction. */
+ if ((set = single_set (insn)) != NULL_RTX
+ /* In rare cases the single set insn might have less 2 operands
+ as the source can be a fixed special reg. */
+ && recog_data.n_operands > 1
+ && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set))
+ {
+ int regno, other_regno;
+ rtx dest = SET_DEST (set);
+ rtx src = SET_SRC (set);
+
+ if (GET_CODE (dest) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (dest))
+ == GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))))
+ dest = SUBREG_REG (dest);
+ if (GET_CODE (src) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (src))
+ == GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))))
+ src = SUBREG_REG (src);
+ if (REG_P (src) && REG_P (dest)
+ && find_regno_note (insn, REG_DEAD, REGNO (src))
+ && (((regno = REGNO (src)) >= FIRST_PSEUDO_REGISTER
+ && (other_regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER)
+ || ((regno = REGNO (dest)) >= FIRST_PSEUDO_REGISTER
+ && (other_regno = REGNO (src)) < FIRST_PSEUDO_REGISTER)))
+ {
+ machine_mode mode = GET_MODE (src);
+ cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
+ enum reg_class *cost_classes = cost_classes_ptr->classes;
+ reg_class_t rclass;
+ int k, nr;
+
+ i = regno == (int) REGNO (src) ? 1 : 0;
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ rclass = cost_classes[k];
+ if (TEST_HARD_REG_BIT (reg_class_contents[rclass], other_regno)
+ && (reg_class_size[(int) rclass]
+ == ira_reg_class_max_nregs [(int) rclass][(int) mode]))
+ {
+ if (reg_class_size[rclass] == 1)
+ op_costs[i]->cost[k] = -frequency;
+ else
+ {
+ for (nr = 0;
+ nr < hard_regno_nregs[other_regno][mode];
+ nr++)
+ if (! TEST_HARD_REG_BIT (reg_class_contents[rclass],
+ other_regno + nr))
+ break;
+
+ if (nr == hard_regno_nregs[other_regno][mode])
+ op_costs[i]->cost[k] = -frequency;
+ }
+ }
+ }
+ }
+ }
}
\f
/* Process one insn INSN. Scan it and record each time it would save
code to put a certain allocnos in a certain class. Return the last
insn processed, so that the scan can be continued from there. */
-static rtx
-scan_one_insn (rtx insn)
+static rtx_insn *
+scan_one_insn (rtx_insn *insn)
{
enum rtx_code pat_code;
rtx set, note;
int i, k;
+ bool counted_mem;
if (!NONDEBUG_INSN_P (insn))
return insn;
pat_code = GET_CODE (PATTERN (insn));
- if (pat_code == USE || pat_code == CLOBBER || pat_code == ASM_INPUT
- || pat_code == ADDR_VEC || pat_code == ADDR_DIFF_VEC)
+ if (pat_code == USE || pat_code == CLOBBER || pat_code == ASM_INPUT)
return insn;
+ counted_mem = false;
set = single_set (insn);
extract_insn (insn);
/* If this insn loads a parameter from its stack slot, then it
represents a savings, rather than a cost, if the parameter is
- stored in memory. Record this fact. */
+ stored in memory. Record this fact.
+
+ Similarly if we're loading other constants from memory (constant
+ pool, TOC references, small data areas, etc) and this is the only
+ assignment to the destination pseudo.
+
+ Don't do this if SET_SRC (set) isn't a general operand, if it is
+ a memory requiring special instructions to load it, decreasing
+ mem_cost might result in it being loaded using the specialized
+ instruction into a register, then stored into stack and loaded
+ again from the stack. See PR52208.
+
+ Don't do this if SET_SRC (set) has side effect. See PR56124. */
if (set != 0 && REG_P (SET_DEST (set)) && MEM_P (SET_SRC (set))
&& (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != NULL_RTX
- && MEM_P (XEXP (note, 0)))
+ && ((MEM_P (XEXP (note, 0))
+ && !side_effects_p (SET_SRC (set)))
+ || (CONSTANT_P (XEXP (note, 0))
+ && targetm.legitimate_constant_p (GET_MODE (SET_DEST (set)),
+ XEXP (note, 0))
+ && REG_N_SETS (REGNO (SET_DEST (set))) == 1))
+ && general_operand (SET_SRC (set), GET_MODE (SET_SRC (set))))
{
enum reg_class cl = GENERAL_REGS;
rtx reg = SET_DEST (set);
int num = COST_INDEX (REGNO (reg));
- if (pref)
- cl = pref[num];
COSTS (costs, num)->mem_cost
-= ira_memory_move_cost[GET_MODE (reg)][cl][1] * frequency;
- record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0),
- 0, MEM, SCRATCH, frequency * 2);
+ record_address_regs (GET_MODE (SET_SRC (set)),
+ MEM_ADDR_SPACE (SET_SRC (set)),
+ XEXP (SET_SRC (set), 0), 0, MEM, SCRATCH,
+ frequency * 2);
+ counted_mem = true;
}
- record_operand_costs (insn, op_costs, pref);
+ record_operand_costs (insn, pref);
/* Now add the cost for each operand to the total costs for its
allocno. */
int regno = REGNO (recog_data.operand[i]);
struct costs *p = COSTS (costs, COST_INDEX (regno));
struct costs *q = op_costs[i];
+ int *p_costs = p->cost, *q_costs = q->cost;
+ cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
+ int add_cost;
- p->mem_cost += q->mem_cost;
- for (k = 0; k < cost_classes_num; k++)
- p->cost[k] += q->cost[k];
+ /* If the already accounted for the memory "cost" above, don't
+ do so again. */
+ if (!counted_mem)
+ {
+ add_cost = q->mem_cost;
+ if (add_cost > 0 && INT_MAX - add_cost < p->mem_cost)
+ p->mem_cost = INT_MAX;
+ else
+ p->mem_cost += add_cost;
+ }
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ add_cost = q_costs[k];
+ if (add_cost > 0 && INT_MAX - add_cost < p_costs[k])
+ p_costs[k] = INT_MAX;
+ else
+ p_costs[k] += add_cost;
+ }
}
return insn;
int i, rclass;
basic_block bb;
int regno = ALLOCNO_REGNO (a);
+ cost_classes_t cost_classes_ptr = regno_cost_classes[regno];
+ enum reg_class *cost_classes = cost_classes_ptr->classes;
i = ALLOCNO_NUM (a);
fprintf (f, " a%d(r%d,", i, regno);
if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
fprintf (f, "b%d", bb->index);
else
- fprintf (f, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
+ fprintf (f, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop_num);
fprintf (f, ") costs:");
- for (k = 0; k < cost_classes_num; k++)
+ for (k = 0; k < cost_classes_ptr->num; k++)
{
rclass = cost_classes[k];
- if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- && (! in_inc_dec[i] || ! forbidden_inc_dec_class[rclass])
-#endif
-#ifdef CANNOT_CHANGE_MODE_CLASS
- && ! invalid_mode_change_p (regno, (enum reg_class) rclass,
- PSEUDO_REGNO_MODE (regno))
-#endif
- )
- {
- fprintf (f, " %s:%d", reg_class_names[rclass],
- COSTS (costs, i)->cost[k]);
- if (flag_ira_region == IRA_REGION_ALL
- || flag_ira_region == IRA_REGION_MIXED)
- fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]);
- }
+ fprintf (f, " %s:%d", reg_class_names[rclass],
+ COSTS (costs, i)->cost[k]);
+ if (flag_ira_region == IRA_REGION_ALL
+ || flag_ira_region == IRA_REGION_MIXED)
+ fprintf (f, ",%d", COSTS (total_allocno_costs, i)->cost[k]);
}
- fprintf (f, " MEM:%i\n", COSTS (costs, i)->mem_cost);
+ fprintf (f, " MEM:%i", COSTS (costs, i)->mem_cost);
+ if (flag_ira_region == IRA_REGION_ALL
+ || flag_ira_region == IRA_REGION_MIXED)
+ fprintf (f, ",%d", COSTS (total_allocno_costs, i)->mem_cost);
+ fprintf (f, "\n");
}
}
{
int regno, k;
int rclass;
+ cost_classes_t cost_classes_ptr;
+ enum reg_class *cost_classes;
ira_assert (! allocno_p);
fprintf (f, "\n");
for (regno = max_reg_num () - 1; regno >= FIRST_PSEUDO_REGISTER; regno--)
{
- if (regno_reg_rtx[regno] == NULL_RTX)
+ if (REG_N_REFS (regno) <= 0)
continue;
+ cost_classes_ptr = regno_cost_classes[regno];
+ cost_classes = cost_classes_ptr->classes;
fprintf (f, " r%d costs:", regno);
- for (k = 0; k < cost_classes_num; k++)
+ for (k = 0; k < cost_classes_ptr->num; k++)
{
rclass = cost_classes[k];
- if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)]
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- && (! in_inc_dec[regno] || ! forbidden_inc_dec_class[rclass])
-#endif
-#ifdef CANNOT_CHANGE_MODE_CLASS
- && ! invalid_mode_change_p (regno, (enum reg_class) rclass,
- PSEUDO_REGNO_MODE (regno))
-#endif
- )
- fprintf (f, " %s:%d", reg_class_names[rclass],
- COSTS (costs, regno)->cost[k]);
+ fprintf (f, " %s:%d", reg_class_names[rclass],
+ COSTS (costs, regno)->cost[k]);
}
fprintf (f, " MEM:%i\n", COSTS (costs, regno)->mem_cost);
}
static void
process_bb_for_costs (basic_block bb)
{
- rtx insn;
+ rtx_insn *insn;
frequency = REG_FREQ_FROM_BB (bb);
if (frequency == 0)
}
/* Find costs of register classes and memory for allocnos or pseudos
- and their best costs. Set up preferred, alternative and cover
+ and their best costs. Set up preferred, alternative and allocno
classes for pseudos. */
static void
find_costs_and_classes (FILE *dump_file)
{
- int i, k, start;
+ int i, k, start, max_cost_classes_num;
int pass;
basic_block bb;
+ enum reg_class *regno_best_class, new_class;
init_recog ();
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- in_inc_dec = ira_allocate (sizeof (bool) * cost_elements_num);
-#endif /* FORBIDDEN_INC_DEC_CLASSES */
- pref = NULL;
- start = 0;
- if (!resize_reg_info () && allocno_p && pseudo_classes_defined_p)
+ regno_best_class
+ = (enum reg_class *) ira_allocate (max_reg_num ()
+ * sizeof (enum reg_class));
+ for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+ regno_best_class[i] = NO_REGS;
+ if (!resize_reg_info () && allocno_p
+ && pseudo_classes_defined_p && flag_expensive_optimizations)
{
ira_allocno_t a;
ira_allocno_iterator ai;
pref = pref_buffer;
+ max_cost_classes_num = 1;
FOR_EACH_ALLOCNO (a, ai)
- pref[ALLOCNO_NUM (a)] = reg_preferred_class (ALLOCNO_REGNO (a));
- if (flag_expensive_optimizations)
- start = 1;
+ {
+ pref[ALLOCNO_NUM (a)] = reg_preferred_class (ALLOCNO_REGNO (a));
+ setup_regno_cost_classes_by_aclass
+ (ALLOCNO_REGNO (a), pref[ALLOCNO_NUM (a)]);
+ max_cost_classes_num
+ = MAX (max_cost_classes_num,
+ regno_cost_classes[ALLOCNO_REGNO (a)]->num);
+ }
+ start = 1;
+ }
+ else
+ {
+ pref = NULL;
+ max_cost_classes_num = ira_important_classes_num;
+ for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+ if (regno_reg_rtx[i] != NULL_RTX)
+ setup_regno_cost_classes_by_mode (i, PSEUDO_REGNO_MODE (i));
+ else
+ setup_regno_cost_classes_by_aclass (i, ALL_REGS);
+ start = 0;
}
if (allocno_p)
/* Clear the flag for the next compiled function. */
if ((!allocno_p || internal_flag_ira_verbose > 0) && dump_file)
fprintf (dump_file,
"\nPass %i for finding pseudo/allocno costs\n\n", pass);
- /* We could use only cover classes. Unfortunately it does not
- work well for some targets where some subclass of cover class
- is costly and wrong cover class is chosen. */
- for (i = 0; i < N_REG_CLASSES; i++)
- cost_class_nums[i] = -1;
- for (cost_classes_num = 0;
- cost_classes_num < ira_important_classes_num;
- cost_classes_num++)
+
+ if (pass != start)
{
- cost_classes[cost_classes_num]
- = ira_important_classes[cost_classes_num];
- cost_class_nums[cost_classes[cost_classes_num]]
- = cost_classes_num;
+ max_cost_classes_num = 1;
+ for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
+ {
+ setup_regno_cost_classes_by_aclass (i, regno_best_class[i]);
+ max_cost_classes_num
+ = MAX (max_cost_classes_num, regno_cost_classes[i]->num);
+ }
}
+
struct_costs_size
- = sizeof (struct costs) + sizeof (int) * (cost_classes_num - 1);
+ = sizeof (struct costs) + sizeof (int) * (max_cost_classes_num - 1);
/* Zero out our accumulation of the cost of each class for each
allocno. */
memset (costs, 0, cost_elements_num * struct_costs_size);
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- memset (in_inc_dec, 0, cost_elements_num * sizeof (bool));
-#endif
if (allocno_p)
{
{
basic_block bb;
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
process_bb_for_costs (bb);
}
for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
{
ira_allocno_t a, parent_a;
- int rclass, a_num, parent_a_num;
+ int rclass, a_num, parent_a_num, add_cost;
ira_loop_tree_node_t parent;
int best_cost, allocno_cost;
enum reg_class best, alt_class;
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- int inc_dec_p = false;
-#endif
+ cost_classes_t cost_classes_ptr = regno_cost_classes[i];
+ enum reg_class *cost_classes = cost_classes_ptr->classes;
+ int *i_costs = temp_costs->cost;
+ int i_mem_cost;
int equiv_savings = regno_equiv_gains[i];
if (! allocno_p)
{
if (regno_reg_rtx[i] == NULL_RTX)
continue;
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- inc_dec_p = in_inc_dec[i];
-#endif
memcpy (temp_costs, COSTS (costs, i), struct_costs_size);
+ i_mem_cost = temp_costs->mem_cost;
}
else
{
if (ira_regno_allocno_map[i] == NULL)
continue;
memset (temp_costs, 0, struct_costs_size);
+ i_mem_cost = 0;
/* Find cost of all allocnos with the same regno. */
for (a = ira_regno_allocno_map[i];
a != NULL;
a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
{
+ int *a_costs, *p_costs;
+
a_num = ALLOCNO_NUM (a);
if ((flag_ira_region == IRA_REGION_ALL
|| flag_ira_region == IRA_REGION_MIXED)
/* Propagate costs to upper levels in the region
tree. */
parent_a_num = ALLOCNO_NUM (parent_a);
- for (k = 0; k < cost_classes_num; k++)
- COSTS (total_allocno_costs, parent_a_num)->cost[k]
- += COSTS (total_allocno_costs, a_num)->cost[k];
- COSTS (total_allocno_costs, parent_a_num)->mem_cost
- += COSTS (total_allocno_costs, a_num)->mem_cost;
+ a_costs = COSTS (total_allocno_costs, a_num)->cost;
+ p_costs = COSTS (total_allocno_costs, parent_a_num)->cost;
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ add_cost = a_costs[k];
+ if (add_cost > 0 && INT_MAX - add_cost < p_costs[k])
+ p_costs[k] = INT_MAX;
+ else
+ p_costs[k] += add_cost;
+ }
+ add_cost = COSTS (total_allocno_costs, a_num)->mem_cost;
+ if (add_cost > 0
+ && (INT_MAX - add_cost
+ < COSTS (total_allocno_costs,
+ parent_a_num)->mem_cost))
+ COSTS (total_allocno_costs, parent_a_num)->mem_cost
+ = INT_MAX;
+ else
+ 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;
}
- for (k = 0; k < cost_classes_num; k++)
- temp_costs->cost[k] += COSTS (costs, a_num)->cost[k];
- temp_costs->mem_cost += COSTS (costs, a_num)->mem_cost;
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- if (in_inc_dec[a_num])
- inc_dec_p = true;
-#endif
+ a_costs = COSTS (costs, a_num)->cost;
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ {
+ add_cost = a_costs[k];
+ if (add_cost > 0 && INT_MAX - add_cost < i_costs[k])
+ i_costs[k] = INT_MAX;
+ else
+ i_costs[k] += add_cost;
+ }
+ add_cost = COSTS (costs, a_num)->mem_cost;
+ if (add_cost > 0 && INT_MAX - add_cost < i_mem_cost)
+ i_mem_cost = INT_MAX;
+ else
+ i_mem_cost += add_cost;
}
}
- if (equiv_savings < 0)
- temp_costs->mem_cost = -equiv_savings;
+ 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)
{
- temp_costs->mem_cost = 0;
- for (k = 0; k < cost_classes_num; k++)
- temp_costs->cost[k] += equiv_savings;
+ i_mem_cost = 0;
+ for (k = cost_classes_ptr->num - 1; k >= 0; k--)
+ i_costs[k] += equiv_savings;
}
best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
alt_class = NO_REGS;
/* Find best common class for all allocnos with the same
regno. */
- for (k = 0; k < cost_classes_num; k++)
+ for (k = 0; k < cost_classes_ptr->num; k++)
{
rclass = cost_classes[k];
- /* Ignore classes that are too small for this operand or
- invalid for an operand that was auto-incremented. */
- if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- || (inc_dec_p && forbidden_inc_dec_class[rclass])
-#endif
-#ifdef CANNOT_CHANGE_MODE_CLASS
- || invalid_mode_change_p (i, (enum reg_class) rclass,
- PSEUDO_REGNO_MODE (i))
-#endif
- )
- continue;
- if (temp_costs->cost[k] < best_cost)
+ if (i_costs[k] < best_cost)
{
- best_cost = temp_costs->cost[k];
+ best_cost = i_costs[k];
best = (enum reg_class) rclass;
}
- else if (temp_costs->cost[k] == best_cost)
- best = ira_reg_class_union[best][rclass];
+ else if (i_costs[k] == best_cost)
+ best = ira_reg_class_subunion[best][rclass];
if (pass == flag_expensive_optimizations
- && temp_costs->cost[k] < temp_costs->mem_cost
+ /* We still prefer registers to memory even at this
+ stage if their costs are the same. We will make
+ a final decision during assigning hard registers
+ when we have all info including more accurate
+ costs which might be affected by assigning hard
+ registers to other pseudos because the pseudos
+ involved in moves can be coalesced. */
+ && i_costs[k] <= i_mem_cost
&& (reg_class_size[reg_class_subunion[alt_class][rclass]]
> reg_class_size[alt_class]))
alt_class = reg_class_subunion[alt_class][rclass];
}
- alt_class = ira_class_translate[alt_class];
- if (best_cost > temp_costs->mem_cost)
- regno_cover_class[i] = NO_REGS;
- else if (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY)
- /* Make the common class the biggest class of best and
- alt_class. */
- regno_cover_class[i] = alt_class == NO_REGS ? best : alt_class;
+ alt_class = ira_allocno_class_translate[alt_class];
+ if (best_cost > i_mem_cost)
+ regno_aclass[i] = NO_REGS;
+ else if (!optimize && !targetm.class_likely_spilled_p (best))
+ /* Registers in the alternative class are likely to need
+ longer or slower sequences than registers in the best class.
+ When optimizing we make some effort to use the best class
+ over the alternative class where possible, but at -O0 we
+ effectively give the alternative class equal weight.
+ We then run the risk of using slower alternative registers
+ when plenty of registers from the best class are still free.
+ This is especially true because live ranges tend to be very
+ short in -O0 code and so register pressure tends to be low.
+
+ Avoid that by ignoring the alternative class if the best
+ class has plenty of registers. */
+ regno_aclass[i] = best;
else
- /* Make the common class a cover class. Remember all
- allocnos with the same regno should have the same cover
- class. */
- regno_cover_class[i] = ira_class_translate[best];
+ {
+ /* Make the common class the biggest class of best and
+ alt_class. */
+ regno_aclass[i]
+ = ira_reg_class_superunion[best][alt_class];
+ ira_assert (regno_aclass[i] != NO_REGS
+ && ira_reg_allocno_class_p[regno_aclass[i]]);
+ }
+ if ((new_class
+ = (reg_class) (targetm.ira_change_pseudo_allocno_class
+ (i, regno_aclass[i]))) != regno_aclass[i])
+ {
+ regno_aclass[i] = new_class;
+ if (hard_reg_set_subset_p (reg_class_contents[new_class],
+ reg_class_contents[best]))
+ best = new_class;
+ if (hard_reg_set_subset_p (reg_class_contents[new_class],
+ reg_class_contents[alt_class]))
+ alt_class = new_class;
+ }
if (pass == flag_expensive_optimizations)
{
- if (best_cost > temp_costs->mem_cost)
+ if (best_cost > i_mem_cost)
best = alt_class = NO_REGS;
else if (best == alt_class)
alt_class = NO_REGS;
- setup_reg_classes (i, best, alt_class, regno_cover_class[i]);
+ setup_reg_classes (i, best, alt_class, regno_aclass[i]);
if ((!allocno_p || internal_flag_ira_verbose > 2)
&& dump_file != NULL)
fprintf (dump_file,
- " r%d: preferred %s, alternative %s, cover %s\n",
+ " r%d: preferred %s, alternative %s, allocno %s\n",
i, reg_class_names[best], reg_class_names[alt_class],
- reg_class_names[regno_cover_class[i]]);
+ reg_class_names[regno_aclass[i]]);
}
+ regno_best_class[i] = best;
if (! allocno_p)
{
- pref[i] = best_cost > temp_costs->mem_cost ? NO_REGS : best;
+ pref[i] = best_cost > i_mem_cost ? NO_REGS : best;
continue;
}
for (a = ira_regno_allocno_map[i];
a != NULL;
a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
{
- a_num = ALLOCNO_NUM (a);
- if (regno_cover_class[i] == NO_REGS)
+ enum reg_class aclass = regno_aclass[i];
+ int a_num = ALLOCNO_NUM (a);
+ int *total_a_costs = COSTS (total_allocno_costs, a_num)->cost;
+ int *a_costs = COSTS (costs, a_num)->cost;
+
+ if (aclass == NO_REGS)
best = NO_REGS;
else
{
best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
allocno_cost = best_cost;
best = ALL_REGS;
- for (k = 0; k < cost_classes_num; k++)
+ for (k = 0; k < cost_classes_ptr->num; k++)
{
rclass = cost_classes[k];
- if (! ira_class_subset_p[rclass][regno_cover_class[i]])
+ if (! ira_class_subset_p[rclass][aclass])
continue;
- /* Ignore classes that are too small for this
- operand or invalid for an operand that was
- auto-incremented. */
- if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)]
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- || (inc_dec_p && forbidden_inc_dec_class[rclass])
-#endif
-#ifdef CANNOT_CHANGE_MODE_CLASS
- || invalid_mode_change_p (i, (enum reg_class) rclass,
- PSEUDO_REGNO_MODE (i))
-#endif
- )
- ;
- else if (COSTS (total_allocno_costs, a_num)->cost[k]
- < best_cost)
+ if (total_a_costs[k] < best_cost)
{
- best_cost
- = COSTS (total_allocno_costs, a_num)->cost[k];
- allocno_cost = COSTS (costs, a_num)->cost[k];
+ best_cost = total_a_costs[k];
+ allocno_cost = a_costs[k];
best = (enum reg_class) rclass;
}
- else if (COSTS (total_allocno_costs, a_num)->cost[k]
- == best_cost)
+ else if (total_a_costs[k] == best_cost)
{
- best = ira_reg_class_union[best][rclass];
- allocno_cost
- = MAX (allocno_cost, COSTS (costs, a_num)->cost[k]);
+ best = ira_reg_class_subunion[best][rclass];
+ allocno_cost = MAX (allocno_cost, a_costs[k]);
}
}
- ALLOCNO_COVER_CLASS_COST (a) = allocno_cost;
+ ALLOCNO_CLASS_COST (a) = allocno_cost;
}
- ira_assert (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY
- || ira_class_translate[best] == regno_cover_class[i]);
if (internal_flag_ira_verbose > 2 && dump_file != NULL
&& (pass == 0 || pref[a_num] != best))
{
fprintf (dump_file, "b%d", bb->index);
else
fprintf (dump_file, "l%d",
- ALLOCNO_LOOP_TREE_NODE (a)->loop->num);
- fprintf (dump_file, ") best %s, cover %s\n",
+ ALLOCNO_LOOP_TREE_NODE (a)->loop_num);
+ fprintf (dump_file, ") best %s, allocno %s\n",
reg_class_names[best],
- reg_class_names[regno_cover_class[i]]);
+ reg_class_names[aclass]);
}
pref[a_num] = best;
+ if (pass == flag_expensive_optimizations && best != aclass
+ && ira_class_hard_regs_num[best] > 0
+ && (ira_reg_class_max_nregs[best][ALLOCNO_MODE (a)]
+ >= ira_class_hard_regs_num[best]))
+ {
+ int ind = cost_classes_ptr->index[aclass];
+
+ ira_assert (ind >= 0);
+ ira_init_register_move_cost_if_necessary (ALLOCNO_MODE (a));
+ ira_add_allocno_pref (a, ira_class_hard_regs[best][0],
+ (a_costs[ind] - ALLOCNO_CLASS_COST (a))
+ / (ira_register_move_cost
+ [ALLOCNO_MODE (a)][best][aclass]));
+ for (k = 0; k < cost_classes_ptr->num; k++)
+ if (ira_class_subset_p[cost_classes[k]][best])
+ a_costs[k] = a_costs[ind];
+ }
}
}
-
+
if (internal_flag_ira_verbose > 4 && dump_file)
{
if (allocno_p)
fprintf (dump_file,"\n");
}
}
-#ifdef FORBIDDEN_INC_DEC_CLASSES
- ira_free (in_inc_dec);
-#endif
+ ira_free (regno_best_class);
}
\f
/* Process moves involving hard regs to modify allocno hard register
- costs. We can do this only after determining allocno cover class.
- If a hard register forms a register class, than moves with the hard
+ costs. We can do this only after determining allocno class. If a
+ hard register forms a register class, then moves with the hard
register are already taken into account in class costs for the
allocno. */
static void
process_bb_node_for_hard_reg_moves (ira_loop_tree_node_t loop_tree_node)
{
- int i, freq, cost, src_regno, dst_regno, hard_regno;
+ int i, freq, src_regno, dst_regno, hard_regno, a_regno;
bool to_p;
- ira_allocno_t a;
- enum reg_class rclass, hard_reg_class;
- enum machine_mode mode;
+ ira_allocno_t a, curr_a;
+ ira_loop_tree_node_t curr_loop_tree_node;
+ enum reg_class rclass;
basic_block bb;
- rtx insn, set, src, dst;
+ rtx_insn *insn;
+ rtx set, src, dst;
bb = loop_tree_node->bb;
if (bb == NULL)
&& src_regno < FIRST_PSEUDO_REGISTER)
{
hard_regno = src_regno;
- to_p = true;
a = ira_curr_regno_allocno_map[dst_regno];
+ to_p = true;
}
else if (src_regno >= FIRST_PSEUDO_REGISTER
&& dst_regno < FIRST_PSEUDO_REGISTER)
{
hard_regno = dst_regno;
- to_p = false;
a = ira_curr_regno_allocno_map[src_regno];
+ to_p = false;
}
else
continue;
- rclass = ALLOCNO_COVER_CLASS (a);
+ rclass = ALLOCNO_CLASS (a);
if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], hard_regno))
continue;
i = ira_class_hard_reg_index[rclass][hard_regno];
if (i < 0)
continue;
- mode = ALLOCNO_MODE (a);
- hard_reg_class = REGNO_REG_CLASS (hard_regno);
- cost
- = (to_p ? ira_get_register_move_cost (mode, hard_reg_class, rclass)
- : ira_get_register_move_cost (mode, rclass, hard_reg_class)) * freq;
- ira_allocate_and_set_costs (&ALLOCNO_HARD_REG_COSTS (a), rclass,
- ALLOCNO_COVER_CLASS_COST (a));
- ira_allocate_and_set_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a),
- rclass, 0);
- ALLOCNO_HARD_REG_COSTS (a)[i] -= cost;
- ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[i] -= cost;
- ALLOCNO_COVER_CLASS_COST (a) = MIN (ALLOCNO_COVER_CLASS_COST (a),
- ALLOCNO_HARD_REG_COSTS (a)[i]);
+ a_regno = ALLOCNO_REGNO (a);
+ for (curr_loop_tree_node = ALLOCNO_LOOP_TREE_NODE (a);
+ curr_loop_tree_node != NULL;
+ curr_loop_tree_node = curr_loop_tree_node->parent)
+ if ((curr_a = curr_loop_tree_node->regno_allocno_map[a_regno]) != NULL)
+ ira_add_allocno_pref (curr_a, hard_regno, freq);
+ {
+ int cost;
+ enum reg_class hard_reg_class;
+ machine_mode mode;
+
+ mode = ALLOCNO_MODE (a);
+ hard_reg_class = REGNO_REG_CLASS (hard_regno);
+ ira_init_register_move_cost_if_necessary (mode);
+ cost = (to_p ? ira_register_move_cost[mode][hard_reg_class][rclass]
+ : ira_register_move_cost[mode][rclass][hard_reg_class]) * freq;
+ ira_allocate_and_set_costs (&ALLOCNO_HARD_REG_COSTS (a), rclass,
+ ALLOCNO_CLASS_COST (a));
+ ira_allocate_and_set_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a),
+ rclass, 0);
+ ALLOCNO_HARD_REG_COSTS (a)[i] -= cost;
+ ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[i] -= cost;
+ ALLOCNO_CLASS_COST (a) = MIN (ALLOCNO_CLASS_COST (a),
+ ALLOCNO_HARD_REG_COSTS (a)[i]);
+ }
}
}
/* After we find hard register and memory costs for allocnos, define
- its cover class and modify hard register cost because insns moving
+ its class and modify hard register cost because insns moving
allocno to/from hard registers. */
static void
-setup_allocno_cover_class_and_costs (void)
+setup_allocno_class_and_costs (void)
{
- int i, j, n, regno, num;
+ int i, j, n, regno, hard_regno, num;
int *reg_costs;
- enum reg_class cover_class, rclass;
+ enum reg_class aclass, rclass;
ira_allocno_t a;
ira_allocno_iterator ai;
+ cost_classes_t cost_classes_ptr;
ira_assert (allocno_p);
FOR_EACH_ALLOCNO (a, ai)
{
i = ALLOCNO_NUM (a);
- cover_class = regno_cover_class[ALLOCNO_REGNO (a)];
- ira_assert (pref[i] == NO_REGS || cover_class != NO_REGS);
+ regno = ALLOCNO_REGNO (a);
+ aclass = regno_aclass[regno];
+ cost_classes_ptr = regno_cost_classes[regno];
+ ira_assert (pref[i] == NO_REGS || aclass != NO_REGS);
ALLOCNO_MEMORY_COST (a) = COSTS (costs, i)->mem_cost;
- ira_set_allocno_cover_class (a, cover_class);
- if (cover_class == NO_REGS)
+ ira_set_allocno_class (a, aclass);
+ if (aclass == NO_REGS)
continue;
- ALLOCNO_AVAILABLE_REGS_NUM (a) = ira_available_class_regs[cover_class];
- if (optimize && ALLOCNO_COVER_CLASS (a) != pref[i])
+ if (optimize && ALLOCNO_CLASS (a) != pref[i])
{
- n = ira_class_hard_regs_num[cover_class];
+ n = ira_class_hard_regs_num[aclass];
ALLOCNO_HARD_REG_COSTS (a)
- = reg_costs = ira_allocate_cost_vector (cover_class);
+ = reg_costs = ira_allocate_cost_vector (aclass);
for (j = n - 1; j >= 0; j--)
{
- regno = ira_class_hard_regs[cover_class][j];
- if (TEST_HARD_REG_BIT (reg_class_contents[pref[i]], regno))
- reg_costs[j] = ALLOCNO_COVER_CLASS_COST (a);
+ hard_regno = ira_class_hard_regs[aclass][j];
+ if (TEST_HARD_REG_BIT (reg_class_contents[pref[i]], hard_regno))
+ reg_costs[j] = ALLOCNO_CLASS_COST (a);
else
{
- rclass = REGNO_REG_CLASS (regno);
- num = cost_class_nums[rclass];
+ rclass = REGNO_REG_CLASS (hard_regno);
+ num = cost_classes_ptr->index[rclass];
if (num < 0)
{
- /* The hard register class is not a cover class or a
- class not fully inside in a cover class -- use
- the allocno cover class. */
- ira_assert (ira_hard_regno_cover_class[regno]
- == cover_class);
- num = cost_class_nums[cover_class];
+ num = cost_classes_ptr->hard_regno_index[hard_regno];
+ ira_assert (num >= 0);
}
reg_costs[j] = COSTS (costs, i)->cost[num];
}
this_op_costs[i] = NULL;
}
temp_costs = NULL;
- cost_classes = NULL;
}
/* Free allocated temporary cost vectors. */
-static void
-free_ira_costs (void)
+void
+target_ira_int::free_ira_costs ()
{
int i;
- if (init_cost != NULL)
- free (init_cost);
- init_cost = NULL;
+ free (x_init_cost);
+ x_init_cost = NULL;
for (i = 0; i < MAX_RECOG_OPERANDS; i++)
{
- if (op_costs[i] != NULL)
- free (op_costs[i]);
- if (this_op_costs[i] != NULL)
- free (this_op_costs[i]);
- op_costs[i] = this_op_costs[i] = NULL;
+ free (x_op_costs[i]);
+ free (x_this_op_costs[i]);
+ x_op_costs[i] = x_this_op_costs[i] = NULL;
}
- if (temp_costs != NULL)
- free (temp_costs);
- temp_costs = NULL;
- if (cost_classes != NULL)
- free (cost_classes);
- cost_classes = NULL;
+ free (x_temp_costs);
+ x_temp_costs = NULL;
}
/* This is called each time register related information is
{
int i;
- free_ira_costs ();
+ this_target_ira_int->free_ira_costs ();
max_struct_costs_size
= sizeof (struct costs) + sizeof (int) * (ira_important_classes_num - 1);
- /* Don't use ira_allocate because vectors live through several IRA calls. */
+ /* Don't use ira_allocate because vectors live through several IRA
+ calls. */
init_cost = (struct costs *) xmalloc (max_struct_costs_size);
init_cost->mem_cost = 1000000;
for (i = 0; i < ira_important_classes_num; i++)
this_op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size);
}
temp_costs = (struct costs *) xmalloc (max_struct_costs_size);
- cost_classes = (enum reg_class *) xmalloc (sizeof (enum reg_class)
- * ira_important_classes_num);
-}
-
-/* Function called once at the end of compiler work. */
-void
-ira_finish_costs_once (void)
-{
- free_ira_costs ();
}
\f
init_subregs_of_mode ();
costs = (struct costs *) ira_allocate (max_struct_costs_size
* cost_elements_num);
- pref_buffer
- = (enum reg_class *) ira_allocate (sizeof (enum reg_class)
- * cost_elements_num);
- regno_cover_class
- = (enum reg_class *) ira_allocate (sizeof (enum reg_class)
- * max_reg_num ());
+ pref_buffer = (enum reg_class *) ira_allocate (sizeof (enum reg_class)
+ * cost_elements_num);
+ regno_aclass = (enum reg_class *) ira_allocate (sizeof (enum reg_class)
+ * max_reg_num ());
regno_equiv_gains = (int *) ira_allocate (sizeof (int) * max_reg_num ());
memset (regno_equiv_gains, 0, sizeof (int) * max_reg_num ());
}
static void
finish_costs (void)
{
+ finish_subregs_of_mode ();
ira_free (regno_equiv_gains);
- ira_free (regno_cover_class);
+ ira_free (regno_aclass);
ira_free (pref_buffer);
ira_free (costs);
}
-/* Entry function which defines cover class, memory and hard register
- costs for each allocno. */
+/* Entry function which defines register class, memory and hard
+ register costs for each allocno. */
void
ira_costs (void)
{
init_costs ();
total_allocno_costs = (struct costs *) ira_allocate (max_struct_costs_size
* ira_allocnos_num);
+ initiate_regno_cost_classes ();
calculate_elim_costs_all_insns ();
find_costs_and_classes (ira_dump_file);
- setup_allocno_cover_class_and_costs ();
+ setup_allocno_class_and_costs ();
+ finish_regno_cost_classes ();
finish_costs ();
ira_free (total_allocno_costs);
}
-/* Entry function which defines classes for pseudos. */
+/* Entry function which defines classes for pseudos.
+ Set pseudo_classes_defined_p only if DEFINE_PSEUDO_CLASSES is true. */
void
-ira_set_pseudo_classes (FILE *dump_file)
+ira_set_pseudo_classes (bool define_pseudo_classes, FILE *dump_file)
{
allocno_p = false;
internal_flag_ira_verbose = flag_ira_verbose;
cost_elements_num = max_reg_num ();
init_costs ();
+ initiate_regno_cost_classes ();
find_costs_and_classes (dump_file);
- pseudo_classes_defined_p = true;
+ finish_regno_cost_classes ();
+ if (define_pseudo_classes)
+ pseudo_classes_defined_p = true;
+
finish_costs ();
}
function calls. This is called only when we found all intersected
calls during building allocno live ranges. */
void
-ira_tune_allocno_costs_and_cover_classes (void)
+ira_tune_allocno_costs (void)
{
int j, n, regno;
int cost, min_cost, *reg_costs;
- enum reg_class cover_class, rclass;
- enum machine_mode mode;
+ enum reg_class aclass, rclass;
+ machine_mode mode;
ira_allocno_t a;
ira_allocno_iterator ai;
+ ira_allocno_object_iterator oi;
+ ira_object_t obj;
+ bool skip_p;
+ HARD_REG_SET *crossed_calls_clobber_regs;
FOR_EACH_ALLOCNO (a, ai)
{
- cover_class = ALLOCNO_COVER_CLASS (a);
- if (cover_class == NO_REGS)
+ aclass = ALLOCNO_CLASS (a);
+ if (aclass == NO_REGS)
continue;
mode = ALLOCNO_MODE (a);
- n = ira_class_hard_regs_num[cover_class];
+ n = ira_class_hard_regs_num[aclass];
min_cost = INT_MAX;
- if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0)
+ if (ALLOCNO_CALLS_CROSSED_NUM (a)
+ != ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a))
{
ira_allocate_and_set_costs
- (&ALLOCNO_HARD_REG_COSTS (a), cover_class,
- ALLOCNO_COVER_CLASS_COST (a));
+ (&ALLOCNO_HARD_REG_COSTS (a), aclass,
+ ALLOCNO_CLASS_COST (a));
reg_costs = ALLOCNO_HARD_REG_COSTS (a);
for (j = n - 1; j >= 0; j--)
{
- regno = ira_class_hard_regs[cover_class][j];
+ regno = ira_class_hard_regs[aclass][j];
+ skip_p = false;
+ FOR_EACH_ALLOCNO_OBJECT (a, obj, oi)
+ {
+ if (ira_hard_reg_set_intersection_p (regno, mode,
+ OBJECT_CONFLICT_HARD_REGS
+ (obj)))
+ {
+ skip_p = true;
+ break;
+ }
+ }
+ if (skip_p)
+ continue;
rclass = REGNO_REG_CLASS (regno);
cost = 0;
- if (! ira_hard_reg_not_in_set_p (regno, mode, call_used_reg_set)
- || HARD_REGNO_CALL_PART_CLOBBERED (regno, mode))
+ crossed_calls_clobber_regs
+ = &(ALLOCNO_CROSSED_CALLS_CLOBBERED_REGS (a));
+ if (ira_hard_reg_set_intersection_p (regno, mode,
+ *crossed_calls_clobber_regs)
+ && (ira_hard_reg_set_intersection_p (regno, mode,
+ call_used_reg_set)
+ || HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
cost += (ALLOCNO_CALL_FREQ (a)
* (ira_memory_move_cost[mode][rclass][0]
+ ira_memory_move_cost[mode][rclass][1]));
* ALLOCNO_FREQ (a)
* IRA_HARD_REGNO_ADD_COST_MULTIPLIER (regno) / 2);
#endif
- reg_costs[j] += cost;
+ if (INT_MAX - cost < reg_costs[j])
+ reg_costs[j] = INT_MAX;
+ else
+ reg_costs[j] += cost;
if (min_cost > reg_costs[j])
min_cost = reg_costs[j];
}
}
if (min_cost != INT_MAX)
- ALLOCNO_COVER_CLASS_COST (a) = min_cost;
+ ALLOCNO_CLASS_COST (a) = min_cost;
- /* Some targets allow pseudos to be allocated to unaligned
- sequences of hard registers. However, selecting an unaligned
- sequence can unnecessarily restrict later allocations. So
- increase the cost of unaligned hard regs to encourage the use
- of aligned hard regs. */
+ /* Some targets allow pseudos to be allocated to unaligned sequences
+ of hard registers. However, selecting an unaligned sequence can
+ unnecessarily restrict later allocations. So increase the cost of
+ unaligned hard regs to encourage the use of aligned hard regs. */
{
- int nregs, index;
+ const int nregs = ira_reg_class_max_nregs[aclass][ALLOCNO_MODE (a)];
- if ((nregs = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)]) > 1)
+ if (nregs > 1)
{
ira_allocate_and_set_costs
- (&ALLOCNO_HARD_REG_COSTS (a), cover_class,
- ALLOCNO_COVER_CLASS_COST (a));
+ (&ALLOCNO_HARD_REG_COSTS (a), aclass, ALLOCNO_CLASS_COST (a));
reg_costs = ALLOCNO_HARD_REG_COSTS (a);
for (j = n - 1; j >= 0; j--)
{
- if (j % nregs != 0)
+ regno = ira_non_ordered_class_hard_regs[aclass][j];
+ if ((regno % nregs) != 0)
{
- regno = ira_non_ordered_class_hard_regs[cover_class][j];
- index = ira_class_hard_reg_index[cover_class][regno];
+ int index = ira_class_hard_reg_index[aclass][regno];
ira_assert (index != -1);
reg_costs[index] += ALLOCNO_FREQ (a);
}
else
regno_equiv_gains[regno] += cost;
}
+
+void
+ira_costs_c_finalize (void)
+{
+ this_target_ira_int->free_ira_costs ();
+}