| /* IRA hard register and memory cost calculation for allocnos. |
| Copyright (C) 2006, 2007, 2008 |
| 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 "tm.h" |
| #include "hard-reg-set.h" |
| #include "rtl.h" |
| #include "expr.h" |
| #include "tm_p.h" |
| #include "flags.h" |
| #include "basic-block.h" |
| #include "regs.h" |
| #include "addresses.h" |
| #include "insn-config.h" |
| #include "recog.h" |
| #include "toplev.h" |
| #include "target.h" |
| #include "params.h" |
| #include "ira-int.h" |
| |
| /* The file contains code is similar to one in regclass but the code |
| works on the allocno basis. */ |
| |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| /* Indexed by n, is TRUE if allocno with number N is used in an |
| auto-inc or auto-dec context. */ |
| static bool *in_inc_dec; |
| #endif |
| |
| /* The `costs' struct records the cost of using hard registers of each |
| class considered for the calculation and of using memory for each |
| allocno. */ |
| struct costs |
| { |
| int mem_cost; |
| /* Costs for register classes start here. We process only some |
| register classes (cover classes on the 1st cost calculation |
| iteration and important classes on the 2nd iteration). */ |
| int cost[1]; |
| }; |
| |
| /* Initialized once. It is a maximal possible size of the allocated |
| struct costs. */ |
| static int max_struct_costs_size; |
| |
| /* Allocated and initialized once, and used to initialize cost values |
| for each insn. */ |
| static struct costs *init_cost; |
| |
| /* Allocated once, and used for temporary purposes. */ |
| static struct costs *temp_costs; |
| |
| /* Allocated once, and used for the cost calculation. */ |
| static struct costs *op_costs[MAX_RECOG_OPERANDS]; |
| static struct costs *this_op_costs[MAX_RECOG_OPERANDS]; |
| |
| /* Original and accumulated costs of each class for each allocno. */ |
| static struct costs *allocno_costs, *total_costs; |
| |
| /* Classes used for cost calculation. They may be different on |
| different iterations of the cost calculations or in different |
| optimization modes. */ |
| static enum reg_class *cost_classes; |
| |
| /* The size of the previous array. */ |
| static int cost_classes_num; |
| |
| /* Map: cost class -> order number (they start with 0) of the cost |
| class. The order number is negative for non-cost classes. */ |
| static int cost_class_nums[N_REG_CLASSES]; |
| |
| /* It is the current size of struct costs. */ |
| static int struct_costs_size; |
| |
| /* Return pointer to structure containing costs of allocno with given |
| NUM in array ARR. */ |
| #define COSTS_OF_ALLOCNO(arr, num) \ |
| ((struct costs *) ((char *) (arr) + (num) * struct_costs_size)) |
| |
| /* Record register class preferences of each allocno. Null value |
| means no preferences. It happens on the 1st iteration of the cost |
| calculation. */ |
| static enum reg_class *allocno_pref; |
| |
| /* Allocated buffers for allocno_pref. */ |
| static enum reg_class *allocno_pref_buffer; |
| |
| /* Record register class of each allocno with the same regno. */ |
| static enum reg_class *common_classes; |
| |
| /* Execution frequency of the current insn. */ |
| static int frequency; |
| |
| |
| |
| /* Compute the cost of loading X into (if TO_P is TRUE) or from (if |
| TO_P is FALSE) a register of class RCLASS in mode MODE. X must not |
| be a pseudo register. */ |
| static int |
| copy_cost (rtx x, enum machine_mode mode, enum reg_class rclass, bool to_p, |
| secondary_reload_info *prev_sri) |
| { |
| secondary_reload_info sri; |
| enum reg_class 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 = 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; |
| secondary_class = targetm.secondary_reload (to_p, x, rclass, mode, &sri); |
| |
| if (secondary_class != NO_REGS) |
| { |
| if (!move_cost[mode]) |
| init_move_cost (mode); |
| return (move_cost[mode][secondary_class][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][rclass][to_p != 0]; |
| else if (REG_P (x)) |
| { |
| if (!move_cost[mode]) |
| init_move_cost (mode); |
| return (sri.extra_cost + move_cost[mode][REGNO_REG_CLASS (REGNO (x))][rclass]); |
| } |
| 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, |
| enum machine_mode *modes, const char **constraints, |
| rtx insn, struct costs **op_costs, |
| enum reg_class *allocno_pref) |
| { |
| int alt; |
| int i, j, k; |
| rtx set; |
| int insn_allows_mem[MAX_RECOG_OPERANDS]; |
| |
| 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. */ |
| for (alt = 0; alt < n_alts; alt++) |
| { |
| enum reg_class classes[MAX_RECOG_OPERANDS]; |
| int allows_mem[MAX_RECOG_OPERANDS]; |
| int rclass; |
| int alt_fail = 0; |
| int alt_cost = 0, op_cost_add; |
| |
| for (i = 0; i < n_ops; i++) |
| { |
| unsigned char c; |
| const char *p = constraints[i]; |
| rtx op = ops[i]; |
| enum 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 && (p[1] == ',' || p[1] == 0)) |
| { |
| /* 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]; |
| |
| for (k = 0; k < cost_classes_num; k++) |
| { |
| rclass = cost_classes[k]; |
| pp->cost[k] |
| = (((recog_data.operand_type[i] != OP_OUT |
| ? ira_get_may_move_cost (mode, rclass, |
| classes[i], true) : 0) |
| + (recog_data.operand_type[i] != OP_IN |
| ? ira_get_may_move_cost (mode, classes[i], |
| rclass, false) : 0)) |
| * frequency); |
| } |
| |
| /* If the alternative actually allows memory, make |
| things a bit cheaper since we won't need an extra |
| insn to load it. */ |
| pp->mem_cost |
| = ((recog_data.operand_type[i] != OP_IN |
| ? ira_memory_move_cost[mode][classes[i]][0] : 0) |
| + (recog_data.operand_type[i] != OP_OUT |
| ? ira_memory_move_cost[mode][classes[i]][1] : 0) |
| - allows_mem[i]) * frequency; |
| |
| /* If we have assigned a class to this allocno in our |
| first pass, add a cost to this alternative |
| corresponding to what we would add if this allocno |
| were not in the appropriate class. We could use |
| cover class here but it is less accurate |
| approximation. */ |
| if (allocno_pref) |
| { |
| enum reg_class pref_class |
| = allocno_pref[ALLOCNO_NUM |
| (ira_curr_regno_allocno_map |
| [REGNO (op)])]; |
| |
| if (pref_class == NO_REGS) |
| alt_cost |
| += ((recog_data.operand_type[i] != OP_IN |
| ? ira_memory_move_cost[mode][classes[i]][0] |
| : 0) |
| + (recog_data.operand_type[i] != OP_OUT |
| ? ira_memory_move_cost[mode][classes[i]][1] |
| : 0)); |
| else if (ira_reg_class_intersect |
| [pref_class][classes[i]] == NO_REGS) |
| alt_cost += ira_get_register_move_cost (mode, |
| pref_class, |
| classes[i]); |
| } |
| if (REGNO (ops[i]) != REGNO (ops[j]) |
| && ! find_reg_note (insn, REG_DEAD, op)) |
| alt_cost += 2; |
| |
| /* This is in place of ordinary cost computation for |
| this operand, so skip to the end of the |
| alternative (should be just one character). */ |
| while (*p && *p++ != ',') |
| ; |
| |
| constraints[i] = p; |
| continue; |
| } |
| } |
| |
| /* 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 ',': |
| break; |
| case '*': |
| /* Ignore the next letter for this pass. */ |
| c = *++p; |
| break; |
| |
| case '?': |
| alt_cost += 2; |
| case '!': case '#': case '&': |
| case '0': case '1': case '2': case '3': case '4': |
| case '5': case '6': case '7': case '8': case '9': |
| break; |
| |
| case 'p': |
| allows_addr = 1; |
| win = address_operand (op, GET_MODE (op)); |
| /* We know this operand is an address, so we want it |
| to be allocated to a register that can be the |
| base of an address, i.e. BASE_REG_CLASS. */ |
| classes[i] |
| = ira_reg_class_union[classes[i]] |
| [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; |
| break; |
| |
| case 'm': case 'o': case 'V': |
| /* It doesn't seem worth distinguishing between |
| offsettable and non-offsettable addresses |
| here. */ |
| insn_allows_mem[i] = allows_mem[i] = 1; |
| if (MEM_P (op)) |
| win = 1; |
| break; |
| |
| case '<': |
| if (MEM_P (op) |
| && (GET_CODE (XEXP (op, 0)) == PRE_DEC |
| || GET_CODE (XEXP (op, 0)) == POST_DEC)) |
| win = 1; |
| break; |
| |
| case '>': |
| if (MEM_P (op) |
| && (GET_CODE (XEXP (op, 0)) == PRE_INC |
| || GET_CODE (XEXP (op, 0)) == POST_INC)) |
| win = 1; |
| break; |
| |
| case 'E': |
| case 'F': |
| if (GET_CODE (op) == CONST_DOUBLE |
| || (GET_CODE (op) == CONST_VECTOR |
| && (GET_MODE_CLASS (GET_MODE (op)) |
| == MODE_VECTOR_FLOAT))) |
| win = 1; |
| break; |
| |
| case 'G': |
| case 'H': |
| if (GET_CODE (op) == CONST_DOUBLE |
| && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p)) |
| win = 1; |
| break; |
| |
| case 's': |
| if (GET_CODE (op) == CONST_INT |
| || (GET_CODE (op) == CONST_DOUBLE |
| && GET_MODE (op) == VOIDmode)) |
| break; |
| |
| case 'i': |
| if (CONSTANT_P (op) |
| && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))) |
| win = 1; |
| break; |
| |
| case 'n': |
| if (GET_CODE (op) == CONST_INT |
| || (GET_CODE (op) == CONST_DOUBLE |
| && GET_MODE (op) == VOIDmode)) |
| win = 1; |
| break; |
| |
| case 'I': |
| case 'J': |
| case 'K': |
| case 'L': |
| case 'M': |
| case 'N': |
| case 'O': |
| case 'P': |
| if (GET_CODE (op) == CONST_INT |
| && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p)) |
| win = 1; |
| break; |
| |
| case 'X': |
| win = 1; |
| 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; |
| case 'r': |
| classes[i] = ira_reg_class_union[classes[i]][GENERAL_REGS]; |
| break; |
| |
| default: |
| if (REG_CLASS_FROM_CONSTRAINT (c, p) != NO_REGS) |
| classes[i] = ira_reg_class_union[classes[i]] |
| [REG_CLASS_FROM_CONSTRAINT (c, p)]; |
| #ifdef EXTRA_CONSTRAINT_STR |
| else if (EXTRA_CONSTRAINT_STR (op, c, p)) |
| win = 1; |
| |
| if (EXTRA_MEMORY_CONSTRAINT (c, p)) |
| { |
| /* Every MEM can be reloaded to fit. */ |
| insn_allows_mem[i] = allows_mem[i] = 1; |
| if (MEM_P (op)) |
| win = 1; |
| } |
| if (EXTRA_ADDRESS_CONSTRAINT (c, p)) |
| { |
| /* Every address can be reloaded to fit. */ |
| allows_addr = 1; |
| if (address_operand (op, GET_MODE (op))) |
| win = 1; |
| /* We know this operand is an address, so we |
| want it to be allocated to a hard register |
| that can be the base of an address, |
| i.e. BASE_REG_CLASS. */ |
| classes[i] |
| = ira_reg_class_union[classes[i]] |
| [base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; |
| } |
| #endif |
| break; |
| } |
| p += CONSTRAINT_LEN (c, p); |
| if (c == ',') |
| break; |
| } |
| |
| constraints[i] = p; |
| |
| /* 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) |
| { |
| /* We must always fail if the operand is a REG, but |
| we did not find a suitable class. |
| |
| Otherwise we may perform an uninitialized read |
| from this_op_costs after the `continue' statement |
| below. */ |
| alt_fail = 1; |
| } |
| else |
| { |
| struct costs *pp = this_op_costs[i]; |
| |
| for (k = 0; k < cost_classes_num; k++) |
| { |
| rclass = cost_classes[k]; |
| pp->cost[k] |
| = (((recog_data.operand_type[i] != OP_OUT |
| ? ira_get_may_move_cost (mode, rclass, |
| classes[i], true) : 0) |
| + (recog_data.operand_type[i] != OP_IN |
| ? ira_get_may_move_cost (mode, classes[i], |
| rclass, false) : 0)) |
| * frequency); |
| } |
| |
| /* If the alternative actually allows memory, make |
| things a bit cheaper since we won't need an extra |
| insn to load it. */ |
| pp->mem_cost |
| = ((recog_data.operand_type[i] != OP_IN |
| ? ira_memory_move_cost[mode][classes[i]][0] : 0) |
| + (recog_data.operand_type[i] != OP_OUT |
| ? ira_memory_move_cost[mode][classes[i]][1] : 0) |
| - allows_mem[i]) * frequency; |
| /* If we have assigned a class to this allocno in our |
| first pass, add a cost to this alternative |
| corresponding to what we would add if this allocno |
| were not in the appropriate class. We could use |
| cover class here but it is less accurate |
| approximation. */ |
| if (allocno_pref) |
| { |
| enum reg_class pref_class |
| = allocno_pref[ALLOCNO_NUM |
| (ira_curr_regno_allocno_map |
| [REGNO (op)])]; |
| |
| if (pref_class == NO_REGS) |
| alt_cost |
| += ((recog_data.operand_type[i] != OP_IN |
| ? ira_memory_move_cost[mode][classes[i]][0] |
| : 0) |
| + (recog_data.operand_type[i] != OP_OUT |
| ? ira_memory_move_cost[mode][classes[i]][1] |
| : 0)); |
| else if (ira_reg_class_intersect[pref_class][classes[i]] |
| == NO_REGS) |
| alt_cost += ira_get_register_move_cost (mode, |
| pref_class, |
| classes[i]); |
| } |
| } |
| } |
| |
| /* 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) |
| 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 scale = 1 + (recog_data.operand_type[i] == OP_INOUT); |
| |
| pp->mem_cost = MIN (pp->mem_cost, |
| (qq->mem_cost + op_cost_add) * scale); |
| |
| for (k = 0; k < cost_classes_num; k++) |
| pp->cost[k] |
| = MIN (pp->cost[k], (qq->cost[k] + op_cost_add) * scale); |
| } |
| } |
| |
| for (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; |
| } |
| |
| /* If this insn is a single set copying operand 1 to operand 0 and |
| one operand is an allocno with the other a hard reg or an allocno |
| that prefers a hard register that is in its own register class |
| then we may want to adjust the cost of that register class to -1. |
| |
| Avoid the adjustment if the source does not die to avoid |
| stressing of register allocator by preferrencing two colliding |
| registers into single class. |
| |
| Also avoid the adjustment if a copy between hard registers of the |
| class is expensive (ten times the cost of a default copy is |
| considered arbitrarily expensive). This avoids losing when the |
| preferred class is very expensive as the source of a copy |
| instruction. */ |
| if ((set = single_set (insn)) != 0 |
| && ops[0] == SET_DEST (set) && ops[1] == SET_SRC (set) |
| && REG_P (ops[0]) && REG_P (ops[1]) |
| && find_regno_note (insn, REG_DEAD, REGNO (ops[1]))) |
| for (i = 0; i <= 1; i++) |
| if (REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) |
| { |
| unsigned int regno = REGNO (ops[!i]); |
| enum machine_mode mode = GET_MODE (ops[!i]); |
| int rclass; |
| unsigned int nr; |
| |
| if (regno < FIRST_PSEUDO_REGISTER) |
| for (k = 0; k < cost_classes_num; k++) |
| { |
| rclass = cost_classes[k]; |
| if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno) |
| && (reg_class_size[rclass] |
| == (unsigned) CLASS_MAX_NREGS (rclass, mode))) |
| { |
| if (reg_class_size[rclass] == 1) |
| op_costs[i]->cost[k] = -frequency; |
| else |
| { |
| for (nr = 0; |
| nr < (unsigned) hard_regno_nregs[regno][mode]; |
| nr++) |
| if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], |
| regno + nr)) |
| break; |
| |
| if (nr == (unsigned) hard_regno_nregs[regno][mode]) |
| op_costs[i]->cost[k] = -frequency; |
| } |
| } |
| } |
| } |
| } |
| |
| |
| |
| /* 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, enum machine_mode mode, |
| enum rtx_code outer_code, enum rtx_code index_code) |
| { |
| unsigned regno = REGNO (reg); |
| |
| if (regno >= FIRST_PSEUDO_REGISTER) |
| return true; |
| return ok_for_base_p_1 (regno, mode, outer_code, index_code); |
| } |
| |
| /* 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 is the mode of the memory reference; OUTER_CODE and INDEX_CODE |
| give the context that the rtx appears in. These three arguments |
| are passed down to base_reg_class. |
| |
| SCALE is twice the amount to multiply the cost by (it is twice so |
| we can represent half-cost adjustments). */ |
| static void |
| record_address_regs (enum machine_mode mode, rtx x, int context, |
| enum rtx_code outer_code, enum rtx_code index_code, |
| int scale) |
| { |
| enum rtx_code code = GET_CODE (x); |
| enum reg_class rclass; |
| |
| if (context == 1) |
| rclass = INDEX_REG_CLASS; |
| else |
| rclass = base_reg_class (mode, outer_code, index_code); |
| |
| 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, arg0, 0, PLUS, code1, scale); |
| |
| /* If index and base registers are the same on this machine, |
| just record registers in any non-constant operands. We |
| assume here, as well as in the tests below, that all |
| addresses are in canonical form. */ |
| else if (INDEX_REG_CLASS == base_reg_class (VOIDmode, PLUS, SCRATCH)) |
| { |
| record_address_regs (mode, arg0, context, PLUS, code1, scale); |
| if (! CONSTANT_P (arg1)) |
| record_address_regs (mode, arg1, context, PLUS, code0, scale); |
| } |
| |
| /* If the second operand is a constant integer, it doesn't |
| change what class the first operand must be. */ |
| else if (code1 == CONST_INT || code1 == CONST_DOUBLE) |
| record_address_regs (mode, arg0, context, PLUS, code1, scale); |
| /* If the second operand is a symbolic constant, the first |
| operand must be an index register. */ |
| else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF) |
| record_address_regs (mode, arg0, 1, PLUS, code1, scale); |
| /* If both operands are registers but one is already a hard |
| register of index or reg-base class, give the other the |
| class that the hard register is not. */ |
| else if (code0 == REG && code1 == REG |
| && REGNO (arg0) < FIRST_PSEUDO_REGISTER |
| && (ok_for_base_p_nonstrict (arg0, mode, PLUS, REG) |
| || ok_for_index_p_nonstrict (arg0))) |
| record_address_regs (mode, arg1, |
| ok_for_base_p_nonstrict (arg0, mode, PLUS, REG) |
| ? 1 : 0, |
| PLUS, REG, scale); |
| else if (code0 == REG && code1 == REG |
| && REGNO (arg1) < FIRST_PSEUDO_REGISTER |
| && (ok_for_base_p_nonstrict (arg1, mode, PLUS, REG) |
| || ok_for_index_p_nonstrict (arg1))) |
| record_address_regs (mode, arg0, |
| ok_for_base_p_nonstrict (arg1, mode, PLUS, REG) |
| ? 1 : 0, |
| PLUS, REG, scale); |
| /* If one operand is known to be a pointer, it must be the |
| base with the other operand the index. Likewise if the |
| other operand is a MULT. */ |
| else if ((code0 == REG && REG_POINTER (arg0)) || code1 == MULT) |
| { |
| record_address_regs (mode, arg0, 0, PLUS, code1, scale); |
| record_address_regs (mode, arg1, 1, PLUS, code0, scale); |
| } |
| else if ((code1 == REG && REG_POINTER (arg1)) || code0 == MULT) |
| { |
| record_address_regs (mode, arg0, 1, PLUS, code1, scale); |
| record_address_regs (mode, arg1, 0, PLUS, code0, scale); |
| } |
| /* Otherwise, count equal chances that each might be a base or |
| index register. This case should be rare. */ |
| else |
| { |
| record_address_regs (mode, arg0, 0, PLUS, code1, scale / 2); |
| record_address_regs (mode, arg0, 1, PLUS, code1, scale / 2); |
| record_address_regs (mode, arg1, 0, PLUS, code0, scale / 2); |
| record_address_regs (mode, arg1, 1, PLUS, code0, scale / 2); |
| } |
| } |
| 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, XEXP (x, 0), 0, code, |
| GET_CODE (XEXP (XEXP (x, 1), 1)), 2 * scale); |
| if (REG_P (XEXP (XEXP (x, 1), 1))) |
| record_address_regs (mode, XEXP (XEXP (x, 1), 1), 1, code, REG, |
| 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. If the operand is a pseudo-register, |
| show it is being used in an INC_DEC context. */ |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| if (REG_P (XEXP (x, 0)) |
| && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER) |
| in_inc_dec[ALLOCNO_NUM (ira_curr_regno_allocno_map |
| [REGNO (XEXP (x, 0))])] = true; |
| #endif |
| record_address_regs (mode, XEXP (x, 0), 0, code, SCRATCH, 2 * scale); |
| break; |
| |
| case REG: |
| { |
| struct costs *pp; |
| int i, k; |
| |
| if (REGNO (x) < FIRST_PSEUDO_REGISTER) |
| break; |
| |
| ALLOCNO_BAD_SPILL_P (ira_curr_regno_allocno_map[REGNO (x)]) = true; |
| pp = COSTS_OF_ALLOCNO (allocno_costs, |
| ALLOCNO_NUM (ira_curr_regno_allocno_map |
| [REGNO (x)])); |
| pp->mem_cost += (ira_memory_move_cost[Pmode][rclass][1] * scale) / 2; |
| for (k = 0; k < cost_classes_num; k++) |
| { |
| i = cost_classes[k]; |
| pp->cost[k] |
| += (ira_get_may_move_cost (Pmode, i, rclass, true) * scale) / 2; |
| } |
| } |
| 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, XEXP (x, i), context, code, SCRATCH, |
| scale); |
| } |
| } |
| } |
| |
| |
| |
| /* Calculate the costs of insn operands. */ |
| static void |
| record_operand_costs (rtx insn, struct costs **op_costs, |
| enum reg_class *allocno_pref) |
| { |
| const char *constraints[MAX_RECOG_OPERANDS]; |
| enum machine_mode modes[MAX_RECOG_OPERANDS]; |
| 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); |
| |
| 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]), |
| XEXP (recog_data.operand[i], 0), |
| 0, MEM, SCRATCH, frequency * 2); |
| else if (constraints[i][0] == 'p' |
| || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], |
| constraints[i])) |
| record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS, |
| SCRATCH, frequency * 2); |
| } |
| |
| /* 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, op_costs, allocno_pref); |
| } |
| record_reg_classes (recog_data.n_alternatives, recog_data.n_operands, |
| recog_data.operand, modes, |
| constraints, insn, op_costs, allocno_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 |
| scan_one_insn (rtx insn) |
| { |
| enum rtx_code pat_code; |
| rtx set, note; |
| int i, k; |
| |
| if (!INSN_P (insn)) |
| return insn; |
| |
| pat_code = GET_CODE (PATTERN (insn)); |
| if (pat_code == USE || pat_code == CLOBBER || pat_code == ASM_INPUT |
| || pat_code == ADDR_VEC || pat_code == ADDR_DIFF_VEC) |
| return insn; |
| |
| 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. */ |
| 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))) |
| { |
| enum reg_class cl = GENERAL_REGS; |
| rtx reg = SET_DEST (set); |
| int num = ALLOCNO_NUM (ira_curr_regno_allocno_map[REGNO (reg)]); |
| |
| if (allocno_pref) |
| cl = allocno_pref[num]; |
| COSTS_OF_ALLOCNO (allocno_costs, num)->mem_cost |
| -= ira_memory_move_cost[GET_MODE (reg)][cl][1] * frequency; |
| record_address_regs (GET_MODE (SET_SRC (set)), XEXP (SET_SRC (set), 0), |
| 0, MEM, SCRATCH, frequency * 2); |
| } |
| |
| record_operand_costs (insn, op_costs, allocno_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_OF_ALLOCNO (allocno_costs, |
| ALLOCNO_NUM (ira_curr_regno_allocno_map[regno])); |
| struct costs *q = op_costs[i]; |
| |
| p->mem_cost += q->mem_cost; |
| for (k = 0; k < cost_classes_num; k++) |
| p->cost[k] += q->cost[k]; |
| } |
| |
| return insn; |
| } |
| |
| |
| |
| /* Print allocnos costs to file F. */ |
| static void |
| print_costs (FILE *f) |
| { |
| int k; |
| ira_allocno_t a; |
| ira_allocno_iterator ai; |
| |
| fprintf (f, "\n"); |
| FOR_EACH_ALLOCNO (a, ai) |
| { |
| int i, rclass; |
| basic_block bb; |
| int regno = ALLOCNO_REGNO (a); |
| |
| 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_num; k++) |
| { |
| rclass = cost_classes[k]; |
| if (contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (regno)] |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| && (! in_inc_dec[i] || ! forbidden_inc_dec_class[rclass]) |
| #endif |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| && ! invalid_mode_change_p (regno, (enum reg_class) rclass, |
| PSEUDO_REGNO_MODE (regno)) |
| #endif |
| ) |
| { |
| fprintf (f, " %s:%d", reg_class_names[rclass], |
| COSTS_OF_ALLOCNO (allocno_costs, i)->cost[k]); |
| if (flag_ira_region == IRA_REGION_ALL |
| || flag_ira_region == IRA_REGION_MIXED) |
| fprintf (f, ",%d", COSTS_OF_ALLOCNO (total_costs, i)->cost[k]); |
| } |
| } |
| fprintf (f, " MEM:%i\n", COSTS_OF_ALLOCNO (allocno_costs, i)->mem_cost); |
| } |
| } |
| |
| /* 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; |
| rtx insn; |
| |
| bb = loop_tree_node->bb; |
| if (bb == NULL) |
| return; |
| frequency = REG_FREQ_FROM_BB (bb); |
| if (frequency == 0) |
| frequency = 1; |
| FOR_BB_INSNS (bb, insn) |
| insn = scan_one_insn (insn); |
| } |
| |
| /* Find costs of register classes and memory for allocnos and their |
| best costs. */ |
| static void |
| find_allocno_class_costs (void) |
| { |
| int i, k; |
| int pass; |
| basic_block bb; |
| |
| init_recog (); |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| in_inc_dec = ira_allocate (sizeof (bool) * ira_allocnos_num); |
| #endif /* FORBIDDEN_INC_DEC_CLASSES */ |
| allocno_pref = NULL; |
| /* 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 = 0; pass <= flag_expensive_optimizations; pass++) |
| { |
| if (internal_flag_ira_verbose > 0 && ira_dump_file) |
| fprintf (ira_dump_file, "\nPass %i for finding allocno costs\n\n", |
| pass); |
| /* We could use only cover classes. Unfortunately it does not |
| work well for some targets where some subclass of cover class |
| is costly and wrong cover class is chosen. */ |
| for (i = 0; i < N_REG_CLASSES; i++) |
| cost_class_nums[i] = -1; |
| for (cost_classes_num = 0; |
| cost_classes_num < ira_important_classes_num; |
| cost_classes_num++) |
| { |
| cost_classes[cost_classes_num] |
| = ira_important_classes[cost_classes_num]; |
| cost_class_nums[cost_classes[cost_classes_num]] |
| = cost_classes_num; |
| } |
| struct_costs_size |
| = sizeof (struct costs) + sizeof (int) * (cost_classes_num - 1); |
| /* Zero out our accumulation of the cost of each class for each |
| allocno. */ |
| memset (allocno_costs, 0, ira_allocnos_num * struct_costs_size); |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| memset (in_inc_dec, 0, ira_allocnos_num * sizeof (bool)); |
| #endif |
| |
| /* 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_costs, allocno_costs, |
| max_struct_costs_size * ira_allocnos_num); |
| if (pass == 0) |
| allocno_pref = allocno_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; |
| ira_loop_tree_node_t parent; |
| int best_cost, allocno_cost; |
| enum reg_class best, alt_class; |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| int inc_dec_p = false; |
| #endif |
| |
| if (ira_regno_allocno_map[i] == NULL) |
| continue; |
| memset (temp_costs, 0, struct_costs_size); |
| /* Find cost of all allocnos with the same regno. */ |
| for (a = ira_regno_allocno_map[i]; |
| a != NULL; |
| a = ALLOCNO_NEXT_REGNO_ALLOCNO (a)) |
| { |
| 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); |
| for (k = 0; k < cost_classes_num; k++) |
| COSTS_OF_ALLOCNO (total_costs, parent_a_num)->cost[k] |
| += COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k]; |
| COSTS_OF_ALLOCNO (total_costs, parent_a_num)->mem_cost |
| += COSTS_OF_ALLOCNO (total_costs, a_num)->mem_cost; |
| } |
| for (k = 0; k < cost_classes_num; k++) |
| temp_costs->cost[k] |
| += COSTS_OF_ALLOCNO (allocno_costs, a_num)->cost[k]; |
| temp_costs->mem_cost |
| += COSTS_OF_ALLOCNO (allocno_costs, a_num)->mem_cost; |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| if (in_inc_dec[a_num]) |
| inc_dec_p = true; |
| #endif |
| } |
| 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_num; k++) |
| { |
| rclass = cost_classes[k]; |
| /* Ignore classes that are too small for this operand or |
| invalid for an operand that was auto-incremented. */ |
| if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)] |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| || (inc_dec_p && forbidden_inc_dec_class[rclass]) |
| #endif |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| || invalid_mode_change_p (i, (enum reg_class) rclass, |
| PSEUDO_REGNO_MODE (i)) |
| #endif |
| ) |
| continue; |
| if (temp_costs->cost[k] < best_cost) |
| { |
| best_cost = temp_costs->cost[k]; |
| best = (enum reg_class) rclass; |
| } |
| else if (temp_costs->cost[k] == best_cost) |
| best = ira_reg_class_union[best][rclass]; |
| if (pass == flag_expensive_optimizations |
| && temp_costs->cost[k] < temp_costs->mem_cost |
| && (reg_class_size[reg_class_subunion[alt_class][rclass]] |
| > reg_class_size[alt_class])) |
| alt_class = reg_class_subunion[alt_class][rclass]; |
| } |
| alt_class = ira_class_translate[alt_class]; |
| if (pass == flag_expensive_optimizations) |
| { |
| if (best_cost > temp_costs->mem_cost) |
| best = alt_class = NO_REGS; |
| else if (best == alt_class) |
| alt_class = NO_REGS; |
| setup_reg_classes (i, best, alt_class); |
| if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL) |
| fprintf (ira_dump_file, |
| " r%d: preferred %s, alternative %s\n", |
| i, reg_class_names[best], reg_class_names[alt_class]); |
| } |
| if (best_cost > temp_costs->mem_cost) |
| common_classes[i] = NO_REGS; |
| else if (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY) |
| /* Make the common class the biggest class of best and |
| alt_class. */ |
| common_classes[i] = alt_class == NO_REGS ? best : alt_class; |
| else |
| /* Make the common class a cover class. Remember all |
| allocnos with the same regno should have the same cover |
| class. */ |
| common_classes[i] = ira_class_translate[best]; |
| for (a = ira_regno_allocno_map[i]; |
| a != NULL; |
| a = ALLOCNO_NEXT_REGNO_ALLOCNO (a)) |
| { |
| a_num = ALLOCNO_NUM (a); |
| if (common_classes[i] == 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_num; k++) |
| { |
| rclass = cost_classes[k]; |
| if (! ira_class_subset_p[rclass][common_classes[i]]) |
| continue; |
| /* Ignore classes that are too small for this |
| operand or invalid for an operand that was |
| auto-incremented. */ |
| if (! contains_reg_of_mode[rclass][PSEUDO_REGNO_MODE (i)] |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| || (inc_dec_p && forbidden_inc_dec_class[rclass]) |
| #endif |
| #ifdef CANNOT_CHANGE_MODE_CLASS |
| || invalid_mode_change_p (i, (enum reg_class) rclass, |
| PSEUDO_REGNO_MODE (i)) |
| #endif |
| ) |
| ; |
| else if (COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k] |
| < best_cost) |
| { |
| best_cost |
| = COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k]; |
| allocno_cost |
| = COSTS_OF_ALLOCNO (allocno_costs, a_num)->cost[k]; |
| best = (enum reg_class) rclass; |
| } |
| else if (COSTS_OF_ALLOCNO (total_costs, a_num)->cost[k] |
| == best_cost) |
| { |
| best = ira_reg_class_union[best][rclass]; |
| allocno_cost |
| = MAX (allocno_cost, |
| COSTS_OF_ALLOCNO (allocno_costs, |
| a_num)->cost[k]); |
| } |
| } |
| ALLOCNO_COVER_CLASS_COST (a) = allocno_cost; |
| } |
| ira_assert (flag_ira_algorithm == IRA_ALGORITHM_PRIORITY |
| || ira_class_translate[best] == common_classes[i]); |
| if (internal_flag_ira_verbose > 2 && ira_dump_file != NULL |
| && (pass == 0 || allocno_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, cover %s\n", |
| reg_class_names[best], |
| reg_class_names[common_classes[i]]); |
| } |
| allocno_pref[a_num] = best; |
| } |
| } |
| |
| if (internal_flag_ira_verbose > 4 && ira_dump_file) |
| { |
| print_costs (ira_dump_file); |
| fprintf (ira_dump_file,"\n"); |
| } |
| } |
| #ifdef FORBIDDEN_INC_DEC_CLASSES |
| ira_free (in_inc_dec); |
| #endif |
| } |
| |
| |
| |
| /* Process moves involving hard regs to modify allocno hard register |
| costs. We can do this only after determining allocno cover class. |
| If a hard register forms a register class, than moves with the hard |
| register are already taken into account in class costs for the |
| allocno. */ |
| static void |
| process_bb_node_for_hard_reg_moves (ira_loop_tree_node_t loop_tree_node) |
| { |
| int i, freq, cost, src_regno, dst_regno, hard_regno; |
| bool to_p; |
| ira_allocno_t a; |
| enum reg_class rclass, hard_reg_class; |
| enum machine_mode mode; |
| basic_block bb; |
| rtx insn, 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 (! 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; |
| to_p = true; |
| a = ira_curr_regno_allocno_map[dst_regno]; |
| } |
| else if (src_regno >= FIRST_PSEUDO_REGISTER |
| && dst_regno < FIRST_PSEUDO_REGISTER) |
| { |
| hard_regno = dst_regno; |
| to_p = false; |
| a = ira_curr_regno_allocno_map[src_regno]; |
| } |
| else |
| continue; |
| rclass = ALLOCNO_COVER_CLASS (a); |
| if (! TEST_HARD_REG_BIT (reg_class_contents[rclass], hard_regno)) |
| continue; |
| i = ira_class_hard_reg_index[rclass][hard_regno]; |
| if (i < 0) |
| continue; |
| mode = ALLOCNO_MODE (a); |
| hard_reg_class = REGNO_REG_CLASS (hard_regno); |
| cost |
| = (to_p ? ira_get_register_move_cost (mode, hard_reg_class, rclass) |
| : ira_get_register_move_cost (mode, rclass, hard_reg_class)) * freq; |
| ira_allocate_and_set_costs (&ALLOCNO_HARD_REG_COSTS (a), rclass, |
| ALLOCNO_COVER_CLASS_COST (a)); |
| ira_allocate_and_set_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (a), |
| rclass, 0); |
| ALLOCNO_HARD_REG_COSTS (a)[i] -= cost; |
| ALLOCNO_CONFLICT_HARD_REG_COSTS (a)[i] -= cost; |
| ALLOCNO_COVER_CLASS_COST (a) = MIN (ALLOCNO_COVER_CLASS_COST (a), |
| ALLOCNO_HARD_REG_COSTS (a)[i]); |
| } |
| } |
| |
| /* After we find hard register and memory costs for allocnos, define |
| its cover class and modify hard register cost because insns moving |
| allocno to/from hard registers. */ |
| static void |
| setup_allocno_cover_class_and_costs (void) |
| { |
| int i, j, n, regno, num; |
| int *reg_costs; |
| enum reg_class cover_class, rclass; |
| enum machine_mode mode; |
| HARD_REG_SET *pref; |
| ira_allocno_t a; |
| ira_allocno_iterator ai; |
| |
| FOR_EACH_ALLOCNO (a, ai) |
| { |
| i = ALLOCNO_NUM (a); |
| mode = ALLOCNO_MODE (a); |
| cover_class = common_classes[ALLOCNO_REGNO (a)]; |
| ira_assert (allocno_pref[i] == NO_REGS || cover_class != NO_REGS); |
| ALLOCNO_MEMORY_COST (a) = COSTS_OF_ALLOCNO (allocno_costs, i)->mem_cost; |
| ira_set_allocno_cover_class (a, cover_class); |
| if (cover_class == NO_REGS) |
| continue; |
| ALLOCNO_AVAILABLE_REGS_NUM (a) = ira_available_class_regs[cover_class]; |
| pref = ®_class_contents[allocno_pref[i]]; |
| if (optimize && ALLOCNO_COVER_CLASS (a) != allocno_pref[i]) |
| { |
| n = ira_class_hard_regs_num[cover_class]; |
| ALLOCNO_HARD_REG_COSTS (a) |
| = reg_costs = ira_allocate_cost_vector (cover_class); |
| for (j = n - 1; j >= 0; j--) |
| { |
| regno = ira_class_hard_regs[cover_class][j]; |
| if (TEST_HARD_REG_BIT (*pref, regno)) |
| reg_costs[j] = ALLOCNO_COVER_CLASS_COST (a); |
| else |
| { |
| rclass = REGNO_REG_CLASS (regno); |
| num = cost_class_nums[rclass]; |
| if (num < 0) |
| { |
| /* The hard register class is not a cover class or a |
| class not fully inside in a cover class -- use |
| the allocno cover class. */ |
| ira_assert (ira_hard_regno_cover_class[regno] |
| == cover_class); |
| num = cost_class_nums[cover_class]; |
| } |
| reg_costs[j] = COSTS_OF_ALLOCNO (allocno_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; |
| cost_classes = NULL; |
| } |
| |
| /* Free allocated temporary cost vectors. */ |
| static void |
| free_ira_costs (void) |
| { |
| int i; |
| |
| if (init_cost != NULL) |
| free (init_cost); |
| init_cost = NULL; |
| for (i = 0; i < MAX_RECOG_OPERANDS; i++) |
| { |
| if (op_costs[i] != NULL) |
| free (op_costs[i]); |
| if (this_op_costs[i] != NULL) |
| free (this_op_costs[i]); |
| op_costs[i] = this_op_costs[i] = NULL; |
| } |
| if (temp_costs != NULL) |
| free (temp_costs); |
| temp_costs = NULL; |
| if (cost_classes != NULL) |
| free (cost_classes); |
| cost_classes = NULL; |
| } |
| |
| /* This is called each time register related information is |
| changed. */ |
| void |
| ira_init_costs (void) |
| { |
| int i; |
| |
| 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); |
| cost_classes = (enum reg_class *) xmalloc (sizeof (enum reg_class) |
| * ira_important_classes_num); |
| } |
| |
| /* Function called once at the end of compiler work. */ |
| void |
| ira_finish_costs_once (void) |
| { |
| free_ira_costs (); |
| } |
| |
| |
| |
| /* Entry function which defines cover class, memory and hard register |
| costs for each allocno. */ |
| void |
| ira_costs (void) |
| { |
| allocno_costs = (struct costs *) ira_allocate (max_struct_costs_size |
| * ira_allocnos_num); |
| total_costs = (struct costs *) ira_allocate (max_struct_costs_size |
| * ira_allocnos_num); |
| allocno_pref_buffer |
| = (enum reg_class *) ira_allocate (sizeof (enum reg_class) |
| * ira_allocnos_num); |
| common_classes |
| = (enum reg_class *) ira_allocate (sizeof (enum reg_class) |
| * max_reg_num ()); |
| find_allocno_class_costs (); |
| setup_allocno_cover_class_and_costs (); |
| ira_free (common_classes); |
| ira_free (allocno_pref_buffer); |
| ira_free (total_costs); |
| ira_free (allocno_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_and_cover_classes (void) |
| { |
| int j, n, regno; |
| int cost, min_cost, *reg_costs; |
| enum reg_class cover_class, rclass; |
| enum machine_mode mode; |
| ira_allocno_t a; |
| ira_allocno_iterator ai; |
| |
| FOR_EACH_ALLOCNO (a, ai) |
| { |
| cover_class = ALLOCNO_COVER_CLASS (a); |
| if (cover_class == NO_REGS) |
| continue; |
| mode = ALLOCNO_MODE (a); |
| n = ira_class_hard_regs_num[cover_class]; |
| min_cost = INT_MAX; |
| if (ALLOCNO_CALLS_CROSSED_NUM (a) != 0) |
| { |
| ira_allocate_and_set_costs |
| (&ALLOCNO_HARD_REG_COSTS (a), cover_class, |
| ALLOCNO_COVER_CLASS_COST (a)); |
| reg_costs = ALLOCNO_HARD_REG_COSTS (a); |
| for (j = n - 1; j >= 0; j--) |
| { |
| regno = ira_class_hard_regs[cover_class][j]; |
| rclass = REGNO_REG_CLASS (regno); |
| cost = 0; |
| if (! ira_hard_reg_not_in_set_p (regno, mode, call_used_reg_set) |
| || HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)) |
| 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 |
| reg_costs[j] += cost; |
| if (min_cost > reg_costs[j]) |
| min_cost = reg_costs[j]; |
| } |
| } |
| if (min_cost != INT_MAX) |
| ALLOCNO_COVER_CLASS_COST (a) = min_cost; |
| } |
| } |