local-alloc.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,992 行 · 第 1/5 页
C
1,992 行
/* ... Fall through ... */ case 2: /* Put the best one to allocate in qty_order[0]. */ if (qty_sugg_compare (0, 1) > 0) EXCHANGE (0, 1); /* ... Fall through ... */ case 1: case 0: /* Nothing to do here. */ break; default: qsort (qty_order, next_qty, sizeof (int), qty_sugg_compare_1); } /* Try to put each quantity in a suggested physical register, if it has one. This may cause registers to be allocated that otherwise wouldn't be, but this seems acceptable in local allocation (unlike global allocation). */ for (i = 0; i < next_qty; i++) { q = qty_order[i]; if (qty_phys_num_sugg[q] != 0 || qty_phys_num_copy_sugg[q] != 0) qty_phys_reg[q] = find_free_reg (qty_min_class[q], qty_mode[q], q, 0, 1, qty_birth[q], qty_death[q]); else qty_phys_reg[q] = -1; } /* Order the qtys so we assign them registers in order of decreasing length of life. Normally call qsort, but if we have only a very small number of quantities, sort them ourselves. */ for (i = 0; i < next_qty; i++) qty_order[i] = i;#define EXCHANGE(I1, I2) \ { i = qty_order[I1]; qty_order[I1] = qty_order[I2]; qty_order[I2] = i; } switch (next_qty) { case 3: /* Make qty_order[2] be the one to allocate last. */ if (qty_compare (0, 1) > 0) EXCHANGE (0, 1); if (qty_compare (1, 2) > 0) EXCHANGE (2, 1); /* ... Fall through ... */ case 2: /* Put the best one to allocate in qty_order[0]. */ if (qty_compare (0, 1) > 0) EXCHANGE (0, 1); /* ... Fall through ... */ case 1: case 0: /* Nothing to do here. */ break; default: qsort (qty_order, next_qty, sizeof (int), qty_compare_1); } /* Now for each qty that is not a hardware register, look for a hardware register to put it in. First try the register class that is cheapest for this qty, if there is more than one class. */ for (i = 0; i < next_qty; i++) { q = qty_order[i]; if (qty_phys_reg[q] < 0) { if (N_REG_CLASSES > 1) { qty_phys_reg[q] = find_free_reg (qty_min_class[q], qty_mode[q], q, 0, 0, qty_birth[q], qty_death[q]); if (qty_phys_reg[q] >= 0) continue; } if (qty_alternate_class[q] != NO_REGS) qty_phys_reg[q] = find_free_reg (qty_alternate_class[q], qty_mode[q], q, 0, 0, qty_birth[q], qty_death[q]); } } /* Now propagate the register assignments to the pseudo regs belonging to the qtys. */ for (q = 0; q < next_qty; q++) if (qty_phys_reg[q] >= 0) { for (i = qty_first_reg[q]; i >= 0; i = reg_next_in_qty[i]) reg_renumber[i] = qty_phys_reg[q] + reg_offset[i]; if (qty_scratch_rtx[q]) { if (GET_CODE (qty_scratch_rtx[q]) == REG) abort (); qty_scratch_rtx[q] = gen_rtx (REG, GET_MODE (qty_scratch_rtx[q]), qty_phys_reg[q]); scratch_block[scratch_index] = b; scratch_list[scratch_index++] = qty_scratch_rtx[q]; } }}/* Compare two quantities' priority for getting real registers. We give shorter-lived quantities higher priority. Quantities with more references are also preferred, as are quantities that require multiple registers. This is the identical prioritization as done by global-alloc. We used to give preference to registers with *longer* lives, but using the same algorithm in both local- and global-alloc can speed up execution of some programs by as much as a factor of three! *//* Note that the quotient will never be bigger than the value of floor_log2 times the maximum number of times a register can occur in one insn (surely less than 100). Multiplying this by 10000 can't overflow. QTY_CMP_PRI is also used by qty_sugg_compare. */#define QTY_CMP_PRI(q) \ ((int) (((double) (floor_log2 (qty_n_refs[q]) * qty_n_refs[q] * qty_size[q]) \ / (qty_death[q] - qty_birth[q])) * 10000))static intqty_compare (q1, q2) int q1, q2;{ return QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1);}static intqty_compare_1 (q1p, q2p) const GENERIC_PTR q1p; const GENERIC_PTR q2p;{ register int q1 = *(int *)q1p, q2 = *(int *)q2p; register int tem = QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1); if (tem != 0) return tem; /* If qtys are equally good, sort by qty number, so that the results of qsort leave nothing to chance. */ return q1 - q2;}/* Compare two quantities' priority for getting real registers. This version is called for quantities that have suggested hard registers. First priority goes to quantities that have copy preferences, then to those that have normal preferences. Within those groups, quantities with the lower number of preferences have the highest priority. Of those, we use the same algorithm as above. */#define QTY_CMP_SUGG(q) \ (qty_phys_num_copy_sugg[q] \ ? qty_phys_num_copy_sugg[q] \ : qty_phys_num_sugg[q] * FIRST_PSEUDO_REGISTER)static intqty_sugg_compare (q1, q2) int q1, q2;{ register int tem = QTY_CMP_SUGG (q1) - QTY_CMP_SUGG (q2); if (tem != 0) return tem; return QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1);}static intqty_sugg_compare_1 (q1p, q2p) const GENERIC_PTR q1p; const GENERIC_PTR q2p;{ register int q1 = *(int *)q1p, q2 = *(int *)q2p; register int tem = QTY_CMP_SUGG (q1) - QTY_CMP_SUGG (q2); if (tem != 0) return tem; tem = QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1); if (tem != 0) return tem; /* If qtys are equally good, sort by qty number, so that the results of qsort leave nothing to chance. */ return q1 - q2;}#undef QTY_CMP_SUGG#undef QTY_CMP_PRI/* Attempt to combine the two registers (rtx's) USEDREG and SETREG. Returns 1 if have done so, or 0 if cannot. Combining registers means marking them as having the same quantity and adjusting the offsets within the quantity if either of them is a SUBREG). We don't actually combine a hard reg with a pseudo; instead we just record the hard reg as the suggestion for the pseudo's quantity. If we really combined them, we could lose if the pseudo lives across an insn that clobbers the hard reg (eg, movstr). ALREADY_DEAD is non-zero if USEDREG is known to be dead even though there is no REG_DEAD note on INSN. This occurs during the processing of REG_NO_CONFLICT blocks. MAY_SAVE_COPYCOPY is non-zero if this insn is simply copying USEDREG to SETREG or if the input and output must share a register. In that case, we record a hard reg suggestion in QTY_PHYS_COPY_SUGG. There are elaborate checks for the validity of combining. */ static intcombine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead) rtx usedreg, setreg; int may_save_copy; int insn_number; rtx insn; int already_dead;{ register int ureg, sreg; register int offset = 0; int usize, ssize; register int sqty; /* Determine the numbers and sizes of registers being used. If a subreg is present that does not change the entire register, don't consider this a copy insn. */ while (GET_CODE (usedreg) == SUBREG) { if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD) may_save_copy = 0; offset += SUBREG_WORD (usedreg); usedreg = SUBREG_REG (usedreg); } if (GET_CODE (usedreg) != REG) return 0; ureg = REGNO (usedreg); usize = REG_SIZE (usedreg); while (GET_CODE (setreg) == SUBREG) { if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (setreg))) > UNITS_PER_WORD) may_save_copy = 0; offset -= SUBREG_WORD (setreg); setreg = SUBREG_REG (setreg); } if (GET_CODE (setreg) != REG) return 0; sreg = REGNO (setreg); ssize = REG_SIZE (setreg); /* If UREG is a pseudo-register that hasn't already been assigned a quantity number, it means that it is not local to this block or dies more than once. In either event, we can't do anything with it. */ if ((ureg >= FIRST_PSEUDO_REGISTER && reg_qty[ureg] < 0) /* Do not combine registers unless one fits within the other. */ || (offset > 0 && usize + offset > ssize) || (offset < 0 && usize + offset < ssize) /* Do not combine with a smaller already-assigned object if that smaller object is already combined with something bigger. */ || (ssize > usize && ureg >= FIRST_PSEUDO_REGISTER && usize < qty_size[reg_qty[ureg]]) /* Can't combine if SREG is not a register we can allocate. */ || (sreg >= FIRST_PSEUDO_REGISTER && reg_qty[sreg] == -1) /* Don't combine with a pseudo mentioned in a REG_NO_CONFLICT note. These have already been taken care of. This probably wouldn't combine anyway, but don't take any chances. */ || (ureg >= FIRST_PSEUDO_REGISTER && find_reg_note (insn, REG_NO_CONFLICT, usedreg)) /* Don't tie something to itself. In most cases it would make no difference, but it would screw up if the reg being tied to itself also dies in this insn. */ || ureg == sreg /* Don't try to connect two different hardware registers. */ || (ureg < FIRST_PSEUDO_REGISTER && sreg < FIRST_PSEUDO_REGISTER) /* Don't connect two different machine modes if they have different implications as to which registers may be used. */ || !MODES_TIEABLE_P (GET_MODE (usedreg), GET_MODE (setreg))) return 0; /* Now, if UREG is a hard reg and SREG is a pseudo, record the hard reg in qty_phys_sugg for the pseudo instead of tying them. Return "failure" so that the lifespan of UREG is terminated here; that way the two lifespans will be disjoint and nothing will prevent the pseudo reg from being given this hard reg. */ if (ureg < FIRST_PSEUDO_REGISTER) { /* Allocate a quantity number so we have a place to put our suggestions. */ if (reg_qty[sreg] == -2) reg_is_born (setreg, 2 * insn_number); if (reg_qty[sreg] >= 0) { if (may_save_copy && ! TEST_HARD_REG_BIT (qty_phys_copy_sugg[reg_qty[sreg]], ureg)) { SET_HARD_REG_BIT (qty_phys_copy_sugg[reg_qty[sreg]], ureg); qty_phys_num_copy_sugg[reg_qty[sreg]]++; } else if (! TEST_HARD_REG_BIT (qty_phys_sugg[reg_qty[sreg]], ureg)) { SET_HARD_REG_BIT (qty_phys_sugg[reg_qty[sreg]], ureg); qty_phys_num_sugg[reg_qty[sreg]]++; } } return 0; } /* Similarly for SREG a hard register and UREG a pseudo register. */ if (sreg < FIRST_PSEUDO_REGISTER) { if (may_save_copy && ! TEST_HARD_REG_BIT (qty_phys_copy_sugg[reg_qty[ureg]], sreg)) { SET_HARD_REG_BIT (qty_phys_copy_sugg[reg_qty[ureg]], sreg); qty_phys_num_copy_sugg[reg_qty[ureg]]++; } else if (! TEST_HARD_REG_BIT (qty_phys_sugg[reg_qty[ureg]], sreg)) { SET_HARD_REG_BIT (qty_phys_sugg[reg_qty[ureg]], sreg); qty_phys_num_sugg[reg_qty[ureg]]++; } return 0; } /* At this point we know that SREG and UREG are both pseudos. Do nothing if SREG already has a quantity or is a register that we don't allocate. */ if (reg_qty[sreg] >= -1 /* If we are not going to let any regs live across calls, don't tie a call-crossing reg to a non-call-crossing reg. */ || (current_function_has_nonlocal_label && ((REG_N_CALLS_CROSSED (ureg) > 0) != (REG_N_CALLS_CROSSED (sreg) > 0)))) return 0; /* We don't already know about SREG, so tie it to UREG if this is the last use of UREG, provided the classes they want are compatible. */ if ((already_dead || find_regno_note (insn, REG_DEAD, ureg)) && reg_meets_class_p (sreg, qty_min_class[reg_qty[ureg]])) { /* Add SREG to UREG's quantity. */ sqty = reg_qty[ureg]; reg_qty[sreg] = sqty; reg_offset[sreg] = reg_offset[ureg] + offset; reg_next_in_qty[sreg] = qty_first_reg[sqty]; qty_first_reg[sqty] = sreg; /* If SREG's reg class is smaller, set qty_min_class[SQTY]. */ update_qty_class (sqty, sreg); /* Update info about quantity SQTY. */ qty_n_calls_crossed[sqty] += REG_N_CALLS_CROSSED (sreg); qty_n_refs[sqty] += REG_N_REFS (sreg); if (usize < ssize) { register int i; for (i = qty_first_reg[sqty]; i >= 0; i = reg_next_in_qty[i]) reg_offset[i] -= offset; qty_size[sqty] = ssize; qty_mode[sqty] = GET_MODE (setreg); } } else return 0; return 1;}/* Return 1 if the preferred class of REG allows it to be tied to a quantity or register whose class is CLAS
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?