📄 global.c
字号:
CLEAR_HARD_REG_SET (regs_someone_prefers[allocno]); /* Merge in the preferences of lower-priority registers (they have already been pruned). If we also prefer some of those registers, don't exclude them unless we are of a smaller size (in which case we want to give the lower-priority allocno the first chance for these registers). */ for (j = i + 1; j < max_allocno; j++) if (CONFLICTP (allocno, allocno_order[j]) || CONFLICTP (allocno_order[j], allocno)) { COPY_HARD_REG_SET (temp, hard_reg_full_preferences[allocno_order[j]]); if (allocno_size[allocno_order[j]] <= allocno_size[allocno]) AND_COMPL_HARD_REG_SET (temp, hard_reg_full_preferences[allocno]); IOR_HARD_REG_SET (regs_someone_prefers[allocno], temp); } }}/* Assign a hard register to ALLOCNO; look for one that is the beginning of a long enough stretch of hard regs none of which conflicts with ALLOCNO. The registers marked in PREFREGS are tried first. LOSERS, if non-zero, is a HARD_REG_SET indicating registers that cannot be used for this allocation. If ALT_REGS_P is zero, consider only the preferred class of ALLOCNO's reg. Otherwise ignore that preferred class and use the alternate class. If ACCEPT_CALL_CLOBBERED is nonzero, accept a call-clobbered hard reg that will have to be saved and restored at calls. RETRYING is nonzero if this is called from retry_global_alloc. If we find one, record it in reg_renumber. If not, do nothing. */static voidfind_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying) int allocno; HARD_REG_SET losers; int alt_regs_p; int accept_call_clobbered; int retrying;{ register int i, best_reg, pass;#ifdef HARD_REG_SET register /* Declare it register if it's a scalar. */#endif HARD_REG_SET used, used1, used2; enum reg_class class = (alt_regs_p ? reg_alternate_class (allocno_reg[allocno]) : reg_preferred_class (allocno_reg[allocno])); enum machine_mode mode = PSEUDO_REGNO_MODE (allocno_reg[allocno]); if (accept_call_clobbered) COPY_HARD_REG_SET (used1, call_fixed_reg_set); else if (allocno_calls_crossed[allocno] == 0) COPY_HARD_REG_SET (used1, fixed_reg_set); else COPY_HARD_REG_SET (used1, call_used_reg_set); /* Some registers should not be allocated in global-alloc. */ IOR_HARD_REG_SET (used1, no_global_alloc_regs); if (losers) IOR_HARD_REG_SET (used1, losers); IOR_COMPL_HARD_REG_SET (used1, reg_class_contents[(int) class]); COPY_HARD_REG_SET (used2, used1); IOR_HARD_REG_SET (used1, hard_reg_conflicts[allocno]);#ifdef CLASS_CANNOT_CHANGE_SIZE if (REG_CHANGES_SIZE (allocno_reg[allocno])) IOR_HARD_REG_SET (used1, reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);#endif /* Try each hard reg to see if it fits. Do this in two passes. In the first pass, skip registers that are preferred by some other pseudo to give it a better chance of getting one of those registers. Only if we can't get a register when excluding those do we take one of them. However, we never allocate a register for the first time in pass 0. */ COPY_HARD_REG_SET (used, used1); IOR_COMPL_HARD_REG_SET (used, regs_used_so_far); IOR_HARD_REG_SET (used, regs_someone_prefers[allocno]); best_reg = -1; for (i = FIRST_PSEUDO_REGISTER, pass = 0; pass <= 1 && i >= FIRST_PSEUDO_REGISTER; pass++) { if (pass == 1) COPY_HARD_REG_SET (used, used1); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) {#ifdef REG_ALLOC_ORDER int regno = reg_alloc_order[i];#else int regno = i;#endif if (! TEST_HARD_REG_BIT (used, regno) && HARD_REGNO_MODE_OK (regno, mode)) { register int j; register int lim = regno + HARD_REGNO_NREGS (regno, mode); for (j = regno + 1; (j < lim && ! TEST_HARD_REG_BIT (used, j)); j++); if (j == lim) { best_reg = regno; break; }#ifndef REG_ALLOC_ORDER i = j; /* Skip starting points we know will lose */#endif } } } /* See if there is a preferred register with the same class as the register we allocated above. Making this restriction prevents register preferencing from creating worse register allocation. Remove from the preferred registers and conflicting registers. Note that additional conflicts may have been added after `prune_preferences' was called. First do this for those register with copy preferences, then all preferred registers. */ AND_COMPL_HARD_REG_SET (hard_reg_copy_preferences[allocno], used); GO_IF_HARD_REG_SUBSET (hard_reg_copy_preferences[allocno], reg_class_contents[(int) NO_REGS], no_copy_prefs); if (best_reg >= 0) { for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (hard_reg_copy_preferences[allocno], i) && HARD_REGNO_MODE_OK (i, mode) && (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg) || reg_class_subset_p (REGNO_REG_CLASS (i), REGNO_REG_CLASS (best_reg)) || reg_class_subset_p (REGNO_REG_CLASS (best_reg), REGNO_REG_CLASS (i)))) { register int j; register int lim = i + HARD_REGNO_NREGS (i, mode); for (j = i + 1; (j < lim && ! TEST_HARD_REG_BIT (used, j) && (REGNO_REG_CLASS (j) == REGNO_REG_CLASS (best_reg + (j - i)) || reg_class_subset_p (REGNO_REG_CLASS (j), REGNO_REG_CLASS (best_reg + (j - i))) || reg_class_subset_p (REGNO_REG_CLASS (best_reg + (j - i)), REGNO_REG_CLASS (j)))); j++); if (j == lim) { best_reg = i; goto no_prefs; } } } no_copy_prefs: AND_COMPL_HARD_REG_SET (hard_reg_preferences[allocno], used); GO_IF_HARD_REG_SUBSET (hard_reg_preferences[allocno], reg_class_contents[(int) NO_REGS], no_prefs); if (best_reg >= 0) { for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (hard_reg_preferences[allocno], i) && HARD_REGNO_MODE_OK (i, mode) && (REGNO_REG_CLASS (i) == REGNO_REG_CLASS (best_reg) || reg_class_subset_p (REGNO_REG_CLASS (i), REGNO_REG_CLASS (best_reg)) || reg_class_subset_p (REGNO_REG_CLASS (best_reg), REGNO_REG_CLASS (i)))) { register int j; register int lim = i + HARD_REGNO_NREGS (i, mode); for (j = i + 1; (j < lim && ! TEST_HARD_REG_BIT (used, j) && (REGNO_REG_CLASS (j) == REGNO_REG_CLASS (best_reg + (j - i)) || reg_class_subset_p (REGNO_REG_CLASS (j), REGNO_REG_CLASS (best_reg + (j - i))) || reg_class_subset_p (REGNO_REG_CLASS (best_reg + (j - i)), REGNO_REG_CLASS (j)))); j++); if (j == lim) { best_reg = i; break; } } } no_prefs: /* If we haven't succeeded yet, try with caller-saves. We need not check to see if the current function has nonlocal labels because we don't put any pseudos that are live over calls in registers in that case. */ if (flag_caller_saves && best_reg < 0) { /* Did not find a register. If it would be profitable to allocate a call-clobbered register and save and restore it around calls, do that. */ if (! accept_call_clobbered && allocno_calls_crossed[allocno] != 0 && CALLER_SAVE_PROFITABLE (allocno_n_refs[allocno], allocno_calls_crossed[allocno])) { HARD_REG_SET new_losers; if (! losers) CLEAR_HARD_REG_SET (new_losers); else COPY_HARD_REG_SET (new_losers, losers); IOR_HARD_REG_SET(new_losers, losing_caller_save_reg_set); find_reg (allocno, new_losers, alt_regs_p, 1, retrying); if (reg_renumber[allocno_reg[allocno]] >= 0) { caller_save_needed = 1; return; } } } /* If we haven't succeeded yet, see if some hard reg that conflicts with us was utilized poorly by local-alloc. If so, kick out the regs that were put there by local-alloc so we can use it instead. */ if (best_reg < 0 && !retrying /* Let's not bother with multi-reg allocnos. */ && allocno_size[allocno] == 1) { /* Count from the end, to find the least-used ones first. */ for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) {#ifdef REG_ALLOC_ORDER int regno = reg_alloc_order[i];#else int regno = i;#endif if (local_reg_n_refs[regno] != 0 /* Don't use a reg no good for this pseudo. */ && ! TEST_HARD_REG_BIT (used2, regno) && HARD_REGNO_MODE_OK (regno, mode)#ifdef CLASS_CANNOT_CHANGE_SIZE && ! (REG_CHANGES_SIZE (allocno_reg[allocno]) && (TEST_HARD_REG_BIT (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE], regno)))#endif ) { /* We explicitly evaluate the divide results into temporary variables so as to avoid excess precision problems that occur on a i386-unknown-sysv4.2 (unixware) host. */ double tmp1 = ((double) local_reg_n_refs[regno] / local_reg_live_length[regno]); double tmp2 = ((double) allocno_n_refs[allocno] / allocno_live_length[allocno]); if (tmp1 < tmp2) { /* Hard reg REGNO was used less in total by local regs than it would be used by this one allocno! */ int k; for (k = 0; k < max_regno; k++) if (reg_renumber[k] >= 0) { int r = reg_renumber[k]; int endregno = r + HARD_REGNO_NREGS (r, PSEUDO_REGNO_MODE (k)); if (regno >= r && regno < endregno) reg_renumber[k] = -1; } best_reg = regno; break; } } } } /* Did we find a register? */ if (best_reg >= 0) { register int lim, j; HARD_REG_SET this_reg; /* Yes. Record it as the hard register of this pseudo-reg. */ reg_renumber[allocno_reg[allocno]] = best_reg; /* Also of any pseudo-regs that share with it. */ if (reg_may_share[allocno_reg[allocno]]) for (j = FIRST_PSEUDO_REGISTER; j < max_regno; j++) if (reg_allocno[j] == allocno) reg_renumber[j] = best_reg; /* Make a set of the hard regs being allocated. */ CLEAR_HARD_REG_SET (this_reg); lim = best_reg + HARD_REGNO_NREGS (best_reg, mode); for (j = best_reg; j < lim; j++) { SET_HARD_REG_BIT (this_reg, j); SET_HARD_REG_BIT (regs_used_so_far, j); /* This is no longer a reg used just by local regs. */ local_reg_n_refs[j] = 0; } /* For each other pseudo-reg conflicting with this one, mark it as conflicting with the hard regs this one occupies. */ lim = allocno; for (j = 0; j < max_allocno; j++) if (CONFLICTP (lim, j) || CONFLICTP (j, lim)) { IOR_HARD_REG_SET (hard_reg_conflicts[j], this_reg); } }}/* Called from `reload' to look for a hard reg to put pseudo reg REGNO in. Perhaps it had previously seemed not worth a hard reg, or perhaps its old hard reg has been commandeered for reloads. FORBIDDEN_REGS indicates certain hard regs that may not be used, even if they do not appear to be allocated. If FORBIDDEN_REGS is zero, no regs are forbidden. */voidretry_global_alloc (regno, forbidden_regs) int regno; HARD_REG_SET forbidden_regs;{ int allocno = reg_allocno[regno]; if (allocno >= 0) { /* If we have more than one register class, first try allocating in the class that is cheapest for this pseudo-reg. If that fails, try any reg. */ if (N_REG_CLASSES > 1) find_reg (allocno, forbidden_regs, 0, 0, 1); if (reg_renumber[regno] < 0 && reg_alternate_class (regno) != NO_REGS) find_reg (allocno, forbidden_regs, 1, 0, 1); /* If we found a register, modify the RTL for the register to show the hard register, and mark that register live. */ if (reg_renumber[regno] >= 0) { REGNO (regno_reg_rtx[regno]) = reg_renumber[regno]; mark_home_live (regno); } }}/* Record a conflict between register REGNO and everything currently live. REGNO must not be a pseudo reg that was allocated by local_alloc; such numbers must be translated through reg_renumber before calling here. */static voidrecord_one_conflict (regno) int regno;{ register int j; if (regno < FIRST_PSEUDO_REGISTER) /* When a hard register becomes live, record conflicts with live pseudo regs. */ for (j = 0; j < max_allocno; j++) { if (ALLOCNO_LIVE_P (j)) SET_HARD_REG_BIT (hard_reg_conflicts[j], regno); } else /* When a pseudo-register becomes live, record conflicts first with hard regs, then with other pseudo regs. */ { register int ialloc = reg_allocno[regno]; register int ialloc_prod = ialloc * allocno_row_words; IOR_HARD_REG_SET (hard_reg_conflicts[ialloc], hard_regs_live); for (j = allocno_row_words - 1; j >= 0; j--) {#if 0 int k; for (k = 0; k < n_no_conflict_pairs; k++) if (! ((j == no_conflict_pairs[k].allocno1 && ialloc == no_conflict_pairs[k].allocno2) || (j == no_conflict_pairs[k].allocno2 && ialloc == no_conflict_pairs[k].allocno1)))#endif /* 0 */ conflicts[ialloc_prod + j] |= allocnos_live[j]; } }}/* Record all allocnos currently live as conflicting with each other and with all hard regs currently live. ALLOCNO_VEC is a vector of LEN allocnos, all allocnos that are currently live. Their bits are also flagged in allocnos_live. */static voidrecord_conflicts (allocno_vec, len) register short *allocno_vec; register int len;{ register int allocno; register int j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -