📄 jump.c
字号:
2) if (...) x = 0; and jumps are expensive, 3) x = a; if (...) x = b; and A and B are constants where all the set bits in A are also set in B and jumps are expensive, 4) x = a; if (...) x = b; and A and B non-zero, and jumps are more expensive, and 5) if (...) x = b; if jumps are even more expensive. */ if (GET_MODE_CLASS (GET_MODE (temp1)) == MODE_INT && ((GET_CODE (temp3) == CONST_INT) /* Make the latter case look like x = x; if (...) x = 0; */ || (temp3 = temp1, ((BRANCH_COST >= 2 && temp2 == const0_rtx) || BRANCH_COST >= 3))) /* If B is zero, OK; if A is zero, can only do (1) if we can reverse the condition. See if (3) applies possibly by reversing the condition. Prefer reversing to (4) when branches are very expensive. */ && ((reversep = 0, temp2 == const0_rtx) || (temp3 == const0_rtx && (reversep = can_reverse_comparison_p (temp4, insn))) || (BRANCH_COST >= 2 && GET_CODE (temp2) == CONST_INT && GET_CODE (temp3) == CONST_INT && ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp2) || ((INTVAL (temp2) & INTVAL (temp3)) == INTVAL (temp3) && (reversep = can_reverse_comparison_p (temp4, insn))))) || BRANCH_COST >= 3) ) { enum rtx_code code = GET_CODE (temp4); rtx uval, cval, var = temp1; int normalizep; rtx target; /* If necessary, reverse the condition. */ if (reversep) code = reverse_condition (code), uval = temp2, cval = temp3; else uval = temp3, cval = temp2; /* If CVAL is non-zero, normalize to -1. Otherwise, if UVAL is the constant 1, it is best to just compute the result directly. If UVAL is constant and STORE_FLAG_VALUE includes all of its bits, it is best to compute the flag value unnormalized and `and' it with UVAL. Otherwise, normalize to -1 and `and' with UVAL. */ normalizep = (cval != const0_rtx ? -1 : (uval == const1_rtx ? 1 : (GET_CODE (uval) == CONST_INT && (INTVAL (uval) & ~STORE_FLAG_VALUE) == 0) ? 0 : -1)); /* We will be putting the store-flag insn immediately in front of the comparison that was originally being done, so we know all the variables in TEMP4 will be valid. However, this might be in front of the assignment of A to VAR. If it is, it would clobber the store-flag we will be emitting. Therefore, emit into a temporary which will be copied to VAR immediately after TEMP. */ start_sequence (); target = emit_store_flag (gen_reg_rtx (GET_MODE (var)), code, XEXP (temp4, 0), XEXP (temp4, 1), VOIDmode, (code == LTU || code == LEU || code == GEU || code == GTU), normalizep); if (target) { rtx seq; rtx before = insn; seq = get_insns (); end_sequence (); /* Put the store-flag insns in front of the first insn used to compute the condition to ensure that we use the same values of them as the current comparison. However, the remainder of the insns we generate will be placed directly in front of the jump insn, in case any of the pseudos we use are modified earlier. */ emit_insns_before (seq, temp5); start_sequence (); /* Both CVAL and UVAL are non-zero. */ if (cval != const0_rtx && uval != const0_rtx) { rtx tem1, tem2; tem1 = expand_and (uval, target, NULL_RTX); if (GET_CODE (cval) == CONST_INT && GET_CODE (uval) == CONST_INT && (INTVAL (cval) & INTVAL (uval)) == INTVAL (cval)) tem2 = cval; else { tem2 = expand_unop (GET_MODE (var), one_cmpl_optab, target, NULL_RTX, 0); tem2 = expand_and (cval, tem2, (GET_CODE (tem2) == REG ? tem2 : 0)); } /* If we usually make new pseudos, do so here. This turns out to help machines that have conditional move insns. */ /* ??? Conditional moves have already been handled. This may be obsolete. */ if (flag_expensive_optimizations) target = 0; target = expand_binop (GET_MODE (var), ior_optab, tem1, tem2, target, 1, OPTAB_WIDEN); } else if (normalizep != 1) { /* We know that either CVAL or UVAL is zero. If UVAL is zero, negate TARGET and `and' with CVAL. Otherwise, `and' with UVAL. */ if (uval == const0_rtx) { target = expand_unop (GET_MODE (var), one_cmpl_optab, target, NULL_RTX, 0); uval = cval; } target = expand_and (uval, target, (GET_CODE (target) == REG && ! preserve_subexpressions_p () ? target : NULL_RTX)); } emit_move_insn (var, target); seq = get_insns (); end_sequence ();#ifdef HAVE_cc0 /* If INSN uses CC0, we must not separate it from the insn that sets cc0. */ if (reg_mentioned_p (cc0_rtx, PATTERN (before))) before = prev_nonnote_insn (before);#endif emit_insns_before (seq, before); delete_insn (temp); next = NEXT_INSN (insn); delete_jump (insn); changed = 1; continue; } else end_sequence (); } } /* If branches are expensive, convert if (foo) bar++; to bar += (foo != 0); and similarly for "bar--;" INSN is the conditional branch around the arithmetic. We set: TEMP is the arithmetic insn. TEMP1 is the SET doing the arithmetic. TEMP2 is the operand being incremented or decremented. TEMP3 to the condition being tested. TEMP4 to the earliest insn used to find the condition. */ if ((BRANCH_COST >= 2#ifdef HAVE_incscc || HAVE_incscc#endif#ifdef HAVE_decscc || HAVE_decscc#endif ) && ! reload_completed && this_is_condjump && ! this_is_simplejump && (temp = next_nonnote_insn (insn)) != 0 && (temp1 = single_set (temp)) != 0 && (temp2 = SET_DEST (temp1), GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT) && GET_CODE (SET_SRC (temp1)) == PLUS && (XEXP (SET_SRC (temp1), 1) == const1_rtx || XEXP (SET_SRC (temp1), 1) == constm1_rtx) && rtx_equal_p (temp2, XEXP (SET_SRC (temp1), 0)) && ! side_effects_p (temp2) && ! may_trap_p (temp2) /* INSN must either branch to the insn after TEMP or the insn after TEMP must branch to the same place as INSN. */ && (reallabelprev == temp || ((temp3 = next_active_insn (temp)) != 0 && simplejump_p (temp3) && JUMP_LABEL (temp3) == JUMP_LABEL (insn))) && (temp3 = get_condition (insn, &temp4)) != 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 (temp3, 0)) != BLKmode && can_reverse_comparison_p (temp3, insn)) { rtx temp6, target = 0, seq, init_insn = 0, init = temp2; enum rtx_code code = reverse_condition (GET_CODE (temp3)); start_sequence (); /* It must be the case that TEMP2 is not modified in the range [TEMP4, INSN). The one exception we make is if the insn before INSN sets TEMP2 to something which is also unchanged in that range. In that case, we can move the initialization into our sequence. */ if ((temp5 = prev_active_insn (insn)) != 0 && GET_CODE (temp5) == INSN && (temp6 = single_set (temp5)) != 0 && rtx_equal_p (temp2, SET_DEST (temp6)) && (CONSTANT_P (SET_SRC (temp6)) || GET_CODE (SET_SRC (temp6)) == REG || GET_CODE (SET_SRC (temp6)) == SUBREG)) { emit_insn (PATTERN (temp5)); init_insn = temp5; init = SET_SRC (temp6); } if (CONSTANT_P (init) || ! reg_set_between_p (init, PREV_INSN (temp4), insn)) target = emit_store_flag (gen_reg_rtx (GET_MODE (temp2)), code, XEXP (temp3, 0), XEXP (temp3, 1), VOIDmode, (code == LTU || code == LEU || code == GTU || code == GEU), 1); /* If we can do the store-flag, do the addition or subtraction. */ if (target) target = expand_binop (GET_MODE (temp2), (XEXP (SET_SRC (temp1), 1) == const1_rtx ? add_optab : sub_optab), temp2, target, temp2, 0, OPTAB_WIDEN); if (target != 0) { /* Put the result back in temp2 in case it isn't already. Then replace the jump, possible a CC0-setting insn in front of the jump, and TEMP, with the sequence we have made. */ if (target != temp2) emit_move_insn (temp2, target); seq = get_insns (); end_sequence (); emit_insns_before (seq, temp4); delete_insn (temp); if (init_insn) delete_insn (init_insn); next = NEXT_INSN (insn);#ifdef HAVE_cc0 delete_insn (prev_nonnote_insn (insn));#endif delete_insn (insn); changed = 1; continue; } else end_sequence (); } /* Simplify if (...) x = 1; else {...} if (x) ... We recognize this case scanning backwards as well. TEMP is the assignment to x; TEMP1 is the label at the head of the second if. */ /* ?? This should call get_condition to find the values being compared, instead of looking for a COMPARE insn when HAVE_cc0 is not defined. This would allow it to work on the m88k. */ /* ?? This optimization is only safe before cse is run if HAVE_cc0 is not defined and the condition is tested by a separate compare insn. This is because the code below assumes that the result of the compare dies in the following branch. Not only that, but there might be other insns between the compare and branch whose results are live. Those insns need to be executed. A way to fix this is to move the insns at JUMP_LABEL (insn) to before INSN. If we are running before flow, they will be deleted if they aren't needed. But this doesn't work well after flow. This is really a special-case of jump threading, anyway. The right thing to do is to replace this and jump threading with much simpler code in cse. This code has been turned off in the non-cc0 case in the meantime. */#ifdef HAVE_cc0 else if (this_is_simplejump /* Safe to skip USE and CLOBBER insns here since they will not be deleted. */ && (temp = prev_active_insn (insn)) && no_labels_between_p (temp, insn) && GET_CODE (temp) == INSN && GET_CODE (PATTERN (temp)) == SET && GET_CODE (SET_DEST (PATTERN (temp))) == REG && CONSTANT_P (SET_SRC (PATTERN (temp))) && (temp1 = next_active_insn (JUMP_LABEL (insn))) /* If we find that the next value tested is `x' (TEMP1 is the insn where this happens), win. */ && GET_CODE (temp1) == INSN && GET_CODE (PATTERN (temp1)) == SET#ifdef HAVE_cc0 /* Does temp1 `tst' the value of x? */ && SET_SRC (PATTERN (temp1)) == SET_DEST (PATTERN (temp)) && SET_DEST (PATTERN (temp1)) == cc0_rtx && (temp1 = next_nonnote_insn (temp1))#else /* Does temp1 compare the value of x against zero? */ && GET_CODE (SET_SRC (PATTERN (temp1))) == COMPARE && XEXP (SET_SRC (PATTERN (temp1)), 1) == const0_rtx && (XEXP (SET_SRC (PATTERN (temp1)), 0) == SET_DEST (PATTERN (temp))) && GET_CODE (SET_DEST (PATTERN (temp1))) == REG && (temp1 = find_next_ref (SET_DEST (PATTERN (temp1)), temp1))#endif && condjump_p (temp1)) { /* Get the if_then_else from the condjump. */ rtx choice = SET_SRC (PATTERN (temp1)); if (GET_CODE (choice) == IF_THEN_ELSE) { enum rtx_code code = GET_CODE (XEXP (choice, 0)); rtx val = SET_SRC (PATTERN (temp)); rtx cond = simplify_relational_operation (code, GET_MODE (SET_DEST (PATTERN (temp))), val, const0_rtx); rtx ultimate; if (cond == const_true_rtx) ultimate = XEXP (choice, 1); else if (cond == const0_rtx) ultimate = XEXP (choice, 2); else ultimate = 0; if (ultimate == pc_rtx) ultimate = get_label_after (temp1); else if (ultimate && GET_CODE (ultimate) != RETURN) ultimate = XEXP (ultimate, 0); if (ultimate) changed |= redirect_jump (insn, ultimate); } }#endif#if 0 /* @@ This needs a bit of work before it will be right. Any type of comparison can be accepted for the first and second compare. When rewriting the first jump, we must compute the what conditions can reach label3, and use the appropriate code. We can not simply reverse/swap the code of the first jump. In some cases, the second jump must be rewritten also. For example,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -