📄 flow.c
字号:
cc0_live = 0; if (! insn_is_dead) mark_used_regs (old, live, PATTERN (insn), final, insn); /* Sometimes we may have inserted something before INSN (such as a move) when we make an auto-inc. So ensure we will scan those insns. */#ifdef AUTO_INC_DEC prev = PREV_INSN (insn);#endif if (! insn_is_dead && GET_CODE (insn) == CALL_INSN) { register int i; rtx note; for (note = CALL_INSN_FUNCTION_USAGE (insn); note; note = XEXP (note, 1)) if (GET_CODE (XEXP (note, 0)) == USE) mark_used_regs (old, live, SET_DEST (XEXP (note, 0)), final, insn); /* Each call clobbers all call-clobbered regs that are not global. Note that the function-value reg is a call-clobbered reg, and mark_set_regs has already had a chance to handle it. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (call_used_regs[i] && ! global_regs[i]) dead[i / REGSET_ELT_BITS] |= ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)); /* The stack ptr is used (honorarily) by a CALL insn. */ live[STACK_POINTER_REGNUM / REGSET_ELT_BITS] |= ((REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS)); /* Calls may also reference any of the global registers, so they are made live. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (global_regs[i]) mark_used_regs (old, live, gen_rtx (REG, reg_raw_mode[i], i), final, insn); /* Calls also clobber memory. */ last_mem_set = 0; } /* Update OLD for the registers used or set. */ for (i = 0; i < regset_size; i++) { old[i] &= ~dead[i]; old[i] |= live[i]; } if (GET_CODE (insn) == CALL_INSN && final) { /* Any regs live at the time of a call instruction must not go in a register clobbered by calls. Find all regs now live and record this for them. */ register struct sometimes *p = regs_sometimes_live; for (i = 0; i < sometimes_max; i++, p++) if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit)) reg_n_calls_crossed[p->offset * REGSET_ELT_BITS + p->bit]+= 1; } } /* On final pass, add any additional sometimes-live regs into MAXLIVE and REGS_SOMETIMES_LIVE. Also update counts of how many insns each reg is live at. */ if (final) { for (i = 0; i < regset_size; i++) { register REGSET_ELT_TYPE diff = live[i] & ~maxlive[i]; if (diff) { register int regno; maxlive[i] |= diff; for (regno = 0; diff && regno < REGSET_ELT_BITS; regno++) if (diff & ((REGSET_ELT_TYPE) 1 << regno)) { regs_sometimes_live[sometimes_max].offset = i; regs_sometimes_live[sometimes_max].bit = regno; diff &= ~ ((REGSET_ELT_TYPE) 1 << regno); sometimes_max++; } } } { register struct sometimes *p = regs_sometimes_live; for (i = 0; i < sometimes_max; i++, p++) { if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit)) reg_live_length[p->offset * REGSET_ELT_BITS + p->bit]++; } } } } flushed: ; if (insn == first) break; } if (num_scratch > max_scratch) max_scratch = num_scratch;}/* Return 1 if X (the body of an insn, or part of it) is just dead stores (SET expressions whose destinations are registers dead after the insn). NEEDED is the regset that says which regs are alive after the insn. Unless CALL_OK is non-zero, an insn is needed if it contains a CALL. */static intinsn_dead_p (x, needed, call_ok) rtx x; regset needed; int call_ok;{ register RTX_CODE code = GET_CODE (x); /* If setting something that's a reg or part of one, see if that register's altered value will be live. */ if (code == SET) { register rtx r = SET_DEST (x); /* A SET that is a subroutine call cannot be dead. */ if (! call_ok && GET_CODE (SET_SRC (x)) == CALL) return 0;#ifdef HAVE_cc0 if (GET_CODE (r) == CC0) return ! cc0_live;#endif if (GET_CODE (r) == MEM && last_mem_set && ! MEM_VOLATILE_P (r) && rtx_equal_p (r, last_mem_set)) return 1; while (GET_CODE (r) == SUBREG || GET_CODE (r) == STRICT_LOW_PART || GET_CODE (r) == ZERO_EXTRACT || GET_CODE (r) == SIGN_EXTRACT) r = SUBREG_REG (r); if (GET_CODE (r) == REG) { register int regno = REGNO (r); register int offset = regno / REGSET_ELT_BITS; register REGSET_ELT_TYPE bit = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS); /* Don't delete insns to set global regs. */ if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno]) /* Make sure insns to set frame pointer aren't deleted. */ || regno == FRAME_POINTER_REGNUM#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM#endif#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM /* Make sure insns to set arg pointer are never deleted (if the arg pointer isn't fixed, there will be a USE for it, so we can treat it normally). */ || (regno == ARG_POINTER_REGNUM && fixed_regs[regno])#endif || (needed[offset] & bit) != 0) return 0; /* If this is a hard register, verify that subsequent words are not needed. */ if (regno < FIRST_PSEUDO_REGISTER) { int n = HARD_REGNO_NREGS (regno, GET_MODE (r)); while (--n > 0) if ((needed[(regno + n) / REGSET_ELT_BITS] & ((REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS))) != 0) return 0; } return 1; } } /* If performing several activities, insn is dead if each activity is individually dead. Also, CLOBBERs and USEs can be ignored; a CLOBBER or USE that's inside a PARALLEL doesn't make the insn worth keeping. */ else if (code == PARALLEL) { register int i = XVECLEN (x, 0); for (i--; i >= 0; i--) { rtx elt = XVECEXP (x, 0, i); if (!insn_dead_p (elt, needed, call_ok) && GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE) return 0; } return 1; } /* We do not check CLOBBER or USE here. An insn consisting of just a CLOBBER or just a USE should not be deleted. */ return 0;}/* If X is the pattern of the last insn in a libcall, and assuming X is dead, return 1 if the entire library call is dead. This is true if X copies a register (hard or pseudo) and if the hard return reg of the call insn is dead. (The caller should have tested the destination of X already for death.) If this insn doesn't just copy a register, then we don't have an ordinary libcall. In that case, cse could not have managed to substitute the source for the dest later on, so we can assume the libcall is dead. NEEDED is the bit vector of pseudoregs live before this insn. NOTE is the REG_RETVAL note of the insn. INSN is the insn itself. */static intlibcall_dead_p (x, needed, note, insn) rtx x; regset needed; rtx note; rtx insn;{ register RTX_CODE code = GET_CODE (x); if (code == SET) { register rtx r = SET_SRC (x); if (GET_CODE (r) == REG) { rtx call = XEXP (note, 0); register int i; /* Find the call insn. */ while (call != insn && GET_CODE (call) != CALL_INSN) call = NEXT_INSN (call); /* If there is none, do nothing special, since ordinary death handling can understand these insns. */ if (call == insn) return 0; /* See if the hard reg holding the value is dead. If this is a PARALLEL, find the call within it. */ call = PATTERN (call); if (GET_CODE (call) == PARALLEL) { for (i = XVECLEN (call, 0) - 1; i >= 0; i--) if (GET_CODE (XVECEXP (call, 0, i)) == SET && GET_CODE (SET_SRC (XVECEXP (call, 0, i))) == CALL) break; /* This may be a library call that is returning a value via invisible pointer. Do nothing special, since ordinary death handling can understand these insns. */ if (i < 0) return 0; call = XVECEXP (call, 0, i); } return insn_dead_p (call, needed, 1); } } return 1;}/* Return 1 if register REGNO was used before it was set. In other words, if it is live at function entry. Don't count global register variables, though. */intregno_uninitialized (regno) int regno;{ if (n_basic_blocks == 0 || (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])) return 0; return (basic_block_live_at_start[0][regno / REGSET_ELT_BITS] & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS)));}/* 1 if register REGNO was alive at a place where `setjmp' was called and was set more than once or is an argument. Such regs may be clobbered by `longjmp'. */intregno_clobbered_at_setjmp (regno) int regno;{ if (n_basic_blocks == 0) return 0; return ((reg_n_sets[regno] > 1 || (basic_block_live_at_start[0][regno / REGSET_ELT_BITS] & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS)))) && (regs_live_at_setjmp[regno / REGSET_ELT_BITS] & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))));}/* Process the registers that are set within X. Their bits are set to 1 in the regset DEAD, because they are dead prior to this insn. If INSN is nonzero, it is the insn being processed and the fact that it is nonzero implies this is the FINAL pass in propagate_block. In this case, various info about register usage is stored, LOG_LINKS fields of insns are set up. */static voidmark_set_regs (needed, dead, x, insn, significant) regset needed; regset dead; rtx x; rtx insn; regset significant;{ register RTX_CODE code = GET_CODE (x); if (code == SET || code == CLOBBER) mark_set_1 (needed, dead, x, insn, significant); else if (code == PARALLEL) { register int i; for (i = XVECLEN (x, 0) - 1; i >= 0; i--) { code = GET_CODE (XVECEXP (x, 0, i)); if (code == SET || code == CLOBBER) mark_set_1 (needed, dead, XVECEXP (x, 0, i), insn, significant); } }}/* Process a single SET rtx, X. */static voidmark_set_1 (needed, dead, x, insn, significant) regset needed; regset dead; rtx x; rtx insn; regset significant;{ register int regno; register rtx reg = SET_DEST (x); /* Modifying just one hardware register of a multi-reg value or just a byte field of a register does not mean the value from before this insn is now dead. But it does mean liveness of that register at the end of the block is significant. Within mark_set_1, however, we treat it as if the register is indeed modified. mark_used_regs will, however, also treat this register as being used. Thus, we treat these insns as setting a new value for the register as a function of its old value. This cases LOG_LINKS to be made appropriately and this will help combine. */ while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT || GET_CODE (reg) == SIGN_EXTRACT || GET_CODE (reg) == STRICT_LOW_PART) reg = XEXP (reg, 0); /* If we are writing into memory or into a register mentioned in the address of the last thing stored into memory, show we don't know what the last store was. If we are writing memory, save the address unless it is volatile. */ if (GET_CODE (reg) == MEM || (GET_CODE (reg) == REG && last_mem_set != 0 && reg_overlap_mentioned_p (reg, last_mem_set))) last_mem_set = 0; if (GET_CODE (reg) == MEM && ! side_effects_p (reg) /* There are no REG_INC notes for SP, so we can't assume we'll see everything that invalidates it. To be safe, don't eliminate any stores though SP; none of them should be redundant anyway. */ && ! reg_mentioned_p (stack_pointer_rtx, reg)) last_mem_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -