/* IRA hard register and memory cost calculation for allocnos or pseudos.
- Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011
- 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 "diagnostic-core.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];
};
(this_target_ira_int->x_op_costs)
#define this_op_costs \
(this_target_ira_int->x_this_op_costs)
-#define cost_classes \
- (this_target_ira_int->x_cost_classes)
/* 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;
-/* 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, reg_class_t 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;
if (secondary_class != NO_REGS)
{
- if (!move_cost[mode])
- init_move_cost (mode);
- return (move_cost[mode][(int) secondary_class][(int) rclass]
+ 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));
}
+ ira_memory_move_cost[mode][(int) rclass][to_p != 0];
else if (REG_P (x))
{
- if (!move_cost[mode])
- init_move_cost (mode);
+ reg_class_t x_class = REGNO_REG_CLASS (REGNO (x));
+
+ ira_init_register_move_cost_if_necessary (mode);
return (sri.extra_cost
- + move_cost[mode][REGNO_REG_CLASS (REGNO (x))][(int) rclass]);
+ + 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, 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, 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. */
record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
recog_data.operand, modes,
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;
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;
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. */
+ 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))
- && LEGITIMATE_CONSTANT_P (XEXP (note, 0))
- && REG_N_SETS (REGNO (SET_DEST (set))) == 1)))
+ && 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;
}
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;
/* If the already accounted for the memory "cost" above, don't
do so again. */
if (!counted_mem)
- p->mem_cost += q->mem_cost;
- for (k = 0; k < cost_classes_num; k++)
- p->cost[k] += q->cost[k];
+ {
+ 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)
-#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)
-#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)
-#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)
-#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 ());
}
{
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. */
{
- const int nregs = ira_reg_class_nregs[cover_class][ALLOCNO_MODE (a)];
+ const int nregs = ira_reg_class_max_nregs[aclass][ALLOCNO_MODE (a)];
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--)
{
- regno = ira_non_ordered_class_hard_regs[cover_class][j];
+ regno = ira_non_ordered_class_hard_regs[aclass][j];
if ((regno % nregs) != 0)
{
- int 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 ();
+}