OSDN Git Service

* config/i386/i386.c (ix86_expand_prologue): Use
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index 341e755..21794b3 100644 (file)
@@ -1,5 +1,5 @@
 /* If-conversion support.
-   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 #include "expr.h"
 #include "real.h"
 #include "output.h"
+#include "optabs.h"
 #include "toplev.h"
 #include "tm_p.h"
+#include "cfgloop.h"
+#include "target.h"
 
 
 #ifndef HAVE_conditional_execution
@@ -72,8 +75,8 @@ static int num_possible_if_blocks;
    execution.  */
 static int num_updated_if_blocks;
 
-/* # of basic blocks that were removed.  */
-static int num_removed_blocks;
+/* # of changes made which require life information to be updated.  */
+static int num_true_changes;
 
 /* Whether conditional execution changes were made.  */
 static int cond_exec_changed_p;
@@ -85,37 +88,64 @@ static bool life_data_ok;
 static dominance_info post_dominators;
 
 /* Forward references.  */
-static int count_bb_insns              PARAMS ((basic_block));
-static rtx first_active_insn           PARAMS ((basic_block));
-static rtx last_active_insn            PARAMS ((basic_block, int));
-static int seq_contains_jump           PARAMS ((rtx));
-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 ((ce_if_block_t *, int));
-static rtx noce_get_condition          PARAMS ((rtx, rtx *));
-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, basic_block, int));
-static void noce_emit_move_insn                PARAMS ((rtx, rtx));
-static rtx block_has_only_trap         PARAMS ((basic_block));
+static int count_bb_insns (basic_block);
+static rtx first_active_insn (basic_block);
+static rtx last_active_insn (basic_block, int);
+static int seq_contains_jump (rtx);
+static basic_block block_fallthru (basic_block);
+static int cond_exec_process_insns (ce_if_block_t *, rtx, rtx, rtx, rtx, int);
+static rtx cond_exec_get_condition (rtx);
+static int cond_exec_process_if_block (ce_if_block_t *, int);
+static rtx noce_get_condition (rtx, rtx *);
+static int noce_operand_ok (rtx);
+static int noce_process_if_block (ce_if_block_t *);
+static int process_if_block (ce_if_block_t *);
+static void merge_if_block (ce_if_block_t *);
+static int find_cond_trap (basic_block, edge, edge);
+static basic_block find_if_header (basic_block, int);
+static int block_jumps_and_fallthru_p (basic_block, basic_block);
+static int find_if_block (ce_if_block_t *);
+static int find_if_case_1 (basic_block, edge, edge);
+static int find_if_case_2 (basic_block, edge, edge);
+static int find_memory (rtx *, void *);
+static int dead_or_predicable (basic_block, basic_block, basic_block,
+                              basic_block, int);
+static void noce_emit_move_insn (rtx, rtx);
+static rtx block_has_only_trap (basic_block);
+static void mark_loop_exit_edges (void);
 \f
+/* Sets EDGE_LOOP_EXIT flag for all loop exits.  */
+static void
+mark_loop_exit_edges (void)
+{
+  struct loops loops;
+  basic_block bb;
+  edge e;
+  
+  flow_loops_find (&loops, LOOP_TREE);
+  
+  if (loops.num > 1)
+    {
+      FOR_EACH_BB (bb)
+       {
+         for (e = bb->succ; e; e = e->succ_next)
+           {
+             if (find_common_loop (bb->loop_father, e->dest->loop_father)
+                 != bb->loop_father)
+               e->flags |= EDGE_LOOP_EXIT;
+             else
+               e->flags &= ~EDGE_LOOP_EXIT;
+           }
+       }
+    }
+
+  flow_loops_free (&loops);
+}
+
 /* Count the number of non-jump active insns in BB.  */
 
 static int
-count_bb_insns (bb)
-     basic_block bb;
+count_bb_insns (basic_block bb)
 {
   int count = 0;
   rtx insn = bb->head;
@@ -136,8 +166,7 @@ count_bb_insns (bb)
 /* Return the first non-jump active insn in the basic block.  */
 
 static rtx
-first_active_insn (bb)
-     basic_block bb;
+first_active_insn (basic_block bb)
 {
   rtx insn = bb->head;
 
@@ -164,9 +193,7 @@ first_active_insn (bb)
 /* Return the last non-jump active (non-jump) insn in the basic block.  */
 
 static rtx
-last_active_insn (bb, skip_use_p)
-     basic_block bb;
-     int skip_use_p;
+last_active_insn (basic_block bb, int skip_use_p)
 {
   rtx insn = bb->end;
   rtx head = bb->head;
@@ -188,14 +215,13 @@ last_active_insn (bb, skip_use_p)
   return insn;
 }
 
-/* It is possible, especially when having dealt with multi-word 
+/* It is possible, especially when having dealt with multi-word
    arithmetic, for the expanders to have emitted jumps.  Search
    through the sequence and return TRUE if a jump exists so that
    we can abort the conversion.  */
 
 static int
-seq_contains_jump (insn)
-     rtx insn;
+seq_contains_jump (rtx insn)
 {
   while (insn)
     {
@@ -207,8 +233,7 @@ seq_contains_jump (insn)
 }
 
 static basic_block
-block_fallthru (bb)
-     basic_block bb;
+block_fallthru (basic_block bb)
 {
   edge e;
 
@@ -225,13 +250,12 @@ block_fallthru (bb)
    insns were processed.  */
 
 static int
-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 */
-     rtx prob_val;             /* probability of branch taken.  */
-     int mod_ok;               /* true if modifications ok last insn.  */
+cond_exec_process_insns (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 */rtx prob_val,
+                        /* probability of branch taken. */int mod_ok)
 {
   int must_be_last = FALSE;
   rtx insn;
@@ -252,7 +276,7 @@ cond_exec_process_insns (ce_info, start, end, test, prob_val, mod_ok)
       /* Remove USE insns that get in the way.  */
       if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
        {
-         /* ??? Ug.  Actually unlinking the thing is problematic, 
+         /* ??? Ug.  Actually unlinking the thing is problematic,
             given what we'd have to coordinate with our callers.  */
          PUT_CODE (insn, NOTE);
          NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
@@ -316,8 +340,7 @@ cond_exec_process_insns (ce_info, start, end, test, prob_val, mod_ok)
 /* Return the condition for a jump.  Do not do any special processing.  */
 
 static rtx
-cond_exec_get_condition (jump)
-     rtx jump;
+cond_exec_get_condition (rtx jump)
 {
   rtx test_if, cond;
 
@@ -348,9 +371,8 @@ cond_exec_get_condition (jump)
    converting the block.  */
 
 static int
-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 */
+cond_exec_process_if_block (ce_if_block_t * ce_info,
+                           /* if block information */int do_multiple_p)
 {
   basic_block test_bb = ce_info->test_bb;      /* last test block */
   basic_block then_bb = ce_info->then_bb;      /* THEN */
@@ -415,7 +437,7 @@ cond_exec_process_if_block (ce_info, do_multiple_p)
 
   /* Map test_expr/test_jump into the appropriate MD tests to use on
      the conditionally executed code.  */
-  
+
   true_expr = test_expr;
 
   false_code = reversed_comparison_code (true_expr, test_bb->end);
@@ -565,10 +587,10 @@ cond_exec_process_if_block (ce_info, do_multiple_p)
   return FALSE;
 }
 \f
-/* Used by noce_process_if_block to communicate with its subroutines. 
+/* Used by noce_process_if_block to communicate with its subroutines.
 
    The subroutines know that A and B may be evaluated freely.  They
-   know that X is a register.  They should insert new instructions 
+   know that X is a register.  They should insert new instructions
    before cond_earliest.  */
 
 struct noce_if_info
@@ -579,29 +601,24 @@ struct noce_if_info
   rtx jump, cond, cond_earliest;
 };
 
-static rtx noce_emit_store_flag                PARAMS ((struct noce_if_info *,
-                                                rtx, int, int));
-static int noce_try_store_flag         PARAMS ((struct noce_if_info *));
-static int noce_try_addcc              PARAMS ((struct noce_if_info *));
-static int noce_try_store_flag_constants PARAMS ((struct noce_if_info *));
-static int noce_try_store_flag_mask    PARAMS ((struct noce_if_info *));
-static rtx noce_emit_cmove             PARAMS ((struct noce_if_info *,
-                                                rtx, enum rtx_code, rtx,
-                                                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 *));
+static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int);
+static int noce_try_store_flag (struct noce_if_info *);
+static int noce_try_addcc (struct noce_if_info *);
+static int noce_try_store_flag_constants (struct noce_if_info *);
+static int noce_try_store_flag_mask (struct noce_if_info *);
+static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx,
+                           rtx, rtx, rtx);
+static int noce_try_cmove (struct noce_if_info *);
+static int noce_try_cmove_arith (struct noce_if_info *);
+static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx *);
+static int noce_try_minmax (struct noce_if_info *);
+static int noce_try_abs (struct noce_if_info *);
 
 /* Helper function for noce_try_store_flag*.  */
 
 static rtx
-noce_emit_store_flag (if_info, x, reversep, normalize)
-     struct noce_if_info *if_info;
-     rtx x;
-     int reversep, normalize;
+noce_emit_store_flag (struct noce_if_info *if_info, rtx x, int reversep,
+                     int normalize)
 {
   rtx cond = if_info->cond;
   int cond_complex;
@@ -659,8 +676,7 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
 
 /* Emit instruction to move an rtx into STRICT_LOW_PART.  */
 static void
-noce_emit_move_insn (x, y)
-     rtx x, y;
+noce_emit_move_insn (rtx x, rtx y)
 {
   enum machine_mode outmode, inmode;
   rtx outer, inner;
@@ -688,8 +704,7 @@ noce_emit_move_insn (x, y)
    a go at the conversion.  */
 
 static int
-noce_try_store_flag (if_info)
-     struct noce_if_info *if_info;
+noce_try_store_flag (struct noce_if_info *if_info)
 {
   int reversep;
   rtx target, seq;
@@ -717,7 +732,7 @@ noce_try_store_flag (if_info)
 
       seq = get_insns ();
       end_sequence ();
-      emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
+      emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
 
       return TRUE;
     }
@@ -731,8 +746,7 @@ noce_try_store_flag (if_info)
 /* Convert "if (test) x = a; else x = b", for A and B constant.  */
 
 static int
-noce_try_store_flag_constants (if_info)
-     struct noce_if_info *if_info;
+noce_try_store_flag_constants (struct noce_if_info *if_info)
 {
   rtx target, seq;
   int reversep;
@@ -782,7 +796,7 @@ noce_try_store_flag_constants (if_info)
        return FALSE;
 
       if (reversep)
-       {
+       {
          tmp = itrue; itrue = ifalse; ifalse = tmp;
          diff = trunc_int_for_mode (-diff, mode);
        }
@@ -852,7 +866,7 @@ noce_try_store_flag_constants (if_info)
       if (seq_contains_jump (seq))
        return FALSE;
 
-      emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
+      emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
 
       return TRUE;
     }
@@ -860,12 +874,11 @@ noce_try_store_flag_constants (if_info)
   return FALSE;
 }
 
-/* Convert "if (test) foo++" into "foo += (test != 0)", and 
+/* Convert "if (test) foo++" into "foo += (test != 0)", and
    similarly for "foo--".  */
 
 static int
-noce_try_addcc (if_info)
-     struct noce_if_info *if_info;
+noce_try_addcc (struct noce_if_info *if_info)
 {
   rtx target, seq;
   int subtract, normalize;
@@ -900,13 +913,13 @@ noce_try_addcc (if_info)
 
              seq = get_insns ();
              end_sequence ();
-             emit_insn_before_scope (seq, if_info->jump,
-                                     INSN_SCOPE (if_info->insn_a));
+             emit_insn_before_setloc (seq, if_info->jump,
+                                     INSN_LOCATOR (if_info->insn_a));
              return TRUE;
            }
          end_sequence ();
        }
-       
+
       /* If that fails, construct conditional increment or decrement using
         setcc.  */
       if (BRANCH_COST >= 2
@@ -942,8 +955,8 @@ noce_try_addcc (if_info)
              if (seq_contains_jump (seq))
                return FALSE;
 
-             emit_insn_before_scope (seq, if_info->jump,
-                                     INSN_SCOPE (if_info->insn_a));
+             emit_insn_before_setloc (seq, if_info->jump,
+                                     INSN_LOCATOR (if_info->insn_a));
 
              return TRUE;
            }
@@ -957,8 +970,7 @@ noce_try_addcc (if_info)
 /* Convert "if (test) x = 0;" to "x &= -(test == 0);"  */
 
 static int
-noce_try_store_flag_mask (if_info)
-     struct noce_if_info *if_info;
+noce_try_store_flag_mask (struct noce_if_info *if_info)
 {
   rtx target, seq;
   int reversep;
@@ -995,8 +1007,8 @@ noce_try_store_flag_mask (if_info)
          if (seq_contains_jump (seq))
            return FALSE;
 
-         emit_insn_before_scope (seq, if_info->jump,
-                                 INSN_SCOPE (if_info->insn_a));
+         emit_insn_before_setloc (seq, if_info->jump,
+                                 INSN_LOCATOR (if_info->insn_a));
 
          return TRUE;
        }
@@ -1010,10 +1022,8 @@ noce_try_store_flag_mask (if_info)
 /* Helper function for noce_try_cmove and noce_try_cmove_arith.  */
 
 static rtx
-noce_emit_cmove (if_info, x, code, cmp_a, cmp_b, vfalse, vtrue)
-     struct noce_if_info *if_info;
-     rtx x, cmp_a, cmp_b, vfalse, vtrue;
-     enum rtx_code code;
+noce_emit_cmove (struct noce_if_info *if_info, rtx x, enum rtx_code code,
+                rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue)
 {
   /* If earliest == jump, try to build the cmove insn directly.
      This is helpful when combine has created some complex condition
@@ -1056,7 +1066,7 @@ noce_emit_cmove (if_info, x, code, cmp_a, cmp_b, vfalse, vtrue)
 #else
   /* We'll never get here, as noce_process_if_block doesn't call the
      functions involved.  Ifdef code, however, should be discouraged
-     because it leads to typos in the code not selected.  However, 
+     because it leads to typos in the code not selected.  However,
      emit_conditional_move won't exist either.  */
   return NULL_RTX;
 #endif
@@ -1067,8 +1077,7 @@ noce_emit_cmove (if_info, x, code, cmp_a, cmp_b, vfalse, vtrue)
    has had a go at it.  */
 
 static int
-noce_try_cmove (if_info)
-     struct noce_if_info *if_info;
+noce_try_cmove (struct noce_if_info *if_info)
 {
   enum rtx_code code;
   rtx target, seq;
@@ -1091,8 +1100,8 @@ noce_try_cmove (if_info)
 
          seq = get_insns ();
          end_sequence ();
-         emit_insn_before_scope (seq, if_info->jump,
-                                 INSN_SCOPE (if_info->insn_a));
+         emit_insn_before_setloc (seq, if_info->jump,
+                                 INSN_LOCATOR (if_info->insn_a));
          return TRUE;
        }
       else
@@ -1108,8 +1117,7 @@ noce_try_cmove (if_info)
 /* Try more complex cases involving conditional_move.  */
 
 static int
-noce_try_cmove_arith (if_info)
-     struct noce_if_info *if_info;
+noce_try_cmove_arith (struct noce_if_info *if_info)
 {
   rtx a = if_info->a;
   rtx b = if_info->b;
@@ -1145,7 +1153,7 @@ noce_try_cmove_arith (if_info)
        if (test)
          x = y;
   */
-  
+
   code = GET_CODE (if_info->cond);
   insn_a = if_info->insn_a;
   insn_b = if_info->insn_b;
@@ -1171,7 +1179,7 @@ noce_try_cmove_arith (if_info)
 
   /* If either operand is complex, load it into a register first.
      The best way to do this is to copy the original insn.  In this
-     way we preserve any clobbers etc that the insn may have had.  
+     way we preserve any clobbers etc that the insn may have had.
      This is of course not possible in the IS_MEM case.  */
   if (! general_operand (a, GET_MODE (a)))
     {
@@ -1254,7 +1262,7 @@ noce_try_cmove_arith (if_info)
 
   tmp = get_insns ();
   end_sequence ();
-  emit_insn_before_scope (tmp, if_info->jump, INSN_SCOPE (if_info->insn_a));
+  emit_insn_before_setloc (tmp, if_info->jump, INSN_LOCATOR (if_info->insn_a));
   return TRUE;
 
  end_seq_and_fail:
@@ -1267,10 +1275,8 @@ noce_try_cmove_arith (if_info)
    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;
+noce_get_alt_condition (struct noce_if_info *if_info, rtx target,
+                       rtx *earliest)
 {
   rtx cond, set, insn;
   int reverse;
@@ -1391,7 +1397,7 @@ noce_get_alt_condition (if_info, target, earliest)
     }
 
   cond = canonicalize_condition (if_info->jump, cond, reverse,
-                                earliest, target);
+                                earliest, target, false);
   if (! cond || ! reg_mentioned_p (target, cond))
     return NULL;
 
@@ -1416,9 +1422,8 @@ noce_get_alt_condition (if_info, target, earliest)
 /* 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;
-{ 
+noce_try_minmax (struct noce_if_info *if_info)
+{
   rtx cond, earliest, target, seq;
   enum rtx_code code, op;
   int unsignedp;
@@ -1501,12 +1506,12 @@ noce_try_minmax (if_info)
     noce_emit_move_insn (if_info->x, target);
 
   seq = get_insns ();
-  end_sequence ();  
+  end_sequence ();
 
   if (seq_contains_jump (seq))
     return FALSE;
 
-  emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
+  emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
   if_info->cond = cond;
   if_info->cond_earliest = earliest;
 
@@ -1516,9 +1521,8 @@ noce_try_minmax (if_info)
 /* 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;
-{ 
+noce_try_abs (struct noce_if_info *if_info)
+{
   rtx cond, earliest, target, seq, a, b, c;
   int negate;
 
@@ -1538,7 +1542,7 @@ noce_try_abs (if_info)
     }
   else
     return FALSE;
-   
+
   cond = noce_get_alt_condition (if_info, b, &earliest);
   if (!cond)
     return FALSE;
@@ -1559,7 +1563,7 @@ noce_try_abs (if_info)
       for (insn = earliest;
           insn != if_info->test_bb->head;
           insn = PREV_INSN (insn))
-       if (INSN_P (insn) 
+       if (INSN_P (insn)
            && ((note = find_reg_note (insn, REG_EQUAL, c))
                || (note = find_reg_note (insn, REG_EQUIV, c))))
          break;
@@ -1573,7 +1577,7 @@ noce_try_abs (if_info)
     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 
+     Note that these rtx constants are known to be CONST_INT, and
      therefore imply integer comparisons.  */
   if (c == constm1_rtx && GET_CODE (cond) == GT)
     ;
@@ -1602,7 +1606,7 @@ noce_try_abs (if_info)
 
   start_sequence ();
 
-  target = expand_simple_unop (GET_MODE (if_info->x), ABS, b, if_info->x, 0);
+  target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
 
   /* ??? It's a quandry whether cmove would be better here, especially
      for integers.  Perhaps combine will clean things up.  */
@@ -1619,12 +1623,12 @@ noce_try_abs (if_info)
     noce_emit_move_insn (if_info->x, target);
 
   seq = get_insns ();
-  end_sequence ();  
+  end_sequence ();
 
   if (seq_contains_jump (seq))
     return FALSE;
 
-  emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
+  emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATOR (if_info->insn_a));
   if_info->cond = cond;
   if_info->cond_earliest = earliest;
 
@@ -1635,9 +1639,7 @@ noce_try_abs (if_info)
    valid at JUMP, instead of at EARLIEST.  */
 
 static rtx
-noce_get_condition (jump, earliest)
-     rtx jump;
-     rtx *earliest;
+noce_get_condition (rtx jump, rtx *earliest)
 {
   rtx cond, set, tmp, insn;
   bool reverse;
@@ -1669,7 +1671,8 @@ noce_get_condition (jump, earliest)
   /* 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);
+  tmp = canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX,
+                               false);
   if (!tmp)
     return NULL_RTX;
 
@@ -1688,7 +1691,8 @@ noce_get_condition (jump, earliest)
   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);
+  tmp = canonicalize_condition (jump, cond, reverse, earliest, tmp,
+                               false);
   if (!tmp)
     return NULL_RTX;
 
@@ -1703,8 +1707,7 @@ noce_get_condition (jump, earliest)
 /* Return true if OP is ok for if-then-else processing.  */
 
 static int
-noce_operand_ok (op)
-     rtx op;
+noce_operand_ok (rtx op)
 {
   /* We special-case memories, so handle any of them with
      no address side effects.  */
@@ -1722,8 +1725,7 @@ noce_operand_ok (op)
    successful at converting the block.  */
 
 static int
-noce_process_if_block (ce_info)
-     struct ce_if_block * ce_info;
+noce_process_if_block (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 */
@@ -1802,17 +1804,33 @@ noce_process_if_block (ce_info)
   else
     {
       insn_b = prev_nonnote_insn (if_info.cond_earliest);
+      /* We're going to be moving the evaluation of B down from above
+        COND_EARLIEST to JUMP.  Make sure the relevant data is still
+        intact.  */
       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 (SET_SRC (set_b),
-                                PREV_INSN (if_info.cond_earliest), jump))
+                                PREV_INSN (if_info.cond_earliest), jump)
+         /* Likewise with X.  In particular this can happen when
+            noce_get_condition looks farther back in the instruction
+            stream than one might expect.  */
+         || reg_overlap_mentioned_p (x, cond)
+         || reg_overlap_mentioned_p (x, a)
+         || modified_between_p (x, PREV_INSN (if_info.cond_earliest), jump))
        insn_b = set_b = NULL_RTX;
     }
+
+  /* If x has side effects then only the if-then-else form is safe to
+     convert.  But even in that case we would need to restore any notes
+     (such as REG_INC) at then end.  That can be tricky if
+     noce_emit_move_insn expands to more than one insn, so disable the
+     optimization entirely for now if there are side effects.  */
+  if (side_effects_p (x))
+    return FALSE;
+
   b = (set_b ? SET_SRC (set_b) : x);
 
   /* Only operate on register destinations, and even then avoid extending
@@ -1822,7 +1840,7 @@ noce_process_if_block (ce_info)
       || (SMALL_REGISTER_CLASSES
          && REGNO (x) < FIRST_PSEUDO_REGISTER))
     {
-      if (no_new_pseudos)
+      if (no_new_pseudos || GET_MODE (x) == BLKmode)
        return FALSE;
       x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
                                 ? XEXP (x, 0) : x));
@@ -1873,7 +1891,7 @@ noce_process_if_block (ce_info)
         x must be executed twice.  */
       else if (insn_b && side_effects_p (orig_x))
        return FALSE;
-       
+
       x = orig_x;
       goto success;
     }
@@ -1928,7 +1946,7 @@ noce_process_if_block (ce_info)
       insn_b = get_insns ();
       end_sequence ();
 
-      emit_insn_after_scope (insn_b, test_bb->end, INSN_SCOPE (insn_a));
+      emit_insn_after_setloc (insn_b, test_bb->end, INSN_LOCATOR (insn_a));
     }
 
   /* Merge the blocks!  */
@@ -1941,8 +1959,7 @@ noce_process_if_block (ce_info)
    straight line code.  Return true if successful.  */
 
 static int
-process_if_block (ce_info)
-     struct ce_if_block * ce_info;
+process_if_block (struct ce_if_block * ce_info)
 {
   if (! reload_completed
       && noce_process_if_block (ce_info))
@@ -1972,8 +1989,7 @@ process_if_block (ce_info)
 /* Merge the blocks and mark for local life update.  */
 
 static void
-merge_if_block (ce_info)
-     struct ce_if_block * ce_info;
+merge_if_block (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 */
@@ -1992,15 +2008,15 @@ merge_if_block (ce_info)
       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++;
+         merge_blocks (combo_bb, bb);
+         num_true_changes++;
        }
       while (bb != last_test_bb);
     }
@@ -2016,8 +2032,8 @@ merge_if_block (ce_info)
                      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++;
+      merge_blocks (combo_bb, then_bb);
+      num_true_changes++;
     }
 
   /* The ELSE block, if it existed, had a label.  That label count
@@ -2027,8 +2043,8 @@ merge_if_block (ce_info)
     {
       if (post_dominators)
        delete_from_dominance_info (post_dominators, else_bb);
-      merge_blocks_nomove (combo_bb, else_bb);
-      num_removed_blocks++;
+      merge_blocks (combo_bb, else_bb);
+      num_true_changes++;
     }
 
   /* If there was no join block reported, that means it was not adjacent
@@ -2071,7 +2087,7 @@ merge_if_block (ce_info)
      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.  There
-     may be zero incoming edges if the THEN block didn't actually join 
+     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)
@@ -2084,8 +2100,8 @@ merge_if_block (ce_info)
 
       if (post_dominators)
        delete_from_dominance_info (post_dominators, join_bb);
-      merge_blocks_nomove (combo_bb, join_bb);
-      num_removed_blocks++;
+      merge_blocks (combo_bb, join_bb);
+      num_true_changes++;
     }
   else
     {
@@ -2111,9 +2127,7 @@ merge_if_block (ce_info)
    first block if some transformation was done.  Return NULL otherwise.  */
 
 static basic_block
-find_if_header (test_bb, pass)
-     basic_block test_bb;
-     int pass;
+find_if_header (basic_block test_bb, int pass)
 {
   ce_if_block_t ce_info;
   edge then_edge;
@@ -2130,6 +2144,11 @@ find_if_header (test_bb, pass)
       || (else_edge->flags & EDGE_COMPLEX))
     return NULL;
 
+  /* Nor exit the loop.  */
+  if ((then_edge->flags & EDGE_LOOP_EXIT)
+      || (else_edge->flags & EDGE_LOOP_EXIT))
+    return NULL;
+
   /* The THEN edge is canonically the one that falls through.  */
   if (then_edge->flags & EDGE_FALLTHRU)
     ;
@@ -2143,7 +2162,7 @@ find_if_header (test_bb, pass)
     /* Otherwise this must be a multiway branch of some sort.  */
     return NULL;
 
-  memset ((PTR) &ce_info, '\0', sizeof (ce_info));
+  memset (&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;
@@ -2183,9 +2202,7 @@ find_if_header (test_bb, pass)
    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;
+block_jumps_and_fallthru_p (basic_block cur_bb, basic_block target_bb)
 {
   edge cur_edge;
   int fallthru_p = FALSE;
@@ -2254,8 +2271,7 @@ block_jumps_and_fallthru_p (cur_bb, target_bb)
    Return TRUE if we were successful at converting the block.  */
 
 static int
-find_if_block (ce_info)
-     struct ce_if_block * ce_info;
+find_if_block (struct ce_if_block * ce_info)
 {
   basic_block test_bb = ce_info->test_bb;
   basic_block then_bb = ce_info->then_bb;
@@ -2291,7 +2307,7 @@ find_if_block (ce_info)
        }
       else if ((n_insns = block_jumps_and_fallthru_p (bb, then_bb)) >= 0)
        {
-         ce_info->and_and_p = FALSE;     
+         ce_info->and_and_p = FALSE;
          target_bb = then_bb;
        }
       else
@@ -2358,7 +2374,8 @@ find_if_block (ce_info)
   /* 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)))
+          || (then_succ->flags & EDGE_COMPLEX)
+         || (flow2_completed && tablejump_p (then_bb->end, NULL, NULL))))
     return FALSE;
 
   /* If the THEN block has no successors, conditional execution can still
@@ -2405,12 +2422,13 @@ find_if_block (ce_info)
           && then_succ->dest == else_succ->dest
           && else_bb->pred->pred_next == NULL_EDGE
           && else_succ->succ_next == NULL_EDGE
-          && ! (else_succ->flags & EDGE_COMPLEX))
+          && ! (else_succ->flags & EDGE_COMPLEX)
+          && ! (flow2_completed && tablejump_p (else_bb->end, NULL, NULL)))
     join_bb = else_succ->dest;
 
   /* Otherwise it is not an IF-THEN or IF-THEN-ELSE combination.  */
   else
-    return FALSE;         
+    return FALSE;
 
   num_possible_if_blocks++;
 
@@ -2472,9 +2490,7 @@ find_if_block (ce_info)
    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;
+find_cond_trap (basic_block test_bb, edge then_edge, edge else_edge)
 {
   basic_block then_bb = then_edge->dest;
   basic_block else_bb = else_edge->dest;
@@ -2528,8 +2544,10 @@ find_cond_trap (test_bb, then_edge, else_edge)
   if (seq == NULL)
     return FALSE;
 
+  num_true_changes++;
+
   /* Emit the new insns before cond_earliest.  */
-  emit_insn_before_scope (seq, cond_earliest, INSN_SCOPE (trap));
+  emit_insn_before_setloc (seq, cond_earliest, INSN_LOCATOR (trap));
 
   /* Delete the trap block if possible.  */
   remove_edge (trap_bb == then_bb ? then_edge : else_edge);
@@ -2537,8 +2555,7 @@ find_cond_trap (test_bb, then_edge, else_edge)
     {
       if (post_dominators)
        delete_from_dominance_info (post_dominators, trap_bb);
-      flow_delete_block (trap_bb);
-      num_removed_blocks++;
+      delete_block (trap_bb);
     }
 
   /* If the non-trap block and the test are now adjacent, merge them.
@@ -2547,7 +2564,7 @@ find_cond_trap (test_bb, then_edge, else_edge)
     {
       struct ce_if_block new_ce_info;
       delete_insn (jump);
-      memset ((PTR) &new_ce_info, '\0', sizeof (new_ce_info));
+      memset (&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;
@@ -2570,12 +2587,11 @@ find_cond_trap (test_bb, then_edge, else_edge)
   return TRUE;
 }
 
-/* Subroutine of find_cond_trap: if BB contains only a trap insn, 
+/* Subroutine of find_cond_trap: if BB contains only a trap insn,
    return it.  */
 
 static rtx
-block_has_only_trap (bb)
-     basic_block bb;
+block_has_only_trap (basic_block bb)
 {
   rtx trap;
 
@@ -2675,9 +2691,7 @@ block_has_only_trap (bb)
 /* Tests for case 1 above.  */
 
 static int
-find_if_case_1 (test_bb, then_edge, else_edge)
-      basic_block test_bb;
-      edge then_edge, else_edge;
+find_if_case_1 (basic_block test_bb, edge then_edge, edge else_edge)
 {
   basic_block then_bb = then_edge->dest;
   basic_block else_bb = else_edge->dest, new_bb;
@@ -2711,7 +2725,7 @@ find_if_case_1 (test_bb, then_edge, else_edge)
     return FALSE;
 
   /* Registers set are dead, or are predicable.  */
-  if (! dead_or_predicable (test_bb, then_bb, else_bb, 
+  if (! dead_or_predicable (test_bb, then_bb, else_bb,
                            then_bb->succ->dest, 1))
     return FALSE;
 
@@ -2721,12 +2735,12 @@ find_if_case_1 (test_bb, then_edge, else_edge)
   bitmap_operation (test_bb->global_live_at_end,
                    else_bb->global_live_at_start,
                    then_bb->global_live_at_end, BITMAP_IOR);
-  
+
   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);
+  delete_block (then_bb);
 
   /* Make rest of code believe that the newly created block is the THEN_BB
      block we removed.  */
@@ -2734,11 +2748,13 @@ find_if_case_1 (test_bb, then_edge, else_edge)
     {
       new_bb->index = then_bb_index;
       BASIC_BLOCK (then_bb_index) = new_bb;
+      if (post_dominators)
+       add_to_dominance_info (post_dominators, new_bb);
     }
   /* We've possibly created jump to next insn, cleanup_cfg will solve that
      later.  */
 
-  num_removed_blocks++;
+  num_true_changes++;
   num_updated_if_blocks++;
 
   return TRUE;
@@ -2747,9 +2763,7 @@ find_if_case_1 (test_bb, then_edge, else_edge)
 /* Test for case 2 above.  */
 
 static int
-find_if_case_2 (test_bb, then_edge, else_edge)
-      basic_block test_bb;
-      edge then_edge, else_edge;
+find_if_case_2 (basic_block test_bb, edge then_edge, edge else_edge)
 {
   basic_block then_bb = then_edge->dest;
   basic_block else_bb = else_edge->dest;
@@ -2777,7 +2791,7 @@ 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
-          || dominated_by_p (post_dominators, then_bb, 
+          || dominated_by_p (post_dominators, then_bb,
                              else_succ->dest))
     ;
   else
@@ -2803,12 +2817,12 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   bitmap_operation (test_bb->global_live_at_end,
                    then_bb->global_live_at_start,
                    else_bb->global_live_at_end, BITMAP_IOR);
-  
+
   if (post_dominators)
     delete_from_dominance_info (post_dominators, else_bb);
-  flow_delete_block (else_bb);
+  delete_block (else_bb);
 
-  num_removed_blocks++;
+  num_true_changes++;
   num_updated_if_blocks++;
 
   /* ??? We may now fallthru from one of THEN's successors into a join
@@ -2821,9 +2835,7 @@ find_if_case_2 (test_bb, then_edge, else_edge)
    Return 1 if a memory is found.  */
 
 static int
-find_memory (px, data)
-     rtx *px;
-     void *data ATTRIBUTE_UNUSED;
+find_memory (rtx *px, void *data ATTRIBUTE_UNUSED)
 {
   return GET_CODE (*px) == MEM;
 }
@@ -2837,10 +2849,8 @@ find_memory (px, data)
    REVERSEP is true if the sense of the branch should be reversed.  */
 
 static int
-dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
-     basic_block test_bb, merge_bb, other_bb;
-     basic_block new_dest;
-     int reversep;
+dead_or_predicable (basic_block test_bb, basic_block merge_bb,
+                   basic_block other_bb, basic_block new_dest, int reversep)
 {
   rtx head, end, jump, earliest, old_dest, new_label = NULL_RTX;
 
@@ -2965,7 +2975,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
       test_set = INITIALIZE_REG_SET (test_set_head);
 
       /* ??? bb->local_set is only valid during calculate_global_regs_live,
-        so we must recompute usage for MERGE_BB.  Not so bad, I suppose, 
+        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, merge_set, 0);
 
@@ -3096,19 +3106,21 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 /* Main entry point for all if-conversion.  */
 
 void
-if_convert (x_life_data_ok)
-     int x_life_data_ok;
+if_convert (int x_life_data_ok)
 {
   basic_block bb;
   int pass;
 
   num_possible_if_blocks = 0;
   num_updated_if_blocks = 0;
-  num_removed_blocks = 0;
+  num_true_changes = 0;
   life_data_ok = (x_life_data_ok != 0);
 
+  if (! (* targetm.cannot_modify_jumps_p) ())
+    mark_loop_exit_edges ();
+
   /* 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.  */
+     up to date, either here or in merge_blocks.  */
   free_basic_block_vars (1);
 
   /* Compute postdominators if we think we'll use them.  */
@@ -3162,7 +3174,7 @@ if_convert (x_life_data_ok)
   clear_aux_for_blocks ();
 
   /* Rebuild life info for basic blocks that require it.  */
-  if (num_removed_blocks && life_data_ok)
+  if (num_true_changes && life_data_ok)
     {
       /* If we allocated new pseudos, we must resize the array for sched1.  */
       if (max_regno < max_reg_num ())
@@ -3185,8 +3197,8 @@ if_convert (x_life_data_ok)
               "%d IF blocks converted.\n",
               num_updated_if_blocks);
       fprintf (rtl_dump_file,
-              "%d basic blocks deleted.\n\n\n",
-              num_removed_blocks);
+              "%d true changes made.\n\n\n",
+              num_true_changes);
     }
 
 #ifdef ENABLE_CHECKING