📄 jump.c
字号:
multiple branches. See if we can find all the uses of the label that TEMP branches to without hitting a CALL_INSN or a jump to somewhere else. */ rtx target = JUMP_LABEL (temp); int nuses = LABEL_NUSES (target); rtx p, q; /* Set P to the first jump insn that goes around "x = a;". */ for (p = temp; nuses && p; p = prev_nonnote_insn (p)) { if (GET_CODE (p) == JUMP_INSN) { if (condjump_p (p) && ! simplejump_p (p) && JUMP_LABEL (p) == target) { nuses--; if (nuses == 0) break; } else break; } else if (GET_CODE (p) == CALL_INSN) break; }#ifdef HAVE_cc0 /* We cannot insert anything between a set of cc and its use so if P uses cc0, we must back up to the previous insn. */ q = prev_nonnote_insn (p); if (q && GET_RTX_CLASS (GET_CODE (q)) == 'i' && sets_cc0_p (PATTERN (q))) p = q;#endif if (p) p = PREV_INSN (p); /* If we found all the uses and there was no data conflict, we can move the assignment unless we can branch into the middle from somewhere. */ if (nuses == 0 && p && no_labels_between_p (p, insn) && ! reg_referenced_between_p (temp1, p, NEXT_INSN (temp3)) && ! reg_set_between_p (temp1, p, temp3) && (GET_CODE (SET_SRC (temp4)) == CONST_INT || ! reg_set_between_p (SET_SRC (temp4), p, temp2))) { emit_insn_after_with_line_notes (PATTERN (temp2), p, temp2); delete_insn (temp2); /* Set NEXT to an insn that we know won't go away. */ next = next_active_insn (insn); /* Delete the jump around the set. Note that we must do this before we redirect the test jumps so that it won't delete the code immediately following the assignment we moved (which might be a jump). */ delete_insn (insn); /* We either have two consecutive labels or a jump to a jump, so adjust all the JUMP_INSNs to branch to where INSN branches to. */ for (p = NEXT_INSN (p); p != next; p = NEXT_INSN (p)) if (GET_CODE (p) == JUMP_INSN) redirect_jump (p, target); changed = 1; continue; } }#ifndef HAVE_cc0 /* If we have if (...) x = exp; and branches are expensive, EXP is a single insn, does not have any side effects, cannot trap, and is not too costly, convert this to t = exp; if (...) x = t; Don't do this when we have CC0 because it is unlikely to help and we'd need to worry about where to place the new insn and the potential for conflicts. We also can't do this when we have notes on the insn for the same reason as above. We set: TEMP to the "x = exp;" insn. TEMP1 to the single set in the "x = exp; insn. TEMP2 to "x". */ if (! reload_completed && this_is_condjump && ! this_is_simplejump && BRANCH_COST >= 3 && (temp = next_nonnote_insn (insn)) != 0 && GET_CODE (temp) == INSN && REG_NOTES (temp) == 0 && (reallabelprev == temp || ((temp2 = next_active_insn (temp)) != 0 && simplejump_p (temp2) && JUMP_LABEL (temp2) == JUMP_LABEL (insn))) && (temp1 = single_set (temp)) != 0 && (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG) && GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT#ifdef SMALL_REGISTER_CLASSES && REGNO (temp2) >= FIRST_PSEUDO_REGISTER#endif && GET_CODE (SET_SRC (temp1)) != REG && GET_CODE (SET_SRC (temp1)) != SUBREG && GET_CODE (SET_SRC (temp1)) != CONST_INT && ! side_effects_p (SET_SRC (temp1)) && ! may_trap_p (SET_SRC (temp1)) && rtx_cost (SET_SRC (temp1), SET) < 10) { rtx new = gen_reg_rtx (GET_MODE (temp2)); if (validate_change (temp, &SET_DEST (temp1), new, 0)) { next = emit_insn_after (gen_move_insn (temp2, new), insn); emit_insn_after_with_line_notes (PATTERN (temp), PREV_INSN (insn), temp); delete_insn (temp); reallabelprev = prev_active_insn (JUMP_LABEL (insn)); } } /* Similarly, if it takes two insns to compute EXP but they have the same destination. Here TEMP3 will be the second insn and TEMP4 the SET from that insn. */ if (! reload_completed && this_is_condjump && ! this_is_simplejump && BRANCH_COST >= 4 && (temp = next_nonnote_insn (insn)) != 0 && GET_CODE (temp) == INSN && REG_NOTES (temp) == 0 && (temp3 = next_nonnote_insn (temp)) != 0 && GET_CODE (temp3) == INSN && REG_NOTES (temp3) == 0 && (reallabelprev == temp3 || ((temp2 = next_active_insn (temp3)) != 0 && simplejump_p (temp2) && JUMP_LABEL (temp2) == JUMP_LABEL (insn))) && (temp1 = single_set (temp)) != 0 && (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG) && GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT#ifdef SMALL_REGISTER_CLASSES && REGNO (temp2) >= FIRST_PSEUDO_REGISTER#endif && ! side_effects_p (SET_SRC (temp1)) && ! may_trap_p (SET_SRC (temp1)) && rtx_cost (SET_SRC (temp1), SET) < 10 && (temp4 = single_set (temp3)) != 0 && rtx_equal_p (SET_DEST (temp4), temp2) && ! side_effects_p (SET_SRC (temp4)) && ! may_trap_p (SET_SRC (temp4)) && rtx_cost (SET_SRC (temp4), SET) < 10) { rtx new = gen_reg_rtx (GET_MODE (temp2)); if (validate_change (temp, &SET_DEST (temp1), new, 0)) { next = emit_insn_after (gen_move_insn (temp2, new), insn); emit_insn_after_with_line_notes (PATTERN (temp), PREV_INSN (insn), temp); emit_insn_after_with_line_notes (replace_rtx (PATTERN (temp3), temp2, new), PREV_INSN (insn), temp3); delete_insn (temp); delete_insn (temp3); reallabelprev = prev_active_insn (JUMP_LABEL (insn)); } } /* Finally, handle the case where two insns are used to compute EXP but a temporary register is used. Here we must ensure that the temporary register is not used anywhere else. */ if (! reload_completed && after_regscan && this_is_condjump && ! this_is_simplejump && BRANCH_COST >= 4 && (temp = next_nonnote_insn (insn)) != 0 && GET_CODE (temp) == INSN && REG_NOTES (temp) == 0 && (temp3 = next_nonnote_insn (temp)) != 0 && GET_CODE (temp3) == INSN && REG_NOTES (temp3) == 0 && (reallabelprev == temp3 || ((temp2 = next_active_insn (temp3)) != 0 && simplejump_p (temp2) && JUMP_LABEL (temp2) == JUMP_LABEL (insn))) && (temp1 = single_set (temp)) != 0 && (temp5 = SET_DEST (temp1), (GET_CODE (temp5) == REG || (GET_CODE (temp5) == SUBREG && (temp5 = SUBREG_REG (temp5), GET_CODE (temp5) == REG)))) && REGNO (temp5) >= FIRST_PSEUDO_REGISTER && regno_first_uid[REGNO (temp5)] == INSN_UID (temp) && regno_last_uid[REGNO (temp5)] == INSN_UID (temp3) && ! side_effects_p (SET_SRC (temp1)) && ! may_trap_p (SET_SRC (temp1)) && rtx_cost (SET_SRC (temp1), SET) < 10 && (temp4 = single_set (temp3)) != 0 && (temp2 = SET_DEST (temp4), GET_CODE (temp2) == REG) && GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT#ifdef SMALL_REGISTER_CLASSES && REGNO (temp2) >= FIRST_PSEUDO_REGISTER#endif && rtx_equal_p (SET_DEST (temp4), temp2) && ! side_effects_p (SET_SRC (temp4)) && ! may_trap_p (SET_SRC (temp4)) && rtx_cost (SET_SRC (temp4), SET) < 10) { rtx new = gen_reg_rtx (GET_MODE (temp2)); if (validate_change (temp3, &SET_DEST (temp4), new, 0)) { next = emit_insn_after (gen_move_insn (temp2, new), insn); emit_insn_after_with_line_notes (PATTERN (temp), PREV_INSN (insn), temp); emit_insn_after_with_line_notes (PATTERN (temp3), PREV_INSN (insn), temp3); delete_insn (temp); delete_insn (temp3); reallabelprev = prev_active_insn (JUMP_LABEL (insn)); } }#endif /* HAVE_cc0 */ /* Try to use a conditional move (if the target has them), or a store-flag insn. The general case is: 1) x = a; if (...) x = b; and 2) if (...) x = b; If the jump would be faster, the machine should not have defined the movcc or scc insns!. These cases are often made by the previous optimization. The second case is treated as x = x; if (...) x = b;. INSN here is the jump around the store. We set: TEMP to the "x = b;" insn. TEMP1 to X. TEMP2 to B. TEMP3 to A (X in the second case). TEMP4 to the condition being tested. TEMP5 to the earliest insn used to find the condition. */ if (/* We can't do this after reload has completed. */ ! reload_completed && this_is_condjump && ! this_is_simplejump /* Set TEMP to the "x = b;" insn. */ && (temp = next_nonnote_insn (insn)) != 0 && GET_CODE (temp) == INSN && GET_CODE (PATTERN (temp)) == SET && GET_CODE (temp1 = SET_DEST (PATTERN (temp))) == REG#ifdef SMALL_REGISTER_CLASSES && REGNO (temp1) >= FIRST_PSEUDO_REGISTER#endif && (GET_CODE (temp2 = SET_SRC (PATTERN (temp))) == REG || GET_CODE (temp2) == SUBREG /* ??? How about floating point constants? */ || GET_CODE (temp2) == CONST_INT) /* Allow either form, but prefer the former if both apply. There is no point in using the old value of TEMP1 if it is a register, since cse will alias them. It can lose if the old value were a hard register since CSE won't replace hard registers. */ && (((temp3 = reg_set_last (temp1, insn)) != 0) /* Make the latter case look like x = x; if (...) x = b; */ || (temp3 = temp1, 1)) /* INSN must either branch to the insn after TEMP or the insn after TEMP must branch to the same place as INSN. */ && (reallabelprev == temp || ((temp4 = next_active_insn (temp)) != 0 && simplejump_p (temp4) && JUMP_LABEL (temp4) == JUMP_LABEL (insn))) && (temp4 = get_condition (insn, &temp5)) != 0 /* We must be comparing objects whose modes imply the size. We could handle BLKmode if (1) emit_store_flag could and (2) we could find the size reliably. */ && GET_MODE (XEXP (temp4, 0)) != BLKmode /* No point in doing any of this if branches are cheap or we don't have conditional moves. */ && (BRANCH_COST >= 2#ifdef HAVE_conditional_move || 1#endif )#ifdef HAVE_cc0 /* If the previous insn sets CC0 and something else, we can't do this since we are going to delete that insn. */ && ! ((temp6 = prev_nonnote_insn (insn)) != 0 && GET_CODE (temp6) == INSN && (sets_cc0_p (PATTERN (temp6)) == -1 || (sets_cc0_p (PATTERN (temp6)) == 1 && FIND_REG_INC_NOTE (temp6, NULL_RTX))))#endif ) {#ifdef HAVE_conditional_move /* First try a conditional move. */ { enum rtx_code code = GET_CODE (temp4); rtx var = temp1; rtx cond0, cond1, aval, bval; rtx target; /* Copy the compared variables into cond0 and cond1, so that any side effects performed in or after the old comparison, will not affect our compare which will come later. */ /* ??? Is it possible to just use the comparison in the jump insn? After all, we're going to delete it. We'd have to modify emit_conditional_move to take a comparison rtx instead or write a new function. */ cond0 = gen_reg_rtx (GET_MODE (XEXP (temp4, 0))); /* We want the target to be able to simplify comparisons with zero (and maybe other constants as well), so don't create pseudos for them. There's no need to either. */ if (GET_CODE (XEXP (temp4, 1)) == CONST_INT || GET_CODE (XEXP (temp4, 1)) == CONST_DOUBLE) cond1 = XEXP (temp4, 1); else cond1 = gen_reg_rtx (GET_MODE (XEXP (temp4, 1))); aval = temp3; bval = temp2; start_sequence (); target = emit_conditional_move (var, code, cond0, cond1, VOIDmode, aval, bval, GET_MODE (var), (code == LTU || code == GEU || code == LEU || code == GTU)); if (target) { rtx seq1,seq2; /* Save the conditional move sequence but don't emit it yet. On some machines, like the alpha, it is possible that temp5 == insn, so next generate the sequence that saves the compared values and then emit both sequences ensuring seq1 occurs before seq2. */ seq2 = get_insns (); end_sequence (); /* Now that we can't fail, generate the copy insns that preserve the compared values. */ start_sequence (); emit_move_insn (cond0, XEXP (temp4, 0)); if (cond1 != XEXP (temp4, 1)) emit_move_insn (cond1, XEXP (temp4, 1)); seq1 = get_insns (); end_sequence (); emit_insns_before (seq1, temp5); emit_insns_before (seq2, insn); /* ??? We can also delete the insn that sets X to A. Flow will do it too though. */ delete_insn (temp); next = NEXT_INSN (insn); delete_jump (insn); changed = 1; continue; } else end_sequence (); }#endif /* That didn't work, try a store-flag insn. We further divide the cases into: 1) x = a; if (...) x = b; and either A or B is zero,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -