📄 flow.c
字号:
if (GET_CODE (SET_SRC (x)) == CALL) return 0; while (GET_CODE (r) == SUBREG || (strict_low_ok && 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 int bit = 1 << (regno % REGSET_ELT_BITS); return (! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]) && (needed[offset] & bit) == 0); } } /* 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, strict_low_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 last insn in a libcall, and assuming X is dead, return 1 if the entire library call is dead. This is true if the source of X is a dead register (as well as the destination, which we tested already). 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. */static intlibcall_dead_p (x, needed) rtx x; regset needed;{ register RTX_CODE code = GET_CODE (x); if (code == SET) { register rtx r = SET_SRC (x); if (GET_CODE (r) == REG) { register int regno = REGNO (r); register int offset = regno / REGSET_ELT_BITS; register int bit = 1 << (regno % REGSET_ELT_BITS); return (needed[offset] & bit) == 0; } } return 1;}/* Return 1 if register REGNO was used before it was set. In other words, if it is live at function entry. */intregno_uninitialized (regno) int regno;{ if (n_basic_blocks == 0) return 0; return (basic_block_live_at_start[0][regno / REGSET_ELT_BITS] & (1 << (regno % REGSET_ELT_BITS)));}/* 1 if register REGNO was alive at a place where `setjmp' was called and was set more than once. Such regs may be clobbered by `longjmp'. */intregno_clobbered_at_setjmp (regno) int regno;{ return (reg_n_sets[regno] > 1 && (regs_live_at_setjmp[regno / REGSET_ELT_BITS] & (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); int subreg_p = 0; if (reg == 0) return; /* 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. */ while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT || GET_CODE (reg) == SIGN_EXTRACT || GET_CODE (reg) == STRICT_LOW_PART) { if (GET_CODE (reg) == ZERO_EXTRACT || GET_CODE (reg) == SIGN_EXTRACT || (GET_CODE (reg) == SUBREG && REG_SIZE (SUBREG_REG (reg)) > REG_SIZE (reg))) subreg_p = 1; reg = XEXP (reg, 0); } if (GET_CODE (reg) == REG && (regno = REGNO (reg), regno != FRAME_POINTER_REGNUM) && regno != ARG_POINTER_REGNUM && ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])) /* && regno != STACK_POINTER_REGNUM) -- let's try without this. */ { register int offset = regno / REGSET_ELT_BITS; register int bit = 1 << (regno % REGSET_ELT_BITS); int is_needed = 0; /* Mark it as a significant register for this basic block. */ if (significant) significant[offset] |= bit; /* That's all we do, if we are setting only part of the register. */ if (subreg_p) return; /* If entire register being set, 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) { dead[(regno + n) / REGSET_ELT_BITS] |= 1 << ((regno + n) % REGSET_ELT_BITS); if (significant) significant[(regno + n) / REGSET_ELT_BITS] |= 1 << ((regno + n) % REGSET_ELT_BITS); is_needed |= (needed[(regno + n) / REGSET_ELT_BITS] & 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. `combine.c' will get confused if LOG_LINKs are made for hard regs. */ if (regno < FIRST_PSEUDO_REGISTER) { register int i; i = HARD_REGNO_NREGS (regno, GET_MODE (reg)); if (i == 0) i = 1; do regs_ever_live[regno + --i] = 1; while (i > 0); if (! ((needed[offset] & bit) || is_needed)) { /* Note that dead stores have already been deleted if poss. If we get here, we have found a dead store that cannot be eliminated (because the insn does something useful). Indicate this by marking the reg set as dying here. */ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, reg, REG_NOTES (insn)); reg_n_deaths[REGNO (reg)]++; } return; } /* 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; /* Record first insn to use this reg. */ reg_first_use[regno] = insn; /* Count (weighted) references, stores, etc. */ reg_n_refs[regno] += loop_depth; reg_n_sets[regno]++; /* The next use is no longer "next", since a store intervenes. */ reg_next_use[regno] = 0; /* 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]++; if ((needed[offset] & bit) || is_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. */ if (y && (BLOCK_NUM (y) == blocknum)) LOG_LINKS (y) = gen_rtx (INSN_LIST, VOIDmode, insn, LOG_LINKS (y)); } else { /* 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_DEAD, reg, REG_NOTES (insn)); reg_n_deaths[REGNO (reg)]++; } } }}/* Scan expression X and store a 1-bit in LIVE for each reg it uses. This is done assuming the registers needed from X are those that have 1-bits in NEEDED. On the final pass, FINAL is 1. This means try for autoincrement and count the uses and deaths of each pseudo-reg. INSN is the containing instruction. */static voidmark_used_regs (needed, live, x, final, insn) regset needed; regset live; rtx x; rtx insn; int final;{ register RTX_CODE code; register int regno; retry: code = GET_CODE (x); switch (code) { case LABEL_REF: case SYMBOL_REF: case CONST_INT: case CONST: case CONST_DOUBLE: case CC0: case PC: case CLOBBER: case ADDR_VEC: case ADDR_DIFF_VEC: case ASM_INPUT: return;#if defined (HAVE_POST_INCREMENT) || defined (HAVE_POST_DECREMENT) case MEM: /* Here we detect use of an index register which might be good for postincrement or postdecrement. */ if (final) { rtx addr = XEXP (x, 0); register int size = GET_MODE_SIZE (GET_MODE (x)); if (GET_CODE (addr) == REG) { register rtx y; regno = REGNO (addr); /* Is the next use an increment that might make auto-increment? */ y = reg_next_use[regno]; if (y && GET_CODE (PATTERN (y)) == SET && BLOCK_NUM (y) == 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 (y)), (0#ifdef HAVE_POST_INCREMENT || GET_CODE (y) == PLUS#endif#ifdef HAVE_POST_DECREMENT || GET_CODE (y) == MINUS#endif ) && XEXP (y, 0) == addr && GET_CODE (XEXP (y, 1)) == CONST_INT && INTVAL (XEXP (y, 1)) == size) && dead_or_set_p (reg_next_use[regno], addr)) { rtx use = find_use_as_address (PATTERN (insn), addr, 0); /* Make sure this register appears only once in this insn. */ if (use != 0 && use != (rtx) 1) { /* We have found a suitable auto-increment: do POST_INC around the register here, and patch out the increment instruction that follows. */ XEXP (x, 0) = gen_rtx (GET_CODE (y) == PLUS ? POST_INC : POST_DEC, Pmode, addr); /* Record that this insn has an implicit side effect. */ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_INC, addr, REG_NOTES (insn)); /* Modify the old increment-insn to simply copy the already-incremented value of our register. */ y = reg_next_use[regno]; SET_SRC (PATTERN (y)) = addr; /* If that makes it a no-op (copying the register into itself) then change it to a simpler no-op so it won't appear to be a "use" and a "set" of this register. */ if (SET_DEST (PATTERN (y)) == addr) PATTERN (y) = gen_rtx (USE, VOIDmode, const0_rtx); /* Count an extra reference to the reg for the increment. When a reg is incremented. spilling it is worse, so we want to make that less likely. */ reg_n_refs[regno] += loop_depth; /* Count the increment as a setting of the register, even though it isn't a SET in rtl. */ reg_n_sets[regno]++; } } } } break;#endif /* HAVE_POST_INCREMENT or HAVE_POST_DECREMENT */ case REG: /* See a register other than being set => mark it as needed. */ regno = REGNO (x); if (regno != FRAME_POINTER_REGNUM) /* && regno != ARG_POINTER_REGNUM) -- and without this. */ /* && regno != STACK_POINTER_REGNUM) -- let's try without this. */ { register int offset = regno / REGSET_ELT_BITS; register int bit = 1 << (regno % REGSET_ELT_BITS); int is_needed = 0; live[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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -