| /* IRA hard register and memory cost calculation for allocnos or pseudos. |
| Copyright (C) 2006-2024 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 "regset.h" |
| #include "ira.h" |
| #include "ira-int.h" |
| #include "addresses.h" |
| #include "reload.h" |
| #include "print-rtl.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 regs) |
| { |
| 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 = reg_class_contents[cl] & regs; |
| valid_for_cl &= ~(ira_prohibited_class_mode_regs[cl][mode] |
| | 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) |
| { |
| temp = reg_class_contents[aclass] & ~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. */ |
| temp2 = reg_class_contents[cl] & ~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 cannot hold a value of MODE. So the |
| pseudo cannot 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]; |
| const char *p; |
| |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5) |
| { |
| fprintf (ira_dump_file, " Processing insn %u", INSN_UID (insn)); |
| if (INSN_CODE (insn) >= 0 |
| && (p = get_insn_name (INSN_CODE (insn))) != NULL) |
| fprintf (ira_dump_file, " {%s}", p); |
| fprintf (ira_dump_file, " (freq=%d)\n", |
| REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn))); |
| dump_insn_slim (ira_dump_file, insn); |
| } |
| |
| 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; |
| } |
| |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5) |
| { |
| fprintf (ira_dump_file, " Alt %d:", alt); |
| for (i = 0; i < n_ops; i++) |
| { |
| p = constraints[i]; |
| if (*p == '\0') |
| continue; |
| fprintf (ira_dump_file, " (%d) ", i); |
| for (; *p != '\0' && *p != ',' && *p != '#'; p++) |
| fputc (*p, ira_dump_file); |
| } |
| fprintf (ira_dump_file, "\n"); |
| } |
| |
| 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; |
| } |
| else |
| /* Otherwise, add to the cost of this alternative the cost |
| to copy the other operand to the hard register used for |
| this operand. */ |
| { |
| 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: |
| case CT_RELAXED_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 (extract_mem_from_operand (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) |
| { |
| int old_cost; |
| bool cost_change_p = false; |
| 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])]; |
| |
| old_cost = pp->mem_cost; |
| pp->mem_cost = MIN (old_cost, |
| (qq->mem_cost + op_cost_add) * scale); |
| |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5 |
| && pp->mem_cost < old_cost) |
| { |
| cost_change_p = true; |
| fprintf (ira_dump_file, " op %d(r=%u) new costs MEM:%d", |
| i, REGNO(ops[i]), pp->mem_cost); |
| } |
| for (k = cost_classes_ptr->num - 1; k >= 0; k--) |
| { |
| old_cost = pp_costs[k]; |
| pp_costs[k] |
| = MIN (old_cost, (qq_costs[k] + op_cost_add) * scale); |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5 |
| && pp_costs[k] < old_cost) |
| { |
| if (!cost_change_p) |
| fprintf (ira_dump_file, " op %d(r=%u) new costs", |
| i, REGNO(ops[i])); |
| cost_change_p = true; |
| fprintf (ira_dump_file, " %s:%d", |
| reg_class_names[cost_classes_ptr->classes[k]], |
| pp_costs[k]); |
| } |
| } |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5 |
| && cost_change_p) |
| fprintf (ira_dump_file, "\n"); |
| } |
| } |
| |
| 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 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 index registers do not appear, or coincide with base registers, |
| 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. */ |
| if (MAX_REGS_PER_ADDRESS == 1 |
| || 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 set; |
| int i; |
| |
| 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 |
| && recog_data.operand[0] == SET_DEST (set) |
| && recog_data.operand[1] == SET_SRC (set)) |
| { |
| int regno, other_regno; |
| rtx dest = SET_DEST (set); |
| rtx src = SET_SRC (set); |
| |
| if (GET_CODE (dest) == SUBREG |
| && known_eq (GET_MODE_SIZE (GET_MODE (dest)), |
| GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))))) |
| dest = SUBREG_REG (dest); |
| if (GET_CODE (src) == SUBREG |
| && known_eq (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) |
| && (((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 (SET_SRC (set)), cost_mode = mode; |
| machine_mode hard_reg_mode = GET_MODE(regno_reg_rtx[other_regno]); |
| poly_int64 pmode_size = GET_MODE_SIZE (mode); |
| poly_int64 phard_reg_mode_size = GET_MODE_SIZE (hard_reg_mode); |
| HOST_WIDE_INT mode_size, hard_reg_mode_size; |
| cost_classes_t cost_classes_ptr = regno_cost_classes[regno]; |
| enum reg_class *cost_classes = cost_classes_ptr->classes; |
| reg_class_t rclass, hard_reg_class, bigger_hard_reg_class; |
| int cost_factor = 1, cost, k; |
| move_table *move_costs; |
| bool dead_p = find_regno_note (insn, REG_DEAD, REGNO (src)); |
| |
| hard_reg_class = REGNO_REG_CLASS (other_regno); |
| bigger_hard_reg_class = ira_pressure_class_translate[hard_reg_class]; |
| /* Target code may return any cost for mode which does not fit the |
| hard reg class (e.g. DImode for AREG on i386). Check this and use |
| a bigger class to get the right cost. */ |
| if (bigger_hard_reg_class != NO_REGS |
| && ! ira_hard_reg_in_set_p (other_regno, mode, |
| reg_class_contents[hard_reg_class])) |
| hard_reg_class = bigger_hard_reg_class; |
| ira_init_register_move_cost_if_necessary (mode); |
| ira_init_register_move_cost_if_necessary (hard_reg_mode); |
| /* Use smaller movement cost for natural hard reg mode or its mode as |
| operand. */ |
| if (pmode_size.is_constant (&mode_size) |
| && phard_reg_mode_size.is_constant (&hard_reg_mode_size)) |
| { |
| /* Assume we are moving in the natural modes: */ |
| cost_factor = mode_size / hard_reg_mode_size; |
| if (mode_size % hard_reg_mode_size != 0) |
| cost_factor++; |
| if (cost_factor |
| * (ira_register_move_cost |
| [hard_reg_mode][hard_reg_class][hard_reg_class]) |
| < (ira_register_move_cost |
| [mode][hard_reg_class][hard_reg_class])) |
| cost_mode = hard_reg_mode; |
| else |
| cost_factor = 1; |
| } |
| move_costs = ira_register_move_cost[cost_mode]; |
| i = regno == (int) REGNO (src) ? 1 : 0; |
| for (k = cost_classes_ptr->num - 1; k >= 0; k--) |
| { |
| rclass = cost_classes[k]; |
| cost = (i == 0 |
| ? move_costs[hard_reg_class][rclass] |
| : move_costs[rclass][hard_reg_class]); |
| cost *= cost_factor; |
| op_costs[i]->cost[k] = cost * frequency; |
| /* 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. */ |
| if (dead_p |
| && TEST_HARD_REG_BIT (reg_class_contents[rclass], other_regno) |
| && (reg_class_size[(int) rclass] |
| == (ira_reg_class_max_nregs |
| [(int) rclass][(int) GET_MODE(src)]))) |
| { |
| if (reg_class_size[rclass] == 1) |
| op_costs[i]->cost[k] = -frequency; |
| else if (in_hard_reg_set_p (reg_class_contents[rclass], |
| GET_MODE(src), other_regno)) |
| op_costs[i]->cost[k] = -frequency; |
| } |
| } |
| op_costs[i]->mem_cost |
| = ira_memory_move_cost[mode][hard_reg_class][i] * frequency; |
| return; |
| } |
| } |
| |
| 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++) |
| { |
| rtx op_mem = extract_mem_from_operand (recog_data.operand[i]); |
| memcpy (op_costs[i], init_cost, struct_costs_size); |
| |
| if (GET_CODE (recog_data.operand[i]) == SUBREG) |
| recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]); |
| |
| if (MEM_P (op_mem)) |
| record_address_regs (GET_MODE (op_mem), |
| MEM_ADDR_SPACE (op_mem), |
| XEXP (op_mem, 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); |
| } |
| |
| |
| |
| /* 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))) |
| /* LRA does not use equiv with a symbol for PIC code. */ |
| && (! ira_use_lra_p || ! pic_offset_table_rtx |
| || ! contains_symbol_ref_p (XEXP (note, 0)))) |
| { |
| enum reg_class cl = GENERAL_REGS; |
| rtx reg = SET_DEST (set); |
| int num = COST_INDEX (REGNO (reg)); |
| /* Costs for NO_REGS are used in cost calculation on the |
| 1st pass when the preferred register classes are not |
| known yet. In this case we take the best scenario when |
| mode can't be put into GENERAL_REGS. */ |
| if (!targetm.hard_regno_mode_ok (ira_class_hard_regs[cl][0], |
| GET_MODE (reg))) |
| cl = NO_REGS; |
| |
| 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); |
| |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5) |
| { |
| const char *p; |
| fprintf (ira_dump_file, " Final costs after insn %u", INSN_UID (insn)); |
| if (INSN_CODE (insn) >= 0 |
| && (p = get_insn_name (INSN_CODE (insn))) != NULL) |
| fprintf (ira_dump_file, " {%s}", p); |
| fprintf (ira_dump_file, " (freq=%d)\n", |
| REG_FREQ_FROM_BB (BLOCK_FOR_INSN (insn))); |
| dump_insn_slim (ira_dump_file, insn); |
| } |
| |
| /* Now add the cost for each operand to the total costs for its |
| allocno. */ |
| for (i = 0; i < recog_data.n_operands; i++) |
| { |
| rtx op = recog_data.operand[i]; |
| |
| if (GET_CODE (op) == SUBREG) |
| op = SUBREG_REG (op); |
| if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER) |
| { |
| int regno = REGNO (op); |
| 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 = 0; |
| |
| /* 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; |
| } |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5) |
| { |
| fprintf (ira_dump_file, " op %d(r=%u) MEM:%d(+%d)", |
| i, REGNO(op), 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; |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5) |
| { |
| fprintf (ira_dump_file, " %s:%d(+%d)", |
| reg_class_names[cost_classes_ptr->classes[k]], |
| p_costs[k], add_cost); |
| } |
| } |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5) |
| fprintf (ira_dump_file, "\n"); |
| } |
| } |
| return insn; |
| } |
| |
| |
| |
| /* Print allocnos costs to the dump file. */ |
| static void |
| print_allocno_costs (void) |
| { |
| int k; |
| ira_allocno_t a; |
| ira_allocno_iterator ai; |
| |
| ira_assert (allocno_p); |
| fprintf (ira_dump_file, "\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 (ira_dump_file, " a%d(r%d,", i, regno); |
| if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL) |
| fprintf (ira_dump_file, "b%d", bb->index); |
| else |
| fprintf (ira_dump_file, "l%d", ALLOCNO_LOOP_TREE_NODE (a)->loop_num); |
| fprintf (ira_dump_file, ") costs:"); |
| for (k = 0; k < cost_classes_ptr->num; k++) |
| { |
| rclass = cost_classes[k]; |
| fprintf (ira_dump_file, " %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 (ira_dump_file, ",%d", |
| COSTS (total_allocno_costs, i)->cost[k]); |
| } |
| fprintf (ira_dump_file, " MEM:%i", COSTS (costs, i)->mem_cost); |
| if (flag_ira_region == IRA_REGION_ALL |
| || flag_ira_region == IRA_REGION_MIXED) |
| fprintf (ira_dump_file, ",%d", |
| COSTS (total_allocno_costs, i)->mem_cost); |
| fprintf (ira_dump_file, "\n"); |
| } |
| } |
| |
| /* Print pseudo costs to the dump file. */ |
| static void |
| print_pseudo_costs (void) |
| { |
| int regno, k; |
| int rclass; |
| cost_classes_t cost_classes_ptr; |
| enum reg_class *cost_classes; |
| |
| ira_assert (! allocno_p); |
| fprintf (ira_dump_file, "\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 (ira_dump_file, " r%d costs:", regno); |
| for (k = 0; k < cost_classes_ptr->num; k++) |
| { |
| rclass = cost_classes[k]; |
| fprintf (ira_dump_file, " %s:%d", reg_class_names[rclass], |
| COSTS (costs, regno)->cost[k]); |
| } |
| fprintf (ira_dump_file, " 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); |
| } |
| |
| /* Return true if all autoinc rtx in X change only a register and memory is |
| valid. */ |
| static bool |
| validate_autoinc_and_mem_addr_p (rtx x) |
| { |
| enum rtx_code code = GET_CODE (x); |
| if (GET_RTX_CLASS (code) == RTX_AUTOINC) |
| return REG_P (XEXP (x, 0)); |
| const char *fmt = GET_RTX_FORMAT (code); |
| for (int i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| if (fmt[i] == 'e') |
| { |
| if (!validate_autoinc_and_mem_addr_p (XEXP (x, i))) |
| return false; |
| } |
| else if (fmt[i] == 'E') |
| { |
| for (int j = 0; j < XVECLEN (x, i); j++) |
| if (!validate_autoinc_and_mem_addr_p (XVECEXP (x, i, j))) |
| return false; |
| } |
| /* Check memory after checking autoinc to guarantee that autoinc is already |
| valid for machine-dependent code checking memory address. */ |
| return (!MEM_P (x) |
| || memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0), |
| MEM_ADDR_SPACE (x))); |
| } |
| |
| /* Check that reg REGNO can be changed by TO in INSN. Return true in case the |
| result insn would be valid one. */ |
| static bool |
| equiv_can_be_consumed_p (int regno, rtx to, rtx_insn *insn) |
| { |
| validate_replace_src_group (regno_reg_rtx[regno], to, insn); |
| /* We can change register to equivalent memory in autoinc rtl. Some code |
| including verify_changes assumes that autoinc contains only a register. |
| So check this first. */ |
| bool res = validate_autoinc_and_mem_addr_p (PATTERN (insn)); |
| if (res) |
| res = verify_changes (0); |
| cancel_changes (0); |
| return res; |
| } |
| |
| /* Return true if X contains a pseudo with equivalence. In this case also |
| return the pseudo through parameter REG. If the pseudo is a part of subreg, |
| return the subreg through parameter SUBREG. */ |
| |
| static bool |
| get_equiv_regno (rtx x, int ®no, rtx &subreg) |
| { |
| subreg = NULL_RTX; |
| if (GET_CODE (x) == SUBREG) |
| { |
| subreg = x; |
| x = SUBREG_REG (x); |
| } |
| if (REG_P (x) |
| && (ira_reg_equiv[REGNO (x)].memory != NULL |
| || ira_reg_equiv[REGNO (x)].invariant != NULL |
| || ira_reg_equiv[REGNO (x)].constant != NULL)) |
| { |
| regno = REGNO (x); |
| return true; |
| } |
| RTX_CODE code = GET_CODE (x); |
| const char *fmt = GET_RTX_FORMAT (code); |
| |
| for (int i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) |
| if (fmt[i] == 'e') |
| { |
| if (get_equiv_regno (XEXP (x, i), regno, subreg)) |
| return true; |
| } |
| else if (fmt[i] == 'E') |
| { |
| for (int j = 0; j < XVECLEN (x, i); j++) |
| if (get_equiv_regno (XVECEXP (x, i, j), regno, subreg)) |
| return true; |
| } |
| return false; |
| } |
| |
| /* A pass through the current function insns. Calculate costs of using |
| equivalences for pseudos and store them in regno_equiv_gains. */ |
| |
| static void |
| calculate_equiv_gains (void) |
| { |
| basic_block bb; |
| int regno, freq, cost; |
| rtx subreg; |
| rtx_insn *insn; |
| machine_mode mode; |
| enum reg_class rclass; |
| bitmap_head equiv_pseudos; |
| |
| ira_assert (allocno_p); |
| bitmap_initialize (&equiv_pseudos, ®_obstack); |
| for (regno = max_reg_num () - 1; regno >= FIRST_PSEUDO_REGISTER; regno--) |
| if (ira_reg_equiv[regno].init_insns != NULL |
| && (ira_reg_equiv[regno].memory != NULL |
| || ira_reg_equiv[regno].invariant != NULL |
| || (ira_reg_equiv[regno].constant != NULL |
| /* Ignore complicated constants which probably will be placed |
| in memory: */ |
| && GET_CODE (ira_reg_equiv[regno].constant) != CONST_DOUBLE |
| && GET_CODE (ira_reg_equiv[regno].constant) != CONST_VECTOR |
| && GET_CODE (ira_reg_equiv[regno].constant) != LABEL_REF))) |
| { |
| rtx_insn_list *x; |
| for (x = ira_reg_equiv[regno].init_insns; x != NULL; x = x->next ()) |
| { |
| insn = x->insn (); |
| rtx set = single_set (insn); |
| |
| if (set == NULL_RTX || SET_DEST (set) != regno_reg_rtx[regno]) |
| break; |
| bb = BLOCK_FOR_INSN (insn); |
| ira_curr_regno_allocno_map |
| = ira_bb_nodes[bb->index].parent->regno_allocno_map; |
| mode = PSEUDO_REGNO_MODE (regno); |
| rclass = pref[COST_INDEX (regno)]; |
| ira_init_register_move_cost_if_necessary (mode); |
| if (ira_reg_equiv[regno].memory != NULL) |
| cost = ira_memory_move_cost[mode][rclass][1]; |
| else |
| cost = ira_register_move_cost[mode][rclass][rclass]; |
| freq = REG_FREQ_FROM_BB (bb); |
| regno_equiv_gains[regno] += cost * freq; |
| } |
| if (x != NULL) |
| /* We found complicated equiv or reverse equiv mem=reg. Ignore |
| them. */ |
| regno_equiv_gains[regno] = 0; |
| else |
| bitmap_set_bit (&equiv_pseudos, regno); |
| } |
| |
| FOR_EACH_BB_FN (bb, cfun) |
| { |
| freq = REG_FREQ_FROM_BB (bb); |
| ira_curr_regno_allocno_map |
| = ira_bb_nodes[bb->index].parent->regno_allocno_map; |
| FOR_BB_INSNS (bb, insn) |
| { |
| if (!NONDEBUG_INSN_P (insn) |
| || !get_equiv_regno (PATTERN (insn), regno, subreg) |
| || !bitmap_bit_p (&equiv_pseudos, regno)) |
| continue; |
| rtx subst = ira_reg_equiv[regno].memory; |
| |
| if (subst == NULL) |
| subst = ira_reg_equiv[regno].constant; |
| if (subst == NULL) |
| subst = ira_reg_equiv[regno].invariant; |
| ira_assert (subst != NULL); |
| mode = PSEUDO_REGNO_MODE (regno); |
| ira_init_register_move_cost_if_necessary (mode); |
| bool consumed_p = equiv_can_be_consumed_p (regno, subst, insn); |
| |
| rclass = pref[COST_INDEX (regno)]; |
| if (MEM_P (subst) |
| /* If it is a change of constant into double for example, the |
| result constant probably will be placed in memory. */ |
| || (subreg != NULL_RTX && !INTEGRAL_MODE_P (GET_MODE (subreg)))) |
| cost = ira_memory_move_cost[mode][rclass][1] + (consumed_p ? 0 : 1); |
| else if (consumed_p) |
| continue; |
| else |
| cost = ira_register_move_cost[mode][rclass][rclass]; |
| regno_equiv_gains[regno] -= cost * freq; |
| } |
| } |
| bitmap_clear (&equiv_pseudos); |
| } |
| |
| /* 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 (void) |
| { |
| 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) && ira_dump_file) |
| fprintf (ira_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; |
| |
| if (ira_use_lra_p && allocno_p && pass == 1) |
| /* It is a pass through all insns. So do it once and only for RA (not |
| for insn scheduler) when we already found preferable pseudo register |
| classes on the previous pass. */ |
| calculate_equiv_gains (); |
| |
| /* 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; |
| 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; |
| cost_classes = cost_classes_ptr->classes; |
| } |
| else |
| { |
| if (ira_regno_allocno_map[i] == NULL) |
| continue; |
| memset (temp_costs, 0, struct_costs_size); |
| i_mem_cost = 0; |
| cost_classes = cost_classes_ptr->classes; |
| /* 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 (ira_use_lra_p) |
| { |
| if (equiv_savings > 0) |
| { |
| i_mem_cost = 0; |
| if (ira_dump_file != NULL && internal_flag_ira_verbose > 5) |
| fprintf (ira_dump_file, |
| " Use MEM for r%d as the equiv savings is %d\n", |
| i, equiv_savings); |
| } |
| } |
| 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 (pic_offset_table_rtx != NULL |
| && i == (int) REGNO (pic_offset_table_rtx)) |
| { |
| /* For some targets, integer pseudos can be assigned to fp |
| regs. As we don't want reload pic offset table pseudo, we |
| should avoid using non-integer regs. */ |
| regno_aclass[i] |
| = ira_reg_class_intersect[regno_aclass[i]][GENERAL_REGS]; |
| alt_class = ira_reg_class_intersect[alt_class][GENERAL_REGS]; |
| } |
| 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) |
| && ira_dump_file != NULL) |
| fprintf (ira_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 && ira_dump_file != NULL |
| && (pass == 0 || pref[a_num] != best)) |
| { |
| fprintf (ira_dump_file, " a%d (r%d,", a_num, i); |
| if ((bb = ALLOCNO_LOOP_TREE_NODE (a)->bb) != NULL) |
| fprintf (ira_dump_file, "b%d", bb->index); |
| else |
| fprintf (ira_dump_file, "l%d", |
| ALLOCNO_LOOP_TREE_NODE (a)->loop_num); |
| fprintf (ira_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 && ira_dump_file) |
| { |
| if (allocno_p) |
| print_allocno_costs (); |
| else |
| print_pseudo_costs (); |
| fprintf (ira_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; |
| if (reg_class_size[(int) REGNO_REG_CLASS (hard_regno)] |
| == (ira_reg_class_max_nregs |
| [REGNO_REG_CLASS (hard_regno)][(int) ALLOCNO_MODE(a)])) |
| /* If the class can provide only one hard reg to the allocno, |
| we processed the insn record_operand_costs already and we |
| actually updated the hard reg cost there. */ |
| 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 (); |
| if (!ira_use_lra_p) |
| /* Process equivs in reload to update costs through hook |
| ira_adjust_equiv_reg_cost. */ |
| calculate_elim_costs_all_insns (); |
| find_costs_and_classes (); |
| 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) |
| { |
| FILE *saved_file = ira_dump_file; |
| allocno_p = false; |
| internal_flag_ira_verbose = flag_ira_verbose; |
| ira_dump_file = dump_file; |
| cost_elements_num = max_reg_num (); |
| init_costs (); |
| initiate_regno_cost_classes (); |
| find_costs_and_classes (); |
| finish_regno_cost_classes (); |
| if (define_pseudo_classes) |
| pseudo_classes_defined_p = true; |
| |
| finish_costs (); |
| ira_dump_file = saved_file; |
| } |
| |
| |
| |
| /* 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; |
| machine_mode mode; |
| ira_allocno_t a; |
| ira_allocno_iterator ai; |
| ira_allocno_object_iterator oi; |
| ira_object_t obj; |
| bool skip_p; |
| |
| 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; |
| cost = 0; |
| if (ira_need_caller_save_p (a, regno)) |
| cost += ira_caller_save_cost (a); |
| #ifdef IRA_HARD_REGNO_ADD_COST_MULTIPLIER |
| { |
| auto rclass = REGNO_REG_CLASS (regno); |
| 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); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /* A hook from the reload pass. 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) |
| { |
| ira_assert (!ira_use_lra_p); |
| if (cost == 0) |
| regno_equiv_gains[regno] = 0; |
| else |
| regno_equiv_gains[regno] += cost; |
| } |
| |
| void |
| ira_costs_cc_finalize (void) |
| { |
| this_target_ira_int->free_ira_costs (); |
| } |