X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fifcvt.c;h=d23fd3a76825d41b872de940ba54d9b66b63ec74;hb=3461a998f83f6aba603802fcc1031a5898e9956f;hp=54ad8a73a6f2ffdd285c2ed5abdfe8f9f8645a60;hpb=2102d80056a029d75dcd8921d02edd69e8589709;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 54ad8a73a6f..d23fd3a7682 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -30,7 +30,9 @@ #include "hard-reg-set.h" #include "basic-block.h" #include "expr.h" +#include "real.h" #include "output.h" +#include "toplev.h" #include "tm_p.h" @@ -46,6 +48,12 @@ #ifndef HAVE_decscc #define HAVE_decscc 0 #endif +#ifndef HAVE_trap +#define HAVE_trap 0 +#endif +#ifndef HAVE_conditional_trap +#define HAVE_conditional_trap 0 +#endif #ifndef MAX_CONDITIONAL_EXECUTE #define MAX_CONDITIONAL_EXECUTE (BRANCH_COST + 1) @@ -64,6 +72,9 @@ static int num_updated_if_blocks; /* # of basic blocks that were removed. */ static int num_removed_blocks; +/* True if life data ok at present. */ +static bool life_data_ok; + /* The post-dominator relation on the original block numbers. */ static sbitmap *post_dominators; @@ -79,6 +90,7 @@ static int cond_exec_process_if_block PARAMS ((basic_block, basic_block, basic_block, basic_block)); static rtx noce_get_condition PARAMS ((rtx, rtx *)); +static int noce_operand_ok PARAMS ((rtx)); static int noce_process_if_block PARAMS ((basic_block, basic_block, basic_block, basic_block)); @@ -91,9 +103,11 @@ static int find_if_header PARAMS ((basic_block)); static int find_if_block PARAMS ((basic_block, edge, edge)); static int find_if_case_1 PARAMS ((basic_block, edge, edge)); static int find_if_case_2 PARAMS ((basic_block, edge, edge)); +static int find_cond_trap PARAMS ((basic_block, edge, edge)); static int find_memory PARAMS ((rtx *, void *)); static int dead_or_predicable PARAMS ((basic_block, basic_block, basic_block, rtx, int)); +static void noce_emit_move_insn PARAMS ((rtx, rtx)); /* Abuse the basic_block AUX field to store the original block index, as well as a flag indicating that the block should be rescaned for @@ -284,9 +298,14 @@ cond_exec_get_condition (jump) reverse the condition. */ if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF && XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump)) - cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)), - GET_MODE (cond), XEXP (cond, 0), - XEXP (cond, 1)); + { + enum rtx_code rev = reversed_comparison_code (cond, jump); + if (rev == UNKNOWN) + return NULL_RTX; + + cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0), + XEXP (cond, 1)); + } return cond; } @@ -314,6 +333,7 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) rtx true_prob_val; /* probability of else block */ rtx false_prob_val; /* probability of then block */ int n_insns; + enum rtx_code false_code; /* Find the conditional jump to the ELSE or JOIN part, and isolate the test. */ @@ -375,9 +395,13 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) the conditionally executed code. */ true_expr = test_expr; - false_expr = gen_rtx_fmt_ee (reverse_condition (GET_CODE (true_expr)), - GET_MODE (true_expr), XEXP (true_expr, 0), - XEXP (true_expr, 1)); + + false_code = reversed_comparison_code (true_expr, test_bb->end); + if (false_code != UNKNOWN) + false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr), + XEXP (true_expr, 0), XEXP (true_expr, 1)); + else + false_expr = NULL_RTX; #ifdef IFCVT_MODIFY_TESTS /* If the machine description needs to modify the tests, such as setting a @@ -407,8 +431,9 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) to conditional execution. */ if (then_end - && ! cond_exec_process_insns (then_start, then_end, - false_expr, false_prob_val, then_mod_ok)) + && (! false_expr + || ! cond_exec_process_insns (then_start, then_end, false_expr, + false_prob_val, then_mod_ok))) goto fail; if (else_bb @@ -451,6 +476,7 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) struct noce_if_info { + basic_block test_bb; rtx insn_a, insn_b; rtx x, a, b; rtx jump, cond, cond_earliest; @@ -467,6 +493,10 @@ static rtx noce_emit_cmove PARAMS ((struct noce_if_info *, rtx, rtx, rtx)); static int noce_try_cmove PARAMS ((struct noce_if_info *)); static int noce_try_cmove_arith PARAMS ((struct noce_if_info *)); +static rtx noce_get_alt_condition PARAMS ((struct noce_if_info *, + rtx, rtx *)); +static int noce_try_minmax PARAMS ((struct noce_if_info *)); +static int noce_try_abs PARAMS ((struct noce_if_info *)); /* Helper function for noce_try_store_flag*. */ @@ -487,17 +517,18 @@ noce_emit_store_flag (if_info, x, reversep, normalize) build the store_flag insn directly. */ if (cond_complex) - cond = XEXP (SET_SRC (PATTERN (if_info->jump)), 0); + cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0); + + if (reversep) + code = reversed_comparison_code (cond, if_info->jump); + else + code = GET_CODE (cond); if ((if_info->cond_earliest == if_info->jump || cond_complex) && (normalize == 0 || STORE_FLAG_VALUE == normalize)) { rtx tmp; - code = GET_CODE (cond); - if (reversep) - code = reverse_condition (code); - tmp = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0), XEXP (cond, 1)); tmp = gen_rtx_SET (VOIDmode, x, tmp); @@ -523,16 +554,37 @@ noce_emit_store_flag (if_info, x, reversep, normalize) if (cond_complex) return NULL_RTX; - code = GET_CODE (cond); - if (reversep) - code = reverse_condition (code); - return emit_store_flag (x, code, XEXP (cond, 0), XEXP (cond, 1), VOIDmode, (code == LTU || code == LEU || code == GEU || code == GTU), normalize); } +/* Emit instruction to move a rtx into STRICT_LOW_PART. */ +static void +noce_emit_move_insn (x, y) + rtx x, y; +{ + enum machine_mode outmode, inmode; + rtx outer, inner; + int bitpos; + + if (GET_CODE (x) != STRICT_LOW_PART) + { + emit_move_insn (x, y); + return; + } + + outer = XEXP (x, 0); + inner = XEXP (outer, 0); + outmode = GET_MODE (outer); + inmode = GET_MODE (inner); + bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT; + store_bit_field (inner, GET_MODE_BITSIZE (outmode), + bitpos, outmode, y, GET_MODE_BITSIZE (inmode), + GET_MODE_BITSIZE (inmode)); +} + /* Convert "if (test) x = 1; else x = 0". Only try 0 and STORE_FLAG_VALUE here. Other combinations will be @@ -553,7 +605,8 @@ noce_try_store_flag (if_info) else if (if_info->b == const0_rtx && GET_CODE (if_info->a) == CONST_INT && INTVAL (if_info->a) == STORE_FLAG_VALUE - && can_reverse_comparison_p (if_info->cond, if_info->jump)) + && (reversed_comparison_code (if_info->cond, if_info->jump) + != UNKNOWN)) reversep = 1; else return FALSE; @@ -564,7 +617,7 @@ noce_try_store_flag (if_info) if (target) { if (target != if_info->x) - emit_move_insn (if_info->x, target); + noce_emit_move_insn (if_info->x, target); seq = get_insns (); end_sequence (); @@ -598,7 +651,8 @@ noce_try_store_flag_constants (if_info) itrue = INTVAL (if_info->b); diff = itrue - ifalse; - can_reverse = can_reverse_comparison_p (if_info->cond, if_info->jump); + can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump) + != UNKNOWN); reversep = 0; if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE) @@ -686,7 +740,7 @@ noce_try_store_flag_constants (if_info) } if (target != if_info->x) - emit_move_insn (if_info->x, target); + noce_emit_move_insn (if_info->x, target); seq = get_insns (); end_sequence (); @@ -722,7 +776,8 @@ noce_try_store_flag_inc (if_info) && (XEXP (if_info->a, 1) == const1_rtx || XEXP (if_info->a, 1) == constm1_rtx) && rtx_equal_p (XEXP (if_info->a, 0), if_info->x) - && can_reverse_comparison_p (if_info->cond, if_info->jump)) + && (reversed_comparison_code (if_info->cond, if_info->jump) + != UNKNOWN)) { if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1))) subtract = 0, normalize = 0; @@ -744,7 +799,7 @@ noce_try_store_flag_inc (if_info) if (target) { if (target != if_info->x) - emit_move_insn (if_info->x, target); + noce_emit_move_insn (if_info->x, target); seq = get_insns (); end_sequence (); @@ -778,8 +833,9 @@ noce_try_store_flag_mask (if_info) || STORE_FLAG_VALUE == -1) && ((if_info->a == const0_rtx && rtx_equal_p (if_info->b, if_info->x)) - || ((reversep = can_reverse_comparison_p (if_info->cond, - if_info->jump)) + || ((reversep = (reversed_comparison_code (if_info->cond, + if_info->jump) + != UNKNOWN)) && if_info->b == const0_rtx && rtx_equal_p (if_info->a, if_info->x)))) { @@ -795,7 +851,7 @@ noce_try_store_flag_mask (if_info) if (target) { if (target != if_info->x) - emit_move_insn (if_info->x, target); + noce_emit_move_insn (if_info->x, target); seq = get_insns (); end_sequence (); @@ -894,7 +950,7 @@ noce_try_cmove (if_info) if (target) { if (target != if_info->x) - emit_move_insn (if_info->x, target); + noce_emit_move_insn (if_info->x, target); seq = get_insns (); end_sequence (); @@ -957,7 +1013,7 @@ noce_try_cmove_arith (if_info) insn_b = if_info->insn_b; /* Possibly rearrange operands to make things come out more natural. */ - if (can_reverse_comparison_p (if_info->cond, if_info->jump)) + if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN) { int reversep = 0; if (rtx_equal_p (b, x)) @@ -967,7 +1023,7 @@ noce_try_cmove_arith (if_info) if (reversep) { - code = reverse_condition (code); + code = reversed_comparison_code (if_info->cond, if_info->jump); tmp = a, a = b, b = tmp; tmp = insn_a, insn_a = insn_b, insn_b = tmp; } @@ -1049,12 +1105,12 @@ noce_try_cmove_arith (if_info) if (MEM_SCALAR_P (if_info->a) && MEM_SCALAR_P (if_info->b)) MEM_SCALAR_P (tmp) = 1; if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b)) - MEM_ALIAS_SET (tmp) = MEM_ALIAS_SET (if_info->a); + set_mem_alias_set (tmp, MEM_ALIAS_SET (if_info->a)); - emit_move_insn (if_info->x, tmp); + noce_emit_move_insn (if_info->x, tmp); } else if (target != x) - emit_move_insn (x, target); + noce_emit_move_insn (x, target); tmp = get_insns (); end_sequence (); @@ -1066,6 +1122,274 @@ noce_try_cmove_arith (if_info) return FALSE; } +/* For most cases, the simplified condition we found is the best + choice, but this is not the case for the min/max/abs transforms. + For these we wish to know that it is A or B in the condition. */ + +static rtx +noce_get_alt_condition (if_info, target, earliest) + struct noce_if_info *if_info; + rtx target; + rtx *earliest; +{ + rtx cond, set, insn; + int reverse; + + /* If target is already mentioned in the known condition, return it. */ + if (reg_mentioned_p (target, if_info->cond)) + { + *earliest = if_info->cond_earliest; + return if_info->cond; + } + + set = pc_set (if_info->jump); + cond = XEXP (SET_SRC (set), 0); + reverse + = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF + && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump); + + cond = canonicalize_condition (if_info->jump, cond, reverse, + earliest, target); + if (! cond || ! reg_mentioned_p (target, cond)) + return NULL; + + /* We almost certainly searched back to a different place. + Need to re-verify correct lifetimes. */ + + /* X may not be mentioned in the range (cond_earliest, jump]. */ + for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn)) + if (INSN_P (insn) && reg_mentioned_p (if_info->x, insn)) + return NULL; + + /* A and B may not be modified in the range [cond_earliest, jump). */ + for (insn = *earliest; insn != if_info->jump; insn = NEXT_INSN (insn)) + if (INSN_P (insn) + && (modified_in_p (if_info->a, insn) + || modified_in_p (if_info->b, insn))) + return NULL; + + return cond; +} + +/* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc. */ + +static int +noce_try_minmax (if_info) + struct noce_if_info *if_info; +{ + rtx cond, earliest, target, seq; + enum rtx_code code; + int unsignedp; + optab op; + + /* ??? Can't guarantee that expand_binop won't create pseudos. */ + if (no_new_pseudos) + return FALSE; + + /* ??? Reject FP modes since we don't know how 0 vs -0 or NaNs + will be resolved with an SMIN/SMAX. It wouldn't be too hard + to get the target to tell us... */ + if (FLOAT_MODE_P (GET_MODE (if_info->x)) + && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT + && ! flag_unsafe_math_optimizations) + return FALSE; + + cond = noce_get_alt_condition (if_info, if_info->a, &earliest); + if (!cond) + return FALSE; + + /* Verify the condition is of the form we expect, and canonicalize + the comparison code. */ + code = GET_CODE (cond); + if (rtx_equal_p (XEXP (cond, 0), if_info->a)) + { + if (! rtx_equal_p (XEXP (cond, 1), if_info->b)) + return FALSE; + } + else if (rtx_equal_p (XEXP (cond, 1), if_info->a)) + { + if (! rtx_equal_p (XEXP (cond, 0), if_info->b)) + return FALSE; + code = swap_condition (code); + } + else + return FALSE; + + /* Determine what sort of operation this is. Note that the code is for + a taken branch, so the code->operation mapping appears backwards. */ + switch (code) + { + case LT: + case LE: + case UNLT: + case UNLE: + op = smax_optab; + unsignedp = 0; + break; + case GT: + case GE: + case UNGT: + case UNGE: + op = smin_optab; + unsignedp = 0; + break; + case LTU: + case LEU: + op = umax_optab; + unsignedp = 1; + break; + case GTU: + case GEU: + op = umin_optab; + unsignedp = 1; + break; + default: + return FALSE; + } + + start_sequence (); + + target = expand_binop (GET_MODE (if_info->x), op, if_info->a, if_info->b, + if_info->x, unsignedp, OPTAB_WIDEN); + if (! target) + { + end_sequence (); + return FALSE; + } + if (target != if_info->x) + noce_emit_move_insn (if_info->x, target); + + seq = get_insns (); + end_sequence (); + + if (seq_contains_jump (seq)) + return FALSE; + + emit_insns_before (seq, earliest); + if_info->cond = cond; + if_info->cond_earliest = earliest; + + return TRUE; +} + +/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", etc. */ + +static int +noce_try_abs (if_info) + struct noce_if_info *if_info; +{ + rtx cond, earliest, target, seq, a, b, c; + int negate; + + /* ??? Can't guarantee that expand_binop won't create pseudos. */ + if (no_new_pseudos) + return FALSE; + + /* Recognize A and B as constituting an ABS or NABS. */ + a = if_info->a; + b = if_info->b; + if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b)) + negate = 0; + else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a)) + { + c = a; a = b; b = c; + negate = 1; + } + else + return FALSE; + + cond = noce_get_alt_condition (if_info, b, &earliest); + if (!cond) + return FALSE; + + /* Verify the condition is of the form we expect. */ + if (rtx_equal_p (XEXP (cond, 0), b)) + c = XEXP (cond, 1); + else if (rtx_equal_p (XEXP (cond, 1), b)) + c = XEXP (cond, 0); + else + return FALSE; + + /* Verify that C is zero. Search backward through the block for + a REG_EQUAL note if necessary. */ + if (REG_P (c)) + { + rtx insn, note = NULL; + for (insn = earliest; + insn != if_info->test_bb->head; + insn = PREV_INSN (insn)) + if (INSN_P (insn) + && ((note = find_reg_note (insn, REG_EQUAL, c)) + || (note = find_reg_note (insn, REG_EQUIV, c)))) + break; + if (! note) + return FALSE; + c = XEXP (note, 0); + } + if (GET_CODE (c) == MEM + && GET_CODE (XEXP (c, 0)) == SYMBOL_REF + && CONSTANT_POOL_ADDRESS_P (XEXP (c, 0))) + c = get_pool_constant (XEXP (c, 0)); + + /* Work around funny ideas get_condition has wrt canonicalization. + Note that these rtx constants are known to be CONST_INT, and + therefore imply integer comparisons. */ + if (c == constm1_rtx && GET_CODE (cond) == GT) + ; + else if (c == const1_rtx && GET_CODE (cond) == LT) + ; + else if (c != CONST0_RTX (GET_MODE (b))) + return FALSE; + + /* Determine what sort of operation this is. */ + switch (GET_CODE (cond)) + { + case LT: + case LE: + case UNLT: + case UNLE: + negate = !negate; + break; + case GT: + case GE: + case UNGT: + case UNGE: + break; + default: + return FALSE; + } + + start_sequence (); + + target = expand_unop (GET_MODE (if_info->x), abs_optab, b, if_info->x, 0); + + /* ??? It's a quandry whether cmove would be better here, especially + for integers. Perhaps combine will clean things up. */ + if (target && negate) + target = expand_unop (GET_MODE (target), neg_optab, target, if_info->x, 0); + + if (! target) + { + end_sequence (); + return FALSE; + } + + if (target != if_info->x) + noce_emit_move_insn (if_info->x, target); + + seq = get_insns (); + end_sequence (); + + if (seq_contains_jump (seq)) + return FALSE; + + emit_insns_before (seq, earliest); + if_info->cond = cond; + if_info->cond_earliest = earliest; + + return TRUE; +} + /* Look for the condition for the jump first. We'd prefer to avoid get_condition if we can -- it tries to look back for the contents of an original compare. On targets that use normal integers for @@ -1107,6 +1431,52 @@ noce_get_condition (jump, earliest) return cond; } +/* Return true if OP is ok for if-then-else processing. */ + +static int +noce_operand_ok (op) + rtx op; +{ + /* We special-case memories, so handle any of them with + no address side effects. */ + if (GET_CODE (op) == MEM) + return ! side_effects_p (XEXP (op, 0)); + + if (side_effects_p (op)) + return FALSE; + + /* ??? Unfortuantely may_trap_p can't look at flag_trapping_math, due to + being linked into the genfoo programs. This is probably a mistake. + With finite operands, most fp operations don't trap. */ + if (!flag_trapping_math && FLOAT_MODE_P (GET_MODE (op))) + switch (GET_CODE (op)) + { + case DIV: + case MOD: + case UDIV: + case UMOD: + /* ??? This is kinda lame -- almost every target will have forced + the constant into a register first. But given the expense of + division, this is probably for the best. */ + return (CONSTANT_P (XEXP (op, 1)) + && XEXP (op, 1) != CONST0_RTX (GET_MODE (op)) + && ! may_trap_p (XEXP (op, 0))); + + default: + switch (GET_RTX_CLASS (GET_CODE (op))) + { + case '1': + return ! may_trap_p (XEXP (op, 0)); + case 'c': + case '2': + return ! may_trap_p (XEXP (op, 0)) && ! may_trap_p (XEXP (op, 1)); + } + break; + } + + return ! may_trap_p (op); +} + /* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it without using conditional execution. Return TRUE if we were successful at converting the the block. */ @@ -1210,16 +1580,16 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb) { if (no_new_pseudos) return FALSE; - x = gen_reg_rtx (GET_MODE (x)); + x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART + ? XEXP (x, 0) : x)); } /* Don't operate on sources that may trap or are volatile. */ - if (side_effects_p (a) || side_effects_p (b) - || (GET_CODE (a) != MEM && may_trap_p (a)) - || (GET_CODE (b) != MEM && may_trap_p (b))) + if (! noce_operand_ok (a) || ! noce_operand_ok (b)) return FALSE; /* Set up the info block for our subroutines. */ + if_info.test_bb = test_bb; if_info.cond = cond; if_info.jump = jump; if_info.insn_a = insn_a; @@ -1242,17 +1612,34 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb) that case don't do anything and let the code below delete INSN_A. */ if (insn_b && else_bb) { + rtx note; + if (else_bb && insn_b == else_bb->end) else_bb->end = PREV_INSN (insn_b); reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest)); + + /* If there was a REG_EQUAL note, delete it since it may have been + true due to this insn being after a jump. */ + if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0) + remove_note (insn_b, note); + insn_b = NULL_RTX; } + /* If we have "x = b; if (...) x = a;", and x has side-effects, then + x must be executed twice. */ + else if (insn_b && side_effects_p (orig_x)) + return FALSE; + x = orig_x; goto success; } if (noce_try_store_flag (&if_info)) goto success; + if (noce_try_minmax (&if_info)) + goto success; + if (noce_try_abs (&if_info)) + goto success; if (HAVE_conditional_move && noce_try_cmove (&if_info)) goto success; @@ -1300,7 +1687,7 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb) if (orig_x != x) { start_sequence (); - emit_move_insn (orig_x, x); + noce_emit_move_insn (orig_x, x); insn_b = gen_sequence (); end_sequence (); @@ -1353,7 +1740,7 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb) /* First merge TEST block into THEN block. This is a no-brainer since the THEN block did not have a code label to begin with. */ - if (combo_bb->global_live_at_end) + if (life_data_ok) COPY_REG_SET (combo_bb->global_live_at_end, then_bb->global_live_at_end); merge_blocks_nomove (combo_bb, then_bb); num_removed_blocks++; @@ -1377,10 +1764,9 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb) if (combo_bb->succ == NULL_EDGE) abort (); - /* There should sill be a branch at the end of the THEN or ELSE + /* There should still be a branch at the end of the THEN or ELSE blocks taking us to our final destination. */ - if (! simplejump_p (combo_bb->end) - && ! returnjump_p (combo_bb->end)) + if (GET_CODE (combo_bb->end) != JUMP_INSN) abort (); } @@ -1393,7 +1779,7 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb) else if (join_bb->pred == NULL || join_bb->pred->pred_next == NULL) { /* We can merge the JOIN. */ - if (combo_bb->global_live_at_end) + if (life_data_ok) COPY_REG_SET (combo_bb->global_live_at_end, join_bb->global_live_at_end); merge_blocks_nomove (combo_bb, join_bb); @@ -1455,6 +1841,9 @@ find_if_header (test_bb) if (find_if_block (test_bb, then_edge, else_edge)) goto success; + if (HAVE_trap && HAVE_conditional_trap + && find_cond_trap (test_bb, then_edge, else_edge)) + goto success; if (post_dominators && (! HAVE_conditional_execution || reload_completed)) { @@ -1500,11 +1889,26 @@ find_if_block (test_bb, then_edge, else_edge) /* If the THEN block has no successors, conditional execution can still make a conditional call. Don't do this unless the ELSE block has - only one incoming edge -- the CFG manipulation is too ugly otherwise. */ + only one incoming edge -- the CFG manipulation is too ugly otherwise. + Check for the last insn of the THEN block being an indirect jump, which + is listed as not having any successors, but confuses the rest of the CE + code processing. XXX we should fix this in the future. */ if (then_succ == NULL) { if (else_bb->pred->pred_next == NULL_EDGE) { + rtx last_insn = then_bb->end; + + while (last_insn + && GET_CODE (last_insn) == NOTE + && last_insn != then_bb->head) + last_insn = PREV_INSN (last_insn); + + if (last_insn + && GET_CODE (last_insn) == JUMP_INSN + && ! simplejump_p (last_insn)) + return FALSE; + join_bb = else_bb; else_bb = NULL_BLOCK; } @@ -1552,7 +1956,7 @@ find_if_block (test_bb, then_edge, else_edge) /* Make sure IF, THEN, and ELSE, blocks are adjacent. Actually, we get the first condition for free, since we've already asserted that there's a fallthru edge from IF to THEN. */ - /* ??? As an enhancement, move the ELSE block. Have to deal with EH and + /* ??? As an enhancement, move the ELSE block. Have to deal with BLOCK notes, if by no other means than aborting the merge if they exist. Sticky enough I don't want to think about it now. */ next_index = then_bb->index; @@ -1570,6 +1974,130 @@ find_if_block (test_bb, then_edge, else_edge) return process_if_block (test_bb, then_bb, else_bb, join_bb); } +/* Convert a branch over a trap, or a branch to a trap, + into a conditional trap. */ + +static int +find_cond_trap (test_bb, then_edge, else_edge) + basic_block test_bb; + edge then_edge, else_edge; +{ + basic_block then_bb, else_bb, join_bb, trap_bb; + rtx trap, jump, cond, cond_earliest, seq; + enum rtx_code code; + + then_bb = then_edge->dest; + else_bb = else_edge->dest; + join_bb = NULL; + + /* Locate the block with the trap instruction. */ + /* ??? While we look for no successors, we really ought to allow + EH successors. Need to fix merge_if_block for that to work. */ + /* ??? We can't currently handle merging the blocks if they are not + already adjacent. Prevent losage in merge_if_block by detecting + this now. */ + if (then_bb->succ == NULL) + { + trap_bb = then_bb; + if (else_bb->index != then_bb->index + 1) + return FALSE; + join_bb = else_bb; + else_bb = NULL; + } + else if (else_bb->succ == NULL) + { + trap_bb = else_bb; + if (else_bb->index != then_bb->index + 1) + else_bb = NULL; + else if (then_bb->succ + && ! then_bb->succ->succ_next + && ! (then_bb->succ->flags & EDGE_COMPLEX) + && then_bb->succ->dest->index == else_bb->index + 1) + join_bb = then_bb->succ->dest; + } + else + return FALSE; + + /* Don't confuse a conditional return with something we want to + optimize here. */ + if (trap_bb == EXIT_BLOCK_PTR) + return FALSE; + + /* The only instruction in the THEN block must be the trap. */ + trap = first_active_insn (trap_bb); + if (! (trap == trap_bb->end + && GET_CODE (PATTERN (trap)) == TRAP_IF + && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx)) + return FALSE; + + if (rtl_dump_file) + { + if (trap_bb == then_bb) + fprintf (rtl_dump_file, + "\nTRAP-IF block found, start %d, trap %d", + test_bb->index, then_bb->index); + else + fprintf (rtl_dump_file, + "\nTRAP-IF block found, start %d, then %d, trap %d", + test_bb->index, then_bb->index, trap_bb->index); + if (join_bb) + fprintf (rtl_dump_file, ", join %d\n", join_bb->index); + else + fputc ('\n', rtl_dump_file); + } + + /* If this is not a standard conditional jump, we can't parse it. */ + jump = test_bb->end; + cond = noce_get_condition (jump, &cond_earliest); + if (! cond) + return FALSE; + + /* If the conditional jump is more than just a conditional jump, + then we can not do if-conversion on this block. */ + if (! onlyjump_p (jump)) + return FALSE; + + /* We must be comparing objects whose modes imply the size. */ + if (GET_MODE (XEXP (cond, 0)) == BLKmode) + return FALSE; + + /* Reverse the comparison code, if necessary. */ + code = GET_CODE (cond); + if (then_bb == trap_bb) + { + code = reversed_comparison_code (cond, jump); + if (code == UNKNOWN) + return FALSE; + } + + /* Attempt to generate the conditional trap. */ + seq = gen_cond_trap (code, XEXP (cond, 0), XEXP (cond, 1), + TRAP_CODE (PATTERN (trap))); + if (seq == NULL) + return FALSE; + + /* Emit the new insns before cond_earliest; delete the old jump + and trap insns. */ + + emit_insn_before (seq, cond_earliest); + + test_bb->end = PREV_INSN (jump); + flow_delete_insn (jump); + + trap_bb->end = PREV_INSN (trap); + flow_delete_insn (trap); + + /* Merge the blocks! */ + if (trap_bb != then_bb && ! else_bb) + { + flow_delete_block (trap_bb); + num_removed_blocks++; + } + merge_if_block (test_bb, then_bb, else_bb, join_bb); + + return TRUE; +} + /* Look for IF-THEN-ELSE cases in which one of THEN or ELSE is transformable, but not necessarily the other. There need be no JOIN block. @@ -1877,6 +2405,8 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) rtx cond, prob_val; cond = cond_exec_get_condition (jump); + if (! cond) + return FALSE; prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX); if (prob_val) @@ -1884,8 +2414,10 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) if (reversep) { - cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)), - GET_MODE (cond), XEXP (cond, 0), + enum rtx_code rev = reversed_comparison_code (cond, jump); + if (rev == UNKNOWN) + return FALSE; + cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0), XEXP (cond, 1)); if (prob_val) prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val)); @@ -1953,7 +2485,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) /* ??? bb->local_set is only valid during calculate_global_regs_live, so we must recompute usage for MERGE_BB. Not so bad, I suppose, since we've already asserted that MERGE_BB is small. */ - propagate_block (merge_bb, tmp, merge_set, 0); + propagate_block (merge_bb, tmp, merge_set, merge_set, 0); /* For small register class machines, don't lengthen lifetimes of hard registers before reload. */ @@ -1973,7 +2505,8 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) Moreover, we're interested in the insns live from OTHER_BB. */ COPY_REG_SET (test_live, other_bb->global_live_at_start); - pbi = init_propagate_block_info (test_bb, test_live, test_set, 0); + pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set, + 0); for (insn = jump; ; insn = prev) { @@ -2028,11 +2561,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) JUMP_LABEL (jump) = new_dest; if (reversep) - { - rtx note = find_reg_note (jump, REG_BR_PROB, NULL_RTX); - if (note) - XEXP (note, 0) = GEN_INT (REG_BR_PROB_BASE - INTVAL (XEXP (note, 0))); - } + invert_br_probabilities (jump); /* Move the insns out of MERGE_BB to before the branch. */ if (head != NULL) @@ -2066,14 +2595,15 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) /* Main entry point for all if-conversion. */ void -if_convert (life_data_ok) - int life_data_ok; +if_convert (x_life_data_ok) + int x_life_data_ok; { int block_num; num_possible_if_blocks = 0; num_updated_if_blocks = 0; num_removed_blocks = 0; + life_data_ok = (x_life_data_ok != 0); /* Free up basic_block_for_insn so that we don't have to keep it up to date, either here or in merge_blocks_nomove. */ @@ -2084,7 +2614,7 @@ if_convert (life_data_ok) if (HAVE_conditional_execution || life_data_ok) { post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks); - compute_flow_dominators (NULL, post_dominators); + calculate_dominance_info (NULL, post_dominators, CDI_POST_DOMINATORS); } /* Record initial block numbers. */