OSDN Git Service

Fix bad regexp
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index 6ad1d35..f46a6cf 100644 (file)
@@ -1,22 +1,22 @@
 /* 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 "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"
 
 
 #ifndef HAVE_decscc
 #define HAVE_decscc 0
 #endif
+#ifndef HAVE_trap
+#define HAVE_trap 0
+#endif
+#ifndef HAVE_conditional_trap
+#define HAVE_conditional_trap 0
+#endif
 
 #ifndef MAX_CONDITIONAL_EXECUTE
 #define MAX_CONDITIONAL_EXECUTE   (BRANCH_COST + 1)
@@ -64,6 +73,9 @@ static int num_updated_if_blocks;
 /* # of basic blocks that were removed.  */
 static int num_removed_blocks;
 
+/* True if life data ok at present.  */
+static bool life_data_ok;
+
 /* The post-dominator relation on the original block numbers.  */
 static sbitmap *post_dominators;
 
@@ -79,6 +91,7 @@ static int cond_exec_process_if_block PARAMS ((basic_block, basic_block,
                                                 basic_block, basic_block));
 
 static rtx noce_get_condition          PARAMS ((rtx, rtx *));
+static int noce_operand_ok             PARAMS ((rtx));
 static int noce_process_if_block       PARAMS ((basic_block, basic_block,
                                                 basic_block, basic_block));
 
@@ -91,18 +104,19 @@ static int find_if_header          PARAMS ((basic_block));
 static int find_if_block               PARAMS ((basic_block, edge, edge));
 static int find_if_case_1              PARAMS ((basic_block, edge, edge));
 static int find_if_case_2              PARAMS ((basic_block, edge, edge));
+static int find_cond_trap              PARAMS ((basic_block, edge, edge));
+static rtx block_has_only_trap         PARAMS ((basic_block));
 static int find_memory                 PARAMS ((rtx *, void *));
 static int dead_or_predicable          PARAMS ((basic_block, basic_block,
-                                                basic_block, rtx, int));
+                                                basic_block, basic_block, int));
+static void noce_emit_move_insn                PARAMS ((rtx, rtx));
 \f
 /* 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)
+#define SET_ORIG_INDEX(BB,I)   ((BB)->aux = (void *)((size_t)(I)))
+#define ORIG_INDEX(BB)         ((size_t)(BB)->aux)
 
 \f
 /* Count the number of non-jump active insns in BB.  */
@@ -284,9 +298,14 @@ cond_exec_get_condition (jump)
      reverse the condition.  */
   if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
       && XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump))
-    cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                          GET_MODE (cond), XEXP (cond, 0),
-                          XEXP (cond, 1));
+    {
+      enum rtx_code rev = reversed_comparison_code (cond, jump);
+      if (rev == UNKNOWN)
+       return NULL_RTX;
+
+      cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
+                            XEXP (cond, 1));
+    }
 
   return cond;
 }
@@ -307,13 +326,14 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   rtx then_end;                        /* last insn + 1 in THEN block */
   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 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;
 
   /* Find the conditional jump to the ELSE or JOIN part, and isolate
      the test.  */
@@ -375,9 +395,13 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
      the conditionally executed code.  */
   
   true_expr = test_expr;
-  false_expr = gen_rtx_fmt_ee (reverse_condition (GET_CODE (true_expr)),
-                              GET_MODE (true_expr), XEXP (true_expr, 0),
-                              XEXP (true_expr, 1));
+
+  false_code = reversed_comparison_code (true_expr, test_bb->end);
+  if (false_code != UNKNOWN)
+    false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr),
+                                XEXP (true_expr, 0), XEXP (true_expr, 1));
+  else
+    false_expr = NULL_RTX;
 
 #ifdef IFCVT_MODIFY_TESTS
   /* If the machine description needs to modify the tests, such as setting a
@@ -407,8 +431,9 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
      to conditional execution.  */
 
   if (then_end
-      && ! cond_exec_process_insns (then_start, then_end,
-                                   false_expr, false_prob_val, then_mod_ok))
+      && (! false_expr
+         || ! cond_exec_process_insns (then_start, then_end, false_expr,
+                                       false_prob_val, then_mod_ok)))
     goto fail;
 
   if (else_bb
@@ -451,6 +476,7 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
 
 struct noce_if_info
 {
+  basic_block test_bb;
   rtx insn_a, insn_b;
   rtx x, a, b;
   rtx jump, cond, cond_earliest;
@@ -467,6 +493,10 @@ static rtx noce_emit_cmove         PARAMS ((struct noce_if_info *,
                                                 rtx, rtx, rtx));
 static int noce_try_cmove              PARAMS ((struct noce_if_info *));
 static int noce_try_cmove_arith                PARAMS ((struct noce_if_info *));
+static rtx noce_get_alt_condition      PARAMS ((struct noce_if_info *,
+                                                rtx, rtx *));
+static int noce_try_minmax             PARAMS ((struct noce_if_info *));
+static int noce_try_abs                        PARAMS ((struct noce_if_info *));
 
 /* Helper function for noce_try_store_flag*.  */
 
@@ -487,17 +517,18 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
      build the store_flag insn directly.  */
 
   if (cond_complex)
-    cond = XEXP (SET_SRC (PATTERN (if_info->jump)), 0);
+    cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0);
+
+  if (reversep)
+    code = reversed_comparison_code (cond, if_info->jump);
+  else
+    code = GET_CODE (cond);
 
   if ((if_info->cond_earliest == if_info->jump || cond_complex)
       && (normalize == 0 || STORE_FLAG_VALUE == normalize))
     {
       rtx tmp;
 
-      code = GET_CODE (cond);
-      if (reversep)
-       code = reverse_condition (code);
-
       tmp = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
                            XEXP (cond, 1));
       tmp = gen_rtx_SET (VOIDmode, x, tmp);
@@ -523,16 +554,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
@@ -553,7 +604,8 @@ noce_try_store_flag (if_info)
   else if (if_info->b == const0_rtx
           && GET_CODE (if_info->a) == CONST_INT
           && INTVAL (if_info->a) == STORE_FLAG_VALUE
-          && can_reverse_comparison_p (if_info->cond, if_info->jump))
+          && (reversed_comparison_code (if_info->cond, if_info->jump)
+              != UNKNOWN))
     reversep = 1;
   else
     return FALSE;
@@ -564,7 +616,7 @@ noce_try_store_flag (if_info)
   if (target)
     {
       if (target != if_info->x)
-       emit_move_insn (if_info->x, target);
+       noce_emit_move_insn (if_info->x, target);
 
       seq = get_insns ();
       end_sequence ();
@@ -589,16 +641,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)
@@ -626,7 +687,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 ();
@@ -641,42 +702,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)
@@ -686,7 +747,7 @@ noce_try_store_flag_constants (if_info)
        }
 
       if (target != if_info->x)
-       emit_move_insn (if_info->x, target);
+       noce_emit_move_insn (if_info->x, target);
 
       seq = get_insns ();
       end_sequence ();
@@ -722,7 +783,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;
@@ -738,13 +800,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 ();
@@ -778,8 +841,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))))
     {
@@ -788,14 +852,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 ();
@@ -894,7 +958,7 @@ noce_try_cmove (if_info)
       if (target)
        {
          if (target != if_info->x)
-           emit_move_insn (if_info->x, target);
+           noce_emit_move_insn (if_info->x, target);
 
          seq = get_insns ();
          end_sequence ();
@@ -957,7 +1021,7 @@ noce_try_cmove_arith (if_info)
   insn_b = if_info->insn_b;
 
   /* Possibly rearrange operands to make things come out more natural.  */
-  if (can_reverse_comparison_p (if_info->cond, if_info->jump))
+  if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
     {
       int reversep = 0;
       if (rtx_equal_p (b, x))
@@ -967,7 +1031,7 @@ noce_try_cmove_arith (if_info)
 
       if (reversep)
        {
-         code = reverse_condition (code);
+         code = reversed_comparison_code (if_info->cond, if_info->jump);
          tmp = a, a = b, b = tmp;
          tmp = insn_a, insn_a = insn_b, insn_b = tmp;
        }
@@ -1049,12 +1113,14 @@ 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 ();
@@ -1066,6 +1132,375 @@ noce_try_cmove_arith (if_info)
   return FALSE;
 }
 
+/* For most cases, the simplified condition we found is the best
+   choice, but this is not the case for the min/max/abs transforms.
+   For these we wish to know that it is A or B in the condition.  */
+
+static rtx
+noce_get_alt_condition (if_info, target, earliest)
+     struct noce_if_info *if_info;
+     rtx target;
+     rtx *earliest;
+{
+  rtx cond, set, insn;
+  int reverse;
+
+  /* If target is already mentioned in the known condition, return it.  */
+  if (reg_mentioned_p (target, if_info->cond))
+    {
+      *earliest = if_info->cond_earliest;
+      return if_info->cond;
+    }
+
+  set = pc_set (if_info->jump);
+  cond = XEXP (SET_SRC (set), 0);
+  reverse
+    = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
+      && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump);
+
+  /* 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:
+
+     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)
+    {
+      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);
+               }
+           }
+       }
+
+      /* 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);
+
+         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;
+           }
+       }
+
+      /* 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;
+       }
+    }
+
+  cond = canonicalize_condition (if_info->jump, cond, reverse,
+                                earliest, target);
+  if (! cond || ! reg_mentioned_p (target, cond))
+    return NULL;
+
+  /* We almost certainly searched back to a different place.
+     Need to re-verify correct lifetimes.  */
+
+  /* X may not be mentioned in the range (cond_earliest, jump].  */
+  for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn))
+    if (INSN_P (insn) && reg_mentioned_p (if_info->x, insn))
+      return NULL;
+
+  /* A and B may not be modified in the range [cond_earliest, jump).  */
+  for (insn = *earliest; insn != if_info->jump; insn = NEXT_INSN (insn))
+    if (INSN_P (insn)
+       && (modified_in_p (if_info->a, insn)
+           || modified_in_p (if_info->b, insn)))
+      return NULL;
+
+  return cond;
+}
+
+/* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc.  */
+
+static int
+noce_try_minmax (if_info)
+     struct noce_if_info *if_info;
+{ 
+  rtx cond, earliest, target, seq;
+  enum rtx_code code, op;
+  int unsignedp;
+
+  /* ??? Can't guarantee that expand_binop won't create pseudos.  */
+  if (no_new_pseudos)
+    return FALSE;
+
+  /* ??? 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;
+
+  cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
+  if (!cond)
+    return FALSE;
+
+  /* Verify the condition is of the form we expect, and canonicalize
+     the comparison code.  */
+  code = GET_CODE (cond);
+  if (rtx_equal_p (XEXP (cond, 0), if_info->a))
+    {
+      if (! rtx_equal_p (XEXP (cond, 1), if_info->b))
+       return FALSE;
+    }
+  else if (rtx_equal_p (XEXP (cond, 1), if_info->a))
+    {
+      if (! rtx_equal_p (XEXP (cond, 0), if_info->b))
+       return FALSE;
+      code = swap_condition (code);
+    }
+  else
+    return FALSE;
+
+  /* Determine what sort of operation this is.  Note that the code is for
+     a taken branch, so the code->operation mapping appears backwards.  */
+  switch (code)
+    {
+    case LT:
+    case LE:
+    case UNLT:
+    case UNLE:
+      op = SMAX;
+      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;
+    }
+
+  start_sequence ();
+
+  target = expand_simple_binop (GET_MODE (if_info->x), op,
+                               if_info->a, if_info->b,
+                               if_info->x, unsignedp, OPTAB_WIDEN);
+  if (! target)
+    {
+      end_sequence ();
+      return FALSE;
+    }
+  if (target != if_info->x)
+    noce_emit_move_insn (if_info->x, target);
+
+  seq = get_insns ();
+  end_sequence ();  
+
+  if (seq_contains_jump (seq))
+    return FALSE;
+
+  emit_insns_before (seq, earliest);
+  if_info->cond = cond;
+  if_info->cond_earliest = earliest;
+
+  return TRUE;
+}
+
+/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", etc.  */
+
+static int
+noce_try_abs (if_info)
+     struct noce_if_info *if_info;
+{ 
+  rtx cond, earliest, target, seq, a, b, c;
+  int negate;
+
+  /* ??? Can't guarantee that expand_binop won't create pseudos.  */
+  if (no_new_pseudos)
+    return FALSE;
+
+  /* Recognize A and B as constituting an ABS or NABS.  */
+  a = if_info->a;
+  b = if_info->b;
+  if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b))
+    negate = 0;
+  else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a))
+    {
+      c = a; a = b; b = c;
+      negate = 1;
+    }
+  else
+    return FALSE;
+   
+  cond = noce_get_alt_condition (if_info, b, &earliest);
+  if (!cond)
+    return FALSE;
+
+  /* Verify the condition is of the form we expect.  */
+  if (rtx_equal_p (XEXP (cond, 0), b))
+    c = XEXP (cond, 1);
+  else if (rtx_equal_p (XEXP (cond, 1), b))
+    c = XEXP (cond, 0);
+  else
+    return FALSE;
+
+  /* Verify that C is zero.  Search backward through the block for
+     a REG_EQUAL note if necessary.  */
+  if (REG_P (c))
+    {
+      rtx insn, note = NULL;
+      for (insn = earliest;
+          insn != if_info->test_bb->head;
+          insn = PREV_INSN (insn))
+       if (INSN_P (insn) 
+           && ((note = find_reg_note (insn, REG_EQUAL, c))
+               || (note = find_reg_note (insn, REG_EQUIV, c))))
+         break;
+      if (! note)
+       return FALSE;
+      c = XEXP (note, 0);
+    }
+  if (GET_CODE (c) == MEM
+      && GET_CODE (XEXP (c, 0)) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (XEXP (c, 0)))
+    c = get_pool_constant (XEXP (c, 0));
+
+  /* Work around funny ideas get_condition has wrt canonicalization.
+     Note that these rtx constants are known to be CONST_INT, and 
+     therefore imply integer comparisons.  */
+  if (c == constm1_rtx && GET_CODE (cond) == GT)
+    ;
+  else if (c == const1_rtx && GET_CODE (cond) == LT)
+    ;
+  else if (c != CONST0_RTX (GET_MODE (b)))
+    return FALSE;
+
+  /* Determine what sort of operation this is.  */
+  switch (GET_CODE (cond))
+    {
+    case LT:
+    case LE:
+    case UNLT:
+    case UNLE:
+      negate = !negate;
+      break;
+    case GT:
+    case GE:
+    case UNGT:
+    case UNGE:
+      break;
+    default:
+      return FALSE;
+    }
+
+  start_sequence ();
+
+  target = expand_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_insns_before (seq, earliest);
+  if_info->cond = cond;
+  if_info->cond_earliest = earliest;
+
+  return TRUE;
+}
+
 /* Look for the condition for the jump first.  We'd prefer to avoid
    get_condition if we can -- it tries to look back for the contents
    of an original compare.  On targets that use normal integers for
@@ -1107,6 +1542,23 @@ noce_get_condition (jump, earliest)
   return cond;
 }
 
+/* Return true if OP is ok for if-then-else processing.  */
+
+static int
+noce_operand_ok (op)
+     rtx op;
+{
+  /* We special-case memories, so handle any of them with
+     no address side effects.  */
+  if (GET_CODE (op) == MEM)
+    return ! side_effects_p (XEXP (op, 0));
+
+  if (side_effects_p (op))
+    return FALSE;
+
+  return ! may_trap_p (op);
+}
+
 /* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
    without using conditional execution.  Return TRUE if we were
    successful at converting the the block.  */
@@ -1210,16 +1662,16 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
     {
       if (no_new_pseudos)
        return FALSE;
-      x = gen_reg_rtx (GET_MODE (x));
+      x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
+                                ? XEXP (x, 0) : x));
     }
 
   /* Don't operate on sources that may trap or are volatile.  */
-  if (side_effects_p (a) || side_effects_p (b)
-      || (GET_CODE (a) != MEM && may_trap_p (a))
-      || (GET_CODE (b) != MEM && may_trap_p (b)))
+  if (! noce_operand_ok (a) || ! noce_operand_ok (b))
     return FALSE;
 
   /* Set up the info block for our subroutines.  */
+  if_info.test_bb = test_bb;
   if_info.cond = cond;
   if_info.jump = jump;
   if_info.insn_a = insn_a;
@@ -1242,9 +1694,17 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
         that case don't do anything and let the code below delete INSN_A.  */
       if (insn_b && else_bb)
        {
+         rtx note;
+
          if (else_bb && insn_b == else_bb->end)
            else_bb->end = PREV_INSN (insn_b);
          reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
+
+         /* If there was a REG_EQUAL note, delete it since it may have been
+            true due to this insn being after a jump.  */
+         if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0)
+           remove_note (insn_b, note);
+
          insn_b = NULL_RTX;
        }
       /* If we have "x = b; if (...) x = a;", and x has side-effects, then
@@ -1258,6 +1718,10 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
 
   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;
@@ -1278,9 +1742,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
@@ -1289,27 +1751,22 @@ 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);
+  delete_insn (jump);
 
   /* If we used a temporary, fix it up now.  */
   if (orig_x != x)
     {
       start_sequence ();
-      emit_move_insn (orig_x, x);
+      noce_emit_move_insn (copy_rtx (orig_x), x);
       insn_b = gen_sequence ();
       end_sequence ();
 
-      test_bb->end = emit_insn_after (insn_b, test_bb->end);
+      emit_insn_after (insn_b, test_bb->end);
     }
 
   /* Merge the blocks!  */
@@ -1357,11 +1814,14 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
 
   /* First merge TEST block into THEN block.  This is a no-brainer since
      the THEN block did not have a code label to begin with.  */
-
-  if (combo_bb->global_live_at_end)
-    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++;
+  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);
+      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
@@ -1377,15 +1837,34 @@ 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 ();
     }
 
@@ -1395,7 +1874,9 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
      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)
+  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)
@@ -1415,12 +1896,10 @@ 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++;
 }
 \f
@@ -1460,6 +1939,9 @@ find_if_header (test_bb)
 
   if (find_if_block (test_bb, then_edge, else_edge))
     goto success;
+  if (HAVE_trap && HAVE_conditional_trap
+      && find_cond_trap (test_bb, then_edge, else_edge))
+    goto success;
   if (post_dominators
       && (! HAVE_conditional_execution || reload_completed))
     {
@@ -1572,13 +2054,13 @@ find_if_block (test_bb, then_edge, else_edge)
   /* Make sure IF, THEN, and ELSE, blocks are adjacent.  Actually, we
      get the first condition for free, since we've already asserted that
      there's a fallthru edge from IF to THEN.  */
-  /* ??? As an enhancement, move the ELSE block.  Have to deal with EH and
+  /* ??? As an enhancement, move the ELSE block.  Have to deal with
      BLOCK notes, if by no other means than aborting the merge if they
      exist.  Sticky enough I don't want to think about it now.  */
   next_index = then_bb->index;
   if (else_bb && ++next_index != else_bb->index)
     return FALSE;
-  if (++next_index != join_bb->index)
+  if (++next_index != join_bb->index && join_bb->index != EXIT_BLOCK)
     {
       if (else_bb)
        join_bb = NULL;
@@ -1590,6 +2072,128 @@ find_if_block (test_bb, then_edge, else_edge)
   return process_if_block (test_bb, then_bb, else_bb, join_bb);
 }
 
+/* Convert a branch over a trap, or a branch to a trap,
+   into a conditional trap.  */
+
+static int
+find_cond_trap (test_bb, then_edge, else_edge)
+     basic_block test_bb;
+     edge then_edge, else_edge;
+{
+  basic_block then_bb, else_bb, trap_bb, other_bb;
+  rtx trap, jump, cond, cond_earliest, seq;
+  enum rtx_code code;
+
+  then_bb = then_edge->dest;
+  else_bb = else_edge->dest;
+
+  /* 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 (seq, cond_earliest);
+
+  /* Delete the trap block if possible.  */
+  remove_edge (trap_bb == then_bb ? then_edge : else_edge);
+  if (trap_bb->pred == NULL)
+    {
+      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->index + 1 == other_bb->index)
+    {
+      delete_insn (jump);
+      merge_if_block (test_bb, NULL, NULL, other_bb);
+    }
+  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.
@@ -1673,9 +2277,8 @@ 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;
 
   /* THEN has one successor.  */
   if (!then_succ || then_succ->succ_next != NULL)
@@ -1689,8 +2292,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++;
@@ -1703,31 +2306,26 @@ 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);
+  /* Make rest of code believe that the newly created block is the THEN_BB
+     block we are going to remove.  */
+  if (new_bb)
+    new_bb->aux = then_bb->aux;
   flow_delete_block (then_bb);
-  tidy_fallthru_edge (else_edge, test_bb, else_bb);
+  /* We've possibly created jump to next insn, cleanup_cfg will solve that
+     later.  */
 
   num_removed_blocks++;
   num_updated_if_blocks++;
@@ -1745,7 +2343,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)
@@ -1784,39 +2382,17 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   if (count_bb_insns (then_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);
   flow_delete_block (else_bb);
 
   num_removed_blocks++;
@@ -1850,10 +2426,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;
 
@@ -1897,6 +2473,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)
@@ -1904,8 +2482,10 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 
       if (reversep)
        {
-         cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                                GET_MODE (cond), XEXP (cond, 0),
+         enum rtx_code rev = reversed_comparison_code (cond, jump);
+         if (rev == UNKNOWN)
+           return FALSE;
+         cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
                                 XEXP (cond, 1));
          if (prob_val)
            prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
@@ -1942,7 +2522,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;
@@ -1973,7 +2553,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.  */
@@ -1993,7 +2573,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)
        {
@@ -2033,25 +2614,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.  */
@@ -2060,22 +2657,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:
@@ -2086,14 +2682,15 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 /* Main entry point for all if-conversion.  */
 
 void
-if_convert (life_data_ok)
-     int life_data_ok;
+if_convert (x_life_data_ok)
+     int x_life_data_ok;
 {
   int block_num;
 
   num_possible_if_blocks = 0;
   num_updated_if_blocks = 0;
   num_removed_blocks = 0;
+  life_data_ok = (x_life_data_ok != 0);
 
   /* Free up basic_block_for_insn so that we don't have to keep it 
      up to date, either here or in merge_blocks_nomove.  */
@@ -2106,6 +2703,8 @@ if_convert (life_data_ok)
       post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
       calculate_dominance_info (NULL, post_dominators, 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++)
@@ -2127,34 +2726,20 @@ if_convert (life_data_ok)
   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.  */