📄 reload1.c
字号:
} alter_reg (i, regno); if (dumpfile) { if (reg_renumber[i] == -1) fprintf (dumpfile, " Register %d now on stack.\n\n", i); else fprintf (dumpfile, " Register %d now in %d.\n\n", i, reg_renumber[i]); } } return something_changed || regs_explicitly_used[regno];}/* Find all paradoxical subregs within X and update reg_max_ref_width. */static rtxscan_paradoxical_subregs (x) register rtx x;{ register int i; register char *fmt; register enum rtx_code code = GET_CODE (x); switch (code) { case CONST_INT: case CONST: case SYMBOL_REF: case LABEL_REF: case CONST_DOUBLE: case CC0: case PC: case REG: case USE: case CLOBBER: return; case SUBREG: if (GET_CODE (SUBREG_REG (x)) == REG && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) reg_max_ref_width[REGNO (SUBREG_REG (x))] = GET_MODE_SIZE (GET_MODE (x)); return; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') scan_paradoxical_subregs (XEXP (x, i)); else if (fmt[i] == 'E') { register int j; for (j = XVECLEN (x, i) - 1; j >=0; j--) scan_paradoxical_subregs (XVECEXP (x, i, j)); } }}struct hard_reg_n_uses { int regno; int uses; };static inthard_reg_use_compare (p1, p2) struct hard_reg_n_uses *p1, *p2;{ int tem = p1->uses - p2->uses; if (tem != 0) return tem; /* If regs are equally good, sort by regno, so that the results of qsort leave nothing to chance. */ return p1->regno - p2->regno;}/* Choose the order to consider regs for use as reload registers based on how much trouble would be caused by spilling one. Store them in order of decreasing preference in potential_reload_regs. */static voidorder_regs_for_reload (){ register int i; register int o = 0; int large = 0; struct hard_reg_n_uses hard_reg_n_uses[FIRST_PSEUDO_REGISTER]; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) potential_reload_regs[i] = -1; /* Count number of uses of each hard reg by pseudo regs allocated to it and then order them by decreasing use. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { hard_reg_n_uses[i].uses = 0; hard_reg_n_uses[i].regno = i; } for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) { int regno = reg_renumber[i]; if (regno >= 0) { int lim = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (i)); while (regno < lim) hard_reg_n_uses[regno++].uses += reg_n_refs[i]; } large += reg_n_refs[i]; } /* Now fixed registers (which cannot safely be used for reloading) get a very high use count so they will be considered least desirable. Registers used explicitly in the rtl code are almost as bad. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (fixed_regs[i]) hard_reg_n_uses[i].uses += large + 2; else if (regs_explicitly_used[i]) hard_reg_n_uses[i].uses += large + 1; } hard_reg_n_uses[FRAME_POINTER_REGNUM].uses += large + 2; qsort (hard_reg_n_uses, FIRST_PSEUDO_REGISTER, sizeof hard_reg_n_uses[0], hard_reg_use_compare); /* Prefer registers not so far used, for use in temporary loading. Among them, prefer registers not preserved by calls. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) {#ifdef REG_ALLOC_ORDER int regno = reg_alloc_order[i];#else int regno = i;#endif if (regs_ever_live[regno] == 0 && call_used_regs[regno] && ! fixed_regs[regno]) potential_reload_regs[o++] = regno; } for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) {#ifdef REG_ALLOC_ORDER int regno = reg_alloc_order[i];#else int regno = i;#endif if (regs_ever_live[regno] == 0 && ! call_used_regs[regno] && regno != FRAME_POINTER_REGNUM) potential_reload_regs[o++] = regno; } /* Now add the regs that are already used, preferring those used less often. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (regs_ever_live[hard_reg_n_uses[i].regno] != 0) potential_reload_regs[o++] = hard_reg_n_uses[i].regno;#if 0 /* For regs that are used, don't prefer those not preserved by calls because those are likely to contain high priority things that are live for short periods of time. */ for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) if (regs_ever_live[i] != 0 && ! call_used_regs[i]) potential_reload_regs[o++] = i;#endif}/* Reload pseudo-registers into hard regs around each insn as needed. Additional register load insns are output before the insn that needs it and perhaps store insns after insns that modify the reloaded pseudo reg. reg_last_reload_reg and reg_reloaded_contents keep track of which pseudo-registers are already available in reload registers. We update these for the reloads that we perform, as the insns are scanned. */static voidreload_as_needed (first, live_known) rtx first; int live_known;{ register rtx insn; register int i; int this_block = 0; rtx x; rtx after_call = 0; bzero (spill_reg_rtx, sizeof spill_reg_rtx); reg_last_reload_reg = (rtx *) alloca (max_regno * sizeof (rtx)); bzero (reg_last_reload_reg, max_regno * sizeof (rtx)); reg_has_output_reload = (char *) alloca (max_regno); for (i = 0; i < n_spills; i++) { reg_reloaded_contents[i] = -1; reg_reloaded_insn[i] = 0; } for (insn = first; insn;) { register rtx next = NEXT_INSN (insn); /* Notice when we move to a new basic block. */ if (basic_block_needs && this_block + 1 < n_basic_blocks && insn == basic_block_head[this_block+1]) ++this_block; if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN) { rtx avoid_return_reg = 0; /* If insn has no reloads, we want these to be zero, down below. */ bzero (reg_has_output_reload, max_regno); bzero (reg_is_output_reload, FIRST_PSEUDO_REGISTER); /* Set avoid_return_reg if this is an insn that might use the value of a function call. */ if (GET_CODE (insn) == CALL_INSN) { if (GET_CODE (PATTERN (insn)) == SET) after_call = SET_DEST (PATTERN (insn)); else if (GET_CODE (PATTERN (insn)) == PARALLEL && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET) after_call = SET_DEST (XVECEXP (PATTERN (insn), 0, 0)); else after_call = 0; } else if (after_call != 0 && !(GET_CODE (PATTERN (insn)) == SET && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)) { if (reg_mentioned_p (after_call, PATTERN (insn))) avoid_return_reg = after_call; after_call = 0; } if (GET_MODE (insn) == VOIDmode) n_reloads = 0; /* First find the pseudo regs that must be reloaded for this insn. This info is returned in the tables reload_... (see reload.h). Also modify the body of INSN by substituting RELOAD rtx's for those pseudo regs. */ else find_reloads (insn, 1, spill_indirect_ok, live_known, spill_reg_order); if (n_reloads > 0) { /* If this block has not had spilling done, deactivate any optional reloads lest they try to use a spill-reg which isn't available here. If we have any non-optionals that need a spill reg, abort. */ if (basic_block_needs != 0 && basic_block_needs[this_block] == 0) { for (i = 0; i < n_reloads; i++) { if (reload_optional[i]) reload_in[i] = reload_out[i] = 0; else if (reload_reg_rtx[i] == 0) abort (); } } /* Now compute which reload regs to reload them into. Perhaps reusing reload regs from previous insns, or else output load insns to reload them. Maybe output store insns too. Record the choices of reload reg in reload_reg_rtx. */ choose_reload_regs (insn, avoid_return_reg); /* Generate the insns to reload operands into or out of their reload regs. */ emit_reload_insns (insn); /* Substitute the chosen reload regs from reload_reg_rtx into the insn's body (or perhaps into the bodies of other load and store insn that we just made for reloading and that we moved the structure into). */ subst_reloads (); } /* Any previously reloaded spilled pseudo reg, stored in this insn, is no longer validly lying around to save a future reload. Note that this does not detect pseudos that were reloaded for this insn in order to be stored in (obeying register constraints). That is correct; such reload registers ARE still valid. */ note_stores (PATTERN (insn), forget_old_reloads_1); /* Likewise for regs altered by auto-increment in this insn. But note that the reg-notes are not changed by reloading: they still contain the pseudo-regs, not the spill regs. */ for (x = REG_NOTES (insn); x; x = XEXP (x, 1)) if (REG_NOTE_KIND (x) == REG_INC) { /* See if this pseudo reg was reloaded in this insn. If so, its last-reload info is still valid because it is based on this insn's reload. */ for (i = 0; i < n_reloads; i++) if (reload_out[i] == XEXP (x, 0)) break; if (i != n_reloads) forget_old_reloads_1 (XEXP (x, 0)); } } /* A reload reg's contents are unknown after a label. */ if (GET_CODE (insn) == CODE_LABEL) for (i = 0; i < n_spills; i++) { reg_reloaded_contents[i] = -1; reg_reloaded_insn[i] = 0; } /* Don't assume a reload reg is still good after a call insn if it is a call-used reg. */ if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == CALL_INSN) for (i = 0; i < n_spills; i++) if (call_used_regs[spill_regs[i]]) { reg_reloaded_contents[i] = -1; reg_reloaded_insn[i] = 0; } /* In case registers overlap, allow certain insns to invalidate particular hard registers. */#ifdef INSN_CLOBBERS_REGNO_P for (i = 0 ; i < n_spills ; i++) if (INSN_CLOBBERS_REGNO_P (insn, spill_regs[i])) { reg_reloaded_contents[i] = -1; reg_reloaded_insn[i] = 0; }#endif insn = next;#ifdef USE_C_ALLOCA alloca (0);#endif }}/* Discard all record of any value reloaded from X, or reloaded in X from someplace else; unless X is an output reload reg of the current insn. X may be a hard reg (the reload reg) or it may be a pseudo reg that was reloaded from. This function is not called for instructions generated by reload. */static voidforget_old_reloads_1 (x) rtx x;{ register int regno; int nr; if (GET_CODE (x) != REG) return; regno = REGNO (x); if (regno >= FIRST_PSEUDO_REGISTER) nr = 1; else { int i; nr = HARD_REGNO_NREGS (regno, GET_MODE (x)); /* Storing into a spilled-reg invalidates its contents. This can happen if a block-local pseudo is allocated to that reg and it wasn't spilled because this block's total need is 0. Then some insn might have an optional reload and use this reg. */ for (i = 0; i < nr; i++) if (spill_reg_order[regno + i] >= 0 /* But don't do this if the reg actually serves as an output reload reg in the current instruction. */ && reg_is_output_reload[regno + i] == 0) { reg_reloaded_contents[spill_reg_order[regno + i]] = -1; reg_reloaded_insn[spill_reg_order[regno + i]] = 0; } } /* Since value of X has changed, forget any value previously copied from it. */ while (nr-- > 0) /* But don't forget a copy if this is the output reload that establishes the copy's validity. */ if (reg_has_output_reload[regno
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -