OSDN Git Service

Merge basic-improvements-branch to trunk
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index 3b15c14..0652afd 100644 (file)
@@ -1,25 +1,27 @@
 /* If-conversion support.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "rtl.h"
 #include "regs.h"
 #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)
 #endif
 
-#define EDGE_COMPLEX   (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_EH)
-
 #define NULL_EDGE      ((struct edge_def *)NULL)
 #define NULL_BLOCK     ((struct basic_block_def *)NULL)
 
@@ -66,45 +75,41 @@ static int num_updated_if_blocks;
 /* # of basic blocks that were removed.  */
 static int num_removed_blocks;
 
+/* Whether conditional execution changes were made.  */
+static int cond_exec_changed_p;
+
+/* True if life data ok at present.  */
+static bool life_data_ok;
+
 /* The post-dominator relation on the original block numbers.  */
-static sbitmap *post_dominators;
+static dominance_info post_dominators;
 
 /* Forward references.  */
 static int count_bb_insns              PARAMS ((basic_block));
 static rtx first_active_insn           PARAMS ((basic_block));
-static int last_active_insn_p          PARAMS ((basic_block, rtx));
-
-static int cond_exec_process_insns     PARAMS ((rtx, rtx, rtx, rtx, int));
+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 ((basic_block, basic_block,
-                                                basic_block, basic_block));
-
+static int cond_exec_process_if_block  PARAMS ((ce_if_block_t *, int));
 static rtx noce_get_condition          PARAMS ((rtx, rtx *));
-static int noce_process_if_block       PARAMS ((basic_block, basic_block,
-                                                basic_block, basic_block));
-
-static int process_if_block            PARAMS ((basic_block, basic_block,
-                                                basic_block, basic_block));
-static void merge_if_block             PARAMS ((basic_block, basic_block,
-                                                basic_block, basic_block));
-
-static int find_if_header              PARAMS ((basic_block));
-static int find_if_block               PARAMS ((basic_block, edge, edge));
+static int noce_operand_ok             PARAMS ((rtx));
+static int noce_process_if_block       PARAMS ((ce_if_block_t *));
+static int process_if_block            PARAMS ((ce_if_block_t *));
+static void merge_if_block             PARAMS ((ce_if_block_t *));
+static int find_cond_trap              PARAMS ((basic_block, edge, edge));
+static basic_block find_if_header      PARAMS ((basic_block, int));
+static int block_jumps_and_fallthru_p  PARAMS ((basic_block, basic_block));
+static int find_if_block               PARAMS ((ce_if_block_t *));
 static int find_if_case_1              PARAMS ((basic_block, edge, edge));
 static int find_if_case_2              PARAMS ((basic_block, edge, edge));
 static int find_memory                 PARAMS ((rtx *, void *));
 static int dead_or_predicable          PARAMS ((basic_block, basic_block,
-                                                basic_block, rtx, int));
-\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)
-
+                                                basic_block, basic_block, int));
+static void noce_emit_move_insn                PARAMS ((rtx, rtx));
+static rtx block_has_only_trap         PARAMS ((basic_block));
 \f
 /* Count the number of non-jump active insns in BB.  */
 
@@ -156,22 +161,63 @@ first_active_insn (bb)
   return insn;
 }
 
-/* Return true if INSN is the last active non-jump insn in BB.  */
+/* Return the last non-jump active (non-jump) insn in the basic block.  */
 
-static int
-last_active_insn_p (bb, insn)
+static rtx
+last_active_insn (bb, skip_use_p)
      basic_block bb;
+     int skip_use_p;
+{
+  rtx insn = bb->end;
+  rtx head = bb->head;
+
+  while (GET_CODE (insn) == NOTE
+        || GET_CODE (insn) == JUMP_INSN
+        || (skip_use_p
+            && GET_CODE (insn) == INSN
+            && GET_CODE (PATTERN (insn)) == USE))
+    {
+      if (insn == head)
+       return NULL_RTX;
+      insn = PREV_INSN (insn);
+    }
+
+  if (GET_CODE (insn) == CODE_LABEL)
+    return NULL_RTX;
+
+  return insn;
+}
+
+/* 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;
 {
-  do
+  while (insn)
     {
-      if (insn == bb->end)
-       return TRUE;
+      if (GET_CODE (insn) == JUMP_INSN)
+       return 1;
       insn = NEXT_INSN (insn);
     }
-  while (GET_CODE (insn) == NOTE);
+  return 0;
+}
+
+static basic_block
+block_fallthru (bb)
+     basic_block bb;
+{
+  edge e;
+
+  for (e = bb->succ;
+       e != NULL_EDGE && (e->flags & EDGE_FALLTHRU) == 0;
+       e = e->succ_next)
+    ;
 
-  return GET_CODE (insn) == JUMP_INSN;
+  return (e) ? e->dest : NULL_BLOCK;
 }
 \f
 /* Go through a bunch of insns, converting them to conditional
@@ -179,7 +225,8 @@ last_active_insn_p (bb, insn)
    insns were processed.  */
 
 static int
-cond_exec_process_insns (start, end, test, prob_val, mod_ok)
+cond_exec_process_insns (ce_info, start, end, test, prob_val, mod_ok)
+     ce_if_block_t *ce_info ATTRIBUTE_UNUSED;  /* if block information */
      rtx start;                        /* first insn to look at */
      rtx end;                  /* last insn to look at */
      rtx test;                 /* conditional execution test */
@@ -188,6 +235,11 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok)
 {
   int must_be_last = FALSE;
   rtx insn;
+  rtx xtest;
+  rtx pattern;
+
+  if (!start || !end)
+    return FALSE;
 
   for (insn = start; ; insn = NEXT_INSN (insn))
     {
@@ -197,10 +249,8 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok)
       if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
        abort ();
 
-      /* Remove USE and CLOBBER insns that get in the way.  */
-      if (reload_completed
-         && (GET_CODE (PATTERN (insn)) == USE
-             || GET_CODE (PATTERN (insn)) == CLOBBER))
+      /* Remove USE insns that get in the way.  */
+      if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
        {
          /* ??? Ug.  Actually unlinking the thing is problematic, 
             given what we'd have to coordinate with our callers.  */
@@ -222,9 +272,33 @@ cond_exec_process_insns (start, end, test, prob_val, mod_ok)
        }
 
       /* Now build the conditional form of the instruction.  */
-      validate_change (insn, &PATTERN (insn),
-                      gen_rtx_COND_EXEC (VOIDmode, copy_rtx (test),
-                                         PATTERN (insn)), 1);
+      pattern = PATTERN (insn);
+      xtest = copy_rtx (test);
+
+      /* If this is already a COND_EXEC, rewrite the test to be an AND of the
+         two conditions.  */
+      if (GET_CODE (pattern) == COND_EXEC)
+       {
+         if (GET_MODE (xtest) != GET_MODE (COND_EXEC_TEST (pattern)))
+           return FALSE;
+
+         xtest = gen_rtx_AND (GET_MODE (xtest), xtest,
+                              COND_EXEC_TEST (pattern));
+         pattern = COND_EXEC_CODE (pattern);
+       }
+
+      pattern = gen_rtx_COND_EXEC (VOIDmode, xtest, pattern);
+
+      /* If the machine needs to modify the insn being conditionally executed,
+         say for example to force a constant integer operand into a temp
+         register, do so here.  */
+#ifdef IFCVT_MODIFY_INSN
+      IFCVT_MODIFY_INSN (ce_info, pattern, insn);
+      if (! pattern)
+       return FALSE;
+#endif
+
+      validate_change (insn, &PATTERN (insn), pattern, 1);
 
       if (GET_CODE (insn) == CALL_INSN && prob_val)
        validate_change (insn, &REG_NOTES (insn),
@@ -247,10 +321,8 @@ cond_exec_get_condition (jump)
 {
   rtx test_if, cond;
 
-  if (condjump_p (jump))
-    test_if = SET_SRC (PATTERN (jump));
-  else if (condjump_in_parallel_p (jump))
-    test_if = SET_SRC (XVECEXP (PATTERN (jump), 0, 0));
+  if (any_condjump_p (jump))
+    test_if = SET_SRC (pc_set (jump));
   else
     return NULL_RTX;
   cond = XEXP (test_if, 0);
@@ -259,36 +331,57 @@ cond_exec_get_condition (jump)
      reverse the condition.  */
   if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
       && XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump))
-    cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                          GET_MODE (cond), XEXP (cond, 0),
-                          XEXP (cond, 1));
+    {
+      enum rtx_code rev = reversed_comparison_code (cond, jump);
+      if (rev == UNKNOWN)
+       return NULL_RTX;
+
+      cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
+                            XEXP (cond, 1));
+    }
 
   return cond;
 }
 
 /* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
    to conditional execution.  Return TRUE if we were successful at
-   converting the the block.  */
+   converting the block.  */
 
 static int
-cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
-     basic_block test_bb;      /* Basic block test is in */
-     basic_block then_bb;      /* Basic block for THEN block */
-     basic_block else_bb;      /* Basic block for ELSE block */
-     basic_block join_bb;      /* Basic block the join label is in */
+cond_exec_process_if_block (ce_info, do_multiple_p)
+     ce_if_block_t * ce_info;  /* if block information */
+     int do_multiple_p;                /* != 0 if we should handle && and || blocks */
 {
+  basic_block test_bb = ce_info->test_bb;      /* last test block */
+  basic_block then_bb = ce_info->then_bb;      /* THEN */
+  basic_block else_bb = ce_info->else_bb;      /* ELSE or NULL */
   rtx test_expr;               /* expression in IF_THEN_ELSE that is tested */
   rtx then_start;              /* first insn in THEN block */
   rtx then_end;                        /* last insn + 1 in THEN block */
-  rtx else_start;              /* first insn in ELSE block or NULL */
-  rtx else_end;                        /* last insn + 1 in ELSE block */
-  int max;                     /* max # of insns to convert. */
+  rtx else_start = NULL_RTX;   /* first insn in ELSE block or NULL */
+  rtx else_end = NULL_RTX;     /* last insn + 1 in ELSE block */
+  int max;                     /* max # of insns to convert.  */
   int then_mod_ok;             /* whether conditional mods are ok in THEN */
   rtx true_expr;               /* test for else block insns */
   rtx false_expr;              /* test for then block insns */
   rtx true_prob_val;           /* probability of else block */
   rtx false_prob_val;          /* probability of then block */
   int n_insns;
+  enum rtx_code false_code;
+
+  /* If test is comprised of && or || elements, and we've failed at handling
+     all of them together, just use the last test if it is the special case of
+     && elements without an ELSE block.  */
+  if (!do_multiple_p && ce_info->num_multiple_test_blocks)
+    {
+      if (else_bb || ! ce_info->and_and_p)
+       return FALSE;
+
+      ce_info->test_bb = test_bb = ce_info->last_test_bb;
+      ce_info->num_multiple_test_blocks = 0;
+      ce_info->num_and_and_blocks = 0;
+      ce_info->num_or_or_blocks = 0;
+    }
 
   /* Find the conditional jump to the ELSE or JOIN part, and isolate
      the test.  */
@@ -296,48 +389,27 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   if (! test_expr)
     return FALSE;
 
-  /* Collect the bounds of where we're to search.  */
-
-  then_start = then_bb->head;
-  then_end = then_bb->end;
-
-  /* Skip a label heading THEN block.  */
-  if (GET_CODE (then_start) == CODE_LABEL)
-    then_start = NEXT_INSN (then_start);
+  /* If the conditional jump is more than just a conditional jump,
+     then we can not do conditional execution conversion on this block.  */
+  if (! onlyjump_p (test_bb->end))
+    return FALSE;
 
-  /* Skip a (use (const_int 0)) or branch as the final insn.  */
-  if (GET_CODE (then_end) == INSN
-      && GET_CODE (PATTERN (then_end)) == USE
-      && GET_CODE (XEXP (PATTERN (then_end), 0)) == CONST_INT)
-    then_end = PREV_INSN (then_end);
-  else if (GET_CODE (then_end) == JUMP_INSN)
-    then_end = PREV_INSN (then_end);
+  /* Collect the bounds of where we're to search, skipping any labels, jumps
+     and notes at the beginning and end of the block.  Then count the total
+     number of insns and see if it is small enough to convert.  */
+  then_start = first_active_insn (then_bb);
+  then_end = last_active_insn (then_bb, TRUE);
+  n_insns = ce_info->num_then_insns = count_bb_insns (then_bb);
+  max = MAX_CONDITIONAL_EXECUTE;
 
   if (else_bb)
     {
-      /* Skip the ELSE block's label.  */
-      else_start = NEXT_INSN (else_bb->head);
-      else_end = else_bb->end;
-
-      /* Skip a (use (const_int 0)) or branch as the final insn.  */
-      if (GET_CODE (else_end) == INSN
-         && GET_CODE (PATTERN (else_end)) == USE
-         && GET_CODE (XEXP (PATTERN (else_end), 0)) == CONST_INT)
-       else_end = PREV_INSN (else_end);
-      else if (GET_CODE (else_end) == JUMP_INSN)
-       else_end = PREV_INSN (else_end);
+      max *= 2;
+      else_start = first_active_insn (else_bb);
+      else_end = last_active_insn (else_bb, TRUE);
+      n_insns += ce_info->num_else_insns = count_bb_insns (else_bb);
     }
 
-  /* How many instructions should we convert in total?  */
-  n_insns = 0;
-  if (else_bb)
-    {
-      max = 2 * MAX_CONDITIONAL_EXECUTE;
-      n_insns = count_bb_insns (else_bb);
-    }
-  else
-    max = MAX_CONDITIONAL_EXECUTE;
-  n_insns += count_bb_insns (then_bb);
   if (n_insns > max)
     return FALSE;
 
@@ -345,9 +417,23 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
      the conditionally executed code.  */
   
   true_expr = test_expr;
-  false_expr = gen_rtx_fmt_ee (reverse_condition (GET_CODE (true_expr)),
-                              GET_MODE (true_expr), XEXP (true_expr, 0),
-                              XEXP (true_expr, 1));
+
+  false_code = reversed_comparison_code (true_expr, test_bb->end);
+  if (false_code != UNKNOWN)
+    false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr),
+                                XEXP (true_expr, 0), XEXP (true_expr, 1));
+  else
+    false_expr = NULL_RTX;
+
+#ifdef IFCVT_MODIFY_TESTS
+  /* If the machine description needs to modify the tests, such as setting a
+     conditional execution register from a comparison, it can do so here.  */
+  IFCVT_MODIFY_TESTS (ce_info, true_expr, false_expr);
+
+  /* See if the conversion failed */
+  if (!true_expr || !false_expr)
+    goto fail;
+#endif
 
   true_prob_val = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX);
   if (true_prob_val)
@@ -358,6 +444,72 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   else
     false_prob_val = NULL_RTX;
 
+  /* If we have && or || tests, do them here.  These tests are in the adjacent
+     blocks after the first block containing the test.  */
+  if (ce_info->num_multiple_test_blocks > 0)
+    {
+      basic_block bb = test_bb;
+      basic_block last_test_bb = ce_info->last_test_bb;
+
+      if (! false_expr)
+       goto fail;
+
+      do
+       {
+         rtx start, end;
+         rtx t, f;
+
+         bb = block_fallthru (bb);
+         start = first_active_insn (bb);
+         end = last_active_insn (bb, TRUE);
+         if (start
+             && ! cond_exec_process_insns (ce_info, start, end, false_expr,
+                                           false_prob_val, FALSE))
+           goto fail;
+
+         /* If the conditional jump is more than just a conditional jump, then
+            we can not do conditional execution conversion on this block.  */
+         if (! onlyjump_p (bb->end))
+           goto fail;
+
+         /* Find the conditional jump and isolate the test.  */
+         t = cond_exec_get_condition (bb->end);
+         if (! t)
+           goto fail;
+
+         f = gen_rtx_fmt_ee (reverse_condition (GET_CODE (t)),
+                             GET_MODE (t),
+                             XEXP (t, 0),
+                             XEXP (t, 1));
+
+         if (ce_info->and_and_p)
+           {
+             t = gen_rtx_AND (GET_MODE (t), true_expr, t);
+             f = gen_rtx_IOR (GET_MODE (t), false_expr, f);
+           }
+         else
+           {
+             t = gen_rtx_IOR (GET_MODE (t), true_expr, t);
+             f = gen_rtx_AND (GET_MODE (t), false_expr, f);
+           }
+
+         /* If the machine description needs to modify the tests, such as
+            setting a conditional execution register from a comparison, it can
+            do so here.  */
+#ifdef IFCVT_MODIFY_MULTIPLE_TESTS
+         IFCVT_MODIFY_MULTIPLE_TESTS (ce_info, bb, t, f);
+
+         /* See if the conversion failed */
+         if (!t || !f)
+           goto fail;
+#endif
+
+         true_expr = t;
+         false_expr = f;
+       }
+      while (bb != last_test_bb);
+    }
+
   /* For IF-THEN-ELSE blocks, we don't allow modifications of the test
      on then THEN block.  */
   then_mod_ok = (else_bb == NULL_BLOCK);
@@ -366,17 +518,32 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
      to conditional execution.  */
 
   if (then_end
-      && ! cond_exec_process_insns (then_start, then_end,
-                                   false_expr, false_prob_val, then_mod_ok))
+      && (! false_expr
+         || ! cond_exec_process_insns (ce_info, then_start, then_end,
+                                       false_expr, false_prob_val,
+                                       then_mod_ok)))
     goto fail;
 
-  if (else_bb
-      && ! cond_exec_process_insns (else_start, else_end,
+  if (else_bb && else_end
+      && ! cond_exec_process_insns (ce_info, else_start, else_end,
                                    true_expr, true_prob_val, TRUE))
     goto fail;
 
+  /* If we cannot apply the changes, fail.  Do not go through the normal fail
+     processing, since apply_change_group will call cancel_changes.  */
   if (! apply_change_group ())
-    return FALSE;
+    {
+#ifdef IFCVT_MODIFY_CANCEL
+      /* Cancel any machine dependent changes.  */
+      IFCVT_MODIFY_CANCEL (ce_info);
+#endif
+      return FALSE;
+    }
+
+#ifdef IFCVT_MODIFY_FINAL
+  /* Do any machine dependent final modifications */
+  IFCVT_MODIFY_FINAL (ce_info);
+#endif
 
   /* Conversion succeeded.  */
   if (rtl_dump_file)
@@ -384,10 +551,16 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
             n_insns, (n_insns == 1) ? " was" : "s were");
 
   /* Merge the blocks!  */
-  merge_if_block (test_bb, then_bb, else_bb, join_bb);
+  merge_if_block (ce_info);
+  cond_exec_changed_p = TRUE;
   return TRUE;
 
  fail:
+#ifdef IFCVT_MODIFY_CANCEL
+  /* Cancel any machine dependent changes.  */
+  IFCVT_MODIFY_CANCEL (ce_info);
+#endif
+
   cancel_changes (0);
   return FALSE;
 }
@@ -400,6 +573,7 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
 
 struct noce_if_info
 {
+  basic_block test_bb;
   rtx insn_a, insn_b;
   rtx x, a, b;
   rtx jump, cond, cond_earliest;
@@ -416,6 +590,10 @@ static rtx noce_emit_cmove         PARAMS ((struct noce_if_info *,
                                                 rtx, rtx, rtx));
 static int noce_try_cmove              PARAMS ((struct noce_if_info *));
 static int noce_try_cmove_arith                PARAMS ((struct noce_if_info *));
+static rtx noce_get_alt_condition      PARAMS ((struct noce_if_info *,
+                                                rtx, rtx *));
+static int noce_try_minmax             PARAMS ((struct noce_if_info *));
+static int noce_try_abs                        PARAMS ((struct noce_if_info *));
 
 /* Helper function for noce_try_store_flag*.  */
 
@@ -436,17 +614,18 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
      build the store_flag insn directly.  */
 
   if (cond_complex)
-    cond = XEXP (SET_SRC (PATTERN (if_info->jump)), 0);
+    cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0);
+
+  if (reversep)
+    code = reversed_comparison_code (cond, if_info->jump);
+  else
+    code = GET_CODE (cond);
 
   if ((if_info->cond_earliest == if_info->jump || cond_complex)
       && (normalize == 0 || STORE_FLAG_VALUE == normalize))
     {
       rtx tmp;
 
-      code = GET_CODE (cond);
-      if (reversep)
-       code = reverse_condition (code);
-
       tmp = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
                            XEXP (cond, 1));
       tmp = gen_rtx_SET (VOIDmode, x, tmp);
@@ -458,7 +637,7 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
        {
          tmp = get_insns ();
          end_sequence ();
-         emit_insns (tmp);
+         emit_insn (tmp);
 
          if_info->cond_earliest = if_info->jump;
 
@@ -472,16 +651,36 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
   if (cond_complex)
     return NULL_RTX;
 
-  code = GET_CODE (cond);
-  if (reversep)
-    code = reverse_condition (code);
-
   return emit_store_flag (x, code, XEXP (cond, 0),
                          XEXP (cond, 1), VOIDmode,
                          (code == LTU || code == LEU
                           || code == GEU || code == GTU), normalize);
 }
 
+/* Emit instruction to move an rtx into STRICT_LOW_PART.  */
+static void
+noce_emit_move_insn (x, y)
+     rtx x, y;
+{
+  enum machine_mode outmode, inmode;
+  rtx outer, inner;
+  int bitpos;
+
+  if (GET_CODE (x) != STRICT_LOW_PART)
+    {
+      emit_move_insn (x, y);
+      return;
+    }
+
+  outer = XEXP (x, 0);
+  inner = XEXP (outer, 0);
+  outmode = GET_MODE (outer);
+  inmode = GET_MODE (inner);
+  bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
+  store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y,
+                  GET_MODE_BITSIZE (inmode));
+}
+
 /* Convert "if (test) x = 1; else x = 0".
 
    Only try 0 and STORE_FLAG_VALUE here.  Other combinations will be
@@ -502,7 +701,8 @@ noce_try_store_flag (if_info)
   else if (if_info->b == const0_rtx
           && GET_CODE (if_info->a) == CONST_INT
           && INTVAL (if_info->a) == STORE_FLAG_VALUE
-          && can_reverse_comparison_p (if_info->cond, if_info->jump))
+          && (reversed_comparison_code (if_info->cond, if_info->jump)
+              != UNKNOWN))
     reversep = 1;
   else
     return FALSE;
@@ -513,11 +713,11 @@ noce_try_store_flag (if_info)
   if (target)
     {
       if (target != if_info->x)
-       emit_move_insn (if_info->x, target);
+       noce_emit_move_insn (if_info->x, target);
 
       seq = get_insns ();
       end_sequence ();
-      emit_insns_before (seq, if_info->cond_earliest);
+      emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
 
       return TRUE;
     }
@@ -538,16 +738,25 @@ noce_try_store_flag_constants (if_info)
   int reversep;
   HOST_WIDE_INT itrue, ifalse, diff, tmp;
   int normalize, can_reverse;
+  enum machine_mode mode;
 
   if (! no_new_pseudos
       && GET_CODE (if_info->a) == CONST_INT
       && GET_CODE (if_info->b) == CONST_INT)
     {
+      mode = GET_MODE (if_info->x);
       ifalse = INTVAL (if_info->a);
       itrue = INTVAL (if_info->b);
-      diff = itrue - ifalse;
 
-      can_reverse = can_reverse_comparison_p (if_info->cond, if_info->jump);
+      /* Make sure we can represent the difference between the two values.  */
+      if ((itrue - ifalse > 0)
+         != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
+       return FALSE;
+
+      diff = trunc_int_for_mode (itrue - ifalse, mode);
+
+      can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
+                    != UNKNOWN);
 
       reversep = 0;
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
@@ -575,7 +784,7 @@ noce_try_store_flag_constants (if_info)
       if (reversep)
        {
          tmp = itrue; itrue = ifalse; ifalse = tmp;
-         diff = -diff;
+         diff = trunc_int_for_mode (-diff, mode);
        }
 
       start_sequence ();
@@ -590,42 +799,42 @@ noce_try_store_flag_constants (if_info)
         =>   x = 3 + (test == 0);  */
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
        {
-         target = expand_binop (GET_MODE (if_info->x),
-                                (diff == STORE_FLAG_VALUE
-                                 ? add_optab : sub_optab),
-                                GEN_INT (ifalse), target, if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode,
+                                       (diff == STORE_FLAG_VALUE
+                                        ? PLUS : MINUS),
+                                       GEN_INT (ifalse), target, if_info->x, 0,
+                                       OPTAB_WIDEN);
        }
 
       /* if (test) x = 8; else x = 0;
         =>   x = (test != 0) << 3;  */
       else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
        {
-         target = expand_binop (GET_MODE (if_info->x), ashl_optab,
-                                target, GEN_INT (tmp), if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode, ASHIFT,
+                                       target, GEN_INT (tmp), if_info->x, 0,
+                                       OPTAB_WIDEN);
        }
 
       /* if (test) x = -1; else x = b;
         =>   x = -(test != 0) | b;  */
       else if (itrue == -1)
        {
-         target = expand_binop (GET_MODE (if_info->x), ior_optab,
-                                target, GEN_INT (ifalse), if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode, IOR,
+                                       target, GEN_INT (ifalse), if_info->x, 0,
+                                       OPTAB_WIDEN);
        }
 
       /* if (test) x = a; else x = b;
         =>   x = (-(test != 0) & (b - a)) + a;  */
       else
        {
-         target = expand_binop (GET_MODE (if_info->x), and_optab,
-                                target, GEN_INT (diff), if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode, AND,
+                                       target, GEN_INT (diff), if_info->x, 0,
+                                       OPTAB_WIDEN);
          if (target)
-           target = expand_binop (GET_MODE (if_info->x), add_optab,
-                                  target, GEN_INT (ifalse), if_info->x, 0,
-                                  OPTAB_WIDEN);
+           target = expand_simple_binop (mode, PLUS,
+                                         target, GEN_INT (ifalse),
+                                         if_info->x, 0, OPTAB_WIDEN);
        }
 
       if (! target)
@@ -635,11 +844,15 @@ 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 ();
-      emit_insns_before (seq, if_info->cond_earliest);
+
+      if (seq_contains_jump (seq))
+       return FALSE;
+
+      emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
 
       return TRUE;
     }
@@ -667,7 +880,8 @@ noce_try_store_flag_inc (if_info)
       && (XEXP (if_info->a, 1) == const1_rtx
          || XEXP (if_info->a, 1) == constm1_rtx)
       && rtx_equal_p (XEXP (if_info->a, 0), if_info->x)
-      && can_reverse_comparison_p (if_info->cond, if_info->jump))
+      && (reversed_comparison_code (if_info->cond, if_info->jump)
+         != UNKNOWN))
     {
       if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
        subtract = 0, normalize = 0;
@@ -683,17 +897,23 @@ 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 ();
-         emit_insns_before (seq, if_info->cond_earliest);
+
+         if (seq_contains_jump (seq))
+           return FALSE;
+
+         emit_insn_before_scope (seq, if_info->jump,
+                                 INSN_SCOPE (if_info->insn_a));
 
          return TRUE;
        }
@@ -719,8 +939,9 @@ noce_try_store_flag_mask (if_info)
          || STORE_FLAG_VALUE == -1)
       && ((if_info->a == const0_rtx
           && rtx_equal_p (if_info->b, if_info->x))
-         || ((reversep = can_reverse_comparison_p (if_info->cond,
-                                                   if_info->jump))
+         || ((reversep = (reversed_comparison_code (if_info->cond,
+                                                    if_info->jump)
+                          != UNKNOWN))
              && if_info->b == const0_rtx
              && rtx_equal_p (if_info->a, if_info->x))))
     {
@@ -729,18 +950,23 @@ 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 ();
-         emit_insns_before (seq, if_info->cond_earliest);
+
+         if (seq_contains_jump (seq))
+           return FALSE;
+
+         emit_insn_before_scope (seq, if_info->jump,
+                                 INSN_SCOPE (if_info->insn_a));
 
          return TRUE;
        }
@@ -779,7 +1005,7 @@ noce_emit_cmove (if_info, x, code, cmp_a, cmp_b, vfalse, vtrue)
        {
          tmp = get_insns ();
          end_sequence ();
-         emit_insns (tmp);
+         emit_insn (tmp);
 
          return x;
        }
@@ -831,11 +1057,12 @@ noce_try_cmove (if_info)
       if (target)
        {
          if (target != if_info->x)
-           emit_move_insn (if_info->x, target);
+           noce_emit_move_insn (if_info->x, target);
 
          seq = get_insns ();
          end_sequence ();
-         emit_insns_before (seq, if_info->cond_earliest);
+         emit_insn_before_scope (seq, if_info->jump,
+                                 INSN_SCOPE (if_info->insn_a));
          return TRUE;
        }
       else
@@ -894,7 +1121,7 @@ noce_try_cmove_arith (if_info)
   insn_b = if_info->insn_b;
 
   /* Possibly rearrange operands to make things come out more natural.  */
-  if (can_reverse_comparison_p (if_info->cond, if_info->jump))
+  if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
     {
       int reversep = 0;
       if (rtx_equal_p (b, x))
@@ -904,7 +1131,7 @@ noce_try_cmove_arith (if_info)
 
       if (reversep)
        {
-         code = reverse_condition (code);
+         code = reversed_comparison_code (if_info->cond, if_info->jump);
          tmp = a, a = b, b = tmp;
          tmp = insn_a, insn_a = insn_b, insn_b = tmp;
        }
@@ -986,16 +1213,18 @@ noce_try_cmove_arith (if_info)
       if (MEM_SCALAR_P (if_info->a) && MEM_SCALAR_P (if_info->b))
        MEM_SCALAR_P (tmp) = 1;
       if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b))
-       MEM_ALIAS_SET (tmp) = MEM_ALIAS_SET (if_info->a);
+       set_mem_alias_set (tmp, MEM_ALIAS_SET (if_info->a));
+      set_mem_align (tmp,
+                    MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b)));
 
-      emit_move_insn (if_info->x, tmp);
+      noce_emit_move_insn (if_info->x, tmp);
     }
   else if (target != x)
-    emit_move_insn (x, target);
+    noce_emit_move_insn (x, target);
 
   tmp = get_insns ();
   end_sequence ();
-  emit_insns_before (tmp, if_info->cond_earliest);
+  emit_insn_before_scope (tmp, if_info->jump, INSN_SCOPE (if_info->insn_a));
   return TRUE;
 
  end_seq_and_fail:
@@ -1003,185 +1232,627 @@ noce_try_cmove_arith (if_info)
   return FALSE;
 }
 
-/* Look for the condition for the jump first.  We'd prefer to avoid
-   get_condition if we can -- it tries to look back for the contents
-   of an original compare.  On targets that use normal integers for
-   comparisons, e.g. alpha, this is wasteful.  */
+/* For most cases, the simplified condition we found is the best
+   choice, but this is not the case for the min/max/abs transforms.
+   For these we wish to know that it is A or B in the condition.  */
 
 static rtx
-noce_get_condition (jump, earliest)
-     rtx jump;
+noce_get_alt_condition (if_info, target, earliest)
+     struct noce_if_info *if_info;
+     rtx target;
      rtx *earliest;
 {
-  rtx cond;
+  rtx 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;
+    }
 
-  /* If the condition variable is a register and is MODE_INT, accept it.
-     Otherwise, fall back on get_condition.  */
+  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 (! condjump_p (jump))
-    return NULL_RTX;
+  /* 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.  */
 
-  cond = XEXP (SET_SRC (PATTERN (jump)), 0);
-  if (GET_CODE (XEXP (cond, 0)) == REG
-      && GET_MODE_CLASS (GET_MODE (XEXP (cond, 0))) == MODE_INT)
+  if (GET_CODE (target) == CONST_INT)
     {
-      *earliest = jump;
+      enum rtx_code code = GET_CODE (if_info->cond);
+      rtx op_a = XEXP (if_info->cond, 0);
+      rtx op_b = XEXP (if_info->cond, 1);
+      rtx prev_insn;
+
+      /* First, look to see if we put a constant in a register.  */
+      prev_insn = PREV_INSN (if_info->cond_earliest);
+      if (prev_insn
+         && INSN_P (prev_insn)
+         && GET_CODE (PATTERN (prev_insn)) == SET)
+       {
+         rtx src = find_reg_equal_equiv_note (prev_insn);
+         if (!src)
+           src = SET_SRC (PATTERN (prev_insn));
+         if (GET_CODE (src) == CONST_INT)
+           {
+             if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn))))
+               op_a = src;
+             else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn))))
+               op_b = src;
+
+             if (GET_CODE (op_a) == CONST_INT)
+               {
+                 rtx tmp = op_a;
+                 op_a = op_b;
+                 op_b = tmp;
+                 code = swap_condition (code);
+               }
+           }
+       }
 
-      /* If this branches to JUMP_LABEL when the condition is false,
-        reverse the condition.  */
-      if (GET_CODE (XEXP (SET_SRC (PATTERN (jump)), 2)) == LABEL_REF
-         && XEXP (XEXP (SET_SRC (PATTERN (jump)), 2), 0) == JUMP_LABEL (jump))
-       cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                              GET_MODE (cond), XEXP (cond, 0),
-                              XEXP (cond, 1));
+      /* 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;
+       }
     }
-  else
-    cond = get_condition (jump, earliest);
 
-  return cond;
-}
+  cond = canonicalize_condition (if_info->jump, cond, reverse,
+                                earliest, target);
+  if (! cond || ! reg_mentioned_p (target, cond))
+    return NULL;
 
-/* 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.  */
+  /* We almost certainly searched back to a different place.
+     Need to re-verify correct lifetimes.  */
 
-static int
-noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
-     basic_block test_bb;      /* Basic block test is in */
-     basic_block then_bb;      /* Basic block for THEN block */
-     basic_block else_bb;      /* Basic block for ELSE block */
-     basic_block join_bb;      /* Basic block the join label is in */
-{
-  /* We're looking for patterns of the form
+  /* X may not be mentioned in the range (cond_earliest, jump].  */
+  for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn))
+    if (INSN_P (insn) && reg_overlap_mentioned_p (if_info->x, PATTERN (insn)))
+      return NULL;
 
-     (1) if (...) x = a; else x = b;
-     (2) x = b; if (...) x = a;
-     (3) if (...) x = a;   // as if with an initial x = x.
+  /* 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;
 
-     The later patterns require jumps to be more expensive.
+  return cond;
+}
 
-     ??? For future expansion, look for multiple X in such patterns.  */
+/* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc.  */
 
-  struct noce_if_info if_info;
-  rtx insn_a, insn_b;
-  rtx set_a, set_b;
-  rtx orig_x, x, a, b;
-  rtx jump, cond, insn;
+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;
 
-  /* If this is not a standard conditional jump, we can't parse it.  */
-  jump = test_bb->end;
-  cond = noce_get_condition (jump, &if_info.cond_earliest);
-  if (! cond)
+  /* ??? Can't guarantee that expand_binop won't create pseudos.  */
+  if (no_new_pseudos)
     return FALSE;
 
-  /* We must be comparing objects whose modes imply the size.  */
-  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
+  /* ??? 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;
 
-  /* Look for one of the potential sets.  */
-  insn_a = first_active_insn (then_bb);
-  if (! insn_a
-      || ! last_active_insn_p (then_bb, insn_a)
-      || (set_a = single_set (insn_a)) == NULL_RTX)
+  cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
+  if (!cond)
     return FALSE;
 
-  x = SET_DEST (set_a);
-  a = SET_SRC (set_a);
-
-  /* Look for the other potential set.  Make sure we've got equivalent
-     destinations.  */
-  /* ??? This is overconservative.  Storing to two different mems is
-     as easy as conditionally computing the address.  Storing to a
-     single mem merely requires a scratch memory to use as one of the
-     destination addresses; often the memory immediately below the
-     stack pointer is available for this.  */
-  set_b = NULL_RTX;
-  if (else_bb)
+  /* Verify the condition is of the form we expect, and canonicalize
+     the comparison code.  */
+  code = GET_CODE (cond);
+  if (rtx_equal_p (XEXP (cond, 0), if_info->a))
     {
-      insn_b = first_active_insn (else_bb);
-      if (! insn_b
-         || ! last_active_insn_p (else_bb, insn_b)
-         || (set_b = single_set (insn_b)) == NULL_RTX
-         || ! rtx_equal_p (x, SET_DEST (set_b)))
+      if (! rtx_equal_p (XEXP (cond, 1), if_info->b))
        return FALSE;
     }
-  else
+  else if (rtx_equal_p (XEXP (cond, 1), if_info->a))
     {
-      insn_b = prev_nonnote_insn (if_info.cond_earliest);
-      if (! insn_b
-         || GET_CODE (insn_b) != INSN
-         || (set_b = single_set (insn_b)) == NULL_RTX
-         || ! rtx_equal_p (x, SET_DEST (set_b))
-         || reg_mentioned_p (x, cond)
-         || reg_mentioned_p (x, a)
-         || reg_mentioned_p (x, SET_SRC (set_b)))
-       insn_b = set_b = NULL_RTX;
+      if (! rtx_equal_p (XEXP (cond, 0), if_info->b))
+       return FALSE;
+      code = swap_condition (code);
     }
-  b = (set_b ? SET_SRC (set_b) : x);
+  else
+    return FALSE;
 
-  /* X may not be mentioned in the range (cond_earliest, jump].  */
-  for (insn = jump; insn != if_info.cond_earliest; insn = PREV_INSN (insn))
-    if (INSN_P (insn) && reg_mentioned_p (x, insn))
+  /* Determine what sort of operation this is.  Note that the code is for
+     a taken branch, so the code->operation mapping appears backwards.  */
+  switch (code)
+    {
+    case LT:
+    case LE:
+    case UNLT:
+    case UNLE:
+      op = SMAX;
+      unsignedp = 0;
+      break;
+    case GT:
+    case GE:
+    case UNGT:
+    case UNGE:
+      op = SMIN;
+      unsignedp = 0;
+      break;
+    case LTU:
+    case LEU:
+      op = UMAX;
+      unsignedp = 1;
+      break;
+    case GTU:
+    case GEU:
+      op = UMIN;
+      unsignedp = 1;
+      break;
+    default:
       return FALSE;
+    }
 
-  /* A and B may not be modified in the range [cond_earliest, jump).  */
-  for (insn = if_info.cond_earliest; insn != jump; insn = NEXT_INSN (insn))
-    if (INSN_P (insn)
-       && (modified_in_p (a, insn) || modified_in_p (b, insn)))
-      return FALSE;
+  start_sequence ();
 
-  /* Only operate on register destinations, and even then avoid extending
-     the lifetime of hard registers on small register class machines.  */
-  orig_x = x;
-  if (GET_CODE (x) != REG
-      || (SMALL_REGISTER_CLASSES
-         && REGNO (x) < FIRST_PSEUDO_REGISTER))
+  target = expand_simple_binop (GET_MODE (if_info->x), op,
+                               if_info->a, if_info->b,
+                               if_info->x, unsignedp, OPTAB_WIDEN);
+  if (! target)
     {
-      if (no_new_pseudos)
-       return FALSE;
-      x = gen_reg_rtx (GET_MODE (x));
+      end_sequence ();
+      return FALSE;
     }
+  if (target != if_info->x)
+    noce_emit_move_insn (if_info->x, target);
 
-  /* Don't operate on sources that may trap or are volatile.  */
-  if (side_effects_p (a) || side_effects_p (b)
-      || (GET_CODE (a) != MEM && may_trap_p (a))
-      || (GET_CODE (b) != MEM && may_trap_p (b)))
+  seq = get_insns ();
+  end_sequence ();  
+
+  if (seq_contains_jump (seq))
     return FALSE;
 
-  /* Set up the info block for our subroutines.  */
-  if_info.cond = cond;
-  if_info.jump = jump;
-  if_info.insn_a = insn_a;
-  if_info.insn_b = insn_b;
-  if_info.x = x;
-  if_info.a = a;
-  if_info.b = b;
+  emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
+  if_info->cond = cond;
+  if_info->cond_earliest = earliest;
 
-  /* Try optimizations in some approximation of a useful order.  */
-  /* ??? Should first look to see if X is live incoming at all.  If it
-     isn't, we don't need anything but an unconditional set.  */
+  return TRUE;
+}
 
-  /* Look and see if A and B are really the same.  Avoid creating silly
-     cmove constructs that no one will fix up later.  */
-  if (rtx_equal_p (a, b))
+/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", etc.  */
+
+static int
+noce_try_abs (if_info)
+     struct noce_if_info *if_info;
+{ 
+  rtx cond, earliest, target, seq, a, b, c;
+  int negate;
+
+  /* ??? Can't guarantee that expand_binop won't create pseudos.  */
+  if (no_new_pseudos)
+    return FALSE;
+
+  /* Recognize A and B as constituting an ABS or NABS.  */
+  a = if_info->a;
+  b = if_info->b;
+  if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b))
+    negate = 0;
+  else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a))
     {
-      /* If we have an INSN_B, we don't have to create any new rtl.  Just
-        move the instruction that we already have.  If we don't have an
-        INSN_B, that means that A == X, and we've got a noop move.  In
-        that case don't do anything and let the code below delete INSN_A.  */
-      if (insn_b && else_bb)
-       {
+      c = a; a = b; b = c;
+      negate = 1;
+    }
+  else
+    return FALSE;
+   
+  cond = noce_get_alt_condition (if_info, b, &earliest);
+  if (!cond)
+    return FALSE;
+
+  /* Verify the condition is of the form we expect.  */
+  if (rtx_equal_p (XEXP (cond, 0), b))
+    c = XEXP (cond, 1);
+  else if (rtx_equal_p (XEXP (cond, 1), b))
+    c = XEXP (cond, 0);
+  else
+    return FALSE;
+
+  /* Verify that C is zero.  Search backward through the block for
+     a REG_EQUAL note if necessary.  */
+  if (REG_P (c))
+    {
+      rtx insn, note = NULL;
+      for (insn = earliest;
+          insn != if_info->test_bb->head;
+          insn = PREV_INSN (insn))
+       if (INSN_P (insn) 
+           && ((note = find_reg_note (insn, REG_EQUAL, c))
+               || (note = find_reg_note (insn, REG_EQUIV, c))))
+         break;
+      if (! note)
+       return FALSE;
+      c = XEXP (note, 0);
+    }
+  if (GET_CODE (c) == MEM
+      && GET_CODE (XEXP (c, 0)) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (XEXP (c, 0)))
+    c = get_pool_constant (XEXP (c, 0));
+
+  /* Work around funny ideas get_condition has wrt canonicalization.
+     Note that these rtx constants are known to be CONST_INT, and 
+     therefore imply integer comparisons.  */
+  if (c == constm1_rtx && GET_CODE (cond) == GT)
+    ;
+  else if (c == const1_rtx && GET_CODE (cond) == LT)
+    ;
+  else if (c != CONST0_RTX (GET_MODE (b)))
+    return FALSE;
+
+  /* Determine what sort of operation this is.  */
+  switch (GET_CODE (cond))
+    {
+    case LT:
+    case LE:
+    case UNLT:
+    case UNLE:
+      negate = !negate;
+      break;
+    case GT:
+    case GE:
+    case UNGT:
+    case UNGE:
+      break;
+    default:
+      return FALSE;
+    }
+
+  start_sequence ();
+
+  target = expand_simple_unop (GET_MODE (if_info->x), ABS, b, if_info->x, 0);
+
+  /* ??? It's a quandry whether cmove would be better here, especially
+     for integers.  Perhaps combine will clean things up.  */
+  if (target && negate)
+    target = expand_simple_unop (GET_MODE (target), NEG, target, if_info->x, 0);
+
+  if (! target)
+    {
+      end_sequence ();
+      return FALSE;
+    }
+
+  if (target != if_info->x)
+    noce_emit_move_insn (if_info->x, target);
+
+  seq = get_insns ();
+  end_sequence ();  
+
+  if (seq_contains_jump (seq))
+    return FALSE;
+
+  emit_insn_before_scope (seq, if_info->jump, INSN_SCOPE (if_info->insn_a));
+  if_info->cond = cond;
+  if_info->cond_earliest = earliest;
+
+  return TRUE;
+}
+
+/* Similar to get_condition, only the resulting condition must be
+   valid at JUMP, instead of at EARLIEST.  */
+
+static rtx
+noce_get_condition (jump, earliest)
+     rtx jump;
+     rtx *earliest;
+{
+  rtx cond, set, tmp, insn;
+  bool reverse;
+
+  if (! any_condjump_p (jump))
+    return NULL_RTX;
+
+  set = pc_set (jump);
+
+  /* If this branches to JUMP_LABEL when the condition is false,
+     reverse the condition.  */
+  reverse = (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
+            && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump));
+
+  /* If the condition variable is a register and is MODE_INT, accept it.  */
+
+  cond = XEXP (SET_SRC (set), 0);
+  tmp = XEXP (cond, 0);
+  if (REG_P (tmp) && GET_MODE_CLASS (GET_MODE (tmp)) == MODE_INT)
+    {
+      *earliest = jump;
+
+      if (reverse)
+       cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
+                              GET_MODE (cond), tmp, XEXP (cond, 1));
+      return cond;
+    }
+
+  /* Otherwise, fall back on canonicalize_condition to do the dirty
+     work of manipulating MODE_CC values and COMPARE rtx codes.  */
+
+  tmp = canonicalize_condition (jump, cond, reverse, earliest, NULL_RTX);
+  if (!tmp)
+    return NULL_RTX;
+
+  /* We are going to insert code before JUMP, not before EARLIEST.
+     We must therefore be certain that the given condition is valid
+     at JUMP by virtue of not having been modified since.  */
+  for (insn = *earliest; insn != jump; insn = NEXT_INSN (insn))
+    if (INSN_P (insn) && modified_in_p (tmp, insn))
+      break;
+  if (insn == jump)
+    return tmp;
+
+  /* The condition was modified.  See if we can get a partial result
+     that doesn't follow all the reversals.  Perhaps combine can fold
+     them together later.  */
+  tmp = XEXP (tmp, 0);
+  if (!REG_P (tmp) || GET_MODE_CLASS (GET_MODE (tmp)) != MODE_INT)
+    return NULL_RTX;
+  tmp = canonicalize_condition (jump, cond, reverse, earliest, tmp);
+  if (!tmp)
+    return NULL_RTX;
+
+  /* For sanity's sake, re-validate the new result.  */
+  for (insn = *earliest; insn != jump; insn = NEXT_INSN (insn))
+    if (INSN_P (insn) && modified_in_p (tmp, insn))
+      return NULL_RTX;
+
+  return tmp;
+}
+
+/* Return true if OP is ok for if-then-else processing.  */
+
+static int
+noce_operand_ok (op)
+     rtx op;
+{
+  /* We special-case memories, so handle any of them with
+     no address side effects.  */
+  if (GET_CODE (op) == MEM)
+    return ! side_effects_p (XEXP (op, 0));
+
+  if (side_effects_p (op))
+    return FALSE;
+
+  return ! may_trap_p (op);
+}
+
+/* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
+   without using conditional execution.  Return TRUE if we were
+   successful at converting the block.  */
+
+static int
+noce_process_if_block (ce_info)
+     struct ce_if_block * ce_info;
+{
+  basic_block test_bb = ce_info->test_bb;      /* test block */
+  basic_block then_bb = ce_info->then_bb;      /* THEN */
+  basic_block else_bb = ce_info->else_bb;      /* ELSE or NULL */
+  struct noce_if_info if_info;
+  rtx insn_a, insn_b;
+  rtx set_a, set_b;
+  rtx orig_x, x, a, b;
+  rtx jump, cond;
+
+  /* We're looking for patterns of the form
+
+     (1) if (...) x = a; else x = b;
+     (2) x = b; if (...) x = a;
+     (3) if (...) x = a;   // as if with an initial x = x.
+
+     The later patterns require jumps to be more expensive.
+
+     ??? For future expansion, look for multiple X in such patterns.  */
+
+  /* If test is comprised of && or || elements, don't handle it unless it is
+     the special case of && elements without an ELSE block.  */
+  if (ce_info->num_multiple_test_blocks)
+    {
+      if (else_bb || ! ce_info->and_and_p)
+       return FALSE;
+
+      ce_info->test_bb = test_bb = ce_info->last_test_bb;
+      ce_info->num_multiple_test_blocks = 0;
+      ce_info->num_and_and_blocks = 0;
+      ce_info->num_or_or_blocks = 0;
+    }
+
+  /* If this is not a standard conditional jump, we can't parse it.  */
+  jump = test_bb->end;
+  cond = noce_get_condition (jump, &if_info.cond_earliest);
+  if (! cond)
+    return FALSE;
+
+  /* If the conditional jump is more than just a conditional
+     jump, then we can not do if-conversion on this block.  */
+  if (! onlyjump_p (jump))
+    return FALSE;
+
+  /* We must be comparing objects whose modes imply the size.  */
+  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
+    return FALSE;
+
+  /* Look for one of the potential sets.  */
+  insn_a = first_active_insn (then_bb);
+  if (! insn_a
+      || insn_a != last_active_insn (then_bb, FALSE)
+      || (set_a = single_set (insn_a)) == NULL_RTX)
+    return FALSE;
+
+  x = SET_DEST (set_a);
+  a = SET_SRC (set_a);
+
+  /* Look for the other potential set.  Make sure we've got equivalent
+     destinations.  */
+  /* ??? This is overconservative.  Storing to two different mems is
+     as easy as conditionally computing the address.  Storing to a
+     single mem merely requires a scratch memory to use as one of the
+     destination addresses; often the memory immediately below the
+     stack pointer is available for this.  */
+  set_b = NULL_RTX;
+  if (else_bb)
+    {
+      insn_b = first_active_insn (else_bb);
+      if (! insn_b
+         || insn_b != last_active_insn (else_bb, FALSE)
+         || (set_b = single_set (insn_b)) == NULL_RTX
+         || ! rtx_equal_p (x, SET_DEST (set_b)))
+       return FALSE;
+    }
+  else
+    {
+      insn_b = prev_nonnote_insn (if_info.cond_earliest);
+      if (! insn_b
+         || GET_CODE (insn_b) != INSN
+         || (set_b = single_set (insn_b)) == NULL_RTX
+         || ! rtx_equal_p (x, SET_DEST (set_b))
+         || reg_overlap_mentioned_p (x, cond)
+         || reg_overlap_mentioned_p (x, a)
+         || reg_overlap_mentioned_p (x, SET_SRC (set_b))
+         || modified_between_p (x, if_info.cond_earliest, NEXT_INSN (jump)))
+       insn_b = set_b = NULL_RTX;
+    }
+  b = (set_b ? SET_SRC (set_b) : x);
+
+  /* Only operate on register destinations, and even then avoid extending
+     the lifetime of hard registers on small register class machines.  */
+  orig_x = x;
+  if (GET_CODE (x) != REG
+      || (SMALL_REGISTER_CLASSES
+         && REGNO (x) < FIRST_PSEUDO_REGISTER))
+    {
+      if (no_new_pseudos)
+       return FALSE;
+      x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
+                                ? XEXP (x, 0) : x));
+    }
+
+  /* Don't operate on sources that may trap or are volatile.  */
+  if (! noce_operand_ok (a) || ! noce_operand_ok (b))
+    return FALSE;
+
+  /* Set up the info block for our subroutines.  */
+  if_info.test_bb = test_bb;
+  if_info.cond = cond;
+  if_info.jump = jump;
+  if_info.insn_a = insn_a;
+  if_info.insn_b = insn_b;
+  if_info.x = x;
+  if_info.a = a;
+  if_info.b = b;
+
+  /* Try optimizations in some approximation of a useful order.  */
+  /* ??? Should first look to see if X is live incoming at all.  If it
+     isn't, we don't need anything but an unconditional set.  */
+
+  /* Look and see if A and B are really the same.  Avoid creating silly
+     cmove constructs that no one will fix up later.  */
+  if (rtx_equal_p (a, b))
+    {
+      /* If we have an INSN_B, we don't have to create any new rtl.  Just
+        move the instruction that we already have.  If we don't have an
+        INSN_B, that means that A == X, and we've got a noop move.  In
+        that case don't do anything and let the code below delete INSN_A.  */
+      if (insn_b && else_bb)
+       {
+         rtx note;
+
          if (else_bb && insn_b == else_bb->end)
            else_bb->end = PREV_INSN (insn_b);
-         reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
+         reorder_insns (insn_b, insn_b, PREV_INSN (jump));
+
+         /* If there was a REG_EQUAL note, delete it since it may have been
+            true due to this insn being after a jump.  */
+         if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0)
+           remove_note (insn_b, note);
+
          insn_b = NULL_RTX;
        }
+      /* If we have "x = b; if (...) x = a;", and x has side-effects, then
+        x must be executed twice.  */
+      else if (insn_b && side_effects_p (orig_x))
+       return FALSE;
+       
       x = orig_x;
       goto success;
     }
 
   if (noce_try_store_flag (&if_info))
     goto success;
+  if (noce_try_minmax (&if_info))
+    goto success;
+  if (noce_try_abs (&if_info))
+    goto success;
   if (HAVE_conditional_move
       && noce_try_cmove (&if_info))
     goto success;
@@ -1202,9 +1873,7 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
 
  success:
   /* The original sets may now be killed.  */
-  if (insn_a == then_bb->end)
-    then_bb->end = PREV_INSN (insn_a);
-  flow_delete_insn (insn_a);
+  delete_insn (insn_a);
 
   /* Several special cases here: First, we may have reused insn_b above,
      in which case insn_b is now NULL.  Second, we want to delete insn_b
@@ -1213,31 +1882,26 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
      the TEST block, it may in fact be loading data needed for the comparison.
      We'll let life_analysis remove the insn if it's really dead.  */
   if (insn_b && else_bb)
-    {
-      if (insn_b == else_bb->end)
-       else_bb->end = PREV_INSN (insn_b);
-      flow_delete_insn (insn_b);
-    }
+    delete_insn (insn_b);
 
-  /* The new insns will have been inserted before cond_earliest.  We should
-     be able to remove the jump with impunity, but the condition itself may
-     have been modified by gcse to be shared across basic blocks.  */
-  test_bb->end = PREV_INSN (jump);
-  flow_delete_insn (jump);
+  /* The new insns will have been inserted immediately before the jump.  We
+     should be able to remove the jump with impunity, but the condition itself
+     may have been modified by gcse to be shared across basic blocks.  */
+  delete_insn (jump);
 
   /* If we used a temporary, fix it up now.  */
   if (orig_x != x)
     {
       start_sequence ();
-      emit_move_insn (orig_x, x);
-      insn_b = gen_sequence ();
+      noce_emit_move_insn (copy_rtx (orig_x), x);
+      insn_b = get_insns ();
       end_sequence ();
 
-      test_bb->end = emit_insn_after (insn_b, test_bb->end);
+      emit_insn_after_scope (insn_b, test_bb->end, INSN_SCOPE (insn_a));
     }
 
   /* Merge the blocks!  */
-  merge_if_block (test_bb, then_bb, else_bb, join_bb);
+  merge_if_block (ce_info);
 
   return TRUE;
 }
@@ -1246,20 +1910,30 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
    straight line code.  Return true if successful.  */
 
 static int
-process_if_block (test_bb, then_bb, else_bb, join_bb)
-     basic_block test_bb;      /* Basic block test is in */
-     basic_block then_bb;      /* Basic block for THEN block */
-     basic_block else_bb;      /* Basic block for ELSE block */
-     basic_block join_bb;      /* Basic block the join label is in */
+process_if_block (ce_info)
+     struct ce_if_block * ce_info;
 {
   if (! reload_completed
-      && noce_process_if_block (test_bb, then_bb, else_bb, join_bb))
+      && noce_process_if_block (ce_info))
     return TRUE;
 
-  if (HAVE_conditional_execution
-      && reload_completed
-      && cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb))
-    return TRUE;
+  if (HAVE_conditional_execution && reload_completed)
+    {
+      /* If we have && and || tests, try to first handle combining the && and
+         || tests into the conditional code, and if that fails, go back and
+         handle it without the && and ||, which at present handles the && case
+         if there was no ELSE block.  */
+      if (cond_exec_process_if_block (ce_info, TRUE))
+       return TRUE;
+
+      if (ce_info->num_multiple_test_blocks)
+       {
+         cancel_changes (0);
+
+         if (cond_exec_process_if_block (ce_info, FALSE))
+           return TRUE;
+       }
+    }
 
   return FALSE;
 }
@@ -1267,31 +1941,61 @@ process_if_block (test_bb, then_bb, else_bb, join_bb)
 /* Merge the blocks and mark for local life update.  */
 
 static void
-merge_if_block (test_bb, then_bb, else_bb, join_bb)
-     basic_block test_bb;      /* Basic block test is in */
-     basic_block then_bb;      /* Basic block for THEN block */
-     basic_block else_bb;      /* Basic block for ELSE block */
-     basic_block join_bb;      /* Basic block the join label is in */
+merge_if_block (ce_info)
+     struct ce_if_block * ce_info;
 {
+  basic_block test_bb = ce_info->test_bb;      /* last test block */
+  basic_block then_bb = ce_info->then_bb;      /* THEN */
+  basic_block else_bb = ce_info->else_bb;      /* ELSE or NULL */
+  basic_block join_bb = ce_info->join_bb;      /* join block */
   basic_block combo_bb;
 
   /* All block merging is done into the lower block numbers.  */
 
   combo_bb = test_bb;
 
-  /* First merge TEST block into THEN block.  This is a no-brainer since
-     the THEN block did not have a code label to begin with.  */
+  /* Merge any basic blocks to handle && and || subtests.  Each of
+     the blocks are on the fallthru path from the predecessor block.  */
+  if (ce_info->num_multiple_test_blocks > 0)
+    {
+      basic_block bb = test_bb;
+      basic_block last_test_bb = ce_info->last_test_bb;
+      basic_block fallthru = block_fallthru (bb);
+      
+      do
+       {
+         bb = fallthru;
+         fallthru = block_fallthru (bb);
+         if (post_dominators)
+           delete_from_dominance_info (post_dominators, bb);
+         merge_blocks_nomove (combo_bb, bb);
+         num_removed_blocks++;
+       }
+      while (bb != last_test_bb);
+    }
+
+  /* Merge TEST block into THEN block.  Normally the THEN block won't have a
+     label, but it might if there were || tests.  That label's count should be
+     zero, and it normally should be removed.  */
 
-  if (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);
+      if (post_dominators)
+       delete_from_dominance_info (post_dominators, then_bb);
+      merge_blocks_nomove (combo_bb, then_bb);
+      num_removed_blocks++;
+    }
 
   /* The ELSE block, if it existed, had a label.  That label count
      will almost always be zero, but odd things can happen when labels
      get their addresses taken.  */
   if (else_bb)
     {
+      if (post_dominators)
+       delete_from_dominance_info (post_dominators, else_bb);
       merge_blocks_nomove (combo_bb, else_bb);
       num_removed_blocks++;
     }
@@ -1301,28 +2005,54 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
 
   if (! join_bb)
     {
+      rtx last = combo_bb->end;
+
       /* The outgoing edge for the current COMBO block should already
         be correct.  Verify this.  */
       if (combo_bb->succ == NULL_EDGE)
-       abort ();
+       {
+         if (find_reg_note (last, REG_NORETURN, NULL))
+           ;
+         else if (GET_CODE (last) == INSN
+                  && GET_CODE (PATTERN (last)) == TRAP_IF
+                  && TRAP_CONDITION (PATTERN (last)) == const_true_rtx)
+           ;
+         else
+           abort ();
+       }
 
-      /* There should sill be a branch at the end of the THEN or ELSE
+      /* There should still be something at the end of the THEN or ELSE
          blocks taking us to our final destination.  */
-      if (! simplejump_p (combo_bb->end)
-          && ! returnjump_p (combo_bb->end))
+      else if (GET_CODE (last) == JUMP_INSN)
+       ;
+      else if (combo_bb->succ->dest == EXIT_BLOCK_PTR
+              && GET_CODE (last) == CALL_INSN
+              && SIBLING_CALL_P (last))
+       ;
+      else if ((combo_bb->succ->flags & EDGE_EH)
+              && can_throw_internal (last))
+       ;
+      else
        abort ();
     }
 
   /* The JOIN block may have had quite a number of other predecessors too.
      Since we've already merged the TEST, THEN and ELSE blocks, we should
      have only one remaining edge from our if-then-else diamond.  If there
-     is more than one remaining edge, it must come from elsewhere.  */
-  else if (join_bb->pred->pred_next == NULL)
+     is more than one remaining edge, it must come from elsewhere.  There
+     may be zero incoming edges if the THEN block didn't actually join 
+     back up (as with a call to abort).  */
+  else if ((join_bb->pred == NULL
+           || join_bb->pred->pred_next == NULL)
+          && join_bb != EXIT_BLOCK_PTR)
     {
       /* We can merge the JOIN.  */
       if (combo_bb->global_live_at_end)
        COPY_REG_SET (combo_bb->global_live_at_end,
                      join_bb->global_live_at_end);
+
+      if (post_dominators)
+       delete_from_dominance_info (post_dominators, join_bb);
       merge_blocks_nomove (combo_bb, join_bb);
       num_removed_blocks++;
     }
@@ -1337,22 +2067,24 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
        abort ();
 
       /* Remove the jump and cruft from the end of the COMBO block.  */
-      tidy_fallthru_edge (combo_bb->succ, combo_bb, join_bb);
+      if (join_bb != EXIT_BLOCK_PTR)
+       tidy_fallthru_edge (combo_bb->succ, combo_bb, join_bb);
     }
 
-  /* Make sure we update life info properly.  */
-  SET_UPDATE_LIFE (combo_bb);
-
   num_updated_if_blocks++;
 }
 \f
-/* Find a block ending in a simple IF condition.  Return TRUE if
-   we were able to transform it in some way.  */
+/* Find a block ending in a simple IF condition and try to transform it
+   in some way.  When converting a multi-block condition, put the new code
+   in the first such block and delete the rest.  Return a pointer to this
+   first block if some transformation was done.  Return NULL otherwise.  */
 
-static int
-find_if_header (test_bb)
+static basic_block
+find_if_header (test_bb, pass)
      basic_block test_bb;
+     int pass;
 {
+  ce_if_block_t ce_info;
   edge then_edge;
   edge else_edge;
 
@@ -1360,12 +2092,12 @@ find_if_header (test_bb)
   if ((then_edge = test_bb->succ) == NULL_EDGE
       || (else_edge = then_edge->succ_next) == NULL_EDGE
       || else_edge->succ_next != NULL_EDGE)
-    return FALSE;
+    return NULL;
 
   /* Neither edge should be abnormal.  */
   if ((then_edge->flags & EDGE_COMPLEX)
       || (else_edge->flags & EDGE_COMPLEX))
-    return FALSE;
+    return NULL;
 
   /* The THEN edge is canonically the one that falls through.  */
   if (then_edge->flags & EDGE_FALLTHRU)
@@ -1378,10 +2110,25 @@ find_if_header (test_bb)
     }
   else
     /* Otherwise this must be a multiway branch of some sort.  */
-    return FALSE;
+    return NULL;
+
+  memset ((PTR) &ce_info, '\0', sizeof (ce_info));
+  ce_info.test_bb = test_bb;
+  ce_info.then_bb = then_edge->dest;
+  ce_info.else_bb = else_edge->dest;
+  ce_info.pass = pass;
 
-  if (find_if_block (test_bb, then_edge, else_edge))
+#ifdef IFCVT_INIT_EXTRA_FIELDS
+  IFCVT_INIT_EXTRA_FIELDS (&ce_info);
+#endif
+
+  if (find_if_block (&ce_info))
     goto success;
+
+  if (HAVE_trap && HAVE_conditional_trap
+      && find_cond_trap (test_bb, then_edge, else_edge))
+    goto success;
+
   if (post_dominators
       && (! HAVE_conditional_execution || reload_completed))
     {
@@ -1391,43 +2138,230 @@ find_if_header (test_bb)
        goto success;
     }
 
-  return FALSE;
+  return NULL;
 
  success:
   if (rtl_dump_file)
-    fprintf (rtl_dump_file, "Conversion succeeded.\n");
-  return TRUE;
+    fprintf (rtl_dump_file, "Conversion succeeded on pass %d.\n", pass);
+  return ce_info.test_bb;
+}
+
+/* Return true if a block has two edges, one of which falls through to the next
+   block, and the other jumps to a specific block, so that we can tell if the
+   block is part of an && test or an || test.  Returns either -1 or the number
+   of non-note, non-jump, non-USE/CLOBBER insns in the block.  */
+
+static int
+block_jumps_and_fallthru_p (cur_bb, target_bb)
+     basic_block cur_bb;
+     basic_block target_bb;
+{
+  edge cur_edge;
+  int fallthru_p = FALSE;
+  int jump_p = FALSE;
+  rtx insn;
+  rtx end;
+  int n_insns = 0;
+
+  if (!cur_bb || !target_bb)
+    return -1;
+
+  /* If no edges, obviously it doesn't jump or fallthru.  */
+  if (cur_bb->succ == NULL_EDGE)
+    return FALSE;
+
+  for (cur_edge = cur_bb->succ;
+       cur_edge != NULL_EDGE;
+       cur_edge = cur_edge->succ_next)
+    {
+      if (cur_edge->flags & EDGE_COMPLEX)
+       /* Anything complex isn't what we want.  */
+       return -1;
+
+      else if (cur_edge->flags & EDGE_FALLTHRU)
+       fallthru_p = TRUE;
+
+      else if (cur_edge->dest == target_bb)
+       jump_p = TRUE;
+
+      else
+       return -1;
+    }
+
+  if ((jump_p & fallthru_p) == 0)
+    return -1;
+
+  /* Don't allow calls in the block, since this is used to group && and ||
+     together for conditional execution support.  ??? we should support
+     conditional execution support across calls for IA-64 some day, but
+     for now it makes the code simpler.  */
+  end = cur_bb->end;
+  insn = cur_bb->head;
+
+  while (insn != NULL_RTX)
+    {
+      if (GET_CODE (insn) == CALL_INSN)
+       return -1;
+
+      if (INSN_P (insn)
+         && GET_CODE (insn) != JUMP_INSN
+         && GET_CODE (PATTERN (insn)) != USE
+         && GET_CODE (PATTERN (insn)) != CLOBBER)
+       n_insns++;
+
+      if (insn == end)
+       break;
+
+      insn = NEXT_INSN (insn);
+    }
+
+  return n_insns;
 }
 
 /* Determine if a given basic block heads a simple IF-THEN or IF-THEN-ELSE
    block.  If so, we'll try to convert the insns to not require the branch.
-   Return TRUE if we were successful at converting the the block.  */
+   Return TRUE if we were successful at converting the block.  */
 
 static int
-find_if_block (test_bb, then_edge, else_edge)
-      basic_block test_bb;
-      edge then_edge, else_edge;
+find_if_block (ce_info)
+     struct ce_if_block * ce_info;
 {
-  basic_block then_bb = then_edge->dest;
-  basic_block else_bb = else_edge->dest;
+  basic_block test_bb = ce_info->test_bb;
+  basic_block then_bb = ce_info->then_bb;
+  basic_block else_bb = ce_info->else_bb;
   basic_block join_bb = NULL_BLOCK;
   edge then_succ = then_bb->succ;
   edge else_succ = else_bb->succ;
-  int next_index;
+  int then_predecessors;
+  int else_predecessors;
+  edge cur_edge;
+  basic_block next;
+
+  ce_info->last_test_bb = test_bb;
+
+  /* Discover if any fall through predecessors of the current test basic block
+     were && tests (which jump to the else block) or || tests (which jump to
+     the then block).  */
+  if (HAVE_conditional_execution && reload_completed
+      && test_bb->pred != NULL_EDGE
+      && test_bb->pred->pred_next == NULL_EDGE
+      && test_bb->pred->flags == EDGE_FALLTHRU)
+    {
+      basic_block bb = test_bb->pred->src;
+      basic_block target_bb;
+      int max_insns = MAX_CONDITIONAL_EXECUTE;
+      int n_insns;
 
-  /* The THEN block of an IF-THEN combo must have exactly one predecessor.  */
-  if (then_bb->pred->pred_next != NULL_EDGE)
+      /* Determine if the preceeding block is an && or || block.  */
+      if ((n_insns = block_jumps_and_fallthru_p (bb, else_bb)) >= 0)
+       {
+         ce_info->and_and_p = TRUE;
+         target_bb = else_bb;
+       }
+      else if ((n_insns = block_jumps_and_fallthru_p (bb, then_bb)) >= 0)
+       {
+         ce_info->and_and_p = FALSE;     
+         target_bb = then_bb;
+       }
+      else
+       target_bb = NULL_BLOCK;
+
+      if (target_bb && n_insns <= max_insns)
+       {
+         int total_insns = 0;
+         int blocks = 0;
+
+         ce_info->last_test_bb = test_bb;
+
+         /* Found at least one && or || block, look for more.  */
+         do
+           {
+             ce_info->test_bb = test_bb = bb;
+             total_insns += n_insns;
+             blocks++;
+
+             if (bb->pred == NULL_EDGE || bb->pred->pred_next != NULL_EDGE)
+               break;
+
+             bb = bb->pred->src;
+             n_insns = block_jumps_and_fallthru_p (bb, target_bb);
+           }
+         while (n_insns >= 0 && (total_insns + n_insns) <= max_insns);
+
+         ce_info->num_multiple_test_blocks = blocks;
+         ce_info->num_multiple_test_insns = total_insns;
+
+         if (ce_info->and_and_p)
+           ce_info->num_and_and_blocks = blocks;
+         else
+           ce_info->num_or_or_blocks = blocks;
+       }
+    }
+
+  /* Count the number of edges the THEN and ELSE blocks have.  */
+  then_predecessors = 0;
+  for (cur_edge = then_bb->pred;
+       cur_edge != NULL_EDGE;
+       cur_edge = cur_edge->pred_next)
+    {
+      then_predecessors++;
+      if (cur_edge->flags & EDGE_COMPLEX)
+       return FALSE;
+    }
+
+  else_predecessors = 0;
+  for (cur_edge = else_bb->pred;
+       cur_edge != NULL_EDGE;
+       cur_edge = cur_edge->pred_next)
+    {
+      else_predecessors++;
+      if (cur_edge->flags & EDGE_COMPLEX)
+       return FALSE;
+    }
+
+  /* The THEN block of an IF-THEN combo must have exactly one predecessor,
+     other than any || blocks which jump to the THEN block.  */
+  if ((then_predecessors - ce_info->num_or_or_blocks) != 1)
     return FALSE;
 
-  /* The THEN block of an IF-THEN combo must have exactly one successor.  */
-  if (then_succ == NULL_EDGE
-      || then_succ->succ_next != NULL_EDGE
-      || (then_succ->flags & EDGE_COMPLEX))
+  /* The THEN block of an IF-THEN combo must have zero or one successors.  */
+  if (then_succ != NULL_EDGE
+      && (then_succ->succ_next != NULL_EDGE
+          || (then_succ->flags & EDGE_COMPLEX)))
     return FALSE;
 
+  /* If the THEN block has no successors, conditional execution can still
+     make a conditional call.  Don't do this unless the ELSE block has
+     only one incoming edge -- the CFG manipulation is too ugly otherwise.
+     Check for the last insn of the THEN block being an indirect jump, which
+     is listed as not having any successors, but confuses the rest of the CE
+     code processing.  ??? we should fix this in the future.  */
+  if (then_succ == NULL)
+    {
+      if (else_bb->pred->pred_next == NULL_EDGE)
+       {
+         rtx last_insn = then_bb->end;
+
+         while (last_insn
+                && GET_CODE (last_insn) == NOTE
+                && last_insn != then_bb->head)
+           last_insn = PREV_INSN (last_insn);
+
+         if (last_insn
+             && GET_CODE (last_insn) == JUMP_INSN
+             && ! simplejump_p (last_insn))
+           return FALSE;
+
+         join_bb = else_bb;
+         else_bb = NULL_BLOCK;
+       }
+      else
+       return FALSE;
+    }
+
   /* If the THEN block's successor is the other edge out of the TEST block,
      then we have an IF-THEN combo without an ELSE.  */
-  if (then_succ->dest == else_bb)
+  else if (then_succ->dest == else_bb)
     {
       join_bb = else_bb;
       else_bb = NULL_BLOCK;
@@ -1451,27 +2385,44 @@ find_if_block (test_bb, then_edge, else_edge)
 
   if (rtl_dump_file)
     {
+      fprintf (rtl_dump_file, "\nIF-THEN%s block found, pass %d, start block %d [insn %d], then %d [%d]",
+              (else_bb) ? "-ELSE" : "",
+              ce_info->pass,
+              test_bb->index, (test_bb->head) ? (int)INSN_UID (test_bb->head) : -1,
+              then_bb->index, (then_bb->head) ? (int)INSN_UID (then_bb->head) : -1);
+
       if (else_bb)
-       fprintf (rtl_dump_file,
-                "\nIF-THEN-ELSE block found, start %d, then %d, else %d, join %d\n",
-                test_bb->index, then_bb->index, else_bb->index,
-                join_bb->index);
-      else
-       fprintf (rtl_dump_file,
-                "\nIF-THEN block found, start %d, then %d, join %d\n",
-                test_bb->index, then_bb->index, join_bb->index);
+       fprintf (rtl_dump_file, ", else %d [%d]",
+                else_bb->index, (else_bb->head) ? (int)INSN_UID (else_bb->head) : -1);
+
+      fprintf (rtl_dump_file, ", join %d [%d]",
+              join_bb->index, (join_bb->head) ? (int)INSN_UID (join_bb->head) : -1);
+
+      if (ce_info->num_multiple_test_blocks > 0)
+       fprintf (rtl_dump_file, ", %d %s block%s last test %d [%d]",
+                ce_info->num_multiple_test_blocks,
+                (ce_info->and_and_p) ? "&&" : "||",
+                (ce_info->num_multiple_test_blocks == 1) ? "" : "s",
+                ce_info->last_test_bb->index,
+                ((ce_info->last_test_bb->head)
+                 ? (int)INSN_UID (ce_info->last_test_bb->head)
+                 : -1));
+
+      fputc ('\n', rtl_dump_file);
     }
 
-  /* Make sure IF, THEN, and ELSE, blocks are adjacent.  Actually, we
-     get the first condition for free, since we've already asserted that
-     there's a fallthru edge from IF to THEN.  */
-  /* ??? As an enhancement, move the ELSE block.  Have to deal with EH and
+  /* Make sure IF, THEN, and ELSE, blocks are adjacent.  Actually, we get the
+     first condition for free, since we've already asserted that there's a
+     fallthru edge from IF to THEN.  Likewise for the && and || blocks, since
+     we checked the FALLTHRU flag, those are already adjacent to the last IF
+     block.  */
+  /* ??? As an enhancement, move the ELSE block.  Have to deal with
      BLOCK notes, if by no other means than aborting the merge if they
      exist.  Sticky enough I don't want to think about it now.  */
-  next_index = then_bb->index;
-  if (else_bb && ++next_index != else_bb->index)
+  next = then_bb;
+  if (else_bb && (next = next->next_bb) != else_bb)
     return FALSE;
-  if (++next_index != join_bb->index)
+  if ((next = next->next_bb) != join_bb && join_bb != EXIT_BLOCK_PTR)
     {
       if (else_bb)
        join_bb = NULL;
@@ -1480,14 +2431,146 @@ find_if_block (test_bb, then_edge, else_edge)
     }
 
   /* Do the real work.  */
-  return process_if_block (test_bb, then_bb, else_bb, join_bb);
+  ce_info->else_bb = else_bb;
+  ce_info->join_bb = join_bb;
+
+  return process_if_block (ce_info);
+}
+
+/* Convert a branch over a trap, or a branch
+   to a trap, into a conditional trap.  */
+
+static int
+find_cond_trap (test_bb, then_edge, else_edge)
+     basic_block test_bb;
+     edge then_edge, else_edge;
+{
+  basic_block then_bb = then_edge->dest;
+  basic_block else_bb = else_edge->dest;
+  basic_block other_bb, trap_bb;
+  rtx trap, jump, cond, cond_earliest, seq;
+  enum rtx_code code;
+
+  /* Locate the block with the trap instruction.  */
+  /* ??? While we look for no successors, we really ought to allow
+     EH successors.  Need to fix merge_if_block for that to work.  */
+  if ((trap = block_has_only_trap (then_bb)) != NULL)
+    trap_bb = then_bb, other_bb = else_bb;
+  else if ((trap = block_has_only_trap (else_bb)) != NULL)
+    trap_bb = else_bb, other_bb = then_bb;
+  else
+    return FALSE;
+
+  if (rtl_dump_file)
+    {
+      fprintf (rtl_dump_file, "\nTRAP-IF block found, start %d, trap %d\n",
+              test_bb->index, trap_bb->index);
+    }
+
+  /* If this is not a standard conditional jump, we can't parse it.  */
+  jump = test_bb->end;
+  cond = noce_get_condition (jump, &cond_earliest);
+  if (! cond)
+    return FALSE;
+
+  /* If the conditional jump is more than just a conditional jump, then
+     we can not do if-conversion on this block.  */
+  if (! onlyjump_p (jump))
+    return FALSE;
+
+  /* We must be comparing objects whose modes imply the size.  */
+  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
+    return FALSE;
+
+  /* Reverse the comparison code, if necessary.  */
+  code = GET_CODE (cond);
+  if (then_bb == trap_bb)
+    {
+      code = reversed_comparison_code (cond, jump);
+      if (code == UNKNOWN)
+       return FALSE;
+    }
+
+  /* Attempt to generate the conditional trap.  */
+  seq = gen_cond_trap (code, XEXP (cond, 0), XEXP (cond, 1),
+                      TRAP_CODE (PATTERN (trap)));
+  if (seq == NULL)
+    return FALSE;
+
+  /* Emit the new insns before cond_earliest.  */
+  emit_insn_before_scope (seq, cond_earliest, INSN_SCOPE (trap));
+
+  /* Delete the trap block if possible.  */
+  remove_edge (trap_bb == then_bb ? then_edge : else_edge);
+  if (trap_bb->pred == NULL)
+    {
+      if (post_dominators)
+       delete_from_dominance_info (post_dominators, trap_bb);
+      flow_delete_block (trap_bb);
+      num_removed_blocks++;
+    }
+
+  /* If the non-trap block and the test are now adjacent, merge them.
+     Otherwise we must insert a direct branch.  */
+  if (test_bb->next_bb == other_bb)
+    {
+      struct ce_if_block new_ce_info;
+      delete_insn (jump);
+      memset ((PTR) &new_ce_info, '\0', sizeof (new_ce_info));
+      new_ce_info.test_bb = test_bb;
+      new_ce_info.then_bb = NULL;
+      new_ce_info.else_bb = NULL;
+      new_ce_info.join_bb = other_bb;
+      merge_if_block (&new_ce_info);
+    }
+  else
+    {
+      rtx lab, newjump;
+
+      lab = JUMP_LABEL (jump);
+      newjump = emit_jump_insn_after (gen_jump (lab), jump);
+      LABEL_NUSES (lab) += 1;
+      JUMP_LABEL (newjump) = lab;
+      emit_barrier_after (newjump);
+
+      delete_insn (jump);
+    }
+
+  return TRUE;
+}
+
+/* Subroutine of find_cond_trap: if BB contains only a trap insn, 
+   return it.  */
+
+static rtx
+block_has_only_trap (bb)
+     basic_block bb;
+{
+  rtx trap;
+
+  /* We're not the exit block.  */
+  if (bb == EXIT_BLOCK_PTR)
+    return NULL_RTX;
+
+  /* The block must have no successors.  */
+  if (bb->succ)
+    return NULL_RTX;
+
+  /* The only instruction in the THEN block must be the trap.  */
+  trap = first_active_insn (bb);
+  if (! (trap == bb->end
+        && GET_CODE (PATTERN (trap)) == TRAP_IF
+         && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx))
+    return NULL_RTX;
+
+  return trap;
 }
 
 /* Look for IF-THEN-ELSE cases in which one of THEN or ELSE is
    transformable, but not necessarily the other.  There need be no
    JOIN block.
 
-   Return TRUE if we were successful at converting the the block.
+   Return TRUE if we were successful at converting the block.
 
    Cases we'd like to look at:
 
@@ -1566,9 +2649,9 @@ find_if_case_1 (test_bb, then_edge, else_edge)
       edge then_edge, else_edge;
 {
   basic_block then_bb = then_edge->dest;
-  basic_block else_bb = else_edge->dest;
+  basic_block else_bb = else_edge->dest, new_bb;
   edge then_succ = then_bb->succ;
-  rtx new_lab;
+  int then_bb_index;
 
   /* THEN has one successor.  */
   if (!then_succ || then_succ->succ_next != NULL)
@@ -1582,8 +2665,8 @@ find_if_case_1 (test_bb, then_edge, else_edge)
   if (then_bb->pred->pred_next != NULL)
     return FALSE;
 
-  /* ELSE follows THEN.  (??? could be moved)  */
-  if (else_bb->index != then_bb->index + 1)
+  /* THEN must do something.  */
+  if (forwarder_block_p (then_bb))
     return FALSE;
 
   num_possible_if_blocks++;
@@ -1596,31 +2679,33 @@ find_if_case_1 (test_bb, then_edge, else_edge)
   if (count_bb_insns (then_bb) > BRANCH_COST)
     return FALSE;
 
-  /* Find the label for THEN's destination.  */
-  if (then_succ->dest == EXIT_BLOCK_PTR)
-    new_lab = NULL_RTX;
-  else
-    {
-      new_lab = JUMP_LABEL (then_bb->end);
-      if (! new_lab)
-       abort ();
-    }
-
   /* Registers set are dead, or are predicable.  */
-  if (! dead_or_predicable (test_bb, then_bb, else_bb, new_lab, 1))
+  if (! dead_or_predicable (test_bb, then_bb, else_bb, 
+                           then_bb->succ->dest, 1))
     return FALSE;
 
   /* Conversion went ok, including moving the insns and fixing up the
      jump.  Adjust the CFG to match.  */
 
-  SET_UPDATE_LIFE (test_bb);
   bitmap_operation (test_bb->global_live_at_end,
                    else_bb->global_live_at_start,
                    then_bb->global_live_at_end, BITMAP_IOR);
   
-  make_edge (NULL, test_bb, then_succ->dest, 0);
+  new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
+  then_bb_index = then_bb->index;
+  if (post_dominators)
+    delete_from_dominance_info (post_dominators, then_bb);
   flow_delete_block (then_bb);
-  tidy_fallthru_edge (else_edge, test_bb, else_bb);
+
+  /* Make rest of code believe that the newly created block is the THEN_BB
+     block we removed.  */
+  if (new_bb)
+    {
+      new_bb->index = then_bb_index;
+      BASIC_BLOCK (then_bb_index) = new_bb;
+    }
+  /* We've possibly created jump to next insn, cleanup_cfg will solve that
+     later.  */
 
   num_removed_blocks++;
   num_updated_if_blocks++;
@@ -1638,7 +2723,7 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   basic_block then_bb = then_edge->dest;
   basic_block else_bb = else_edge->dest;
   edge else_succ = else_bb->succ;
-  rtx new_lab, note;
+  rtx note;
 
   /* ELSE has one successor.  */
   if (!else_succ || else_succ->succ_next != NULL)
@@ -1661,8 +2746,8 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2)
     ;
   else if (else_succ->dest->index < 0
-          || TEST_BIT (post_dominators[ORIG_INDEX (then_bb)]
-                       ORIG_INDEX (else_succ->dest)))
+          || dominated_by_p (post_dominators, then_bb
+                             else_succ->dest))
     ;
   else
     return FALSE;
@@ -1674,42 +2759,22 @@ find_if_case_2 (test_bb, then_edge, else_edge)
             test_bb->index, else_bb->index);
 
   /* ELSE is small.  */
-  if (count_bb_insns (then_bb) > BRANCH_COST)
+  if (count_bb_insns (else_bb) > BRANCH_COST)
     return FALSE;
 
-  /* Find the label for ELSE's destination.  */
-  if (else_succ->dest == EXIT_BLOCK_PTR)
-    new_lab = NULL_RTX;
-  else
-    {
-      if (else_succ->flags & EDGE_FALLTHRU)
-       {
-         new_lab = else_succ->dest->head;
-         if (GET_CODE (new_lab) != CODE_LABEL)
-           abort ();
-       }
-      else
-       {
-         new_lab = JUMP_LABEL (else_bb->end);
-         if (! new_lab)
-           abort ();
-       }
-    }
-
   /* Registers set are dead, or are predicable.  */
-  if (! dead_or_predicable (test_bb, else_bb, then_bb, new_lab, 0))
+  if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0))
     return FALSE;
 
   /* Conversion went ok, including moving the insns and fixing up the
      jump.  Adjust the CFG to match.  */
 
-  SET_UPDATE_LIFE (test_bb);
   bitmap_operation (test_bb->global_live_at_end,
                    then_bb->global_live_at_start,
                    else_bb->global_live_at_end, BITMAP_IOR);
   
-  remove_edge (else_edge);
-  make_edge (NULL, test_bb, else_succ->dest, 0);
+  if (post_dominators)
+    delete_from_dominance_info (post_dominators, else_bb);
   flow_delete_block (else_bb);
 
   num_removed_blocks++;
@@ -1743,10 +2808,10 @@ find_memory (px, data)
 static int
 dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
      basic_block test_bb, merge_bb, other_bb;
-     rtx new_dest;
+     basic_block new_dest;
      int reversep;
 {
-  rtx head, end, jump, earliest, old_dest;
+  rtx head, end, jump, earliest, old_dest, new_label = NULL_RTX;
 
   jump = test_bb->end;
 
@@ -1776,6 +2841,9 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
       end = PREV_INSN (end);
     }
 
+  /* Disable handling dead code by conditional execution if the machine needs
+     to do anything funny with the tests, etc.  */
+#ifndef IFCVT_MODIFY_TESTS
   if (HAVE_conditional_execution)
     {
       /* In the conditional execution case, we have things easy.  We know
@@ -1787,6 +2855,8 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
       rtx cond, prob_val;
 
       cond = cond_exec_get_condition (jump);
+      if (! cond)
+       return FALSE;
 
       prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
       if (prob_val)
@@ -1794,19 +2864,23 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 
       if (reversep)
        {
-         cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                                GET_MODE (cond), XEXP (cond, 0),
+         enum rtx_code rev = reversed_comparison_code (cond, jump);
+         if (rev == UNKNOWN)
+           return FALSE;
+         cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
                                 XEXP (cond, 1));
          if (prob_val)
            prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
        }
 
-      if (! cond_exec_process_insns (head, end, cond, prob_val, 0))
+      if (! cond_exec_process_insns ((ce_if_block_t *)0, head, end, cond,
+                                    prob_val, 0))
        goto cancel;
 
       earliest = jump;
     }
   else
+#endif
     {
       /* In the non-conditional execution case, we have to verify that there
         are no trapping operations, no calls, no references to memory, and
@@ -1831,7 +2905,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
              /* ??? Even non-trapping memories such as stack frame
                 references must be avoided.  For stores, we collect
                 no lifetime info; for reads, we'd have to assert
-                true_dependance false against every store in the
+                true_dependence false against every store in the
                 TEST range.  */
              if (for_each_rtx (&PATTERN (insn), find_memory, NULL))
                return FALSE;
@@ -1840,7 +2914,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
            break;
        }
 
-      if (! condjump_p (jump))
+      if (! any_condjump_p (jump))
        return FALSE;
 
       /* Find the extent of the conditional.  */
@@ -1862,7 +2936,7 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
       /* ??? bb->local_set is only valid during calculate_global_regs_live,
         so we must recompute usage for MERGE_BB.  Not so bad, I suppose, 
          since we've already asserted that MERGE_BB is small.  */
-      propagate_block (merge_bb, tmp, merge_set, 0);
+      propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
 
       /* For small register class machines, don't lengthen lifetimes of
         hard registers before reload.  */
@@ -1882,7 +2956,8 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
         Moreover, we're interested in the insns live from OTHER_BB.  */
 
       COPY_REG_SET (test_live, other_bb->global_live_at_start);
-      pbi = init_propagate_block_info (test_bb, test_live, test_set, 0);
+      pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
+                                      0);
 
       for (insn = jump; ; insn = prev)
        {
@@ -1922,25 +2997,41 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
      change group management.  */
 
   old_dest = JUMP_LABEL (jump);
-  if (reversep
-      ? ! invert_jump_1 (jump, new_dest)
-      : ! redirect_jump_1 (jump, new_dest))
-    goto cancel;
+  if (other_bb != new_dest)
+    {
+      new_label = block_label (new_dest);
+      if (reversep
+         ? ! invert_jump_1 (jump, new_label)
+         : ! redirect_jump_1 (jump, new_label))
+       goto cancel;
+    }
 
   if (! apply_change_group ())
     return FALSE;
 
-  if (old_dest)
-    LABEL_NUSES (old_dest) -= 1;
-  if (new_dest)
-    LABEL_NUSES (new_dest) += 1;
-  JUMP_LABEL (jump) = new_dest;
-
-  if (reversep)
+  if (other_bb != new_dest)
     {
-      rtx note = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
-      if (note)
-       XEXP (note, 0) = GEN_INT (REG_BR_PROB_BASE - INTVAL (XEXP (note, 0)));
+      if (old_dest)
+       LABEL_NUSES (old_dest) -= 1;
+      if (new_label)
+       LABEL_NUSES (new_label) += 1;
+      JUMP_LABEL (jump) = new_label;
+      if (reversep)
+       invert_br_probabilities (jump);
+
+      redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
+      if (reversep)
+       {
+         gcov_type count, probability;
+         count = BRANCH_EDGE (test_bb)->count;
+         BRANCH_EDGE (test_bb)->count = FALLTHRU_EDGE (test_bb)->count;
+         FALLTHRU_EDGE (test_bb)->count = count;
+         probability = BRANCH_EDGE (test_bb)->probability;
+         BRANCH_EDGE (test_bb)->probability
+           = FALLTHRU_EDGE (test_bb)->probability;
+         FALLTHRU_EDGE (test_bb)->probability = probability;
+         update_br_prob_note (test_bb);
+       }
     }
 
   /* Move the insns out of MERGE_BB to before the branch.  */
@@ -1949,22 +3040,21 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
       if (end == merge_bb->end)
        merge_bb->end = PREV_INSN (head);
 
-      head = squeeze_notes (head, end);
-      if (GET_CODE (end) == NOTE
-         && (NOTE_LINE_NUMBER (end) == NOTE_INSN_BLOCK_END
-              || NOTE_LINE_NUMBER (end) == NOTE_INSN_BLOCK_BEG
-              || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_BEG
-              || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_END
-              || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_CONT
-              || NOTE_LINE_NUMBER (end) == NOTE_INSN_LOOP_VTOP))
-       {
-         if (head == end)
-           return TRUE;
-         end = PREV_INSN (end);
-       }
+      if (squeeze_notes (&head, &end))
+       return TRUE;
 
       reorder_insns (head, end, PREV_INSN (earliest));
     }
+
+  /* Remove the jump and edge if we can.  */
+  if (other_bb == new_dest)
+    {
+      delete_insn (jump);
+      remove_edge (BRANCH_EDGE (test_bb));
+      /* ??? Can't merge blocks here, as then_bb is still in use.
+        At minimum, the merge will get done just before bb-reorder.  */
+    }
+
   return TRUE;
 
  cancel:
@@ -1975,16 +3065,18 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 /* Main entry point for all if-conversion.  */
 
 void
-if_convert (life_data_ok)
-     int life_data_ok;
+if_convert (x_life_data_ok)
+     int x_life_data_ok;
 {
-  int block_num;
+  basic_block bb;
+  int pass;
 
   num_possible_if_blocks = 0;
   num_updated_if_blocks = 0;
   num_removed_blocks = 0;
+  life_data_ok = (x_life_data_ok != 0);
 
-  /* Free up basic_block_for_insn so that we don't have to keep it 
+  /* Free up basic_block_for_insn so that we don't have to keep it
      up to date, either here or in merge_blocks_nomove.  */
   free_basic_block_vars (1);
 
@@ -1992,56 +3084,64 @@ if_convert (life_data_ok)
   post_dominators = NULL;
   if (HAVE_conditional_execution || life_data_ok)
     {
-      post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
-      compute_flow_dominators (NULL, post_dominators);
+      post_dominators = calculate_dominance_info (CDI_POST_DOMINATORS);
     }
+  if (life_data_ok)
+    clear_bb_flags ();
 
-  /* Record initial block numbers.  */
-  for (block_num = 0; block_num < n_basic_blocks; block_num++)
-    SET_ORIG_INDEX (BASIC_BLOCK (block_num), block_num);
-
-  /* Go through each of the basic blocks looking for things to convert.  */
-  for (block_num = 0; block_num < n_basic_blocks; )
+  /* Go through each of the basic blocks looking for things to convert.  If we
+     have conditional execution, we make multiple passes to allow us to handle
+     IF-THEN{-ELSE} blocks within other IF-THEN{-ELSE} blocks.  */
+  pass = 0;
+  do
     {
-      basic_block bb = BASIC_BLOCK (block_num);
-      if (find_if_header (bb))
-       block_num = bb->index;
-      else 
-       block_num++;
+      cond_exec_changed_p = FALSE;
+      pass++;
+
+#ifdef IFCVT_MULTIPLE_DUMPS
+      if (rtl_dump_file && pass > 1)
+       fprintf (rtl_dump_file, "\n\n========== Pass %d ==========\n", pass);
+#endif
+
+      FOR_EACH_BB (bb)
+       {
+         basic_block new_bb;
+         while ((new_bb = find_if_header (bb, pass)))
+           bb = new_bb;
+       }
+
+#ifdef IFCVT_MULTIPLE_DUMPS
+      if (rtl_dump_file && cond_exec_changed_p)
+       print_rtl_with_bb (rtl_dump_file, get_insns ());
+#endif
     }
+  while (cond_exec_changed_p);
+
+#ifdef IFCVT_MULTIPLE_DUMPS
+  if (rtl_dump_file)
+    fprintf (rtl_dump_file, "\n\n========== no more changes\n");
+#endif
 
   if (post_dominators)
-    sbitmap_vector_free (post_dominators);
+    free_dominance_info (post_dominators);
 
   if (rtl_dump_file)
     fflush (rtl_dump_file);
 
-  /* Rebuild basic_block_for_insn for update_life_info and for gcse.  */
-  compute_bb_for_insn (get_max_uid ());
+  clear_aux_for_blocks ();
 
   /* Rebuild life info for basic blocks that require it.  */
   if (num_removed_blocks && life_data_ok)
     {
-      sbitmap update_life_blocks = sbitmap_alloc (n_basic_blocks);
-      sbitmap_zero (update_life_blocks);
-
       /* If we allocated new pseudos, we must resize the array for sched1.  */
       if (max_regno < max_reg_num ())
        {
          max_regno = max_reg_num ();
          allocate_reg_info (max_regno, FALSE, FALSE);
        }
-
-      for (block_num = 0; block_num < n_basic_blocks; block_num++)
-       if (UPDATE_LIFE (BASIC_BLOCK (block_num)))
-         SET_BIT (update_life_blocks, block_num);
-
-      count_or_remove_death_notes (update_life_blocks, 1);
-      update_life_info (update_life_blocks, UPDATE_LIFE_LOCAL,
-                       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.  */