📄 loop.c
字号:
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); 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); else i1 = emit_insn_before (PATTERN (p), loop_start); REG_NOTES (i1) = REG_NOTES (p); 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); }}#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 (XEXP (x, 0) != reg) abort (); XEXP (x, 0) = addr; return; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') replace_call_address (XEXP (x, i), reg, addr); if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) replace_call_address (XVECEXP (x, i, j), reg, addr); } }}#endif/* Return the number of memory refs to addresses that vary in the rtx X. */static intcount_nonfixed_reads (x) rtx x;{ register enum rtx_code code; register int i; register char *fmt; int value; if (x == 0) return 0; 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 0; case MEM: return ((invariant_p (XEXP (x, 0)) != 1) + count_nonfixed_reads (XEXP (x, 0))); } value = 0; fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') value += count_nonfixed_reads (XEXP (x, i)); if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) value += count_nonfixed_reads (XVECEXP (x, i, j)); } } return value;}#if 0/* P is an instruction that sets a register to the result of a ZERO_EXTEND. Replace it with an instruction to load just the low bytes if the machine supports such an instruction, and insert above LOOP_START an instruction to clear the register. */static voidconstant_high_bytes (p, loop_start) rtx p, loop_start;{ register rtx new; register int insn_code_number; /* Try to change (SET (REG ...) (ZERO_EXTEND (..:B ...))) to (SET (STRICT_LOW_PART (SUBREG:B (REG...))) ...). */ new = gen_rtx (SET, VOIDmode, gen_rtx (STRICT_LOW_PART, VOIDmode, gen_rtx (SUBREG, GET_MODE (XEXP (SET_SRC (PATTERN (p)), 0)), SET_DEST (PATTERN (p)), 0)), XEXP (SET_SRC (PATTERN (p)), 0)); insn_code_number = recog (new, p); if (insn_code_number) { register int i; /* Clear destination register before the loop. */ emit_insn_before (gen_rtx (SET, VOIDmode, SET_DEST (PATTERN (p)), const0_rtx), loop_star
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -