?? loop.c
字號:
rtx first; /* Now move the insns that set the reg. */ if (m->partial && m->match) { rtx newpat, i1; rtx r1, r2; /* Find the end of this chain of matching regs. Thus, we load each reg in the chain from that one reg. And that reg is loaded with 0 directly, since it has ->match == 0. */ for (m1 = m; m1->match; m1 = m1->match); newpat = gen_move_insn (SET_DEST (PATTERN (m->insn)), SET_DEST (PATTERN (m1->insn))); i1 = emit_insn_before (newpat, loop_start); /* Mark the moved, invariant reg as being allowed to share a hard reg with the other matching invariant. */ REG_NOTES (i1) = REG_NOTES (m->insn); r1 = SET_DEST (PATTERN (m->insn)); r2 = SET_DEST (PATTERN (m1->insn)); regs_may_share = gen_rtx (EXPR_LIST, VOIDmode, r1, gen_rtx (EXPR_LIST, VOIDmode, r2, regs_may_share)); delete_insn (m->insn); if (new_start == 0) new_start = i1; if (loop_dump_stream) fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1)); } /* If we are to re-generate the item being moved with a new move insn, first delete what we have and then emit the move insn before the loop. */ else if (m->move_insn) { rtx i1, temp; for (count = m->consec; count >= 0; count--) { /* If this is the first insn of a library call sequence, skip to the end. */ if (GET_CODE (p) != NOTE && (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX))) p = XEXP (temp, 0); /* If this is the last insn of a libcall sequence, then delete every insn in the sequence except the last. The last insn is handled in the normal manner. */ if (GET_CODE (p) != NOTE && (temp = find_reg_note (p, REG_RETVAL, NULL_RTX))) { temp = XEXP (temp, 0); while (temp != p) temp = delete_insn (temp); } p = delete_insn (p); while (p && GET_CODE (p) == NOTE) p = NEXT_INSN (p); } start_sequence (); emit_move_insn (m->set_dest, m->set_src); temp = get_insns (); end_sequence (); add_label_notes (m->set_src, temp); i1 = emit_insns_before (temp, loop_start); if (! find_reg_note (i1, REG_EQUAL, NULL_RTX)) REG_NOTES (i1) = gen_rtx (EXPR_LIST, m->is_equiv ? REG_EQUIV : REG_EQUAL, m->set_src, REG_NOTES (i1)); if (loop_dump_stream) fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1)); /* The more regs we move, the less we like moving them. */ threshold -= 3; } else { for (count = m->consec; count >= 0; count--) { rtx i1, temp; /* If first insn of libcall sequence, skip to end. */ /* Do this at start of loop, since p is guaranteed to be an insn here. */ if (GET_CODE (p) != NOTE && (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX))) p = XEXP (temp, 0); /* If last insn of libcall sequence, move all insns except the last before the loop. The last insn is handled in the normal manner. */ if (GET_CODE (p) != NOTE && (temp = find_reg_note (p, REG_RETVAL, NULL_RTX))) { rtx fn_address = 0; rtx fn_reg = 0; rtx fn_address_insn = 0; first = 0; for (temp = XEXP (temp, 0); temp != p; temp = NEXT_INSN (temp)) { rtx body; rtx n; rtx next; if (GET_CODE (temp) == NOTE) continue; body = PATTERN (temp); /* Find the next insn after TEMP, not counting USE or NOTE insns. */ for (next = NEXT_INSN (temp); next != p; next = NEXT_INSN (next)) if (! (GET_CODE (next) == INSN && GET_CODE (PATTERN (next)) == USE) && GET_CODE (next) != NOTE) break; /* If that is the call, this may be the insn that loads the function address. Extract the function address from the insn that loads it into a register. If this insn was cse'd, we get incorrect code. So emit a new move insn that copies the function address into the register that the call insn will use. flow.c will delete any redundant stores that we have created. */ if (GET_CODE (next) == CALL_INSN && GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == REG && (n = find_reg_note (temp, REG_EQUAL, NULL_RTX))) { fn_reg = SET_SRC (body); if (GET_CODE (fn_reg) != REG) fn_reg = SET_DEST (body); fn_address = XEXP (n, 0); fn_address_insn = temp; } /* We have the call insn. If it uses the register we suspect it might, load it with the correct address directly. */ if (GET_CODE (temp) == CALL_INSN && fn_address != 0 && reg_referenced_p (fn_reg, body)) emit_insn_after (gen_move_insn (fn_reg, fn_address), fn_address_insn); if (GET_CODE (temp) == CALL_INSN) { i1 = emit_call_insn_before (body, loop_start); /* Because the USAGE information potentially contains objects other than hard registers we need to copy it. */ if (CALL_INSN_FUNCTION_USAGE (temp)) CALL_INSN_FUNCTION_USAGE (i1) = copy_rtx (CALL_INSN_FUNCTION_USAGE (temp)); } else i1 = emit_insn_before (body, loop_start); if (first == 0) first = i1; if (temp == fn_address_insn) fn_address_insn = 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 = m->set_dest; rtx sequence; rtx tem; start_sequence (); tem = expand_binop (GET_MODE (reg), and_optab, reg, GEN_INT ((((HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (m->savemode))) - 1), reg, 1, OPTAB_LIB_WIDEN); if (tem == 0) abort (); if (tem != reg) emit_move_insn (reg, tem); sequence = gen_sequence (); end_sequence (); i1 = emit_insn_before (sequence, loop_start); } else if (GET_CODE (p) == CALL_INSN) { i1 = emit_call_insn_before (PATTERN (p), loop_start); /* Because the USAGE information potentially contains objects other than hard registers we need to copy it. */ if (CALL_INSN_FUNCTION_USAGE (p)) CALL_INSN_FUNCTION_USAGE (i1) = copy_rtx (CALL_INSN_FUNCTION_USAGE (p)); } else i1 = emit_insn_before (PATTERN (p), loop_start); REG_NOTES (i1) = REG_NOTES (p); /* If there is a REG_EQUAL note present whose value is not loop invariant, then delete it, since it may cause problems with later optimization passes. It is possible for cse to create such notes like this as a result of record_jump_cond. */ if ((temp = find_reg_note (i1, REG_EQUAL, NULL_RTX)) && ! invariant_p (XEXP (temp, 0))) remove_note (i1, temp); if (new_start == 0) new_start = i1; if (loop_dump_stream) fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1));#if 0 /* This isn't needed because REG_NOTES is copied below and is wrong since P might be a PARALLEL. */ 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_EQUAL, SET_SRC (PATTERN (p)), REG_NOTES (i1));#endif /* 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, NULL_RTX)) { XEXP (temp, 0) = first; temp = find_reg_note (first, REG_LIBCALL, NULL_RTX); XEXP (temp, 0) = i1; } delete_insn (p); do p = NEXT_INSN (p); while (p && 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; /* The reg set here is now invariant. */ if (! m->partial) n_times_set[regno] = 0; m->done = 1; /* Change the length-of-life info for the register to say it lives at least the full length of this loop. This will help guide optimizations in outer loops. */ if (uid_luid[regno_first_uid[regno]] > INSN_LUID (loop_start)) /* This is the old insn before all the moved insns. We can't use the moved insn because it is out of range in uid_luid. Only the old insns have luids. */ regno_first_uid[regno] = INSN_UID (loop_start); if (uid_luid[regno_last_uid[regno]] < INSN_LUID (end)) regno_last_uid[regno] = INSN_UID (end); /* Combine with this moved insn any other matching movables. */ if (! m->partial) for (m1 = movables; m1; m1 = m1->next) if (m1->match == m) { rtx temp; /* Schedule the reg loaded by M1 for replacement so that shares the reg of M. If the modes differ (only possible in restricted circumstances, make a SUBREG. */ if (GET_MODE (m->set_dest) == GET_MODE (m1->set_dest)) reg_map[m1->regno] = m->set_dest; else reg_map[m1->regno] = gen_lowpart_common (GET_MODE (m1->set_dest), m->set_dest); /* Get rid of the matching insn and prevent further processing of it. */ m1->done = 1; /* if library call, delete all insn except last, which is deleted below */ if (temp = find_reg_note (m1->insn, REG_RETVAL, NULL_RTX)) { for (temp = XEXP (temp, 0); temp != m1->insn; temp = NEXT_INSN (temp)) delete_insn (temp); } delete_insn (m1->insn); /* Any other movable that loads the same register MUST be moved. */ already_moved[m1->regno] = 1; /* The reg merged here is now invariant, if the reg it matches is invariant. */ if (! m->partial) n_times_set[m1->regno] = 0; } } else if (loop_dump_stream) fprintf (loop_dump_stream, "not desirable"); } else if (loop_dump_stream && !m->match) fprintf (loop_dump_stream, "not safe"); if (loop_dump_stream) fprintf (loop_dump_stream, "\n"); } if (new_start == 0) new_start = loop_start; /* Go through all the instructions in the loop, making all the register substitutions scheduled in REG_MAP. */ for (p = new_start; p != end; p = NEXT_INSN (p)) if (GET_CODE (p) == INSN || GET_CODE (p) == JUMP_INSN || GET_CODE (p) == CALL_INSN) { replace_regs (PATTERN (p), reg_map, nregs, 0); replace_regs (REG_NOTES (p), reg_map, nregs, 0); INSN_CODE (p) = -1; }}#if 0/* Scan X and replace the address of any MEM in it with ADDR. REG is the address that MEM should have before the replacement. */static voidreplace_call_address (x, reg, addr) rtx x, reg, addr;{ register enum rtx_code code; register int i; register char *fmt; if (x == 0) return; code = GET_CODE (x); switch (code) { case PC: case CC0: case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: case REG: return; case SET: /* Short cut for very common case. */ replace_call_address (XEXP (x, 1), reg, addr); return; case CALL: /* Short cut for very common case. */ replace_call_address (XEXP (x, 0), reg, addr); return; case MEM: /* If this MEM uses a reg other than the one we expected, something is wrong. */ if (X
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -