?? loop.c
字號(hào):
if (m->match == 0 && n_times_used[m->regno] == 1 && !m->partial) { register struct movable *m1; int regno = m->regno; bzero (matched_regs, nregs); matched_regs[regno] = 1; for (m1 = m->next; m1; m1 = m1->next) if (m1->match == 0 && n_times_used[m1->regno] == 1 /* A reg used outside the loop mustn't be eliminated. */ && !m1->global /* A reg used for zero-extending mustn't be eliminated. */ && !m1->partial && (matched_regs[m1->regno] || ( /* Can't combine regs with different modes even if loaded from the same constant. */ (GET_MODE (SET_DEST (PATTERN (m->insn))) == GET_MODE (SET_DEST (PATTERN (m1->insn)))) /* See if the source of M1 says it matches M. */ && ((GET_CODE (m1->set_src) == REG && matched_regs[REGNO (m1->set_src)]) || rtx_equal_for_loop_p (m->set_src, m1->set_src, movables) || (REG_NOTES (m->insn) && REG_NOTES (m1->insn) && REG_NOTE_KIND (REG_NOTES (m->insn)) == REG_EQUIV && REG_NOTE_KIND (REG_NOTES (m1->insn)) == REG_EQUIV && rtx_equal_p (XEXP (REG_NOTES (m->insn), 0), XEXP (REG_NOTES (m1->insn), 0))))))) { m->lifetime += m1->lifetime; m->savings += m1->savings; m1->match = m; matched_regs[m1->regno] = 1; } } /* Now combine the regs used for zero-extension. This can be done for those not marked `global' provided their lives don't overlap. */ for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1)) if (GET_MODE_CLASS (mode) == MODE_INT) { register struct movable *m0 = 0; /* Combine all the registers for extension from mode MODE. Don't combine any that are used outside this loop. */ for (m = movables; m; m = m->next) if (m->partial && ! m->global && mode == GET_MODE (SET_SRC (PATTERN (NEXT_INSN (m->insn))))) { register struct movable *m1; int first = uid_luid[regno_first_uid[m->regno]]; int last = uid_luid[regno_last_uid[m->regno]]; if (m0 == 0) { /* First one: don't check for overlap, just record it. */ m0 = m; continue; } /* Make sure they extend to the same mode. (Almost always true.) */ if (GET_MODE (SET_DEST (PATTERN (m->insn))) != GET_MODE (SET_DEST (PATTERN (m0->insn)))) continue; /* We already have one: check for overlap with those already combined together. */ for (m1 = movables; m1 != m; m1 = m1->next) if (m1 == m0 || (m1->partial && m1->match == m0)) if (! (uid_luid[regno_first_uid[m1->regno]] > last || uid_luid[regno_last_uid[m1->regno]] < first)) goto overlap; /* No overlap: we can combine this with the others. */ m0->lifetime += m->lifetime; m0->savings += m->savings; m->match = m0; overlap: ; } }}/* Return 1 if regs X and Y will become the same if moved. */static intregs_match_p (x, y, movables) rtx x, y; struct movable *movables;{ int xn = REGNO (x); int yn = REGNO (y); struct movable *mx, *my; for (mx = movables; mx; mx = mx->next) if (mx->regno == xn) break; for (my = movables; my; my = my->next) if (my->regno == yn) break; return (mx && my && ((mx->match == my->match && mx->match != 0) || mx->match == my || mx == my->match));}/* Return 1 if X and Y are identical-looking rtx's. This is the Lisp function EQUAL for rtx arguments. */static intrtx_equal_for_loop_p (x, y, movables) rtx x, y; struct movable *movables;{ register int i; register int j; register enum rtx_code code; register char *fmt; if (x == y) return 1; if (x == 0 || y == 0) return 0; code = GET_CODE (x); /* Rtx's of different codes cannot be equal. */ if (code != GET_CODE (y)) return 0; /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. (REG:SI x) and (REG:HI x) are NOT equivalent. */ if (GET_MODE (x) != GET_MODE (y)) return 0; /* These three types of rtx's can be compared nonrecursively. */ /* Until the end of reload, don't consider the a reference to the return register of the current function the same as the return from a called function. This eases the job of function integration. Once the distinction no longer matters, the insn will be deleted. */ if (code == REG) return ((REGNO (x) == REGNO (y) && REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y)) || regs_match_p (x, y, movables)); if (code == LABEL_REF) return XEXP (x, 0) == XEXP (y, 0); if (code == SYMBOL_REF) return XSTR (x, 0) == XSTR (y, 0); /* Compare the elements. If any pair of corresponding elements fail to match, return 0 for the whole things. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { switch (fmt[i]) { case 'i': if (XINT (x, i) != XINT (y, i)) return 0; break; case 'E': /* Two vectors must have the same length. */ if (XVECLEN (x, i) != XVECLEN (y, i)) return 0; /* And the corresponding elements must match. */ for (j = 0; j < XVECLEN (x, i); j++) if (rtx_equal_for_loop_p (XVECEXP (x, i, j), XVECEXP (y, i, j), movables) == 0) return 0; break; case 'e': if (rtx_equal_for_loop_p (XEXP (x, i), XEXP (y, i), movables) == 0) return 0; break; case 's': if (strcmp (XSTR (x, i), XSTR (y, i))) return 0; break; case 'u': /* These are just backpointers, so they don't matter. */ break; case '0': break; /* It is believed that rtx's at this level will never contain anything but integers and other rtx's, except for within LABEL_REFs and SYMBOL_REFs. */ default: abort (); } } return 1;}/* Scan MOVABLES, and move the insns that deserve to be moved. If two matching movables are combined, replace one reg with the other throughout. */static voidmove_movables (movables, threshold, insn_count, loop_start, end, nregs) struct movable *movables; int threshold; int insn_count; rtx loop_start; rtx end; int nregs;{ rtx new_start = 0; register struct movable *m; register rtx p; /* Map of pseudo-register replacements to handle combining when we move several insns that load the same value into different pseudo-registers. */ rtx *reg_map = (rtx *) alloca (nregs * sizeof (rtx)); char *already_moved = (char *) alloca (nregs); bzero (already_moved, nregs); bzero (reg_map, nregs * sizeof (rtx)); num_movables = 0; for (m = movables; m; m = m->next) { /* Describe this movable insn. */ if (loop_dump_stream) { fprintf (loop_dump_stream, "Insn %d: regno %d (life %d), ", INSN_UID (m->insn), m->regno, m->lifetime); if (m->consec > 0) fprintf (loop_dump_stream, "consec %d, ", m->consec); if (m->cond) fprintf (loop_dump_stream, "cond "); if (m->force) fprintf (loop_dump_stream, "force "); if (m->global) fprintf (loop_dump_stream, "global "); if (m->done) fprintf (loop_dump_stream, "done "); if (m->match) fprintf (loop_dump_stream, "matches %d ", INSN_UID (m->match->insn)); if (m->forces) fprintf (loop_dump_stream, "forces %d ", INSN_UID (m->forces->insn)); } /* Count movables. Value used in heuristics in strength_reduce. */ num_movables++; /* Ignore the insn if it's already done (it matched something else). Otherwise, see if it is now safe to move. */ if (!m->done && (! m->cond || (1 == invariant_p (m->set_src) && (m->consec == 0 || 1 == consec_sets_invariant_p (SET_DEST (PATTERN (m->insn)), m->consec + 1, m->insn)))) && (! m->forces || m->forces->done)) { register int regno; register rtx p; int savings = m->savings; /* We have an insn that is safe to move. Compute its desirability. */ p = m->insn; regno = m->regno; if (loop_dump_stream) fprintf (loop_dump_stream, "savings %d ", savings); if (moved_once[regno]) { insn_count *= 2; if (loop_dump_stream) fprintf (loop_dump_stream, "halved since already moved "); } /* An insn MUST be moved if we already moved something else which is safe only if this one is moved too: that is, if already_moved[REGNO] is nonzero. */ /* An insn is desirable to move if the new lifetime of the register is no more than THRESHOLD times the old lifetime. If it's not desirable, it means the loop is so big that moving won't speed things up much, and it is liable to make register usage worse. */ /* It is also desirable to move if it can be moved at no extra cost because something else was already moved. */ if (already_moved[regno] || (threshold * savings * m->lifetime) >= insn_count || (m->forces && m->forces->done && n_times_used[m->forces->regno] == 1)) { int count; register struct movable *m1; rtx first; /* Now move the insns that set the reg. */ for (count = m->consec; count >= 0; count--) { rtx i1, temp; /* If first insn of gnulib call sequence, skip to end. */ /* Do this at start of loop, since p is guaranteed to be an insn here. */ if (temp = find_reg_note (p, REG_LIBCALL, 0)) p = XEXP (temp, 0); /* If last insn of gnulib call sequence, move all insns except the last before the loop. The last insn is handled in the normal manner. */ if (temp = find_reg_note (p, REG_RETVAL , 0)) { rtx fn_address = 0; rtx fn_reg = 0; first = 0; for (temp = XEXP (temp, 0); temp != p; temp = NEXT_INSN (temp)) { rtx body = PATTERN (temp); rtx n; /* Extract the function address from the insn that loads it into a register. If this insn was cse'd, we get incorrect code. So delete it and stick the fn address right into the call insn. Since the moved insns won't be cse'd, that does no harm. */ if (GET_CODE (NEXT_INSN (temp)) == CALL_INSN && GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == REG && (n = find_reg_note (temp, REG_EQUIV, 0))) { fn_reg = SET_SRC (body); if (GET_CODE (fn_reg) != REG) fn_reg = SET_DEST (body); fn_address = XEXP (n, 0); continue; } /* We have the call insn. Substitute the fn address for the reg that we believe this insn will use. */ if (GET_CODE (temp) == CALL_INSN && fn_address != 0) replace_call_address (body, fn_reg, fn_address); if (GET_CODE (temp) == CALL_INSN) i1 = emit_call_insn_before (body, loop_start); else i1 = emit_insn_before (body, loop_start); if (first == 0) first = i1; REG_NOTES (i1) = REG_NOTES (temp); delete_insn (temp); } } if (m->savemode != VOIDmode) { /* P sets REG to zero; but we should clear only the bits that are not covered by the mode m->savemode. */ rtx reg = SET_DEST (PATTERN (p)); i1 = emit_insn_before (gen_rtx (SET, VOIDmode, reg, gen_rtx (AND, GET_MODE (reg), reg, gen_rtx (CONST_INT, VOIDmode, (1 << GET_MODE_BITSIZE (m->savemode)) - 1))), loop_start); } else if (GET_CODE (PATTERN (p)) == CALL_INSN) i1 = emit_call_insn_before (PATTERN (p), loop_start); else i1 = emit_insn_before (PATTERN (p), loop_start); if (new_start == 0) new_start = i1; if (loop_dump_stream) fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1)); /* Mark the moved, invariant reg as being equivalent to its constant value. */ REG_NOTES (i1) = REG_NOTES (p); if (REG_NOTES (i1) == 0 && ! m->partial /* But not if it's a zero-extend clr. */ && ! m->global /* and not if used outside the loop (since it might get set outside). */ && CONSTANT_P (SET_SRC (PATTERN (p)))) REG_NOTES (i1) = gen_rtx (EXPR_LIST, REG_EQUIV, SET_SRC (PATTERN (p)), REG_NOTES (i1)); /* If library call, now fix the REG_NOTES that contain insn pointers, namely REG_LIBCALL on FIRST and REG_RETVAL on I1. */ if (temp = find_reg_note (i1, REG_RETVAL, 0)) { XEXP (temp, 0) = first; temp = find_reg_note (first, REG_LIBCALL, 0); XEXP (temp, 0) = i1; } delete_insn (p); do p = NEXT_INSN (p); while (p != 0 && GET_CODE (p) == NOTE); } /* The more regs we move, the less we like moving them. */ threshold -= 3; /* Any other movable that loads the same register MUST be moved. */ already_moved[regno] = 1; /* This reg has been moved out of one loop. */ moved_once[regno] = 1;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -