X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fifcvt.c;h=0652afd99ee060a48fee72a64f393e0b090f9a2c;hb=805e22b2051e9c6a75377ea6599654d7415da483;hp=ee2d143e24120cc167cc86a544d989f4bb12fef3;hpb=2580b9b65f2771e0353dedf49cd263af33cec6e0;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index ee2d143e241..0652afd99ee 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1,25 +1,27 @@ /* If-conversion support. - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. - This file is part of GNU CC. + This file is part of GCC. - GNU CC is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - GNU CC is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. You should have received a copy of the GNU General Public License - along with GNU CC; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "rtl.h" #include "regs.h" @@ -27,10 +29,13 @@ #include "flags.h" #include "insn-config.h" #include "recog.h" +#include "except.h" #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,13 +51,17 @@ #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) #endif -#define EDGE_COMPLEX (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH) - #define NULL_EDGE ((struct edge_def *)NULL) #define NULL_BLOCK ((struct basic_block_def *)NULL) @@ -66,46 +75,41 @@ static int num_updated_if_blocks; /* # of basic blocks that were removed. */ static int num_removed_blocks; +/* Whether conditional execution changes were made. */ +static int cond_exec_changed_p; + +/* 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; +static dominance_info post_dominators; /* Forward references. */ static int count_bb_insns PARAMS ((basic_block)); static rtx first_active_insn PARAMS ((basic_block)); -static int last_active_insn_p PARAMS ((basic_block, rtx)); +static rtx last_active_insn PARAMS ((basic_block, int)); static int seq_contains_jump PARAMS ((rtx)); - -static int cond_exec_process_insns PARAMS ((rtx, rtx, rtx, rtx, int)); +static basic_block block_fallthru PARAMS ((basic_block)); +static int cond_exec_process_insns PARAMS ((ce_if_block_t *, + rtx, rtx, rtx, rtx, int)); static rtx cond_exec_get_condition PARAMS ((rtx)); -static int cond_exec_process_if_block PARAMS ((basic_block, basic_block, - basic_block, basic_block)); - +static int cond_exec_process_if_block PARAMS ((ce_if_block_t *, int)); static rtx noce_get_condition PARAMS ((rtx, rtx *)); -static int noce_process_if_block PARAMS ((basic_block, basic_block, - basic_block, basic_block)); - -static int process_if_block PARAMS ((basic_block, basic_block, - basic_block, basic_block)); -static void merge_if_block PARAMS ((basic_block, basic_block, - basic_block, basic_block)); - -static int find_if_header PARAMS ((basic_block)); -static int find_if_block PARAMS ((basic_block, edge, edge)); +static int noce_operand_ok PARAMS ((rtx)); +static int noce_process_if_block PARAMS ((ce_if_block_t *)); +static int process_if_block PARAMS ((ce_if_block_t *)); +static void merge_if_block PARAMS ((ce_if_block_t *)); +static int find_cond_trap PARAMS ((basic_block, edge, edge)); +static basic_block find_if_header PARAMS ((basic_block, int)); +static int block_jumps_and_fallthru_p PARAMS ((basic_block, basic_block)); +static int find_if_block PARAMS ((ce_if_block_t *)); 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_memory PARAMS ((rtx *, void *)); static int dead_or_predicable PARAMS ((basic_block, basic_block, - basic_block, rtx, int)); - -/* 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 - life analysis. */ - -#define SET_ORIG_INDEX(BB,I) ((BB)->aux = (void *)((size_t)(I) << 1)) -#define ORIG_INDEX(BB) ((size_t)(BB)->aux >> 1) -#define SET_UPDATE_LIFE(BB) ((BB)->aux = (void *)((size_t)(BB)->aux | 1)) -#define UPDATE_LIFE(BB) ((size_t)(BB)->aux & 1) - + basic_block, basic_block, int)); +static void noce_emit_move_insn PARAMS ((rtx, rtx)); +static rtx block_has_only_trap PARAMS ((basic_block)); /* Count the number of non-jump active insns in BB. */ @@ -157,22 +161,31 @@ first_active_insn (bb) return insn; } -/* Return true if INSN is the last active non-jump insn in BB. */ +/* Return the last non-jump active (non-jump) insn in the basic block. */ -static int -last_active_insn_p (bb, insn) +static rtx +last_active_insn (bb, skip_use_p) basic_block bb; - rtx insn; + int skip_use_p; { - do + rtx insn = bb->end; + rtx head = bb->head; + + while (GET_CODE (insn) == NOTE + || GET_CODE (insn) == JUMP_INSN + || (skip_use_p + && GET_CODE (insn) == INSN + && GET_CODE (PATTERN (insn)) == USE)) { - if (insn == bb->end) - return TRUE; - insn = NEXT_INSN (insn); + if (insn == head) + return NULL_RTX; + insn = PREV_INSN (insn); } - while (GET_CODE (insn) == NOTE); - return GET_CODE (insn) == JUMP_INSN; + if (GET_CODE (insn) == CODE_LABEL) + return NULL_RTX; + + return insn; } /* It is possible, especially when having dealt with multi-word @@ -192,13 +205,28 @@ seq_contains_jump (insn) } return 0; } + +static basic_block +block_fallthru (bb) + basic_block bb; +{ + edge e; + + for (e = bb->succ; + e != NULL_EDGE && (e->flags & EDGE_FALLTHRU) == 0; + e = e->succ_next) + ; + + return (e) ? e->dest : NULL_BLOCK; +} /* Go through a bunch of insns, converting them to conditional execution format if possible. Return TRUE if all of the non-note insns were processed. */ static int -cond_exec_process_insns (start, end, test, prob_val, mod_ok) +cond_exec_process_insns (ce_info, start, end, test, prob_val, mod_ok) + ce_if_block_t *ce_info ATTRIBUTE_UNUSED; /* if block information */ rtx start; /* first insn to look at */ rtx end; /* last insn to look at */ rtx test; /* conditional execution test */ @@ -207,6 +235,11 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok) { int must_be_last = FALSE; rtx insn; + rtx xtest; + rtx pattern; + + if (!start || !end) + return FALSE; for (insn = start; ; insn = NEXT_INSN (insn)) { @@ -216,10 +249,8 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok) if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN) abort (); - /* Remove USE and CLOBBER insns that get in the way. */ - if (reload_completed - && (GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER)) + /* Remove USE insns that get in the way. */ + if (reload_completed && GET_CODE (PATTERN (insn)) == USE) { /* ??? Ug. Actually unlinking the thing is problematic, given what we'd have to coordinate with our callers. */ @@ -241,9 +272,33 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok) } /* Now build the conditional form of the instruction. */ - validate_change (insn, &PATTERN (insn), - gen_rtx_COND_EXEC (VOIDmode, copy_rtx (test), - PATTERN (insn)), 1); + pattern = PATTERN (insn); + xtest = copy_rtx (test); + + /* If this is already a COND_EXEC, rewrite the test to be an AND of the + two conditions. */ + if (GET_CODE (pattern) == COND_EXEC) + { + if (GET_MODE (xtest) != GET_MODE (COND_EXEC_TEST (pattern))) + return FALSE; + + xtest = gen_rtx_AND (GET_MODE (xtest), xtest, + COND_EXEC_TEST (pattern)); + pattern = COND_EXEC_CODE (pattern); + } + + pattern = gen_rtx_COND_EXEC (VOIDmode, xtest, pattern); + + /* If the machine needs to modify the insn being conditionally executed, + say for example to force a constant integer operand into a temp + register, do so here. */ +#ifdef IFCVT_MODIFY_INSN + IFCVT_MODIFY_INSN (ce_info, pattern, insn); + if (! pattern) + return FALSE; +#endif + + validate_change (insn, &PATTERN (insn), pattern, 1); if (GET_CODE (insn) == CALL_INSN && prob_val) validate_change (insn, ®_NOTES (insn), @@ -276,36 +331,57 @@ 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; } /* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it to conditional execution. Return TRUE if we were successful at - converting the the block. */ + converting the block. */ static int -cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) - basic_block test_bb; /* Basic block test is in */ - basic_block then_bb; /* Basic block for THEN block */ - basic_block else_bb; /* Basic block for ELSE block */ - basic_block join_bb; /* Basic block the join label is in */ +cond_exec_process_if_block (ce_info, do_multiple_p) + ce_if_block_t * ce_info; /* if block information */ + int do_multiple_p; /* != 0 if we should handle && and || blocks */ { + basic_block test_bb = ce_info->test_bb; /* last test block */ + basic_block then_bb = ce_info->then_bb; /* THEN */ + basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */ rtx test_expr; /* expression in IF_THEN_ELSE that is tested */ rtx then_start; /* first insn in THEN block */ rtx then_end; /* last insn + 1 in THEN block */ - rtx else_start; /* first insn in ELSE block or NULL */ - rtx else_end; /* last insn + 1 in ELSE block */ - int max; /* max # of insns to convert. */ + rtx else_start = NULL_RTX; /* first insn in ELSE block or NULL */ + rtx else_end = NULL_RTX; /* last insn + 1 in ELSE block */ + int max; /* max # of insns to convert. */ int then_mod_ok; /* whether conditional mods are ok in THEN */ rtx true_expr; /* test for else block insns */ rtx false_expr; /* test for then block insns */ rtx true_prob_val; /* probability of else block */ rtx false_prob_val; /* probability of then block */ int n_insns; + enum rtx_code false_code; + + /* If test is comprised of && or || elements, and we've failed at handling + all of them together, just use the last test if it is the special case of + && elements without an ELSE block. */ + if (!do_multiple_p && ce_info->num_multiple_test_blocks) + { + if (else_bb || ! ce_info->and_and_p) + return FALSE; + + ce_info->test_bb = test_bb = ce_info->last_test_bb; + ce_info->num_multiple_test_blocks = 0; + ce_info->num_and_and_blocks = 0; + ce_info->num_or_or_blocks = 0; + } /* Find the conditional jump to the ELSE or JOIN part, and isolate the test. */ @@ -315,51 +391,25 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) /* If the conditional jump is more than just a conditional jump, then we can not do conditional execution conversion on this block. */ - if (!onlyjump_p (test_bb->end)) + if (! onlyjump_p (test_bb->end)) return FALSE; - /* Collect the bounds of where we're to search. */ - - then_start = then_bb->head; - then_end = then_bb->end; - - /* Skip a label heading THEN block. */ - if (GET_CODE (then_start) == CODE_LABEL) - then_start = NEXT_INSN (then_start); - - /* Skip a (use (const_int 0)) or branch as the final insn. */ - if (GET_CODE (then_end) == INSN - && GET_CODE (PATTERN (then_end)) == USE - && GET_CODE (XEXP (PATTERN (then_end), 0)) == CONST_INT) - then_end = PREV_INSN (then_end); - else if (GET_CODE (then_end) == JUMP_INSN) - then_end = PREV_INSN (then_end); + /* Collect the bounds of where we're to search, skipping any labels, jumps + and notes at the beginning and end of the block. Then count the total + number of insns and see if it is small enough to convert. */ + then_start = first_active_insn (then_bb); + then_end = last_active_insn (then_bb, TRUE); + n_insns = ce_info->num_then_insns = count_bb_insns (then_bb); + max = MAX_CONDITIONAL_EXECUTE; if (else_bb) { - /* Skip the ELSE block's label. */ - else_start = NEXT_INSN (else_bb->head); - else_end = else_bb->end; - - /* Skip a (use (const_int 0)) or branch as the final insn. */ - if (GET_CODE (else_end) == INSN - && GET_CODE (PATTERN (else_end)) == USE - && GET_CODE (XEXP (PATTERN (else_end), 0)) == CONST_INT) - else_end = PREV_INSN (else_end); - else if (GET_CODE (else_end) == JUMP_INSN) - else_end = PREV_INSN (else_end); + max *= 2; + else_start = first_active_insn (else_bb); + else_end = last_active_insn (else_bb, TRUE); + n_insns += ce_info->num_else_insns = count_bb_insns (else_bb); } - /* How many instructions should we convert in total? */ - n_insns = 0; - if (else_bb) - { - max = 2 * MAX_CONDITIONAL_EXECUTE; - n_insns = count_bb_insns (else_bb); - } - else - max = MAX_CONDITIONAL_EXECUTE; - n_insns += count_bb_insns (then_bb); if (n_insns > max) return FALSE; @@ -367,9 +417,23 @@ 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 + conditional execution register from a comparison, it can do so here. */ + IFCVT_MODIFY_TESTS (ce_info, true_expr, false_expr); + + /* See if the conversion failed */ + if (!true_expr || !false_expr) + goto fail; +#endif true_prob_val = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX); if (true_prob_val) @@ -380,6 +444,72 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) else false_prob_val = NULL_RTX; + /* If we have && or || tests, do them here. These tests are in the adjacent + blocks after the first block containing the test. */ + if (ce_info->num_multiple_test_blocks > 0) + { + basic_block bb = test_bb; + basic_block last_test_bb = ce_info->last_test_bb; + + if (! false_expr) + goto fail; + + do + { + rtx start, end; + rtx t, f; + + bb = block_fallthru (bb); + start = first_active_insn (bb); + end = last_active_insn (bb, TRUE); + if (start + && ! cond_exec_process_insns (ce_info, start, end, false_expr, + false_prob_val, FALSE)) + goto fail; + + /* If the conditional jump is more than just a conditional jump, then + we can not do conditional execution conversion on this block. */ + if (! onlyjump_p (bb->end)) + goto fail; + + /* Find the conditional jump and isolate the test. */ + t = cond_exec_get_condition (bb->end); + if (! t) + goto fail; + + f = gen_rtx_fmt_ee (reverse_condition (GET_CODE (t)), + GET_MODE (t), + XEXP (t, 0), + XEXP (t, 1)); + + if (ce_info->and_and_p) + { + t = gen_rtx_AND (GET_MODE (t), true_expr, t); + f = gen_rtx_IOR (GET_MODE (t), false_expr, f); + } + else + { + t = gen_rtx_IOR (GET_MODE (t), true_expr, t); + f = gen_rtx_AND (GET_MODE (t), false_expr, f); + } + + /* If the machine description needs to modify the tests, such as + setting a conditional execution register from a comparison, it can + do so here. */ +#ifdef IFCVT_MODIFY_MULTIPLE_TESTS + IFCVT_MODIFY_MULTIPLE_TESTS (ce_info, bb, t, f); + + /* See if the conversion failed */ + if (!t || !f) + goto fail; +#endif + + true_expr = t; + false_expr = f; + } + while (bb != last_test_bb); + } + /* For IF-THEN-ELSE blocks, we don't allow modifications of the test on then THEN block. */ then_mod_ok = (else_bb == NULL_BLOCK); @@ -388,17 +518,32 @@ 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 (ce_info, then_start, then_end, + false_expr, false_prob_val, + then_mod_ok))) goto fail; - if (else_bb - && ! cond_exec_process_insns (else_start, else_end, + if (else_bb && else_end + && ! cond_exec_process_insns (ce_info, else_start, else_end, true_expr, true_prob_val, TRUE)) goto fail; + /* If we cannot apply the changes, fail. Do not go through the normal fail + processing, since apply_change_group will call cancel_changes. */ if (! apply_change_group ()) - return FALSE; + { +#ifdef IFCVT_MODIFY_CANCEL + /* Cancel any machine dependent changes. */ + IFCVT_MODIFY_CANCEL (ce_info); +#endif + return FALSE; + } + +#ifdef IFCVT_MODIFY_FINAL + /* Do any machine dependent final modifications */ + IFCVT_MODIFY_FINAL (ce_info); +#endif /* Conversion succeeded. */ if (rtl_dump_file) @@ -406,10 +551,16 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb) n_insns, (n_insns == 1) ? " was" : "s were"); /* Merge the blocks! */ - merge_if_block (test_bb, then_bb, else_bb, join_bb); + merge_if_block (ce_info); + cond_exec_changed_p = TRUE; return TRUE; fail: +#ifdef IFCVT_MODIFY_CANCEL + /* Cancel any machine dependent changes. */ + IFCVT_MODIFY_CANCEL (ce_info); +#endif + cancel_changes (0); return FALSE; } @@ -422,6 +573,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; @@ -438,6 +590,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*. */ @@ -458,17 +614,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); @@ -480,7 +637,7 @@ noce_emit_store_flag (if_info, x, reversep, normalize) { tmp = get_insns (); end_sequence (); - emit_insns (tmp); + emit_insn (tmp); if_info->cond_earliest = if_info->jump; @@ -494,16 +651,36 @@ 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 an 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)); +} + /* Convert "if (test) x = 1; else x = 0". Only try 0 and STORE_FLAG_VALUE here. Other combinations will be @@ -524,7 +701,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; @@ -535,11 +713,11 @@ 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 (); - emit_insns_before (seq, if_info->cond_earliest); + emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a)); return TRUE; } @@ -560,16 +738,25 @@ noce_try_store_flag_constants (if_info) int reversep; HOST_WIDE_INT itrue, ifalse, diff, tmp; int normalize, can_reverse; + enum machine_mode mode; if (! no_new_pseudos && GET_CODE (if_info->a) == CONST_INT && GET_CODE (if_info->b) == CONST_INT) { + mode = GET_MODE (if_info->x); ifalse = INTVAL (if_info->a); itrue = INTVAL (if_info->b); - diff = itrue - ifalse; - can_reverse = can_reverse_comparison_p (if_info->cond, if_info->jump); + /* Make sure we can represent the difference between the two values. */ + if ((itrue - ifalse > 0) + != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue)) + return FALSE; + + diff = trunc_int_for_mode (itrue - ifalse, mode); + + can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump) + != UNKNOWN); reversep = 0; if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE) @@ -597,7 +784,7 @@ noce_try_store_flag_constants (if_info) if (reversep) { tmp = itrue; itrue = ifalse; ifalse = tmp; - diff = -diff; + diff = trunc_int_for_mode (-diff, mode); } start_sequence (); @@ -612,42 +799,42 @@ noce_try_store_flag_constants (if_info) => x = 3 + (test == 0); */ if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE) { - target = expand_binop (GET_MODE (if_info->x), - (diff == STORE_FLAG_VALUE - ? add_optab : sub_optab), - GEN_INT (ifalse), target, if_info->x, 0, - OPTAB_WIDEN); + target = expand_simple_binop (mode, + (diff == STORE_FLAG_VALUE + ? PLUS : MINUS), + GEN_INT (ifalse), target, if_info->x, 0, + OPTAB_WIDEN); } /* if (test) x = 8; else x = 0; => x = (test != 0) << 3; */ else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0) { - target = expand_binop (GET_MODE (if_info->x), ashl_optab, - target, GEN_INT (tmp), if_info->x, 0, - OPTAB_WIDEN); + target = expand_simple_binop (mode, ASHIFT, + target, GEN_INT (tmp), if_info->x, 0, + OPTAB_WIDEN); } /* if (test) x = -1; else x = b; => x = -(test != 0) | b; */ else if (itrue == -1) { - target = expand_binop (GET_MODE (if_info->x), ior_optab, - target, GEN_INT (ifalse), if_info->x, 0, - OPTAB_WIDEN); + target = expand_simple_binop (mode, IOR, + target, GEN_INT (ifalse), if_info->x, 0, + OPTAB_WIDEN); } /* if (test) x = a; else x = b; => x = (-(test != 0) & (b - a)) + a; */ else { - target = expand_binop (GET_MODE (if_info->x), and_optab, - target, GEN_INT (diff), if_info->x, 0, - OPTAB_WIDEN); + target = expand_simple_binop (mode, AND, + target, GEN_INT (diff), if_info->x, 0, + OPTAB_WIDEN); if (target) - target = expand_binop (GET_MODE (if_info->x), add_optab, - target, GEN_INT (ifalse), if_info->x, 0, - OPTAB_WIDEN); + target = expand_simple_binop (mode, PLUS, + target, GEN_INT (ifalse), + if_info->x, 0, OPTAB_WIDEN); } if (! target) @@ -657,7 +844,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 (); @@ -665,7 +852,7 @@ noce_try_store_flag_constants (if_info) if (seq_contains_jump (seq)) return FALSE; - emit_insns_before (seq, if_info->cond_earliest); + emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a)); return TRUE; } @@ -693,7 +880,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; @@ -709,13 +897,14 @@ noce_try_store_flag_inc (if_info) 1, normalize); if (target) - target = expand_binop (GET_MODE (if_info->x), - subtract ? sub_optab : add_optab, - if_info->x, target, if_info->x, 0, OPTAB_WIDEN); + target = expand_simple_binop (GET_MODE (if_info->x), + subtract ? MINUS : PLUS, + if_info->x, target, if_info->x, + 0, OPTAB_WIDEN); 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 (); @@ -723,7 +912,8 @@ noce_try_store_flag_inc (if_info) if (seq_contains_jump (seq)) return FALSE; - emit_insns_before (seq, if_info->cond_earliest); + emit_insn_before_scope (seq, if_info->jump, + INSN_SCOPE (if_info->insn_a)); return TRUE; } @@ -749,8 +939,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)))) { @@ -759,14 +950,14 @@ noce_try_store_flag_mask (if_info) gen_reg_rtx (GET_MODE (if_info->x)), reversep, -1); if (target) - target = expand_binop (GET_MODE (if_info->x), and_optab, - if_info->x, target, if_info->x, 0, - OPTAB_WIDEN); + target = expand_simple_binop (GET_MODE (if_info->x), AND, + if_info->x, target, if_info->x, 0, + OPTAB_WIDEN); 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 (); @@ -774,7 +965,8 @@ noce_try_store_flag_mask (if_info) if (seq_contains_jump (seq)) return FALSE; - emit_insns_before (seq, if_info->cond_earliest); + emit_insn_before_scope (seq, if_info->jump, + INSN_SCOPE (if_info->insn_a)); return TRUE; } @@ -813,7 +1005,7 @@ noce_emit_cmove (if_info, x, code, cmp_a, cmp_b, vfalse, vtrue) { tmp = get_insns (); end_sequence (); - emit_insns (tmp); + emit_insn (tmp); return x; } @@ -865,11 +1057,12 @@ 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 (); - emit_insns_before (seq, if_info->cond_earliest); + emit_insn_before_scope (seq, if_info->jump, + INSN_SCOPE (if_info->insn_a)); return TRUE; } else @@ -928,7 +1121,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)) @@ -938,7 +1131,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; } @@ -1020,16 +1213,18 @@ 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)); + set_mem_align (tmp, + MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b))); - 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 (); - emit_insns_before (tmp, if_info->cond_earliest); + emit_insn_before_scope (tmp, if_info->jump, INSN_SCOPE (if_info->insn_a)); return TRUE; end_seq_and_fail: @@ -1037,193 +1232,627 @@ noce_try_cmove_arith (if_info) return FALSE; } -/* 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 - comparisons, e.g. alpha, this is wasteful. */ +/* 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_condition (jump, earliest) - rtx jump; +noce_get_alt_condition (if_info, target, earliest) + struct noce_if_info *if_info; + rtx target; rtx *earliest; { - rtx cond; - rtx set; + rtx cond, set, insn; + int reverse; - /* If the condition variable is a register and is MODE_INT, accept it. - Otherwise, fall back on get_condition. */ + /* 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; + } - if (! any_condjump_p (jump)) - return NULL_RTX; + 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); - set = pc_set (jump); + /* If we're looking for a constant, try to make the conditional + have that constant in it. There are two reasons why it may + not have the constant we want: - cond = XEXP (SET_SRC (set), 0); - if (GET_CODE (XEXP (cond, 0)) == REG - && GET_MODE_CLASS (GET_MODE (XEXP (cond, 0))) == MODE_INT) + 1. GCC may have needed to put the constant in a register, because + the target can't compare directly against that constant. For + this case, we look for a SET immediately before the comparison + that puts a constant in that register. + + 2. GCC may have canonicalized the conditional, for example + replacing "if x < 4" with "if x <= 3". We can undo that (or + make equivalent types of changes) to get the constants we need + if they're off by one in the right direction. */ + + if (GET_CODE (target) == CONST_INT) { - *earliest = jump; + enum rtx_code code = GET_CODE (if_info->cond); + rtx op_a = XEXP (if_info->cond, 0); + rtx op_b = XEXP (if_info->cond, 1); + rtx prev_insn; + + /* First, look to see if we put a constant in a register. */ + prev_insn = PREV_INSN (if_info->cond_earliest); + if (prev_insn + && INSN_P (prev_insn) + && GET_CODE (PATTERN (prev_insn)) == SET) + { + rtx src = find_reg_equal_equiv_note (prev_insn); + if (!src) + src = SET_SRC (PATTERN (prev_insn)); + if (GET_CODE (src) == CONST_INT) + { + if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn)))) + op_a = src; + else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn)))) + op_b = src; + + if (GET_CODE (op_a) == CONST_INT) + { + rtx tmp = op_a; + op_a = op_b; + op_b = tmp; + code = swap_condition (code); + } + } + } - /* If this branches to JUMP_LABEL when the condition is false, - reverse the condition. */ - if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF - && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump)) - cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)), - GET_MODE (cond), XEXP (cond, 0), - XEXP (cond, 1)); - } - else - cond = get_condition (jump, earliest); + /* Now, look to see if we can get the right constant by + adjusting the conditional. */ + if (GET_CODE (op_b) == CONST_INT) + { + HOST_WIDE_INT desired_val = INTVAL (target); + HOST_WIDE_INT actual_val = INTVAL (op_b); - return cond; -} + switch (code) + { + case LT: + if (actual_val == desired_val + 1) + { + code = LE; + op_b = GEN_INT (desired_val); + } + break; + case LE: + if (actual_val == desired_val - 1) + { + code = LT; + op_b = GEN_INT (desired_val); + } + break; + case GT: + if (actual_val == desired_val - 1) + { + code = GE; + op_b = GEN_INT (desired_val); + } + break; + case GE: + if (actual_val == desired_val + 1) + { + code = GT; + op_b = GEN_INT (desired_val); + } + break; + default: + break; + } + } -/* 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. */ + /* If we made any changes, generate a new conditional that is + equivalent to what we started with, but has the right + constants in it. */ + if (code != GET_CODE (if_info->cond) + || op_a != XEXP (if_info->cond, 0) + || op_b != XEXP (if_info->cond, 1)) + { + cond = gen_rtx_fmt_ee (code, GET_MODE (cond), op_a, op_b); + *earliest = if_info->cond_earliest; + return cond; + } + } -static int -noce_process_if_block (test_bb, then_bb, else_bb, join_bb) - basic_block test_bb; /* Basic block test is in */ - basic_block then_bb; /* Basic block for THEN block */ - basic_block else_bb; /* Basic block for ELSE block */ - basic_block join_bb; /* Basic block the join label is in */ -{ - /* We're looking for patterns of the form + cond = canonicalize_condition (if_info->jump, cond, reverse, + earliest, target); + if (! cond || ! reg_mentioned_p (target, cond)) + return NULL; - (1) if (...) x = a; else x = b; - (2) x = b; if (...) x = a; - (3) if (...) x = a; // as if with an initial x = x. + /* We almost certainly searched back to a different place. + Need to re-verify correct lifetimes. */ - The later patterns require jumps to be more expensive. + /* 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_overlap_mentioned_p (if_info->x, PATTERN (insn))) + return NULL; - ??? For future expansion, look for multiple X in such patterns. */ + /* 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; - struct noce_if_info if_info; - rtx insn_a, insn_b; - rtx set_a, set_b; - rtx orig_x, x, a, b; - rtx jump, cond, insn; + return cond; +} - /* If this is not a standard conditional jump, we can't parse it. */ - jump = test_bb->end; - cond = noce_get_condition (jump, &if_info.cond_earliest); - if (! cond) - return FALSE; +/* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc. */ - /* 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; +static int +noce_try_minmax (if_info) + struct noce_if_info *if_info; +{ + rtx cond, earliest, target, seq; + enum rtx_code code, op; + int unsignedp; - /* We must be comparing objects whose modes imply the size. */ - if (GET_MODE (XEXP (cond, 0)) == BLKmode) + /* ??? Can't guarantee that expand_binop won't create pseudos. */ + if (no_new_pseudos) return FALSE; - /* Look for one of the potential sets. */ - insn_a = first_active_insn (then_bb); - if (! insn_a - || ! last_active_insn_p (then_bb, insn_a) - || (set_a = single_set (insn_a)) == NULL_RTX) + /* ??? Reject modes with NaNs or signed zeros since we don't know how + they will be resolved with an SMIN/SMAX. It wouldn't be too hard + to get the target to tell us... */ + if (HONOR_SIGNED_ZEROS (GET_MODE (if_info->x)) + || HONOR_NANS (GET_MODE (if_info->x))) return FALSE; - x = SET_DEST (set_a); - a = SET_SRC (set_a); + cond = noce_get_alt_condition (if_info, if_info->a, &earliest); + if (!cond) + return FALSE; - /* Look for the other potential set. Make sure we've got equivalent - destinations. */ - /* ??? This is overconservative. Storing to two different mems is - as easy as conditionally computing the address. Storing to a - single mem merely requires a scratch memory to use as one of the - destination addresses; often the memory immediately below the - stack pointer is available for this. */ - set_b = NULL_RTX; - if (else_bb) + /* 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)) { - insn_b = first_active_insn (else_bb); - if (! insn_b - || ! last_active_insn_p (else_bb, insn_b) - || (set_b = single_set (insn_b)) == NULL_RTX - || ! rtx_equal_p (x, SET_DEST (set_b))) + if (! rtx_equal_p (XEXP (cond, 1), if_info->b)) return FALSE; } - else + else if (rtx_equal_p (XEXP (cond, 1), if_info->a)) { - insn_b = prev_nonnote_insn (if_info.cond_earliest); - if (! insn_b - || GET_CODE (insn_b) != INSN - || (set_b = single_set (insn_b)) == NULL_RTX - || ! rtx_equal_p (x, SET_DEST (set_b)) - || reg_mentioned_p (x, cond) - || reg_mentioned_p (x, a) - || reg_mentioned_p (x, SET_SRC (set_b))) - insn_b = set_b = NULL_RTX; + if (! rtx_equal_p (XEXP (cond, 0), if_info->b)) + return FALSE; + code = swap_condition (code); } - b = (set_b ? SET_SRC (set_b) : x); + else + return FALSE; - /* X may not be mentioned in the range (cond_earliest, jump]. */ - for (insn = jump; insn != if_info.cond_earliest; insn = PREV_INSN (insn)) - if (INSN_P (insn) && reg_mentioned_p (x, insn)) + /* 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; + unsignedp = 0; + break; + case GT: + case GE: + case UNGT: + case UNGE: + op = SMIN; + unsignedp = 0; + break; + case LTU: + case LEU: + op = UMAX; + unsignedp = 1; + break; + case GTU: + case GEU: + op = UMIN; + unsignedp = 1; + break; + default: return FALSE; + } - /* A and B may not be modified in the range [cond_earliest, jump). */ - for (insn = if_info.cond_earliest; insn != jump; insn = NEXT_INSN (insn)) - if (INSN_P (insn) - && (modified_in_p (a, insn) || modified_in_p (b, insn))) - return FALSE; + start_sequence (); - /* Only operate on register destinations, and even then avoid extending - the lifetime of hard registers on small register class machines. */ - orig_x = x; - if (GET_CODE (x) != REG - || (SMALL_REGISTER_CLASSES - && REGNO (x) < FIRST_PSEUDO_REGISTER)) + target = expand_simple_binop (GET_MODE (if_info->x), op, + if_info->a, if_info->b, + if_info->x, unsignedp, OPTAB_WIDEN); + if (! target) { - if (no_new_pseudos) - return FALSE; - x = gen_reg_rtx (GET_MODE (x)); + end_sequence (); + return FALSE; } + if (target != if_info->x) + noce_emit_move_insn (if_info->x, target); - /* 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))) + seq = get_insns (); + end_sequence (); + + if (seq_contains_jump (seq)) return FALSE; - /* Set up the info block for our subroutines. */ - if_info.cond = cond; - if_info.jump = jump; - if_info.insn_a = insn_a; - if_info.insn_b = insn_b; - if_info.x = x; - if_info.a = a; - if_info.b = b; + emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a)); + if_info->cond = cond; + if_info->cond_earliest = earliest; - /* Try optimizations in some approximation of a useful order. */ - /* ??? Should first look to see if X is live incoming at all. If it - isn't, we don't need anything but an unconditional set. */ + return TRUE; +} - /* Look and see if A and B are really the same. Avoid creating silly - cmove constructs that no one will fix up later. */ - if (rtx_equal_p (a, b)) +/* 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)) { - /* If we have an INSN_B, we don't have to create any new rtl. Just - move the instruction that we already have. If we don't have an - INSN_B, that means that A == X, and we've got a noop move. In - that case don't do anything and let the code below delete INSN_A. */ - if (insn_b && else_bb) - { - 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)); - insn_b = NULL_RTX; - } - x = orig_x; - goto success; + 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_simple_unop (GET_MODE (if_info->x), ABS, 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_simple_unop (GET_MODE (target), NEG, 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_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a)); + if_info->cond = cond; + if_info->cond_earliest = earliest; + + return TRUE; +} + +/* Similar to get_condition, only the resulting condition must be + valid at JUMP, instead of at EARLIEST. */ + +static rtx +noce_get_condition (jump, earliest) + rtx jump; + rtx *earliest; +{ + rtx cond, set, tmp, insn; + bool reverse; + + if (! any_condjump_p (jump)) + return NULL_RTX; + + set = pc_set (jump); + + /* If this branches to JUMP_LABEL when the condition is false, + reverse the condition. */ + reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF + && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump)); + + /* If the condition variable is a register and is MODE_INT, accept it. */ + + cond = XEXP (SET_SRC (set), 0); + tmp = XEXP (cond, 0); + if (REG_P (tmp) && GET_MODE_CLASS (GET_MODE (tmp)) == MODE_INT) + { + *earliest = jump; + + if (reverse) + cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)), + GET_MODE (cond), tmp, XEXP (cond, 1)); + return cond; + } + + /* Otherwise, fall back on canonicalize_condition to do the dirty + work of manipulating MODE_CC values and COMPARE rtx codes. */ + + tmp = canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX); + if (!tmp) + return NULL_RTX; + + /* We are going to insert code before JUMP, not before EARLIEST. + We must therefore be certain that the given condition is valid + at JUMP by virtue of not having been modified since. */ + for (insn = *earliest; insn != jump; insn = NEXT_INSN (insn)) + if (INSN_P (insn) && modified_in_p (tmp, insn)) + break; + if (insn == jump) + return tmp; + + /* The condition was modified. See if we can get a partial result + that doesn't follow all the reversals. Perhaps combine can fold + them together later. */ + tmp = XEXP (tmp, 0); + if (!REG_P (tmp) || GET_MODE_CLASS (GET_MODE (tmp)) != MODE_INT) + return NULL_RTX; + tmp = canonicalize_condition (jump, cond, reverse, earliest, tmp); + if (!tmp) + return NULL_RTX; + + /* For sanity's sake, re-validate the new result. */ + for (insn = *earliest; insn != jump; insn = NEXT_INSN (insn)) + if (INSN_P (insn) && modified_in_p (tmp, insn)) + return NULL_RTX; + + return tmp; +} + +/* 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; + + 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 block. */ + +static int +noce_process_if_block (ce_info) + struct ce_if_block * ce_info; +{ + basic_block test_bb = ce_info->test_bb; /* test block */ + basic_block then_bb = ce_info->then_bb; /* THEN */ + basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */ + struct noce_if_info if_info; + rtx insn_a, insn_b; + rtx set_a, set_b; + rtx orig_x, x, a, b; + rtx jump, cond; + + /* We're looking for patterns of the form + + (1) if (...) x = a; else x = b; + (2) x = b; if (...) x = a; + (3) if (...) x = a; // as if with an initial x = x. + + The later patterns require jumps to be more expensive. + + ??? For future expansion, look for multiple X in such patterns. */ + + /* If test is comprised of && or || elements, don't handle it unless it is + the special case of && elements without an ELSE block. */ + if (ce_info->num_multiple_test_blocks) + { + if (else_bb || ! ce_info->and_and_p) + return FALSE; + + ce_info->test_bb = test_bb = ce_info->last_test_bb; + ce_info->num_multiple_test_blocks = 0; + ce_info->num_and_and_blocks = 0; + ce_info->num_or_or_blocks = 0; + } + + /* If this is not a standard conditional jump, we can't parse it. */ + jump = test_bb->end; + cond = noce_get_condition (jump, &if_info.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; + + /* Look for one of the potential sets. */ + insn_a = first_active_insn (then_bb); + if (! insn_a + || insn_a != last_active_insn (then_bb, FALSE) + || (set_a = single_set (insn_a)) == NULL_RTX) + return FALSE; + + x = SET_DEST (set_a); + a = SET_SRC (set_a); + + /* Look for the other potential set. Make sure we've got equivalent + destinations. */ + /* ??? This is overconservative. Storing to two different mems is + as easy as conditionally computing the address. Storing to a + single mem merely requires a scratch memory to use as one of the + destination addresses; often the memory immediately below the + stack pointer is available for this. */ + set_b = NULL_RTX; + if (else_bb) + { + insn_b = first_active_insn (else_bb); + if (! insn_b + || insn_b != last_active_insn (else_bb, FALSE) + || (set_b = single_set (insn_b)) == NULL_RTX + || ! rtx_equal_p (x, SET_DEST (set_b))) + return FALSE; + } + else + { + insn_b = prev_nonnote_insn (if_info.cond_earliest); + if (! insn_b + || GET_CODE (insn_b) != INSN + || (set_b = single_set (insn_b)) == NULL_RTX + || ! rtx_equal_p (x, SET_DEST (set_b)) + || reg_overlap_mentioned_p (x, cond) + || reg_overlap_mentioned_p (x, a) + || reg_overlap_mentioned_p (x, SET_SRC (set_b)) + || modified_between_p (x, if_info.cond_earliest, NEXT_INSN (jump))) + insn_b = set_b = NULL_RTX; + } + b = (set_b ? SET_SRC (set_b) : x); + + /* Only operate on register destinations, and even then avoid extending + the lifetime of hard registers on small register class machines. */ + orig_x = x; + if (GET_CODE (x) != REG + || (SMALL_REGISTER_CLASSES + && REGNO (x) < FIRST_PSEUDO_REGISTER)) + { + if (no_new_pseudos) + return FALSE; + 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 (! 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; + if_info.insn_b = insn_b; + if_info.x = x; + if_info.a = a; + if_info.b = b; + + /* Try optimizations in some approximation of a useful order. */ + /* ??? Should first look to see if X is live incoming at all. If it + isn't, we don't need anything but an unconditional set. */ + + /* Look and see if A and B are really the same. Avoid creating silly + cmove constructs that no one will fix up later. */ + if (rtx_equal_p (a, b)) + { + /* If we have an INSN_B, we don't have to create any new rtl. Just + move the instruction that we already have. If we don't have an + INSN_B, that means that A == X, and we've got a noop move. In + 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 (jump)); + + /* 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; @@ -1244,9 +1873,7 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb) success: /* The original sets may now be killed. */ - if (insn_a == then_bb->end) - then_bb->end = PREV_INSN (insn_a); - flow_delete_insn (insn_a); + delete_insn (insn_a); /* Several special cases here: First, we may have reused insn_b above, in which case insn_b is now NULL. Second, we want to delete insn_b @@ -1255,31 +1882,26 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb) the TEST block, it may in fact be loading data needed for the comparison. We'll let life_analysis remove the insn if it's really dead. */ if (insn_b && else_bb) - { - if (insn_b == else_bb->end) - else_bb->end = PREV_INSN (insn_b); - flow_delete_insn (insn_b); - } + delete_insn (insn_b); - /* The new insns will have been inserted before cond_earliest. We should - be able to remove the jump with impunity, but the condition itself may - have been modified by gcse to be shared across basic blocks. */ - test_bb->end = PREV_INSN (jump); - flow_delete_insn (jump); + /* The new insns will have been inserted immediately before the jump. We + should be able to remove the jump with impunity, but the condition itself + may have been modified by gcse to be shared across basic blocks. */ + delete_insn (jump); /* If we used a temporary, fix it up now. */ if (orig_x != x) { start_sequence (); - emit_move_insn (orig_x, x); - insn_b = gen_sequence (); + noce_emit_move_insn (copy_rtx (orig_x), x); + insn_b = get_insns (); end_sequence (); - test_bb->end = emit_insn_after (insn_b, test_bb->end); + emit_insn_after_scope (insn_b, test_bb->end, INSN_SCOPE (insn_a)); } /* Merge the blocks! */ - merge_if_block (test_bb, then_bb, else_bb, join_bb); + merge_if_block (ce_info); return TRUE; } @@ -1288,20 +1910,30 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb) straight line code. Return true if successful. */ static int -process_if_block (test_bb, then_bb, else_bb, join_bb) - basic_block test_bb; /* Basic block test is in */ - basic_block then_bb; /* Basic block for THEN block */ - basic_block else_bb; /* Basic block for ELSE block */ - basic_block join_bb; /* Basic block the join label is in */ +process_if_block (ce_info) + struct ce_if_block * ce_info; { if (! reload_completed - && noce_process_if_block (test_bb, then_bb, else_bb, join_bb)) + && noce_process_if_block (ce_info)) return TRUE; - if (HAVE_conditional_execution - && reload_completed - && cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)) - return TRUE; + if (HAVE_conditional_execution && reload_completed) + { + /* If we have && and || tests, try to first handle combining the && and + || tests into the conditional code, and if that fails, go back and + handle it without the && and ||, which at present handles the && case + if there was no ELSE block. */ + if (cond_exec_process_if_block (ce_info, TRUE)) + return TRUE; + + if (ce_info->num_multiple_test_blocks) + { + cancel_changes (0); + + if (cond_exec_process_if_block (ce_info, FALSE)) + return TRUE; + } + } return FALSE; } @@ -1309,31 +1941,61 @@ process_if_block (test_bb, then_bb, else_bb, join_bb) /* Merge the blocks and mark for local life update. */ static void -merge_if_block (test_bb, then_bb, else_bb, join_bb) - basic_block test_bb; /* Basic block test is in */ - basic_block then_bb; /* Basic block for THEN block */ - basic_block else_bb; /* Basic block for ELSE block */ - basic_block join_bb; /* Basic block the join label is in */ +merge_if_block (ce_info) + struct ce_if_block * ce_info; { + basic_block test_bb = ce_info->test_bb; /* last test block */ + basic_block then_bb = ce_info->then_bb; /* THEN */ + basic_block else_bb = ce_info->else_bb; /* ELSE or NULL */ + basic_block join_bb = ce_info->join_bb; /* join block */ basic_block combo_bb; /* All block merging is done into the lower block numbers. */ combo_bb = test_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. */ + /* Merge any basic blocks to handle && and || subtests. Each of + the blocks are on the fallthru path from the predecessor block. */ + if (ce_info->num_multiple_test_blocks > 0) + { + basic_block bb = test_bb; + basic_block last_test_bb = ce_info->last_test_bb; + basic_block fallthru = block_fallthru (bb); + + do + { + bb = fallthru; + fallthru = block_fallthru (bb); + if (post_dominators) + delete_from_dominance_info (post_dominators, bb); + merge_blocks_nomove (combo_bb, bb); + num_removed_blocks++; + } + while (bb != last_test_bb); + } - if (combo_bb->global_live_at_end) - 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++; + /* Merge TEST block into THEN block. Normally the THEN block won't have a + label, but it might if there were || tests. That label's count should be + zero, and it normally should be removed. */ + + if (then_bb) + { + if (combo_bb->global_live_at_end) + COPY_REG_SET (combo_bb->global_live_at_end, + then_bb->global_live_at_end); + if (post_dominators) + delete_from_dominance_info (post_dominators, then_bb); + merge_blocks_nomove (combo_bb, then_bb); + num_removed_blocks++; + } /* The ELSE block, if it existed, had a label. That label count will almost always be zero, but odd things can happen when labels get their addresses taken. */ if (else_bb) { + if (post_dominators) + delete_from_dominance_info (post_dominators, else_bb); merge_blocks_nomove (combo_bb, else_bb); num_removed_blocks++; } @@ -1343,28 +2005,54 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb) if (! join_bb) { + rtx last = combo_bb->end; + /* The outgoing edge for the current COMBO block should already be correct. Verify this. */ if (combo_bb->succ == NULL_EDGE) - abort (); + { + if (find_reg_note (last, REG_NORETURN, NULL)) + ; + else if (GET_CODE (last) == INSN + && GET_CODE (PATTERN (last)) == TRAP_IF + && TRAP_CONDITION (PATTERN (last)) == const_true_rtx) + ; + else + abort (); + } - /* There should sill be a branch at the end of the THEN or ELSE + /* There should still be something 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)) + else if (GET_CODE (last) == JUMP_INSN) + ; + else if (combo_bb->succ->dest == EXIT_BLOCK_PTR + && GET_CODE (last) == CALL_INSN + && SIBLING_CALL_P (last)) + ; + else if ((combo_bb->succ->flags & EDGE_EH) + && can_throw_internal (last)) + ; + else abort (); } /* The JOIN block may have had quite a number of other predecessors too. Since we've already merged the TEST, THEN and ELSE blocks, we should have only one remaining edge from our if-then-else diamond. If there - is more than one remaining edge, it must come from elsewhere. */ - else if (join_bb->pred->pred_next == NULL) + is more than one remaining edge, it must come from elsewhere. There + may be zero incoming edges if the THEN block didn't actually join + back up (as with a call to abort). */ + else if ((join_bb->pred == NULL + || join_bb->pred->pred_next == NULL) + && join_bb != EXIT_BLOCK_PTR) { /* We can merge the JOIN. */ if (combo_bb->global_live_at_end) COPY_REG_SET (combo_bb->global_live_at_end, join_bb->global_live_at_end); + + if (post_dominators) + delete_from_dominance_info (post_dominators, join_bb); merge_blocks_nomove (combo_bb, join_bb); num_removed_blocks++; } @@ -1379,22 +2067,24 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb) abort (); /* Remove the jump and cruft from the end of the COMBO block. */ - tidy_fallthru_edge (combo_bb->succ, combo_bb, join_bb); + if (join_bb != EXIT_BLOCK_PTR) + tidy_fallthru_edge (combo_bb->succ, combo_bb, join_bb); } - /* Make sure we update life info properly. */ - SET_UPDATE_LIFE (combo_bb); - num_updated_if_blocks++; } -/* Find a block ending in a simple IF condition. Return TRUE if - we were able to transform it in some way. */ +/* Find a block ending in a simple IF condition and try to transform it + in some way. When converting a multi-block condition, put the new code + in the first such block and delete the rest. Return a pointer to this + first block if some transformation was done. Return NULL otherwise. */ -static int -find_if_header (test_bb) +static basic_block +find_if_header (test_bb, pass) basic_block test_bb; + int pass; { + ce_if_block_t ce_info; edge then_edge; edge else_edge; @@ -1402,12 +2092,12 @@ find_if_header (test_bb) if ((then_edge = test_bb->succ) == NULL_EDGE || (else_edge = then_edge->succ_next) == NULL_EDGE || else_edge->succ_next != NULL_EDGE) - return FALSE; + return NULL; /* Neither edge should be abnormal. */ if ((then_edge->flags & EDGE_COMPLEX) || (else_edge->flags & EDGE_COMPLEX)) - return FALSE; + return NULL; /* The THEN edge is canonically the one that falls through. */ if (then_edge->flags & EDGE_FALLTHRU) @@ -1420,10 +2110,25 @@ find_if_header (test_bb) } else /* Otherwise this must be a multiway branch of some sort. */ - return FALSE; + return NULL; + + memset ((PTR) &ce_info, '\0', sizeof (ce_info)); + ce_info.test_bb = test_bb; + ce_info.then_bb = then_edge->dest; + ce_info.else_bb = else_edge->dest; + ce_info.pass = pass; + +#ifdef IFCVT_INIT_EXTRA_FIELDS + IFCVT_INIT_EXTRA_FIELDS (&ce_info); +#endif - if (find_if_block (test_bb, then_edge, else_edge)) + if (find_if_block (&ce_info)) 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)) { @@ -1433,43 +2138,230 @@ find_if_header (test_bb) goto success; } - return FALSE; + return NULL; success: if (rtl_dump_file) - fprintf (rtl_dump_file, "Conversion succeeded.\n"); - return TRUE; + fprintf (rtl_dump_file, "Conversion succeeded on pass %d.\n", pass); + return ce_info.test_bb; +} + +/* Return true if a block has two edges, one of which falls through to the next + block, and the other jumps to a specific block, so that we can tell if the + block is part of an && test or an || test. Returns either -1 or the number + of non-note, non-jump, non-USE/CLOBBER insns in the block. */ + +static int +block_jumps_and_fallthru_p (cur_bb, target_bb) + basic_block cur_bb; + basic_block target_bb; +{ + edge cur_edge; + int fallthru_p = FALSE; + int jump_p = FALSE; + rtx insn; + rtx end; + int n_insns = 0; + + if (!cur_bb || !target_bb) + return -1; + + /* If no edges, obviously it doesn't jump or fallthru. */ + if (cur_bb->succ == NULL_EDGE) + return FALSE; + + for (cur_edge = cur_bb->succ; + cur_edge != NULL_EDGE; + cur_edge = cur_edge->succ_next) + { + if (cur_edge->flags & EDGE_COMPLEX) + /* Anything complex isn't what we want. */ + return -1; + + else if (cur_edge->flags & EDGE_FALLTHRU) + fallthru_p = TRUE; + + else if (cur_edge->dest == target_bb) + jump_p = TRUE; + + else + return -1; + } + + if ((jump_p & fallthru_p) == 0) + return -1; + + /* Don't allow calls in the block, since this is used to group && and || + together for conditional execution support. ??? we should support + conditional execution support across calls for IA-64 some day, but + for now it makes the code simpler. */ + end = cur_bb->end; + insn = cur_bb->head; + + while (insn != NULL_RTX) + { + if (GET_CODE (insn) == CALL_INSN) + return -1; + + if (INSN_P (insn) + && GET_CODE (insn) != JUMP_INSN + && GET_CODE (PATTERN (insn)) != USE + && GET_CODE (PATTERN (insn)) != CLOBBER) + n_insns++; + + if (insn == end) + break; + + insn = NEXT_INSN (insn); + } + + return n_insns; } /* Determine if a given basic block heads a simple IF-THEN or IF-THEN-ELSE block. If so, we'll try to convert the insns to not require the branch. - Return TRUE if we were successful at converting the the block. */ + Return TRUE if we were successful at converting the block. */ static int -find_if_block (test_bb, then_edge, else_edge) - basic_block test_bb; - edge then_edge, else_edge; +find_if_block (ce_info) + struct ce_if_block * ce_info; { - basic_block then_bb = then_edge->dest; - basic_block else_bb = else_edge->dest; + basic_block test_bb = ce_info->test_bb; + basic_block then_bb = ce_info->then_bb; + basic_block else_bb = ce_info->else_bb; basic_block join_bb = NULL_BLOCK; edge then_succ = then_bb->succ; edge else_succ = else_bb->succ; - int next_index; + int then_predecessors; + int else_predecessors; + edge cur_edge; + basic_block next; + + ce_info->last_test_bb = test_bb; + + /* Discover if any fall through predecessors of the current test basic block + were && tests (which jump to the else block) or || tests (which jump to + the then block). */ + if (HAVE_conditional_execution && reload_completed + && test_bb->pred != NULL_EDGE + && test_bb->pred->pred_next == NULL_EDGE + && test_bb->pred->flags == EDGE_FALLTHRU) + { + basic_block bb = test_bb->pred->src; + basic_block target_bb; + int max_insns = MAX_CONDITIONAL_EXECUTE; + int n_insns; + + /* Determine if the preceeding block is an && or || block. */ + if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0) + { + ce_info->and_and_p = TRUE; + target_bb = else_bb; + } + else if ((n_insns = block_jumps_and_fallthru_p (bb, then_bb)) >= 0) + { + ce_info->and_and_p = FALSE; + target_bb = then_bb; + } + else + target_bb = NULL_BLOCK; + + if (target_bb && n_insns <= max_insns) + { + int total_insns = 0; + int blocks = 0; + + ce_info->last_test_bb = test_bb; + + /* Found at least one && or || block, look for more. */ + do + { + ce_info->test_bb = test_bb = bb; + total_insns += n_insns; + blocks++; + + if (bb->pred == NULL_EDGE || bb->pred->pred_next != NULL_EDGE) + break; + + bb = bb->pred->src; + n_insns = block_jumps_and_fallthru_p (bb, target_bb); + } + while (n_insns >= 0 && (total_insns + n_insns) <= max_insns); + + ce_info->num_multiple_test_blocks = blocks; + ce_info->num_multiple_test_insns = total_insns; + + if (ce_info->and_and_p) + ce_info->num_and_and_blocks = blocks; + else + ce_info->num_or_or_blocks = blocks; + } + } + + /* Count the number of edges the THEN and ELSE blocks have. */ + then_predecessors = 0; + for (cur_edge = then_bb->pred; + cur_edge != NULL_EDGE; + cur_edge = cur_edge->pred_next) + { + then_predecessors++; + if (cur_edge->flags & EDGE_COMPLEX) + return FALSE; + } - /* The THEN block of an IF-THEN combo must have exactly one predecessor. */ - if (then_bb->pred->pred_next != NULL_EDGE) + else_predecessors = 0; + for (cur_edge = else_bb->pred; + cur_edge != NULL_EDGE; + cur_edge = cur_edge->pred_next) + { + else_predecessors++; + if (cur_edge->flags & EDGE_COMPLEX) + return FALSE; + } + + /* The THEN block of an IF-THEN combo must have exactly one predecessor, + other than any || blocks which jump to the THEN block. */ + if ((then_predecessors - ce_info->num_or_or_blocks) != 1) return FALSE; - /* The THEN block of an IF-THEN combo must have exactly one successor. */ - if (then_succ == NULL_EDGE - || then_succ->succ_next != NULL_EDGE - || (then_succ->flags & EDGE_COMPLEX)) + /* The THEN block of an IF-THEN combo must have zero or one successors. */ + if (then_succ != NULL_EDGE + && (then_succ->succ_next != NULL_EDGE + || (then_succ->flags & EDGE_COMPLEX))) return FALSE; + /* 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. + 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. ??? 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; + } + else + return FALSE; + } + /* If the THEN block's successor is the other edge out of the TEST block, then we have an IF-THEN combo without an ELSE. */ - if (then_succ->dest == else_bb) + else if (then_succ->dest == else_bb) { join_bb = else_bb; else_bb = NULL_BLOCK; @@ -1493,27 +2385,44 @@ find_if_block (test_bb, then_edge, else_edge) if (rtl_dump_file) { + fprintf (rtl_dump_file, "\nIF-THEN%s block found, pass %d, start block %d [insn %d], then %d [%d]", + (else_bb) ? "-ELSE" : "", + ce_info->pass, + test_bb->index, (test_bb->head) ? (int)INSN_UID (test_bb->head) : -1, + then_bb->index, (then_bb->head) ? (int)INSN_UID (then_bb->head) : -1); + if (else_bb) - fprintf (rtl_dump_file, - "\nIF-THEN-ELSE block found, start %d, then %d, else %d, join %d\n", - test_bb->index, then_bb->index, else_bb->index, - join_bb->index); - else - fprintf (rtl_dump_file, - "\nIF-THEN block found, start %d, then %d, join %d\n", - test_bb->index, then_bb->index, join_bb->index); + fprintf (rtl_dump_file, ", else %d [%d]", + else_bb->index, (else_bb->head) ? (int)INSN_UID (else_bb->head) : -1); + + fprintf (rtl_dump_file, ", join %d [%d]", + join_bb->index, (join_bb->head) ? (int)INSN_UID (join_bb->head) : -1); + + if (ce_info->num_multiple_test_blocks > 0) + fprintf (rtl_dump_file, ", %d %s block%s last test %d [%d]", + ce_info->num_multiple_test_blocks, + (ce_info->and_and_p) ? "&&" : "||", + (ce_info->num_multiple_test_blocks == 1) ? "" : "s", + ce_info->last_test_bb->index, + ((ce_info->last_test_bb->head) + ? (int)INSN_UID (ce_info->last_test_bb->head) + : -1)); + + fputc ('\n', rtl_dump_file); } - /* 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 + /* 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. Likewise for the && and || blocks, since + we checked the FALLTHRU flag, those are already adjacent to the last IF + block. */ + /* ??? 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; - if (else_bb && ++next_index != else_bb->index) + next = then_bb; + if (else_bb && (next = next->next_bb) != else_bb) return FALSE; - if (++next_index != join_bb->index) + if ((next = next->next_bb) != join_bb && join_bb != EXIT_BLOCK_PTR) { if (else_bb) join_bb = NULL; @@ -1522,14 +2431,146 @@ find_if_block (test_bb, then_edge, else_edge) } /* Do the real work. */ - return process_if_block (test_bb, then_bb, else_bb, join_bb); + ce_info->else_bb = else_bb; + ce_info->join_bb = join_bb; + + return process_if_block (ce_info); +} + +/* 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 = then_edge->dest; + basic_block else_bb = else_edge->dest; + basic_block other_bb, trap_bb; + rtx trap, jump, cond, cond_earliest, seq; + enum rtx_code code; + + /* 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. */ + if ((trap = block_has_only_trap (then_bb)) != NULL) + trap_bb = then_bb, other_bb = else_bb; + else if ((trap = block_has_only_trap (else_bb)) != NULL) + trap_bb = else_bb, other_bb = then_bb; + else + return FALSE; + + if (rtl_dump_file) + { + fprintf (rtl_dump_file, "\nTRAP-IF block found, start %d, trap %d\n", + test_bb->index, trap_bb->index); + } + + /* 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. */ + emit_insn_before_scope (seq, cond_earliest, INSN_SCOPE (trap)); + + /* Delete the trap block if possible. */ + remove_edge (trap_bb == then_bb ? then_edge : else_edge); + if (trap_bb->pred == NULL) + { + if (post_dominators) + delete_from_dominance_info (post_dominators, trap_bb); + flow_delete_block (trap_bb); + num_removed_blocks++; + } + + /* If the non-trap block and the test are now adjacent, merge them. + Otherwise we must insert a direct branch. */ + if (test_bb->next_bb == other_bb) + { + struct ce_if_block new_ce_info; + delete_insn (jump); + memset ((PTR) &new_ce_info, '\0', sizeof (new_ce_info)); + new_ce_info.test_bb = test_bb; + new_ce_info.then_bb = NULL; + new_ce_info.else_bb = NULL; + new_ce_info.join_bb = other_bb; + merge_if_block (&new_ce_info); + } + else + { + rtx lab, newjump; + + lab = JUMP_LABEL (jump); + newjump = emit_jump_insn_after (gen_jump (lab), jump); + LABEL_NUSES (lab) += 1; + JUMP_LABEL (newjump) = lab; + emit_barrier_after (newjump); + + delete_insn (jump); + } + + return TRUE; +} + +/* Subroutine of find_cond_trap: if BB contains only a trap insn, + return it. */ + +static rtx +block_has_only_trap (bb) + basic_block bb; +{ + rtx trap; + + /* We're not the exit block. */ + if (bb == EXIT_BLOCK_PTR) + return NULL_RTX; + + /* The block must have no successors. */ + if (bb->succ) + return NULL_RTX; + + /* The only instruction in the THEN block must be the trap. */ + trap = first_active_insn (bb); + if (! (trap == bb->end + && GET_CODE (PATTERN (trap)) == TRAP_IF + && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx)) + return NULL_RTX; + + return trap; } /* 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. - Return TRUE if we were successful at converting the the block. + Return TRUE if we were successful at converting the block. Cases we'd like to look at: @@ -1608,9 +2649,9 @@ find_if_case_1 (test_bb, then_edge, else_edge) edge then_edge, else_edge; { basic_block then_bb = then_edge->dest; - basic_block else_bb = else_edge->dest; + basic_block else_bb = else_edge->dest, new_bb; edge then_succ = then_bb->succ; - rtx new_lab; + int then_bb_index; /* THEN has one successor. */ if (!then_succ || then_succ->succ_next != NULL) @@ -1624,8 +2665,8 @@ find_if_case_1 (test_bb, then_edge, else_edge) if (then_bb->pred->pred_next != NULL) return FALSE; - /* ELSE follows THEN. (??? could be moved) */ - if (else_bb->index != then_bb->index + 1) + /* THEN must do something. */ + if (forwarder_block_p (then_bb)) return FALSE; num_possible_if_blocks++; @@ -1638,31 +2679,33 @@ find_if_case_1 (test_bb, then_edge, else_edge) if (count_bb_insns (then_bb) > BRANCH_COST) return FALSE; - /* Find the label for THEN's destination. */ - if (then_succ->dest == EXIT_BLOCK_PTR) - new_lab = NULL_RTX; - else - { - new_lab = JUMP_LABEL (then_bb->end); - if (! new_lab) - abort (); - } - /* Registers set are dead, or are predicable. */ - if (! dead_or_predicable (test_bb, then_bb, else_bb, new_lab, 1)) + if (! dead_or_predicable (test_bb, then_bb, else_bb, + then_bb->succ->dest, 1)) return FALSE; /* Conversion went ok, including moving the insns and fixing up the jump. Adjust the CFG to match. */ - SET_UPDATE_LIFE (test_bb); bitmap_operation (test_bb->global_live_at_end, else_bb->global_live_at_start, then_bb->global_live_at_end, BITMAP_IOR); - make_edge (NULL, test_bb, then_succ->dest, 0); + new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb); + then_bb_index = then_bb->index; + if (post_dominators) + delete_from_dominance_info (post_dominators, then_bb); flow_delete_block (then_bb); - tidy_fallthru_edge (else_edge, test_bb, else_bb); + + /* Make rest of code believe that the newly created block is the THEN_BB + block we removed. */ + if (new_bb) + { + new_bb->index = then_bb_index; + BASIC_BLOCK (then_bb_index) = new_bb; + } + /* We've possibly created jump to next insn, cleanup_cfg will solve that + later. */ num_removed_blocks++; num_updated_if_blocks++; @@ -1680,7 +2723,7 @@ find_if_case_2 (test_bb, then_edge, else_edge) basic_block then_bb = then_edge->dest; basic_block else_bb = else_edge->dest; edge else_succ = else_bb->succ; - rtx new_lab, note; + rtx note; /* ELSE has one successor. */ if (!else_succ || else_succ->succ_next != NULL) @@ -1703,8 +2746,8 @@ find_if_case_2 (test_bb, then_edge, else_edge) if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ; else if (else_succ->dest->index < 0 - || TEST_BIT (post_dominators[ORIG_INDEX (then_bb)], - ORIG_INDEX (else_succ->dest))) + || dominated_by_p (post_dominators, then_bb, + else_succ->dest)) ; else return FALSE; @@ -1716,42 +2759,22 @@ find_if_case_2 (test_bb, then_edge, else_edge) test_bb->index, else_bb->index); /* ELSE is small. */ - if (count_bb_insns (then_bb) > BRANCH_COST) + if (count_bb_insns (else_bb) > BRANCH_COST) return FALSE; - /* Find the label for ELSE's destination. */ - if (else_succ->dest == EXIT_BLOCK_PTR) - new_lab = NULL_RTX; - else - { - if (else_succ->flags & EDGE_FALLTHRU) - { - new_lab = else_succ->dest->head; - if (GET_CODE (new_lab) != CODE_LABEL) - abort (); - } - else - { - new_lab = JUMP_LABEL (else_bb->end); - if (! new_lab) - abort (); - } - } - /* Registers set are dead, or are predicable. */ - if (! dead_or_predicable (test_bb, else_bb, then_bb, new_lab, 0)) + if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0)) return FALSE; /* Conversion went ok, including moving the insns and fixing up the jump. Adjust the CFG to match. */ - SET_UPDATE_LIFE (test_bb); bitmap_operation (test_bb->global_live_at_end, then_bb->global_live_at_start, else_bb->global_live_at_end, BITMAP_IOR); - remove_edge (else_edge); - make_edge (NULL, test_bb, else_succ->dest, 0); + if (post_dominators) + delete_from_dominance_info (post_dominators, else_bb); flow_delete_block (else_bb); num_removed_blocks++; @@ -1785,10 +2808,10 @@ find_memory (px, data) static int dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) basic_block test_bb, merge_bb, other_bb; - rtx new_dest; + basic_block new_dest; int reversep; { - rtx head, end, jump, earliest, old_dest; + rtx head, end, jump, earliest, old_dest, new_label = NULL_RTX; jump = test_bb->end; @@ -1818,6 +2841,9 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) end = PREV_INSN (end); } + /* Disable handling dead code by conditional execution if the machine needs + to do anything funny with the tests, etc. */ +#ifndef IFCVT_MODIFY_TESTS if (HAVE_conditional_execution) { /* In the conditional execution case, we have things easy. We know @@ -1829,6 +2855,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) @@ -1836,19 +2864,23 @@ 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)); } - if (! cond_exec_process_insns (head, end, cond, prob_val, 0)) + if (! cond_exec_process_insns ((ce_if_block_t *)0, head, end, cond, + prob_val, 0)) goto cancel; earliest = jump; } else +#endif { /* In the non-conditional execution case, we have to verify that there are no trapping operations, no calls, no references to memory, and @@ -1873,7 +2905,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) /* ??? Even non-trapping memories such as stack frame references must be avoided. For stores, we collect no lifetime info; for reads, we'd have to assert - true_dependance false against every store in the + true_dependence false against every store in the TEST range. */ if (for_each_rtx (&PATTERN (insn), find_memory, NULL)) return FALSE; @@ -1904,7 +2936,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. */ @@ -1924,7 +2956,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) { @@ -1964,25 +2997,41 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) change group management. */ old_dest = JUMP_LABEL (jump); - if (reversep - ? ! invert_jump_1 (jump, new_dest) - : ! redirect_jump_1 (jump, new_dest)) - goto cancel; + if (other_bb != new_dest) + { + new_label = block_label (new_dest); + if (reversep + ? ! invert_jump_1 (jump, new_label) + : ! redirect_jump_1 (jump, new_label)) + goto cancel; + } if (! apply_change_group ()) return FALSE; - if (old_dest) - LABEL_NUSES (old_dest) -= 1; - if (new_dest) - LABEL_NUSES (new_dest) += 1; - JUMP_LABEL (jump) = new_dest; - - if (reversep) + if (other_bb != new_dest) { - 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))); + if (old_dest) + LABEL_NUSES (old_dest) -= 1; + if (new_label) + LABEL_NUSES (new_label) += 1; + JUMP_LABEL (jump) = new_label; + if (reversep) + invert_br_probabilities (jump); + + redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest); + if (reversep) + { + gcov_type count, probability; + count = BRANCH_EDGE (test_bb)->count; + BRANCH_EDGE (test_bb)->count = FALLTHRU_EDGE (test_bb)->count; + FALLTHRU_EDGE (test_bb)->count = count; + probability = BRANCH_EDGE (test_bb)->probability; + BRANCH_EDGE (test_bb)->probability + = FALLTHRU_EDGE (test_bb)->probability; + FALLTHRU_EDGE (test_bb)->probability = probability; + update_br_prob_note (test_bb); + } } /* Move the insns out of MERGE_BB to before the branch. */ @@ -1991,22 +3040,21 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep) if (end == merge_bb->end) merge_bb->end = PREV_INSN (head); - head = squeeze_notes (head, end); - if (GET_CODE (end) == NOTE - && (NOTE_LINE_NUMBER (end) == NOTE_INSN_BLOCK_END - || NOTE_LINE_NUMBER (end) == NOTE_INSN_BLOCK_BEG - || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_BEG - || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_END - || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_CONT - || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_VTOP)) - { - if (head == end) - return TRUE; - end = PREV_INSN (end); - } + if (squeeze_notes (&head, &end)) + return TRUE; reorder_insns (head, end, PREV_INSN (earliest)); } + + /* Remove the jump and edge if we can. */ + if (other_bb == new_dest) + { + delete_insn (jump); + remove_edge (BRANCH_EDGE (test_bb)); + /* ??? Can't merge blocks here, as then_bb is still in use. + At minimum, the merge will get done just before bb-reorder. */ + } + return TRUE; cancel: @@ -2017,16 +3065,18 @@ 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; + basic_block bb; + int pass; 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 + /* 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. */ free_basic_block_vars (1); @@ -2034,58 +3084,64 @@ if_convert (life_data_ok) post_dominators = NULL; if (HAVE_conditional_execution || life_data_ok) { - post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks); - compute_flow_dominators (NULL, post_dominators); + post_dominators = calculate_dominance_info (CDI_POST_DOMINATORS); } + if (life_data_ok) + clear_bb_flags (); - /* Record initial block numbers. */ - for (block_num = 0; block_num < n_basic_blocks; block_num++) - SET_ORIG_INDEX (BASIC_BLOCK (block_num), block_num); - - /* Go through each of the basic blocks looking for things to convert. */ - for (block_num = 0; block_num < n_basic_blocks; ) + /* Go through each of the basic blocks looking for things to convert. If we + have conditional execution, we make multiple passes to allow us to handle + IF-THEN{-ELSE} blocks within other IF-THEN{-ELSE} blocks. */ + pass = 0; + do { - basic_block bb = BASIC_BLOCK (block_num); - if (find_if_header (bb)) - block_num = bb->index; - else - block_num++; + cond_exec_changed_p = FALSE; + pass++; + +#ifdef IFCVT_MULTIPLE_DUMPS + if (rtl_dump_file && pass > 1) + fprintf (rtl_dump_file, "\n\n========== Pass %d ==========\n", pass); +#endif + + FOR_EACH_BB (bb) + { + basic_block new_bb; + while ((new_bb = find_if_header (bb, pass))) + bb = new_bb; + } + +#ifdef IFCVT_MULTIPLE_DUMPS + if (rtl_dump_file && cond_exec_changed_p) + print_rtl_with_bb (rtl_dump_file, get_insns ()); +#endif } + while (cond_exec_changed_p); + +#ifdef IFCVT_MULTIPLE_DUMPS + if (rtl_dump_file) + fprintf (rtl_dump_file, "\n\n========== no more changes\n"); +#endif if (post_dominators) - sbitmap_vector_free (post_dominators); + free_dominance_info (post_dominators); if (rtl_dump_file) fflush (rtl_dump_file); - /* Rebuild basic_block_for_insn for update_life_info and for gcse. */ - compute_bb_for_insn (get_max_uid ()); + clear_aux_for_blocks (); /* Rebuild life info for basic blocks that require it. */ if (num_removed_blocks && life_data_ok) { - sbitmap update_life_blocks = sbitmap_alloc (n_basic_blocks); - sbitmap_zero (update_life_blocks); - /* If we allocated new pseudos, we must resize the array for sched1. */ if (max_regno < max_reg_num ()) { max_regno = max_reg_num (); allocate_reg_info (max_regno, FALSE, FALSE); } - - for (block_num = 0; block_num < n_basic_blocks; block_num++) - if (UPDATE_LIFE (BASIC_BLOCK (block_num))) - SET_BIT (update_life_blocks, block_num); - - count_or_remove_death_notes (update_life_blocks, 1); - /* ??? See about adding a mode that verifies that the initial - set of blocks don't let registers come live. */ - update_life_info (update_life_blocks, UPDATE_LIFE_GLOBAL, - PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE - | PROP_KILL_DEAD_CODE); - - sbitmap_free (update_life_blocks); + update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES, + PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE + | PROP_KILL_DEAD_CODE); } /* Write the final stats. */