local-alloc.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,992 行 · 第 1/5 页
C
1,992 行
int n_calls = 0; int d_n_calls = 0; /* We can do the optimization. Scan forward from INSN again, replacing regs as we go. Set FAILED if a replacement can't be done. In that case, we can't move the death note for SRC. This should be rare. */ /* Set to stop at next insn. */ for (q = next_real_insn (insn); q != next_real_insn (p); q = next_real_insn (q)) { if (reg_overlap_mentioned_p (src, PATTERN (q))) { /* If SRC is a hard register, we might miss some overlapping registers with validate_replace_rtx, so we would have to undo it. We can't if DEST is present in the insn, so fail in that combination of cases. */ if (sregno < FIRST_PSEUDO_REGISTER && reg_mentioned_p (dest, PATTERN (q))) failed = 1; /* Replace all uses and make sure that the register isn't still present. */ else if (validate_replace_rtx (src, dest, q) && (sregno >= FIRST_PSEUDO_REGISTER || ! reg_overlap_mentioned_p (src, PATTERN (q)))) { /* We assume that a register is used exactly once per insn in the updates below. If this is not correct, no great harm is done. */ if (sregno >= FIRST_PSEUDO_REGISTER) REG_N_REFS (sregno) -= loop_depth; if (dregno >= FIRST_PSEUDO_REGISTER) REG_N_REFS (dregno) += loop_depth; } else { validate_replace_rtx (dest, src, q); failed = 1; } } /* Count the insns and CALL_INSNs passed. If we passed the death note of DEST, show increased live length. */ length++; if (dest_death) d_length++; /* If the insn in which SRC dies is a CALL_INSN, don't count it as a call that has been crossed. Otherwise, count it. */ if (q != p && GET_CODE (q) == CALL_INSN) { n_calls++; if (dest_death) d_n_calls++; } /* If DEST dies here, remove the death note and save it for later. Make sure ALL of DEST dies here; again, this is overly conservative. */ if (dest_death == 0 && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0 && GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest)) remove_note (q, dest_death); } if (! failed) { if (sregno >= FIRST_PSEUDO_REGISTER) { if (REG_LIVE_LENGTH (sregno) >= 0) { REG_LIVE_LENGTH (sregno) -= length; /* reg_live_length is only an approximation after combine if sched is not run, so make sure that we still have a reasonable value. */ if (REG_LIVE_LENGTH (sregno) < 2) REG_LIVE_LENGTH (sregno) = 2; } REG_N_CALLS_CROSSED (sregno) -= n_calls; } if (dregno >= FIRST_PSEUDO_REGISTER) { if (REG_LIVE_LENGTH (dregno) >= 0) REG_LIVE_LENGTH (dregno) += d_length; REG_N_CALLS_CROSSED (dregno) += d_n_calls; } /* Move death note of SRC from P to INSN. */ remove_note (p, note); XEXP (note, 1) = REG_NOTES (insn); REG_NOTES (insn) = note; } /* Put death note of DEST on P if we saw it die. */ if (dest_death) { XEXP (dest_death, 1) = REG_NOTES (p); REG_NOTES (p) = dest_death; } return; } /* If SRC is a hard register which is set or killed in some other way, we can't do this optimization. */ else if (sregno < FIRST_PSEUDO_REGISTER && dead_or_set_p (p, src)) break; }}/* INSN is a copy of SRC to DEST, in which SRC dies. See if we now have a sequence of insns that modify DEST followed by an insn that sets SRC to DEST in which DEST dies, with no prior modification of DEST. (There is no need to check if the insns in between actually modify DEST. We should not have cases where DEST is not modified, but the optimization is safe if no such modification is detected.) In that case, we can replace all uses of DEST, starting with INSN and ending with the set of SRC to DEST, with SRC. We do not do this optimization if a CALL_INSN is crossed unless SRC already crosses a call or if DEST dies before the copy back to SRC. It is assumed that DEST and SRC are pseudos; it is too complicated to do this for hard registers since the substitutions we may make might fail. */static voidoptimize_reg_copy_2 (insn, dest, src) rtx insn; rtx dest; rtx src;{ rtx p, q; rtx set; int sregno = REGNO (src); int dregno = REGNO (dest); for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p)) { if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN || (GET_CODE (p) == NOTE && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END))) break; if (GET_RTX_CLASS (GET_CODE (p)) != 'i') continue; set = single_set (p); if (set && SET_SRC (set) == dest && SET_DEST (set) == src && find_reg_note (p, REG_DEAD, dest)) { /* We can do the optimization. Scan forward from INSN again, replacing regs as we go. */ /* Set to stop at next insn. */ for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q)) if (GET_RTX_CLASS (GET_CODE (q)) == 'i') { if (reg_mentioned_p (dest, PATTERN (q))) { PATTERN (q) = replace_rtx (PATTERN (q), dest, src); /* We assume that a register is used exactly once per insn in the updates below. If this is not correct, no great harm is done. */ REG_N_REFS (dregno) -= loop_depth; REG_N_REFS (sregno) += loop_depth; } if (GET_CODE (q) == CALL_INSN) { REG_N_CALLS_CROSSED (dregno)--; REG_N_CALLS_CROSSED (sregno)++; } } remove_note (p, find_reg_note (p, REG_DEAD, dest)); REG_N_DEATHS (dregno)--; remove_note (insn, find_reg_note (insn, REG_DEAD, src)); REG_N_DEATHS (sregno)--; return; } if (reg_set_p (src, p) || find_reg_note (p, REG_DEAD, dest) || (GET_CODE (p) == CALL_INSN && REG_N_CALLS_CROSSED (sregno) == 0)) break; }} /* Find registers that are equivalent to a single value throughout the compilation (either because they can be referenced in memory or are set once from a single constant). Lower their priority for a register. If such a register is only referenced once, try substituting its value into the using insn. If it succeeds, we can eliminate the register completely. */static voidupdate_equiv_regs (){ rtx *reg_equiv_init_insn = (rtx *) alloca (max_regno * sizeof (rtx *)); /* Set when an attempt should be made to replace a register with the associated reg_equiv_replacement entry at the end of this function. */ char *reg_equiv_replace = (char *) alloca (max_regno * sizeof *reg_equiv_replace); rtx insn; int block, depth; reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx *)); bzero ((char *) reg_equiv_init_insn, max_regno * sizeof (rtx *)); bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx *)); bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace); init_alias_analysis (); loop_depth = 1; /* Scan the insns and find which registers have equivalences. Do this in a separate scan of the insns because (due to -fcse-follow-jumps) a register can be set below its use. */ for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { rtx note; rtx set = single_set (insn); rtx dest, src; int regno; if (GET_CODE (insn) == NOTE) { if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) loop_depth++; else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) loop_depth--; } /* If this insn contains more (or less) than a single SET, ignore it. */ if (set == 0) continue; dest = SET_DEST (set); src = SET_SRC (set); /* If this sets a MEM to the contents of a REG that is only used in a single basic block, see if the register is always equivalent to that memory location and if moving the store from INSN to the insn that set REG is safe. If so, put a REG_EQUIV note on the initializing insn. Don't add a REG_EQUIV note if the insn already has one. The existing REG_EQUIV is likely more useful than the one we are adding. If one of the regs in the address is marked as reg_equiv_replace, then we can't add this REG_EQUIV note. The reg_equiv_replace optimization may move the set of this register immediately before insn, which puts it after reg_equiv_init_insn[regno], and hence the mention in the REG_EQUIV note would be to an uninitialized pseudo. */ if (GET_CODE (dest) == MEM && GET_CODE (SET_SRC (set)) == REG && (regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER && REG_BASIC_BLOCK (regno) >= 0 && reg_equiv_init_insn[regno] != 0 && ! find_reg_note (insn, REG_EQUIV, NULL_RTX) && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace) && validate_equiv_mem (reg_equiv_init_insn[regno], SET_SRC (set), dest) && ! memref_used_between_p (SET_DEST (set), reg_equiv_init_insn[regno], insn)) REG_NOTES (reg_equiv_init_insn[regno]) = gen_rtx (EXPR_LIST, REG_EQUIV, dest, REG_NOTES (reg_equiv_init_insn[regno])); /* If this is a register-register copy where SRC is not dead, see if we can optimize it. */ if (flag_expensive_optimizations && GET_CODE (dest) == REG && GET_CODE (SET_SRC (set)) == REG && ! find_reg_note (insn, REG_DEAD, SET_SRC (set))) optimize_reg_copy_1 (insn, dest, SET_SRC (set)); /* Similarly for a pseudo-pseudo copy when SRC is dead. */ else if (flag_expensive_optimizations && GET_CODE (dest) == REG && REGNO (dest) >= FIRST_PSEUDO_REGISTER && GET_CODE (SET_SRC (set)) == REG && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER && find_reg_note (insn, REG_DEAD, SET_SRC (set))) optimize_reg_copy_2 (insn, dest, SET_SRC (set)); /* Otherwise, we only handle the case of a pseudo register being set once and only if neither the source nor the destination are in a register class that's likely to be spilled. */ if (GET_CODE (dest) != REG || (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER || REG_N_SETS (regno) != 1 || CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (dest))) || (GET_CODE (src) == REG && REGNO (src) >= FIRST_PSEUDO_REGISTER && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src))))) continue; note = find_reg_note (insn, REG_EQUAL, NULL_RTX); /* Record this insn as initializing this register. */ reg_equiv_init_insn[regno] = insn; /* If this register is known to be equal to a constant, record that it is always equivalent to the constant. */ if (note && CONSTANT_P (XEXP (note, 0))) PUT_MODE (note, (enum machine_mode) REG_EQUIV); /* If this insn introduces a "constant" register, decrease the priority of that register. Record this insn if the register is only used once more and the equivalence value is the same as our source. The latter condition is checked for two reasons: First, it is an indication that it may be more efficient to actually emit the insn as written (if no registers are available, reload will substitute the equivalence). Secondly, it avoids problems with any registers dying in this insn whose death notes would be missed. If we don't have a REG_EQUIV note, see if this insn is loading a register used only in one basic block from a MEM. If so, and the MEM remains unchanged for the life of the register, add a REG_EQUIV note. */ note = find_reg_note (insn, REG_EQUIV, NULL_RTX); if (note == 0 && REG_BASIC_BLOCK (regno) >= 0 && GET_CODE (SET_SRC (set)) == MEM && validate_equiv_mem (insn, dest, SET_SRC (set))) REG_NOTES (insn) = note = gen_rtx (EXPR_LIST, REG_EQUIV, SET_SRC (set), REG_NOTES (insn)); if (note) { int regno = REGNO (dest); reg_equiv_replacement[regno] = XEXP (note, 0); /* Don't mess with things live during setjmp. */ if (REG_LIVE_LENGTH (regno) >= 0) { /* Note that the statement below does not affect the priority in local-alloc! */ REG_LIVE_LENGTH (regno) *= 2; /* If the register is referenced exactly twice, meaning it is set once and used once, indicate that the reference may be replaced by the equivalence we computed above. If the register is only used in one basic block, this can't succeed or combine would have done it. It would be nice to use "loop_depth * 2" in the compare below. Unfortunately, LOOP_DEPTH need not be constant within a basic block so this would be too complicated. This case normally occurs when a parameter is read from memory and then used exactly once, not in a loop. */ if (REG_N_REFS (regno) == 2 && REG_BASIC_BLOCK (regno) < 0 && rtx_equal_p (XEXP (note, 0), SET_SRC (set))) reg_equiv_replace[regno] = 1; } } } /* Now scan all regs killed in an insn to see if any of them are registers only used that once. If so, see if we can replace the reference with the equivalent from. If we can, delete the initializing reference and this register will go away. If we can't replace the reference, and the instruction is not in a loop, then move the register initialization just before the use, so that they are in the same basic block. */ block = -1; depth = 0; for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { rtx link; /* Keep track of which basic block we are in. */ if (block + 1 < n_basic_blocks && basic_block_head[block + 1] == insn) ++block; if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') { if (GET_CODE (insn) == NOTE)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?