?? flow.c
字號:
/* For stack ptr or arg pointer, nothing below can be necessary, so waste no more time. */ if (regno == STACK_POINTER_REGNUM || regno == ARG_POINTER_REGNUM) return; /* No death notes for global register variables; their values are live after this function exits. */ if (global_regs[regno]) return; n = HARD_REGNO_NREGS (regno, GET_MODE (x)); while (--n > 0) { live[(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)); } } if (final) { if (regno < FIRST_PSEUDO_REGISTER) { /* If a hard reg is being used, record that this function does use it. */ register int i; i = HARD_REGNO_NREGS (regno, GET_MODE (x)); if (i == 0) i = 1; do regs_ever_live[regno + --i] = 1; while (i > 0); } else { /* Keep track of which basic block each reg appears in. */ register int blocknum = BLOCK_NUM (insn); 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 the earliest insn that uses this reg, provided the reg is used only in one basic block. Do this by recording each insn, and the one that sticks is the last one scanned (the earliest insn). */ reg_first_use[regno] = insn; /* Record where each reg is used, so when the reg is set we know the next insn that uses it. */ reg_next_use[regno] = insn; /* Count (weighted) number of uses of each reg. */ reg_n_refs[regno] += loop_depth; } /* Record and count the insns in which a reg dies. If it is used in this insn and was dead below the insn then it dies in this insn. */ if (!(needed[offset] & bit) && !is_needed && ! find_regno_note (insn, REG_DEAD, regno)) { REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (insn)); reg_n_deaths[regno]++; } } } return; case SET: { register rtx testreg = SET_DEST (x); int mark_dest = 0; /* Storing in STRICT_LOW_PART is like storing in a reg in that this SET might be dead, so ignore it in TESTREG. but in some other ways it is like using the reg. */ /* Storing in a SUBREG or a bit field is like storing the entire register in that if the register's value is not used then this SET is not needed. */ while (GET_CODE (testreg) == STRICT_LOW_PART || GET_CODE (testreg) == ZERO_EXTRACT || GET_CODE (testreg) == SIGN_EXTRACT || GET_CODE (testreg) == SUBREG) { /* Modifying a single register in an alternate mode does not use any of the old value. But these other ways of storing in a register do use the old value. */ if (GET_CODE (testreg) == SUBREG && !(REG_SIZE (SUBREG_REG (testreg)) > REG_SIZE (testreg))) ; else mark_dest = 1; testreg = XEXP (testreg, 0); } /* If this is a store into a register, recursively scan the only value being stored, and only if the register's value is live after this insn. If the value being computed here would never be used then the values it uses don't need to be computed either. */ if (GET_CODE (testreg) == REG && (regno = REGNO (testreg), regno != FRAME_POINTER_REGNUM) && regno != ARG_POINTER_REGNUM && ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))#if 0 /* This was added in 1.25, but screws up death notes for hard regs. It probably isn't really needed anyway. */ && (regno >= FIRST_PSEUDO_REGISTER || INSN_VOLATILE (insn)))#endif { register int offset = regno / REGSET_ELT_BITS; register int bit = 1 << (regno % REGSET_ELT_BITS); if ((needed[offset] & bit) /* If insn refers to volatile, we mustn't delete it, so its inputs are all needed. */ || INSN_VOLATILE (insn)) { mark_used_regs (needed, live, SET_SRC (x), final, insn); if (mark_dest) mark_used_regs (needed, live, SET_DEST (x), final, insn); } return; } } break; } /* Recursively scan the operands of this expression. */ { register char *fmt = GET_RTX_FORMAT (code); register int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') { /* Tail recursive case: save a function call level. */ if (i == 0) { x = XEXP (x, 0); goto retry; } mark_used_regs (needed, live, XEXP (x, i), final, insn); } else if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) mark_used_regs (needed, live, XVECEXP (x, i, j), final, insn); } } }}#ifdef AUTO_INC_DECstatic inttry_pre_increment_1 (insn) rtx insn;{ /* Find the next use of this reg. If in same basic block, make it do pre-increment or pre-decrement if appropriate. */ rtx x = PATTERN (insn); int amount = ((GET_CODE (SET_SRC (x)) == PLUS ? 1 : -1) * INTVAL (XEXP (SET_SRC (x), 1))); int regno = REGNO (SET_DEST (x)); rtx y = reg_next_use[regno]; if (y != 0 && BLOCK_NUM (y) == BLOCK_NUM (insn) && try_pre_increment (y, SET_DEST (PATTERN (insn)), amount)) { /* We have found a suitable auto-increment and already changed insn Y to do it. So flush this increment-instruction. */ PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; /* Count a reference to this reg for the increment insn we are deleting. When a reg is incremented. spilling it is worse, so we want to make that less likely. */ reg_n_refs[regno] += loop_depth; reg_n_sets[regno]++; return 1; } return 0;}/* Try to change INSN so that it does pre-increment or pre-decrement addressing on register REG in order to add AMOUNT to REG. AMOUNT is negative for pre-decrement. Returns 1 if the change could be made. This checks all about the validity of the result of modifying INSN. */static inttry_pre_increment (insn, reg, amount) rtx insn, reg; int amount;{ register rtx use; /* Nonzero if we can try to make a pre-increment or pre-decrement. For example, addl $4,r1; movl (r1),... can become movl +(r1),... */ int pre_ok = 0; /* Nonzero if we can try to make a post-increment or post-decrement. For example, addl $4,r1; movl -4(r1),... can become movl (r1)+,... It is possible for both PRE_OK and POST_OK to be nonzero if the machine supports both pre-inc and post-inc, or both pre-dec and post-dec. */ int post_ok = 0; /* Nonzero if the opportunity actually requires post-inc or post-dec. */ int do_post = 0; /* From the sign of increment, see which possibilities are conceivable on this target machine. */#ifdef HAVE_PRE_INCREMENT if (amount > 0) pre_ok = 1;#endif#ifdef HAVE_POST_INCREMENT if (amount > 0) post_ok = 1;#endif#ifdef HAVE_PRE_DECREMENT if (amount < 0) pre_ok = 1;#endif#ifdef HAVE_POST_DECREMENT if (amount < 0) post_ok = 1;#endif if (! (pre_ok || post_ok)) return 0; /* It is not safe to add a side effect to a jump insn because if the incremented register is spilled and must be reloaded there would be no way to store the incremented value back in memory. */ if (GET_CODE (insn) == JUMP_INSN) return 0; use = 0; if (pre_ok) use = find_use_as_address (PATTERN (insn), reg, 0); if (post_ok && (use == 0 || use == (rtx) 1)) { use = find_use_as_address (PATTERN (insn), reg, -amount); do_post = 1; } if (use == 0 || use == (rtx) 1) return 0; if (GET_MODE_SIZE (GET_MODE (use)) != (amount > 0 ? amount : - amount)) return 0; XEXP (use, 0) = gen_rtx (amount > 0 ? (do_post ? POST_INC : PRE_INC) : (do_post ? POST_DEC : PRE_DEC), Pmode, reg); /* Record that this insn now has an implicit side effect on X. */ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_INC, reg, REG_NOTES (insn)); return 1;}#endif /* AUTO_INC_DEC *//* Find the place in the rtx X where REG is used as a memory address. Return the MEM rtx that so uses it. If PLUSCONST is nonzero, search instead for a memory address equivalent to (plus REG (const_int PLUSCONST)). If such an address does not appear, return 0. If REG appears more than once, or is used other than in such an address, return (rtx)1. */static rtxfind_use_as_address (x, reg, plusconst) register rtx x; rtx reg; int plusconst;{ enum rtx_code code = GET_CODE (x); char *fmt = GET_RTX_FORMAT (code); register int i; register rtx value = 0; register rtx tem; if (code == MEM && XEXP (x, 0) == reg && plusconst == 0) return x; if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS && XEXP (XEXP (x, 0), 0) == reg && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && INTVAL (XEXP (XEXP (x, 0), 1)) == plusconst) return x; if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) { /* If REG occurs inside a MEM used in a bit-field reference, that is unacceptable. */ if (find_use_as_address (XEXP (x, 0), reg, 0) != 0) return (rtx) 1; } if (x == reg) return (rtx) 1; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') { tem = find_use_as_address (XEXP (x, i), reg, plusconst); if (value == 0) value = tem; else if (tem != 0) return (rtx) 1; } if (fmt[i] == 'E') { register int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) { tem = find_use_as_address (XVECEXP (x, i, j), reg, plusconst); if (value == 0) value = tem; else if (tem != 0) return (rtx) 1; } } } return value;}/* Write information about registers and basic blocks into FILE. This is part of making a debugging dump. */voiddump_flow_info (file) FILE *file;{ register int i; static char *reg_class_names[] = REG_CLASS_NAMES; fprintf (file, "%d registers.\n", max_regno); for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) if (reg_n_refs[i]) { enum reg_class class; fprintf (file, "\nRegister %d used %d times across %d insns", i, reg_n_refs[i], reg_live_length[i]); if (reg_basic_block[i] >= 0) fprintf (file, " in block %d", reg_basic_block[i]); if (reg_n_deaths[i] != 1) fprintf (file, "; dies in %d places", reg_n_deaths[i]); if (reg_n_calls_crossed[i] == 1) fprintf (file, "; crosses 1 call", reg_n_calls_crossed[i]); else if (reg_n_calls_crossed[i]) fprintf (file, "; crosses %d calls", reg_n_calls_crossed[i]); if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD) fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i)); class = reg_preferred_class (i); if (class != GENERAL_REGS) { if (reg_preferred_or_nothing (i)) fprintf (file, "; %s or none", reg_class_names[(int) class]); else fprintf (file, "; pref %s", reg_class_names[(int) class]); } if (REGNO_POINTER_FLAG (i)) fprintf (file, "; pointer"); fprintf (file, ".\n"); } fprintf (file, "\n%d basic blocks.\n", n_basic_blocks); for (i = 0; i < n_basic_blocks; i++) { register rtx head, jump; register int regno; fprintf (file, "\nBasic block %d: first insn %d, last %d.\n", i, INSN_UID (basic_block_head[i]), INSN_UID (basic_block_end[i])); /* The control flow graph's storage is freed now when flow_analysis returns. Don't try to print it if it is gone. */ if (basic_block_drops_in) { fprintf (file, "Reached from blocks: "); head = basic_block_head[i]; if (GET_CODE (head) == CODE_LABEL) for (jump = LABEL_REFS (head); jump != head; jump = LABEL_NEXTREF (jump)) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -