diff options
author | Doug Evans <dje@gnu.org> | 1995-01-25 04:17:33 +0000 |
---|---|---|
committer | Doug Evans <dje@gnu.org> | 1995-01-25 04:17:33 +0000 |
commit | 7209f1f9e430458aeb12bad7a980687a38b4a38d (patch) | |
tree | 15d94170ad8af6fda6d0885657f85bda80fc0b19 /gcc/jump.c | |
parent | 3c9958cd4adf0f2beb3e2ba2dc7d2b7a662c609a (diff) | |
download | gcc-7209f1f9e430458aeb12bad7a980687a38b4a38d.zip gcc-7209f1f9e430458aeb12bad7a980687a38b4a38d.tar.gz gcc-7209f1f9e430458aeb12bad7a980687a38b4a38d.tar.bz2 |
(jump_optimize): Try to emit a conditional move insn before
trying a store-flag insn.
From-SVN: r8801
Diffstat (limited to 'gcc/jump.c')
-rw-r--r-- | gcc/jump.c | 394 |
1 files changed, 239 insertions, 155 deletions
@@ -987,26 +987,23 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) } #endif /* HAVE_cc0 */ - /* We deal with four cases: - - 1) x = a; if (...) x = b; and either A or B is zero, - 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, and - 4) x = a; if (...) x = b; and A and B non-zero, and jumps are - more expensive. - 5) if (...) x = b; if jumps are even more expensive. - - In each of these try to use a store-flag insn to avoid the jump. - (If the jump would be faster, the machine should not have - defined the scc insns!). These cases are often made by the + /* 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 (const0_rtx in the second case). + 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. */ @@ -1022,25 +1019,18 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) #ifdef SMALL_REGISTER_CLASSES && REGNO (temp1) >= FIRST_PSEUDO_REGISTER #endif - && GET_MODE_CLASS (GET_MODE (temp1)) == MODE_INT && (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 - && GET_CODE (temp3) == CONST_INT) - /* Make the latter case look like x = x; if (...) x = 0; */ - || (temp3 = temp1, - ((BRANCH_COST >= 2 - && temp2 == const0_rtx) -#ifdef HAVE_conditional_move - || HAVE_conditional_move -#endif - || BRANCH_COST >= 3))) + && (((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 @@ -1052,25 +1042,13 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) We could handle BLKmode if (1) emit_store_flag could and (2) we could find the size reliably. */ && GET_MODE (XEXP (temp4, 0)) != BLKmode - - /* 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))))) + /* 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 - || HAVE_conditional_move + || 1 #endif - || BRANCH_COST >= 3) + ) #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. */ @@ -1083,139 +1061,245 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan) #endif ) { - 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; - - /* See if we can do this with a store-flag insn. */ - start_sequence (); +#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))); - /* 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. */ - - 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 before = insn; - rtx seq; + aval = temp3; + bval = temp2; - /* 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. */ + start_sequence (); + target = emit_conditional_move (var, code, + cond0, cond1, VOIDmode, + aval, bval, GET_MODE (var), + (code == LTU || code == GEU + || code == LEU || code == GTU)); - seq = get_insns (); + 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, + 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; - emit_insns_before (seq, temp5); + /* 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 (); - - /* Both CVAL and UVAL are non-zero. */ - if (cval != const0_rtx && uval != const0_rtx) + 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 tem1, tem2; + rtx seq; + rtx before = insn; - 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)); - } + seq = get_insns (); + end_sequence (); - /* If we usually make new pseudos, do so here. This - turns out to help machines that have conditional - move insns. */ + /* 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. */ - if (flag_expensive_optimizations) - target = 0; + emit_insns_before (seq, temp5); - 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) + start_sequence (); + + /* Both CVAL and UVAL are non-zero. */ + if (cval != const0_rtx && uval != const0_rtx) { - target = expand_unop (GET_MODE (var), one_cmpl_optab, - target, NULL_RTX, 0); - uval = cval; + 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)); - } + 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 (); - + 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); + /* 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); - emit_insns_before (seq, before); - - delete_insn (temp); - next = NEXT_INSN (insn); - - delete_jump (insn); - changed = 1; - continue; + delete_insn (temp); + next = NEXT_INSN (insn); + delete_jump (insn); + changed = 1; + continue; + } + else + end_sequence (); } - else - end_sequence (); } /* If branches are expensive, convert |