2c2d5d00f8
PR middle-end/79521 * ira-costs.c (scan_one_insn): Check have_regs_of_mode before calling ira_init_register_move_cost_if_necessary. From-SVN: r245500
2408 lines
74 KiB
C
2408 lines
74 KiB
C
/* IRA hard register and memory cost calculation for allocnos or pseudos.
|
||
Copyright (C) 2006-2017 Free Software Foundation, Inc.
|
||
Contributed by Vladimir Makarov <vmakarov@redhat.com>.
|
||
|
||
This file is part of GCC.
|
||
|
||
GCC is free software; you can redistribute it and/or modify it under
|
||
the terms of the GNU General Public License as published by the Free
|
||
Software Foundation; either version 3, or (at your option) any later
|
||
version.
|
||
|
||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||
for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with GCC; see the file COPYING3. If not see
|
||
<http://www.gnu.org/licenses/>. */
|
||
|
||
#include "config.h"
|
||
#include "system.h"
|
||
#include "coretypes.h"
|
||
#include "backend.h"
|
||
#include "target.h"
|
||
#include "rtl.h"
|
||
#include "tree.h"
|
||
#include "predict.h"
|
||
#include "memmodel.h"
|
||
#include "tm_p.h"
|
||
#include "insn-config.h"
|
||
#include "regs.h"
|
||
#include "ira.h"
|
||
#include "ira-int.h"
|
||
#include "addresses.h"
|
||
#include "reload.h"
|
||
|
||
/* The flags is set up every time when we calculate pseudo register
|
||
classes through function ira_set_pseudo_classes. */
|
||
static bool pseudo_classes_defined_p = false;
|
||
|
||
/* TRUE if we work with allocnos. Otherwise we work with pseudos. */
|
||
static bool allocno_p;
|
||
|
||
/* Number of elements in array `costs'. */
|
||
static int cost_elements_num;
|
||
|
||
/* 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. */
|
||
struct costs
|
||
{
|
||
int mem_cost;
|
||
/* Costs for register classes start here. We process only some
|
||
allocno classes. */
|
||
int cost[1];
|
||
};
|
||
|
||
#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;
|
||
|
||
/* It is the current size of struct costs. */
|
||
static size_t struct_costs_size;
|
||
|
||
/* Return pointer to structure containing costs of allocno or pseudo
|
||
with given NUM in array ARR. */
|
||
#define COSTS(arr, num) \
|
||
((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]) \
|
||
: (int) regno)
|
||
|
||
/* Record register class preferences of each allocno or pseudo. Null
|
||
value means no preferences. It happens on the 1st iteration of the
|
||
cost calculation. */
|
||
static enum reg_class *pref;
|
||
|
||
/* Allocated buffers for pref. */
|
||
static enum reg_class *pref_buffer;
|
||
|
||
/* 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. */
|
||
static int *regno_equiv_gains;
|
||
|
||
/* Execution frequency of the current insn. */
|
||
static int frequency;
|
||
|
||
|
||
|
||
/* 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;
|
||
}
|
||
|
||
|
||
|
||
/* 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, machine_mode mode, reg_class_t rclass, bool to_p,
|
||
secondary_reload_info *prev_sri)
|
||
{
|
||
secondary_reload_info sri;
|
||
reg_class_t secondary_class = NO_REGS;
|
||
|
||
/* If X is a SCRATCH, there is actually nothing to move since we are
|
||
assuming optimal allocation. */
|
||
if (GET_CODE (x) == SCRATCH)
|
||
return 0;
|
||
|
||
/* Get the class we will actually use for a reload. */
|
||
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
|
||
copy it. */
|
||
sri.prev_sri = prev_sri;
|
||
sri.extra_cost = 0;
|
||
/* PR 68770: Secondary reload might examine the t_icode field. */
|
||
sri.t_icode = CODE_FOR_nothing;
|
||
|
||
secondary_class = targetm.secondary_reload (to_p, x, rclass, mode, &sri);
|
||
|
||
if (secondary_class != NO_REGS)
|
||
{
|
||
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));
|
||
}
|
||
|
||
/* For memory, use the memory move cost, for (hard) registers, use
|
||
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][(int) rclass][to_p != 0];
|
||
else if (REG_P (x))
|
||
{
|
||
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
|
||
here. */
|
||
return sri.extra_cost + COSTS_N_INSNS (1);
|
||
}
|
||
|
||
|
||
|
||
/* Record the cost of using memory or hard registers of various
|
||
classes for the operands in INSN.
|
||
|
||
N_ALTS is the number of alternatives.
|
||
N_OPS is the number of operands.
|
||
OPS is an array of the operands.
|
||
MODES are the modes of the operands, in case any are VOIDmode.
|
||
CONSTRAINTS are the constraints to use for the operands. This array
|
||
is modified by this procedure.
|
||
|
||
This procedure works alternative by alternative. For each
|
||
alternative we assume that we will be able to allocate all allocnos
|
||
to their ideal register class and calculate the cost of using that
|
||
alternative. Then we compute, for each operand that is a
|
||
pseudo-register, the cost of having the allocno allocated to each
|
||
register class and using it in that alternative. To this cost is
|
||
added the cost of the alternative.
|
||
|
||
The cost of each class for this insn is its lowest cost among all
|
||
the alternatives. */
|
||
static void
|
||
record_reg_classes (int n_alts, int n_ops, rtx *ops,
|
||
machine_mode *modes, const char **constraints,
|
||
rtx_insn *insn, enum reg_class *pref)
|
||
{
|
||
int alt;
|
||
int i, j, k;
|
||
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 allows_mem[MAX_RECOG_OPERANDS];
|
||
enum reg_class rclass;
|
||
int alt_fail = 0;
|
||
int alt_cost = 0, op_cost_add;
|
||
|
||
if (!TEST_BIT (preferred, alt))
|
||
{
|
||
for (i = 0; i < recog_data.n_operands; i++)
|
||
constraints[i] = skip_alternative (constraints[i]);
|
||
|
||
continue;
|
||
}
|
||
|
||
for (i = 0; i < n_ops; i++)
|
||
{
|
||
unsigned char c;
|
||
const char *p = constraints[i];
|
||
rtx op = ops[i];
|
||
machine_mode mode = modes[i];
|
||
int allows_addr = 0;
|
||
int win = 0;
|
||
|
||
/* Initially show we know nothing about the register class. */
|
||
classes[i] = NO_REGS;
|
||
allows_mem[i] = 0;
|
||
|
||
/* If this operand has no constraints at all, we can
|
||
conclude nothing about it since anything is valid. */
|
||
if (*p == 0)
|
||
{
|
||
if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
|
||
memset (this_op_costs[i], 0, struct_costs_size);
|
||
continue;
|
||
}
|
||
|
||
/* If this alternative is only relevant when this operand
|
||
matches a previous operand, we do different things
|
||
depending on whether this operand is a allocno-reg or not.
|
||
We must process any modifiers for the operand before we
|
||
can make this test. */
|
||
while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
|
||
p++;
|
||
|
||
if (p[0] >= '0' && p[0] <= '0' + i)
|
||
{
|
||
/* Copy class and whether memory is allowed from the
|
||
matching alternative. Then perform any needed cost
|
||
computations and/or adjustments. */
|
||
j = p[0] - '0';
|
||
classes[i] = classes[j];
|
||
allows_mem[i] = allows_mem[j];
|
||
if (allows_mem[i])
|
||
insn_allows_mem[i] = 1;
|
||
|
||
if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
|
||
{
|
||
/* If this matches the other operand, we have no
|
||
added cost and we win. */
|
||
if (rtx_equal_p (ops[j], op))
|
||
win = 1;
|
||
/* If we can put the other operand into a register,
|
||
add to the cost of this alternative the cost to
|
||
copy this operand to the register used for the
|
||
other operand. */
|
||
else if (classes[j] != NO_REGS)
|
||
{
|
||
alt_cost += copy_cost (op, mode, classes[j], 1, NULL);
|
||
win = 1;
|
||
}
|
||
}
|
||
else if (! REG_P (ops[j])
|
||
|| REGNO (ops[j]) < FIRST_PSEUDO_REGISTER)
|
||
{
|
||
/* This op is an allocno but the one it matches is
|
||
not. */
|
||
|
||
/* If we can't put the other operand into a
|
||
register, this alternative can't be used. */
|
||
|
||
if (classes[j] == NO_REGS)
|
||
alt_fail = 1;
|
||
/* Otherwise, add to the cost of this alternative
|
||
the cost to copy the other operand to the hard
|
||
register used for this operand. */
|
||
else
|
||
alt_cost += copy_cost (ops[j], mode, classes[j], 1, NULL);
|
||
}
|
||
else
|
||
{
|
||
/* The costs of this operand are not the same as the
|
||
other operand since move costs are not symmetric.
|
||
Moreover, if we cannot tie them, this alternative
|
||
needs to do a copy, which is one insn. */
|
||
struct costs *pp = this_op_costs[i];
|
||
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)
|
||
{
|
||
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
|
||
= ((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)
|
||
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 (ira_reg_class_intersect
|
||
[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;
|
||
|
||
p++;
|
||
}
|
||
}
|
||
|
||
/* Scan all the constraint letters. See if the operand
|
||
matches any of the constraints. Collect the valid
|
||
register classes and see if this operand accepts
|
||
memory. */
|
||
while ((c = *p))
|
||
{
|
||
switch (c)
|
||
{
|
||
case '*':
|
||
/* Ignore the next letter for this pass. */
|
||
c = *++p;
|
||
break;
|
||
|
||
case '^':
|
||
alt_cost += 2;
|
||
break;
|
||
|
||
case '?':
|
||
alt_cost += 2;
|
||
break;
|
||
|
||
case 'g':
|
||
if (MEM_P (op)
|
||
|| (CONSTANT_P (op)
|
||
&& (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))))
|
||
win = 1;
|
||
insn_allows_mem[i] = allows_mem[i] = 1;
|
||
classes[i] = ira_reg_class_subunion[classes[i]][GENERAL_REGS];
|
||
break;
|
||
|
||
default:
|
||
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;
|
||
break;
|
||
|
||
case CT_SPECIAL_MEMORY:
|
||
insn_allows_mem[i] = allows_mem[i] = 1;
|
||
if (MEM_P (op) && constraint_satisfied_p (op, cn))
|
||
win = 1;
|
||
break;
|
||
|
||
case CT_ADDRESS:
|
||
/* Every address can be reloaded to fit. */
|
||
allows_addr = 1;
|
||
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_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;
|
||
}
|
||
break;
|
||
}
|
||
p += CONSTRAINT_LEN (c, p);
|
||
if (c == ',')
|
||
break;
|
||
}
|
||
|
||
constraints[i] = p;
|
||
|
||
if (alt_fail)
|
||
break;
|
||
|
||
/* How we account for this operand now depends on whether it
|
||
is a pseudo register or not. If it is, we first check if
|
||
any register classes are valid. If not, we ignore this
|
||
alternative, since we want to assume that all allocnos get
|
||
allocated for register preferencing. If some register
|
||
class is valid, compute the costs of moving the allocno
|
||
into that class. */
|
||
if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
|
||
{
|
||
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 and memory is
|
||
not allowed.
|
||
|
||
Otherwise we may perform an uninitialized read
|
||
from this_op_costs after the `continue' statement
|
||
below. */
|
||
alt_fail = 1;
|
||
}
|
||
else
|
||
{
|
||
unsigned int regno = REGNO (op);
|
||
struct costs *pp = this_op_costs[i];
|
||
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)
|
||
{
|
||
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 (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
|
||
+= ((out_p
|
||
? ira_memory_move_cost[mode][pref_class][1]
|
||
: 0)
|
||
+ (in_p
|
||
? ira_memory_move_cost[mode][pref_class][0]
|
||
: 0));
|
||
else if (ira_reg_class_intersect[pref_class][op_class]
|
||
== NO_REGS)
|
||
alt_cost += (ira_register_move_cost
|
||
[mode][pref_class][op_class]);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Otherwise, if this alternative wins, either because we
|
||
have already determined that or if we have a hard
|
||
register of the proper class, there is no cost for this
|
||
alternative. */
|
||
else if (win || (REG_P (op)
|
||
&& reg_fits_class_p (op, classes[i],
|
||
0, GET_MODE (op))))
|
||
;
|
||
|
||
/* If registers are valid, the cost of this alternative
|
||
includes copying the object to and/or from a
|
||
register. */
|
||
else if (classes[i] != NO_REGS)
|
||
{
|
||
if (recog_data.operand_type[i] != OP_OUT)
|
||
alt_cost += copy_cost (op, mode, classes[i], 1, NULL);
|
||
|
||
if (recog_data.operand_type[i] != OP_IN)
|
||
alt_cost += copy_cost (op, mode, classes[i], 0, NULL);
|
||
}
|
||
/* The only other way this alternative can be used is if
|
||
this is a constant that could be placed into memory. */
|
||
else if (CONSTANT_P (op) && (allows_addr || allows_mem[i]))
|
||
alt_cost += ira_memory_move_cost[mode][classes[i]][1];
|
||
else
|
||
alt_fail = 1;
|
||
|
||
if (alt_fail)
|
||
break;
|
||
}
|
||
|
||
if (alt_fail)
|
||
{
|
||
/* The loop above might have exited early once the failure
|
||
was seen. Skip over the constraints for the remaining
|
||
operands. */
|
||
i += 1;
|
||
for (; i < n_ops; ++i)
|
||
constraints[i] = skip_alternative (constraints[i]);
|
||
continue;
|
||
}
|
||
|
||
op_cost_add = alt_cost * frequency;
|
||
/* Finally, update the costs with the information we've
|
||
calculated about this alternative. */
|
||
for (i = 0; i < n_ops; i++)
|
||
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 = cost_classes_ptr->num - 1; k >= 0; k--)
|
||
pp_costs[k]
|
||
= MIN (pp_costs[k], (qq_costs[k] + op_cost_add) * scale);
|
||
}
|
||
}
|
||
|
||
if (allocno_p)
|
||
for (i = 0; i < n_ops; i++)
|
||
{
|
||
ira_allocno_t a;
|
||
rtx op = ops[i];
|
||
|
||
if (! REG_P (op) || REGNO (op) < FIRST_PSEUDO_REGISTER)
|
||
continue;
|
||
a = ira_curr_regno_allocno_map [REGNO (op)];
|
||
if (! ALLOCNO_BAD_SPILL_P (a) && insn_allows_mem[i] == 0)
|
||
ALLOCNO_BAD_SPILL_P (a) = true;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
/* Wrapper around REGNO_OK_FOR_INDEX_P, to allow pseudo registers. */
|
||
static inline bool
|
||
ok_for_index_p_nonstrict (rtx reg)
|
||
{
|
||
unsigned regno = REGNO (reg);
|
||
|
||
return regno >= FIRST_PSEUDO_REGISTER || REGNO_OK_FOR_INDEX_P (regno);
|
||
}
|
||
|
||
/* A version of regno_ok_for_base_p for use here, when all
|
||
pseudo-registers should count as OK. Arguments as for
|
||
regno_ok_for_base_p. */
|
||
static inline bool
|
||
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, as, outer_code, index_code);
|
||
}
|
||
|
||
/* Record the pseudo registers we must reload into hard registers in a
|
||
subexpression of a memory address, X.
|
||
|
||
If CONTEXT is 0, we are looking at the base part of an address,
|
||
otherwise we are looking at the index part.
|
||
|
||
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 (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, as, outer_code, index_code);
|
||
|
||
switch (code)
|
||
{
|
||
case CONST_INT:
|
||
case CONST:
|
||
case CC0:
|
||
case PC:
|
||
case SYMBOL_REF:
|
||
case LABEL_REF:
|
||
return;
|
||
|
||
case PLUS:
|
||
/* When we have an address that is a sum, we must determine
|
||
whether registers are "base" or "index" regs. If there is a
|
||
sum of two registers, we must choose one to be the "base".
|
||
Luckily, we can use the REG_POINTER to make a good choice
|
||
most of the time. We only need to do this on machines that
|
||
can have two registers in an address and where the base and
|
||
index register classes are different.
|
||
|
||
??? This code used to set REGNO_POINTER_FLAG in some cases,
|
||
but that seems bogus since it should only be set when we are
|
||
sure the register is being used as a pointer. */
|
||
{
|
||
rtx arg0 = XEXP (x, 0);
|
||
rtx arg1 = XEXP (x, 1);
|
||
enum rtx_code code0 = GET_CODE (arg0);
|
||
enum rtx_code code1 = GET_CODE (arg1);
|
||
|
||
/* Look inside subregs. */
|
||
if (code0 == SUBREG)
|
||
arg0 = SUBREG_REG (arg0), code0 = GET_CODE (arg0);
|
||
if (code1 == SUBREG)
|
||
arg1 = SUBREG_REG (arg1), code1 = GET_CODE (arg1);
|
||
|
||
/* 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, 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, as, PLUS, SCRATCH))
|
||
{
|
||
record_address_regs (mode, as, arg0, context, PLUS, code1, scale);
|
||
if (! CONSTANT_P (arg1))
|
||
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 (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, 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, as, PLUS, REG)
|
||
|| ok_for_index_p_nonstrict (arg0)))
|
||
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, as, PLUS, REG)
|
||
|| ok_for_index_p_nonstrict (arg1)))
|
||
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, 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, 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, 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;
|
||
|
||
/* 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. */
|
||
case POST_MODIFY:
|
||
case PRE_MODIFY:
|
||
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, as, XEXP (XEXP (x, 1), 1), 1, code, REG,
|
||
2 * scale);
|
||
break;
|
||
|
||
case POST_INC:
|
||
case PRE_INC:
|
||
case POST_DEC:
|
||
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. */
|
||
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, 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]) = 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];
|
||
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;
|
||
|
||
default:
|
||
{
|
||
const char *fmt = GET_RTX_FORMAT (code);
|
||
int i;
|
||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||
if (fmt[i] == 'e')
|
||
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 *insn, enum reg_class *pref)
|
||
{
|
||
const char *constraints[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++)
|
||
{
|
||
constraints[i] = recog_data.constraints[i];
|
||
modes[i] = recog_data.operand_mode[i];
|
||
}
|
||
|
||
/* If we get here, we are set up to record the costs of all the
|
||
operands for this insn. Start by initializing the costs. Then
|
||
handle any address registers. Finally record the desired classes
|
||
for any allocnos, doing it twice if some pair of operands are
|
||
commutative. */
|
||
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'
|
||
|| (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. */
|
||
for (i = 0; i < (int) recog_data.n_operands - 1; i++)
|
||
if (constraints[i][0] == '%')
|
||
{
|
||
const char *xconstraints[MAX_RECOG_OPERANDS];
|
||
int j;
|
||
|
||
/* Handle commutative operands by swapping the constraints.
|
||
We assume the modes are the same. */
|
||
for (j = 0; j < recog_data.n_operands; j++)
|
||
xconstraints[j] = constraints[j];
|
||
|
||
xconstraints[i] = constraints[i+1];
|
||
xconstraints[i+1] = constraints[i];
|
||
record_reg_classes (recog_data.n_alternatives, recog_data.n_operands,
|
||
recog_data.operand, modes,
|
||
xconstraints, insn, pref);
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/* 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_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 == ASM_INPUT)
|
||
return insn;
|
||
|
||
/* If INSN is a USE/CLOBBER of a pseudo in a mode M then go ahead
|
||
and initialize the register move costs of mode M.
|
||
|
||
The pseudo may be related to another pseudo via a copy (implicit or
|
||
explicit) and if there are no mode M uses/sets of the original
|
||
pseudo, then we may leave the register move costs uninitialized for
|
||
mode M. */
|
||
if (pat_code == USE || pat_code == CLOBBER)
|
||
{
|
||
rtx x = XEXP (PATTERN (insn), 0);
|
||
if (GET_CODE (x) == REG
|
||
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
|
||
&& have_regs_of_mode[GET_MODE (x)])
|
||
ira_init_register_move_cost_if_necessary (GET_MODE (x));
|
||
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.
|
||
|
||
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))
|
||
&& !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));
|
||
|
||
COSTS (costs, num)->mem_cost
|
||
-= ira_memory_move_cost[GET_MODE (reg)][cl][1] * frequency;
|
||
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, pref);
|
||
|
||
/* Now add the cost for each operand to the total costs for its
|
||
allocno. */
|
||
for (i = 0; i < recog_data.n_operands; i++)
|
||
if (REG_P (recog_data.operand[i])
|
||
&& REGNO (recog_data.operand[i]) >= FIRST_PSEUDO_REGISTER)
|
||
{
|
||
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)
|
||
{
|
||
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;
|
||
}
|
||
|
||
|
||
|
||
/* Print allocnos costs to file F. */
|
||
static void
|
||
print_allocno_costs (FILE *f)
|
||
{
|
||
int k;
|
||
ira_allocno_t a;
|
||
ira_allocno_iterator ai;
|
||
|
||
ira_assert (allocno_p);
|
||
fprintf (f, "\n");
|
||
FOR_EACH_ALLOCNO (a, ai)
|
||
{
|
||
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, ") costs:");
|
||
for (k = 0; k < cost_classes_ptr->num; k++)
|
||
{
|
||
rclass = cost_classes[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", 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");
|
||
}
|
||
}
|
||
|
||
/* Print pseudo costs to file F. */
|
||
static void
|
||
print_pseudo_costs (FILE *f)
|
||
{
|
||
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 (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_ptr->num; k++)
|
||
{
|
||
rclass = cost_classes[k];
|
||
fprintf (f, " %s:%d", reg_class_names[rclass],
|
||
COSTS (costs, regno)->cost[k]);
|
||
}
|
||
fprintf (f, " MEM:%i\n", COSTS (costs, regno)->mem_cost);
|
||
}
|
||
}
|
||
|
||
/* Traverse the BB represented by LOOP_TREE_NODE to update the allocno
|
||
costs. */
|
||
static void
|
||
process_bb_for_costs (basic_block bb)
|
||
{
|
||
rtx_insn *insn;
|
||
|
||
frequency = REG_FREQ_FROM_BB (bb);
|
||
if (frequency == 0)
|
||
frequency = 1;
|
||
FOR_BB_INSNS (bb, insn)
|
||
insn = scan_one_insn (insn);
|
||
}
|
||
|
||
/* Traverse the BB represented by LOOP_TREE_NODE to update the allocno
|
||
costs. */
|
||
static void
|
||
process_bb_node_for_costs (ira_loop_tree_node_t loop_tree_node)
|
||
{
|
||
basic_block bb;
|
||
|
||
bb = loop_tree_node->bb;
|
||
if (bb != NULL)
|
||
process_bb_for_costs (bb);
|
||
}
|
||
|
||
/* Find costs of register classes and memory for allocnos or pseudos
|
||
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, max_cost_classes_num;
|
||
int pass;
|
||
basic_block bb;
|
||
enum reg_class *regno_best_class, new_class;
|
||
|
||
init_recog ();
|
||
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));
|
||
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. */
|
||
pseudo_classes_defined_p = false;
|
||
/* Normally we scan the insns once and determine the best class to
|
||
use for each allocno. However, if -fexpensive-optimizations are
|
||
on, we do so twice, the second time using the tentative best
|
||
classes to guide the selection. */
|
||
for (pass = start; pass <= flag_expensive_optimizations; pass++)
|
||
{
|
||
if ((!allocno_p || internal_flag_ira_verbose > 0) && dump_file)
|
||
fprintf (dump_file,
|
||
"\nPass %i for finding pseudo/allocno costs\n\n", pass);
|
||
|
||
if (pass != start)
|
||
{
|
||
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) * (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);
|
||
|
||
if (allocno_p)
|
||
{
|
||
/* Scan the instructions and record each time it would save code
|
||
to put a certain allocno in a certain class. */
|
||
ira_traverse_loop_tree (true, ira_loop_tree_root,
|
||
process_bb_node_for_costs, NULL);
|
||
|
||
memcpy (total_allocno_costs, costs,
|
||
max_struct_costs_size * ira_allocnos_num);
|
||
}
|
||
else
|
||
{
|
||
basic_block bb;
|
||
|
||
FOR_EACH_BB_FN (bb, cfun)
|
||
process_bb_for_costs (bb);
|
||
}
|
||
|
||
if (pass == 0)
|
||
pref = pref_buffer;
|
||
|
||
/* Now for each allocno look at how desirable each class is and
|
||
find which class is preferred. */
|
||
for (i = max_reg_num () - 1; i >= FIRST_PSEUDO_REGISTER; i--)
|
||
{
|
||
ira_allocno_t a, parent_a;
|
||
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;
|
||
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;
|
||
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)
|
||
&& (parent = ALLOCNO_LOOP_TREE_NODE (a)->parent) != NULL
|
||
&& (parent_a = parent->regno_allocno_map[i]) != NULL
|
||
/* There are no caps yet. */
|
||
&& bitmap_bit_p (ALLOCNO_LOOP_TREE_NODE
|
||
(a)->border_allocnos,
|
||
ALLOCNO_NUM (a)))
|
||
{
|
||
/* Propagate costs to upper levels in the region
|
||
tree. */
|
||
parent_a_num = ALLOCNO_NUM (parent_a);
|
||
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;
|
||
}
|
||
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 (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)
|
||
{
|
||
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;
|
||
best = ALL_REGS;
|
||
alt_class = NO_REGS;
|
||
/* Find best common class for all allocnos with the same
|
||
regno. */
|
||
for (k = 0; k < cost_classes_ptr->num; k++)
|
||
{
|
||
rclass = cost_classes[k];
|
||
if (i_costs[k] < best_cost)
|
||
{
|
||
best_cost = i_costs[k];
|
||
best = (enum reg_class) rclass;
|
||
}
|
||
else if (i_costs[k] == best_cost)
|
||
best = ira_reg_class_subunion[best][rclass];
|
||
if (pass == flag_expensive_optimizations
|
||
/* 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_allocno_class_translate[alt_class];
|
||
if (best_cost > i_mem_cost
|
||
&& ! non_spilled_static_chain_regno_p (i))
|
||
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.
|
||
|
||
The union class arrays give important classes and only
|
||
part of it are allocno classes. So translate them into
|
||
allocno classes. */
|
||
regno_aclass[i] = ira_allocno_class_translate[best];
|
||
else
|
||
{
|
||
/* Make the common class the biggest class of best and
|
||
alt_class. Translate the common class into an
|
||
allocno class too. */
|
||
regno_aclass[i] = (ira_allocno_class_translate
|
||
[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], best))) != 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 > i_mem_cost
|
||
/* Do not assign NO_REGS to static chain pointer
|
||
pseudo when non-local goto is used. */
|
||
&& ! non_spilled_static_chain_regno_p (i))
|
||
best = alt_class = NO_REGS;
|
||
else if (best == alt_class)
|
||
alt_class = NO_REGS;
|
||
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, allocno %s\n",
|
||
i, reg_class_names[best], reg_class_names[alt_class],
|
||
reg_class_names[regno_aclass[i]]);
|
||
}
|
||
regno_best_class[i] = best;
|
||
if (! allocno_p)
|
||
{
|
||
pref[i] = (best_cost > i_mem_cost
|
||
&& ! non_spilled_static_chain_regno_p (i)
|
||
? NO_REGS : best);
|
||
continue;
|
||
}
|
||
for (a = ira_regno_allocno_map[i];
|
||
a != NULL;
|
||
a = ALLOCNO_NEXT_REGNO_ALLOCNO (a))
|
||
{
|
||
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
|
||
{
|
||
/* Finding best class which is subset of the common
|
||
class. */
|
||
best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1;
|
||
allocno_cost = best_cost;
|
||
best = ALL_REGS;
|
||
for (k = 0; k < cost_classes_ptr->num; k++)
|
||
{
|
||
rclass = cost_classes[k];
|
||
if (! ira_class_subset_p[rclass][aclass])
|
||
continue;
|
||
if (total_a_costs[k] < best_cost)
|
||
{
|
||
best_cost = total_a_costs[k];
|
||
allocno_cost = a_costs[k];
|
||
best = (enum reg_class) rclass;
|
||
}
|
||
else if (total_a_costs[k] == best_cost)
|
||
{
|
||
best = ira_reg_class_subunion[best][rclass];
|
||
allocno_cost = MAX (allocno_cost, a_costs[k]);
|
||
}
|
||
}
|
||
ALLOCNO_CLASS_COST (a) = allocno_cost;
|
||
}
|
||
if (internal_flag_ira_verbose > 2 && dump_file != NULL
|
||
&& (pass == 0 || pref[a_num] != best))
|
||
{
|
||
fprintf (dump_file, " a%d (r%d,", a_num, i);
|
||
if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL)
|
||
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, allocno %s\n",
|
||
reg_class_names[best],
|
||
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)
|
||
print_allocno_costs (dump_file);
|
||
else
|
||
print_pseudo_costs (dump_file);
|
||
fprintf (dump_file,"\n");
|
||
}
|
||
}
|
||
ira_free (regno_best_class);
|
||
}
|
||
|
||
|
||
|
||
/* Process moves involving hard regs to modify allocno hard register
|
||
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, src_regno, dst_regno, hard_regno, a_regno;
|
||
bool to_p;
|
||
ira_allocno_t a, curr_a;
|
||
ira_loop_tree_node_t curr_loop_tree_node;
|
||
enum reg_class rclass;
|
||
basic_block bb;
|
||
rtx_insn *insn;
|
||
rtx set, src, dst;
|
||
|
||
bb = loop_tree_node->bb;
|
||
if (bb == NULL)
|
||
return;
|
||
freq = REG_FREQ_FROM_BB (bb);
|
||
if (freq == 0)
|
||
freq = 1;
|
||
FOR_BB_INSNS (bb, insn)
|
||
{
|
||
if (!NONDEBUG_INSN_P (insn))
|
||
continue;
|
||
set = single_set (insn);
|
||
if (set == NULL_RTX)
|
||
continue;
|
||
dst = SET_DEST (set);
|
||
src = SET_SRC (set);
|
||
if (! REG_P (dst) || ! REG_P (src))
|
||
continue;
|
||
dst_regno = REGNO (dst);
|
||
src_regno = REGNO (src);
|
||
if (dst_regno >= FIRST_PSEUDO_REGISTER
|
||
&& src_regno < FIRST_PSEUDO_REGISTER)
|
||
{
|
||
hard_regno = src_regno;
|
||
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;
|
||
a = ira_curr_regno_allocno_map[src_regno];
|
||
to_p = false;
|
||
}
|
||
else
|
||
continue;
|
||
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;
|
||
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 class and modify hard register cost because insns moving
|
||
allocno to/from hard registers. */
|
||
static void
|
||
setup_allocno_class_and_costs (void)
|
||
{
|
||
int i, j, n, regno, hard_regno, num;
|
||
int *reg_costs;
|
||
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);
|
||
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_class (a, aclass);
|
||
if (aclass == NO_REGS)
|
||
continue;
|
||
if (optimize && ALLOCNO_CLASS (a) != pref[i])
|
||
{
|
||
n = ira_class_hard_regs_num[aclass];
|
||
ALLOCNO_HARD_REG_COSTS (a)
|
||
= reg_costs = ira_allocate_cost_vector (aclass);
|
||
for (j = n - 1; j >= 0; j--)
|
||
{
|
||
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 (hard_regno);
|
||
num = cost_classes_ptr->index[rclass];
|
||
if (num < 0)
|
||
{
|
||
num = cost_classes_ptr->hard_regno_index[hard_regno];
|
||
ira_assert (num >= 0);
|
||
}
|
||
reg_costs[j] = COSTS (costs, i)->cost[num];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (optimize)
|
||
ira_traverse_loop_tree (true, ira_loop_tree_root,
|
||
process_bb_node_for_hard_reg_moves, NULL);
|
||
}
|
||
|
||
|
||
|
||
/* Function called once during compiler work. */
|
||
void
|
||
ira_init_costs_once (void)
|
||
{
|
||
int i;
|
||
|
||
init_cost = NULL;
|
||
for (i = 0; i < MAX_RECOG_OPERANDS; i++)
|
||
{
|
||
op_costs[i] = NULL;
|
||
this_op_costs[i] = NULL;
|
||
}
|
||
temp_costs = NULL;
|
||
}
|
||
|
||
/* Free allocated temporary cost vectors. */
|
||
void
|
||
target_ira_int::free_ira_costs ()
|
||
{
|
||
int i;
|
||
|
||
free (x_init_cost);
|
||
x_init_cost = NULL;
|
||
for (i = 0; i < MAX_RECOG_OPERANDS; i++)
|
||
{
|
||
free (x_op_costs[i]);
|
||
free (x_this_op_costs[i]);
|
||
x_op_costs[i] = x_this_op_costs[i] = NULL;
|
||
}
|
||
free (x_temp_costs);
|
||
x_temp_costs = NULL;
|
||
}
|
||
|
||
/* This is called each time register related information is
|
||
changed. */
|
||
void
|
||
ira_init_costs (void)
|
||
{
|
||
int i;
|
||
|
||
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. */
|
||
init_cost = (struct costs *) xmalloc (max_struct_costs_size);
|
||
init_cost->mem_cost = 1000000;
|
||
for (i = 0; i < ira_important_classes_num; i++)
|
||
init_cost->cost[i] = 1000000;
|
||
for (i = 0; i < MAX_RECOG_OPERANDS; i++)
|
||
{
|
||
op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size);
|
||
this_op_costs[i] = (struct costs *) xmalloc (max_struct_costs_size);
|
||
}
|
||
temp_costs = (struct costs *) xmalloc (max_struct_costs_size);
|
||
}
|
||
|
||
|
||
|
||
/* Common initialization function for ira_costs and
|
||
ira_set_pseudo_classes. */
|
||
static void
|
||
init_costs (void)
|
||
{
|
||
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_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 ());
|
||
}
|
||
|
||
/* Common finalization function for ira_costs and
|
||
ira_set_pseudo_classes. */
|
||
static void
|
||
finish_costs (void)
|
||
{
|
||
finish_subregs_of_mode ();
|
||
ira_free (regno_equiv_gains);
|
||
ira_free (regno_aclass);
|
||
ira_free (pref_buffer);
|
||
ira_free (costs);
|
||
}
|
||
|
||
/* Entry function which defines register class, memory and hard
|
||
register costs for each allocno. */
|
||
void
|
||
ira_costs (void)
|
||
{
|
||
allocno_p = true;
|
||
cost_elements_num = ira_allocnos_num;
|
||
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_class_and_costs ();
|
||
finish_regno_cost_classes ();
|
||
finish_costs ();
|
||
ira_free (total_allocno_costs);
|
||
}
|
||
|
||
/* Entry function which defines classes for pseudos.
|
||
Set pseudo_classes_defined_p only if DEFINE_PSEUDO_CLASSES is true. */
|
||
void
|
||
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);
|
||
finish_regno_cost_classes ();
|
||
if (define_pseudo_classes)
|
||
pseudo_classes_defined_p = true;
|
||
|
||
finish_costs ();
|
||
}
|
||
|
||
|
||
|
||
/* Change hard register costs for allocnos which lives through
|
||
function calls. This is called only when we found all intersected
|
||
calls during building allocno live ranges. */
|
||
void
|
||
ira_tune_allocno_costs (void)
|
||
{
|
||
int j, n, regno;
|
||
int cost, min_cost, *reg_costs;
|
||
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)
|
||
{
|
||
aclass = ALLOCNO_CLASS (a);
|
||
if (aclass == NO_REGS)
|
||
continue;
|
||
mode = ALLOCNO_MODE (a);
|
||
n = ira_class_hard_regs_num[aclass];
|
||
min_cost = INT_MAX;
|
||
if (ALLOCNO_CALLS_CROSSED_NUM (a)
|
||
!= ALLOCNO_CHEAP_CALLS_CROSSED_NUM (a))
|
||
{
|
||
ira_allocate_and_set_costs
|
||
(&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[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;
|
||
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]));
|
||
#ifdef IRA_HARD_REGNO_ADD_COST_MULTIPLIER
|
||
cost += ((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
|
||
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_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_max_nregs[aclass][ALLOCNO_MODE (a)];
|
||
|
||
if (nregs > 1)
|
||
{
|
||
ira_allocate_and_set_costs
|
||
(&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[aclass][j];
|
||
if ((regno % nregs) != 0)
|
||
{
|
||
int index = ira_class_hard_reg_index[aclass][regno];
|
||
ira_assert (index != -1);
|
||
reg_costs[index] += ALLOCNO_FREQ (a);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Add COST to the estimated gain for eliminating REGNO with its
|
||
equivalence. If COST is zero, record that no such elimination is
|
||
possible. */
|
||
|
||
void
|
||
ira_adjust_equiv_reg_cost (unsigned regno, int cost)
|
||
{
|
||
if (cost == 0)
|
||
regno_equiv_gains[regno] = 0;
|
||
else
|
||
regno_equiv_gains[regno] += cost;
|
||
}
|
||
|
||
void
|
||
ira_costs_c_finalize (void)
|
||
{
|
||
this_target_ira_int->free_ira_costs ();
|
||
}
|