📄 flow.c
字号:
/* 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; if (i < 0) abort (); 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 regster variables, though. */intregno_uninitialized (regno) int regno;{ if (n_basic_blocks == 0 || 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 void mark_set_1 ();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_set = reg; if (GET_CODE (reg) == REG && (regno = REGNO (reg), regno != FRAME_POINTER_REGNUM)#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])#endif && ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])) /* && regno != STACK_POINTER_REGNUM) -- let's try without this. */ { register int offset = regno / REGSET_ELT_BITS; register REGSET_ELT_TYPE bit = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS); REGSET_ELT_TYPE all_needed = (needed[offset] & bit); REGSET_ELT_TYPE some_needed = (needed[offset] & bit); /* Mark it as a significant register for this basic block. */ if (significant) significant[offset] |= bit; /* Mark it as as dead before this insn. */ dead[offset] |= bit; /* A hard reg in a wide mode may really be multiple registers. If so, mark all of them just like the first. */ if (regno < FIRST_PSEUDO_REGISTER) { int n; /* Nothing below is needed for the stack pointer; get out asap. Eg, log links aren't needed, since combine won't use them. */ if (regno == STACK_POINTER_REGNUM) return; n = HARD_REGNO_NREGS (regno, GET_MODE (reg)); while (--n > 0) { if (significant) significant[(regno + n) / REGSET_ELT_BITS] |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS); dead[(regno + n) / REGSET_ELT_BITS] |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS); some_needed |= (needed[(regno + n) / REGSET_ELT_BITS] & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS)); all_needed &= (needed[(regno + n) / REGSET_ELT_BITS] & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS)); } } /* Additional data to record if this is the final pass. */ if (insn) { register rtx y = reg_next_use[regno]; register int blocknum = BLOCK_NUM (insn); /* If this is a hard reg, record this function uses the reg. */ if (regno < FIRST_PSEUDO_REGISTER) { register int i; int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (reg)); for (i = regno; i < endregno; i++) { regs_ever_live[i] = 1; reg_n_sets[i]++; } } else { /* Keep track of which basic blocks each reg appears in. */ if (reg_basic_block[regno] == REG_BLOCK_UNKNOWN) reg_basic_block[regno] = blocknum; else if (reg_basic_block[regno] != blocknum) reg_basic_block[regno] = REG_BLOCK_GLOBAL; /* Count (weighted) references, stores, etc. This counts a register twice if it is modified, but that is correct. */ reg_n_sets[regno]++; reg_n_refs[regno] += loop_depth; /* The insns where a reg is live are normally counted elsewhere, but we want the count to include the insn where the reg is set, and the normal counting mechanism would not count it. */ reg_live_length[regno]++; } /* The next use is no longer "next", since a store intervenes. */ reg_next_use[regno] = 0; if (all_needed) { /* Make a logical link from the next following insn that uses this register, back to this insn. The following insns have already been processed. We don't build a LOG_LINK for hard registers containing in ASM_OPERANDs. If these registers get replaced, we might wind up changing the semantics of the insn, even if reload can make what appear to be valid assignments later. */ if (y && (BLOCK_NUM (y) == blocknum) && (regno >= FIRST_PSEUDO_REGISTER || asm_noperands (PATTERN (y)) < 0)) LOG_LINKS (y) = gen_rtx (INSN_LIST, VOIDmode, insn, LOG_LINKS (y)); } else if (! some_needed) { /* Note that dead stores have already been deleted when possible If we get here, we have found a dead store that cannot be eliminated (because the same insn does something useful). Indicate this by marking the reg being set as dying here. */ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED, reg, REG_NOTES (insn)); reg_n_deaths[REGNO (reg)]++; } else { /* This is a case where we have a multi-word hard register and some, but not all, of the words of the register are needed in subsequent insns. Write REG_UNUSED notes for those parts that were not needed. This case should be rare. */ int i; for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1; i >= 0; i--) if ((needed[(regno + i) / REGSET_ELT_BITS] & ((REGSET_ELT_TYPE) 1 << ((regno + i) % REGSET_ELT_BITS))) == 0) REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED, gen_rtx (REG, word_mode, regno + i), REG_NOTES (insn)); } } } /* If this is the last pass and this is a SCRATCH, show it will be dying here and count it. */ else if (GET_CODE (reg) == SCRATCH && insn != 0) { REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED, reg, REG_NOTES (insn)); num_scratch++; }}#ifdef AUTO_INC_DEC/* X is a MEM found in INSN. See if we can convert it into an auto-increment reference. */static voidfind_auto_inc (needed, x, insn) regset needed; rtx x; rtx insn;{ rtx addr = XEXP (x, 0); int offset = 0; /* Here we detect use of an index register which might be good for postincrement, postdecrement, preincrement, or predecrement. */ if (GET_CODE (addr) == PLUS && GET_CODE (XEXP (addr, 1)) == CONST_INT) offset = INTVAL (XEXP (addr, 1)), addr = XEXP (addr, 0); if (GET_CODE (addr) == REG) { register rtx y; register int size = GET_MODE_SIZE (GET_MODE (x)); rtx use; rtx incr; int regno = REGNO (addr); /* Is the next use an increment that might make auto-increment? */ incr = reg_next_use[regno]; if (incr && GET_CODE (PATTERN (incr)) == SET && BLOCK_NUM (incr) == BLOCK_NUM (insn) /* Can't add side effects to jumps; if reg is spilled and reloaded, there's no way to store back the altered value. */ && GET_CODE (insn) != JUMP_INSN && (y = SET_SRC (PATTERN (incr)), GET_CODE (y) == PLUS) && XEXP (y, 0) == addr && GET_CODE (XEXP (y, 1)) == CONST_INT && (0#ifdef HAVE_POST_INCREMENT || (INTVAL (XEXP (y, 1)) == size && offset == 0)#endif#ifdef HAVE_POST_DECREMENT || (INTVAL (XEXP (y, 1)) == - size && offset == 0)#endif#ifdef HAVE_PRE_INCREMENT || (INTVAL (XEXP (y, 1)) == size && offset == size)#endif#ifdef HAVE_PRE_DECREMENT || (INTVAL (XEXP (y, 1)) == - size && offset == - size)#endif ) /* Make sure this reg appears only once in this insn. */ && (use = find_use_as_address (PATTERN (insn), addr, offset), use != 0 && use != (rtx) 1)) { int win = 0; rtx q = SET_DEST (PATTERN (incr)); if (dead_or_set_p (incr, addr)) win = 1; else if (GET_CODE (q) == REG && ! reg_used_between_p (q, insn, incr)) { /* We have *p followed by q = p+size. Both p and q must be live afterward, and q must be dead before. Change it to q = p, ...*q..., q = q+size. Then fall into the usual case. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -