OSDN Git Service

Index: gcc/ChangeLog
[pf3gnuchains/gcc-fork.git] / gcc / ifcvt.c
index c5778e1..2939de4 100644 (file)
@@ -1,22 +1,22 @@
 /* If-conversion support.
-   Copyright (C) 2000 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001 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"
@@ -32,6 +32,7 @@
 #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)
@@ -65,6 +72,9 @@ static int num_updated_if_blocks;
 /* # of basic blocks that were removed.  */
 static int num_removed_blocks;
 
+/* True if life data ok at present.  */
+static bool life_data_ok;
+
 /* The post-dominator relation on the original block numbers.  */
 static sbitmap *post_dominators;
 
@@ -93,9 +103,11 @@ static int find_if_header           PARAMS ((basic_block));
 static int find_if_block               PARAMS ((basic_block, edge, edge));
 static int find_if_case_1              PARAMS ((basic_block, edge, edge));
 static int find_if_case_2              PARAMS ((basic_block, edge, edge));
+static int find_cond_trap              PARAMS ((basic_block, edge, edge));
 static int find_memory                 PARAMS ((rtx *, void *));
 static int dead_or_predicable          PARAMS ((basic_block, basic_block,
-                                                basic_block, rtx, int));
+                                                basic_block, basic_block, int));
+static void noce_emit_move_insn                PARAMS ((rtx, rtx));
 \f
 /* Abuse the basic_block AUX field to store the original block index,
    as well as a flag indicating that the block should be rescaned for
@@ -286,9 +298,14 @@ cond_exec_get_condition (jump)
      reverse the condition.  */
   if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
       && XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump))
-    cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                          GET_MODE (cond), XEXP (cond, 0),
-                          XEXP (cond, 1));
+    {
+      enum rtx_code rev = reversed_comparison_code (cond, jump);
+      if (rev == UNKNOWN)
+       return NULL_RTX;
+
+      cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
+                            XEXP (cond, 1));
+    }
 
   return cond;
 }
@@ -309,13 +326,14 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
   rtx then_end;                        /* last insn + 1 in THEN block */
   rtx else_start = NULL_RTX;   /* first insn in ELSE block or NULL */
   rtx else_end = NULL_RTX;     /* last insn + 1 in ELSE block */
-  int max;                     /* max # of insns to convert. */
+  int max;                     /* max # of insns to convert.  */
   int then_mod_ok;             /* whether conditional mods are ok in THEN */
   rtx true_expr;               /* test for else block insns */
   rtx false_expr;              /* test for then block insns */
   rtx true_prob_val;           /* probability of else block */
   rtx false_prob_val;          /* probability of then block */
   int n_insns;
+  enum rtx_code false_code;
 
   /* Find the conditional jump to the ELSE or JOIN part, and isolate
      the test.  */
@@ -377,9 +395,13 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
      the conditionally executed code.  */
   
   true_expr = test_expr;
-  false_expr = gen_rtx_fmt_ee (reverse_condition (GET_CODE (true_expr)),
-                              GET_MODE (true_expr), XEXP (true_expr, 0),
-                              XEXP (true_expr, 1));
+
+  false_code = reversed_comparison_code (true_expr, test_bb->end);
+  if (false_code != UNKNOWN)
+    false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr),
+                                XEXP (true_expr, 0), XEXP (true_expr, 1));
+  else
+    false_expr = NULL_RTX;
 
 #ifdef IFCVT_MODIFY_TESTS
   /* If the machine description needs to modify the tests, such as setting a
@@ -409,8 +431,9 @@ cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
      to conditional execution.  */
 
   if (then_end
-      && ! cond_exec_process_insns (then_start, then_end,
-                                   false_expr, false_prob_val, then_mod_ok))
+      && (! false_expr
+         || ! cond_exec_process_insns (then_start, then_end, false_expr,
+                                       false_prob_val, then_mod_ok)))
     goto fail;
 
   if (else_bb
@@ -496,15 +519,16 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
   if (cond_complex)
     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);
@@ -530,16 +554,36 @@ noce_emit_store_flag (if_info, x, reversep, normalize)
   if (cond_complex)
     return NULL_RTX;
 
-  code = GET_CODE (cond);
-  if (reversep)
-    code = reverse_condition (code);
-
   return emit_store_flag (x, code, XEXP (cond, 0),
                          XEXP (cond, 1), VOIDmode,
                          (code == LTU || code == LEU
                           || code == GEU || code == GTU), normalize);
 }
 
+/* Emit instruction to move an rtx into STRICT_LOW_PART.  */
+static void
+noce_emit_move_insn (x, y)
+     rtx x, y;
+{
+  enum machine_mode outmode, inmode;
+  rtx outer, inner;
+  int bitpos;
+
+  if (GET_CODE (x) != STRICT_LOW_PART)
+    {
+      emit_move_insn (x, y);
+      return;
+    }
+
+  outer = XEXP (x, 0);
+  inner = XEXP (outer, 0);
+  outmode = GET_MODE (outer);
+  inmode = GET_MODE (inner);
+  bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
+  store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y,
+                  GET_MODE_BITSIZE (inmode));
+}
+
 /* Convert "if (test) x = 1; else x = 0".
 
    Only try 0 and STORE_FLAG_VALUE here.  Other combinations will be
@@ -560,7 +604,8 @@ noce_try_store_flag (if_info)
   else if (if_info->b == const0_rtx
           && GET_CODE (if_info->a) == CONST_INT
           && INTVAL (if_info->a) == STORE_FLAG_VALUE
-          && can_reverse_comparison_p (if_info->cond, if_info->jump))
+          && (reversed_comparison_code (if_info->cond, if_info->jump)
+              != UNKNOWN))
     reversep = 1;
   else
     return FALSE;
@@ -571,7 +616,7 @@ noce_try_store_flag (if_info)
   if (target)
     {
       if (target != if_info->x)
-       emit_move_insn (if_info->x, target);
+       noce_emit_move_insn (if_info->x, target);
 
       seq = get_insns ();
       end_sequence ();
@@ -596,16 +641,25 @@ noce_try_store_flag_constants (if_info)
   int reversep;
   HOST_WIDE_INT itrue, ifalse, diff, tmp;
   int normalize, can_reverse;
+  enum machine_mode mode;
 
   if (! no_new_pseudos
       && GET_CODE (if_info->a) == CONST_INT
       && GET_CODE (if_info->b) == CONST_INT)
     {
+      mode = GET_MODE (if_info->x);
       ifalse = INTVAL (if_info->a);
       itrue = INTVAL (if_info->b);
-      diff = itrue - ifalse;
 
-      can_reverse = can_reverse_comparison_p (if_info->cond, if_info->jump);
+      /* Make sure we can represent the difference between the two values.  */
+      if ((itrue - ifalse > 0)
+         != ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
+       return FALSE;
+
+      diff = trunc_int_for_mode (itrue - ifalse, mode);
+
+      can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
+                    != UNKNOWN);
 
       reversep = 0;
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
@@ -633,7 +687,7 @@ noce_try_store_flag_constants (if_info)
       if (reversep)
        {
          tmp = itrue; itrue = ifalse; ifalse = tmp;
-         diff = -diff;
+         diff = trunc_int_for_mode (-diff, mode);
        }
 
       start_sequence ();
@@ -648,42 +702,42 @@ noce_try_store_flag_constants (if_info)
         =>   x = 3 + (test == 0);  */
       if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
        {
-         target = expand_binop (GET_MODE (if_info->x),
-                                (diff == STORE_FLAG_VALUE
-                                 ? add_optab : sub_optab),
-                                GEN_INT (ifalse), target, if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode,
+                                       (diff == STORE_FLAG_VALUE
+                                        ? PLUS : MINUS),
+                                       GEN_INT (ifalse), target, if_info->x, 0,
+                                       OPTAB_WIDEN);
        }
 
       /* if (test) x = 8; else x = 0;
         =>   x = (test != 0) << 3;  */
       else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
        {
-         target = expand_binop (GET_MODE (if_info->x), ashl_optab,
-                                target, GEN_INT (tmp), if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode, ASHIFT,
+                                       target, GEN_INT (tmp), if_info->x, 0,
+                                       OPTAB_WIDEN);
        }
 
       /* if (test) x = -1; else x = b;
         =>   x = -(test != 0) | b;  */
       else if (itrue == -1)
        {
-         target = expand_binop (GET_MODE (if_info->x), ior_optab,
-                                target, GEN_INT (ifalse), if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode, IOR,
+                                       target, GEN_INT (ifalse), if_info->x, 0,
+                                       OPTAB_WIDEN);
        }
 
       /* if (test) x = a; else x = b;
         =>   x = (-(test != 0) & (b - a)) + a;  */
       else
        {
-         target = expand_binop (GET_MODE (if_info->x), and_optab,
-                                target, GEN_INT (diff), if_info->x, 0,
-                                OPTAB_WIDEN);
+         target = expand_simple_binop (mode, AND,
+                                       target, GEN_INT (diff), if_info->x, 0,
+                                       OPTAB_WIDEN);
          if (target)
-           target = expand_binop (GET_MODE (if_info->x), add_optab,
-                                  target, GEN_INT (ifalse), if_info->x, 0,
-                                  OPTAB_WIDEN);
+           target = expand_simple_binop (mode, PLUS,
+                                         target, GEN_INT (ifalse),
+                                         if_info->x, 0, OPTAB_WIDEN);
        }
 
       if (! target)
@@ -693,7 +747,7 @@ noce_try_store_flag_constants (if_info)
        }
 
       if (target != if_info->x)
-       emit_move_insn (if_info->x, target);
+       noce_emit_move_insn (if_info->x, target);
 
       seq = get_insns ();
       end_sequence ();
@@ -729,7 +783,8 @@ noce_try_store_flag_inc (if_info)
       && (XEXP (if_info->a, 1) == const1_rtx
          || XEXP (if_info->a, 1) == constm1_rtx)
       && rtx_equal_p (XEXP (if_info->a, 0), if_info->x)
-      && can_reverse_comparison_p (if_info->cond, if_info->jump))
+      && (reversed_comparison_code (if_info->cond, if_info->jump)
+         != UNKNOWN))
     {
       if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
        subtract = 0, normalize = 0;
@@ -745,13 +800,14 @@ noce_try_store_flag_inc (if_info)
                                     1, normalize);
 
       if (target)
-       target = expand_binop (GET_MODE (if_info->x),
-                              subtract ? sub_optab : add_optab,
-                              if_info->x, target, if_info->x, 0, OPTAB_WIDEN);
+       target = expand_simple_binop (GET_MODE (if_info->x),
+                                     subtract ? MINUS : PLUS,
+                                     if_info->x, target, if_info->x,
+                                     0, OPTAB_WIDEN);
       if (target)
        {
          if (target != if_info->x)
-           emit_move_insn (if_info->x, target);
+           noce_emit_move_insn (if_info->x, target);
 
          seq = get_insns ();
          end_sequence ();
@@ -785,8 +841,9 @@ noce_try_store_flag_mask (if_info)
          || STORE_FLAG_VALUE == -1)
       && ((if_info->a == const0_rtx
           && rtx_equal_p (if_info->b, if_info->x))
-         || ((reversep = can_reverse_comparison_p (if_info->cond,
-                                                   if_info->jump))
+         || ((reversep = (reversed_comparison_code (if_info->cond,
+                                                    if_info->jump)
+                          != UNKNOWN))
              && if_info->b == const0_rtx
              && rtx_equal_p (if_info->a, if_info->x))))
     {
@@ -795,14 +852,14 @@ noce_try_store_flag_mask (if_info)
                                     gen_reg_rtx (GET_MODE (if_info->x)),
                                     reversep, -1);
       if (target)
-        target = expand_binop (GET_MODE (if_info->x), and_optab,
-                              if_info->x, target, if_info->x, 0,
-                              OPTAB_WIDEN);
+        target = expand_simple_binop (GET_MODE (if_info->x), AND,
+                                     if_info->x, target, if_info->x, 0,
+                                     OPTAB_WIDEN);
 
       if (target)
        {
          if (target != if_info->x)
-           emit_move_insn (if_info->x, target);
+           noce_emit_move_insn (if_info->x, target);
 
          seq = get_insns ();
          end_sequence ();
@@ -901,7 +958,7 @@ noce_try_cmove (if_info)
       if (target)
        {
          if (target != if_info->x)
-           emit_move_insn (if_info->x, target);
+           noce_emit_move_insn (if_info->x, target);
 
          seq = get_insns ();
          end_sequence ();
@@ -964,7 +1021,7 @@ noce_try_cmove_arith (if_info)
   insn_b = if_info->insn_b;
 
   /* Possibly rearrange operands to make things come out more natural.  */
-  if (can_reverse_comparison_p (if_info->cond, if_info->jump))
+  if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
     {
       int reversep = 0;
       if (rtx_equal_p (b, x))
@@ -974,7 +1031,7 @@ noce_try_cmove_arith (if_info)
 
       if (reversep)
        {
-         code = reverse_condition (code);
+         code = reversed_comparison_code (if_info->cond, if_info->jump);
          tmp = a, a = b, b = tmp;
          tmp = insn_a, insn_a = insn_b, insn_b = tmp;
        }
@@ -1056,12 +1113,14 @@ noce_try_cmove_arith (if_info)
       if (MEM_SCALAR_P (if_info->a) && MEM_SCALAR_P (if_info->b))
        MEM_SCALAR_P (tmp) = 1;
       if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b))
-       MEM_ALIAS_SET (tmp) = MEM_ALIAS_SET (if_info->a);
+       set_mem_alias_set (tmp, MEM_ALIAS_SET (if_info->a));
+      set_mem_align (tmp,
+                    MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b)));
 
-      emit_move_insn (if_info->x, tmp);
+      noce_emit_move_insn (if_info->x, tmp);
     }
   else if (target != x)
-    emit_move_insn (x, target);
+    noce_emit_move_insn (x, target);
 
   tmp = get_insns ();
   end_sequence ();
@@ -1099,6 +1158,108 @@ noce_get_alt_condition (if_info, target, earliest)
     = GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
       && XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump);
 
+  /* If we're looking for a constant, try to make the conditional
+     have that constant in it.  There are two reasons why it may
+     not have the constant we want:
+
+     1. GCC may have needed to put the constant in a register, because
+        the target can't compare directly against that constant.  For
+        this case, we look for a SET immediately before the comparison
+        that puts a constant in that register.
+
+     2. GCC may have canonicalized the conditional, for example
+       replacing "if x < 4" with "if x <= 3".  We can undo that (or
+       make equivalent types of changes) to get the constants we need
+       if they're off by one in the right direction.  */
+
+  if (GET_CODE (target) == CONST_INT)
+    {
+      enum rtx_code code = GET_CODE (if_info->cond);
+      rtx op_a = XEXP (if_info->cond, 0);
+      rtx op_b = XEXP (if_info->cond, 1);
+      rtx prev_insn;
+
+      /* First, look to see if we put a constant in a register.  */
+      prev_insn = PREV_INSN (if_info->cond_earliest);
+      if (prev_insn
+         && INSN_P (prev_insn)
+         && GET_CODE (PATTERN (prev_insn)) == SET)
+       {
+         rtx src = find_reg_equal_equiv_note (prev_insn);
+         if (!src)
+           src = SET_SRC (PATTERN (prev_insn));
+         if (GET_CODE (src) == CONST_INT)
+           {
+             if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn))))
+               op_a = src;
+             else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn))))
+               op_b = src;
+
+             if (GET_CODE (op_a) == CONST_INT)
+               {
+                 rtx tmp = op_a;
+                 op_a = op_b;
+                 op_b = tmp;
+                 code = swap_condition (code);
+               }
+           }
+       }
+
+      /* Now, look to see if we can get the right constant by
+        adjusting the conditional.  */
+      if (GET_CODE (op_b) == CONST_INT)
+       {
+         HOST_WIDE_INT desired_val = INTVAL (target);
+         HOST_WIDE_INT actual_val = INTVAL (op_b);
+
+         switch (code)
+           {
+           case LT:
+             if (actual_val == desired_val + 1)
+               {
+                 code = LE;
+                 op_b = GEN_INT (desired_val);
+               }
+             break;
+           case LE:
+             if (actual_val == desired_val - 1)
+               {
+                 code = LT;
+                 op_b = GEN_INT (desired_val);
+               }
+             break;
+           case GT:
+             if (actual_val == desired_val - 1)
+               {
+                 code = GE;
+                 op_b = GEN_INT (desired_val);
+               }
+             break;
+           case GE:
+             if (actual_val == desired_val + 1)
+               {
+                 code = GT;
+                 op_b = GEN_INT (desired_val);
+               }
+             break;
+           default:
+             break;
+           }
+       }
+
+      /* If we made any changes, generate a new conditional that is
+        equivalent to what we started with, but has the right
+        constants in it.  */
+      if (code != GET_CODE (if_info->cond)
+         || op_a != XEXP (if_info->cond, 0)
+         || op_b != XEXP (if_info->cond, 1))
+       {
+         cond = gen_rtx_fmt_ee (code, GET_MODE (cond), op_a, op_b);
+         *earliest = if_info->cond_earliest;
+         return cond;
+       }
+    }
+
   cond = canonicalize_condition (if_info->jump, cond, reverse,
                                 earliest, target);
   if (! cond || ! reg_mentioned_p (target, cond))
@@ -1129,9 +1290,8 @@ noce_try_minmax (if_info)
      struct noce_if_info *if_info;
 { 
   rtx cond, earliest, target, seq;
-  enum rtx_code code;
+  enum rtx_code code, op;
   int unsignedp;
-  optab op;
 
   /* ??? Can't guarantee that expand_binop won't create pseudos.  */
   if (no_new_pseudos)
@@ -1142,7 +1302,7 @@ noce_try_minmax (if_info)
      to get the target to tell us...  */
   if (FLOAT_MODE_P (GET_MODE (if_info->x))
       && TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-      && ! flag_fast_math)
+      && ! flag_unsafe_math_optimizations)
     return FALSE;
 
   cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
@@ -1174,24 +1334,24 @@ noce_try_minmax (if_info)
     case LE:
     case UNLT:
     case UNLE:
-      op = smax_optab;
+      op = SMAX;
       unsignedp = 0;
       break;
     case GT:
     case GE:
     case UNGT:
     case UNGE:
-      op = smin_optab;
+      op = SMIN;
       unsignedp = 0;
       break;
     case LTU:
     case LEU:
-      op = umax_optab;
+      op = UMAX;
       unsignedp = 1;
       break;
     case GTU:
     case GEU:
-      op = umin_optab;
+      op = UMIN;
       unsignedp = 1;
       break;
     default:
@@ -1200,15 +1360,16 @@ noce_try_minmax (if_info)
 
   start_sequence ();
 
-  target = expand_binop (GET_MODE (if_info->x), op, if_info->a, if_info->b,
-                        if_info->x, unsignedp, OPTAB_WIDEN);
+  target = expand_simple_binop (GET_MODE (if_info->x), op,
+                               if_info->a, if_info->b,
+                               if_info->x, unsignedp, OPTAB_WIDEN);
   if (! target)
     {
       end_sequence ();
       return FALSE;
     }
   if (target != if_info->x)
-    emit_move_insn (if_info->x, target);
+    noce_emit_move_insn (if_info->x, target);
 
   seq = get_insns ();
   end_sequence ();  
@@ -1312,12 +1473,12 @@ noce_try_abs (if_info)
 
   start_sequence ();
 
-  target = expand_unop (GET_MODE (if_info->x), abs_optab, b, if_info->x, 0);
+  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_unop (GET_MODE (target), neg_optab, target, if_info->x, 0);
+    target = expand_simple_unop (GET_MODE (target), NEG, target, if_info->x, 0);
 
   if (! target)
     {
@@ -1326,7 +1487,7 @@ noce_try_abs (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 ();  
@@ -1396,10 +1557,10 @@ noce_operand_ok (op)
   if (side_effects_p (op))
     return FALSE;
 
-  /* ??? Unfortuantely may_trap_p can't look at flag_fast_math, due to
+  /* ??? Unfortuantely may_trap_p can't look at flag_trapping_math, due to
      being linked into the genfoo programs.  This is probably a mistake.
      With finite operands, most fp operations don't trap.  */
-  if (flag_fast_math && FLOAT_MODE_P (GET_MODE (op)))
+  if (!flag_trapping_math && FLOAT_MODE_P (GET_MODE (op)))
     switch (GET_CODE (op))
       {
       case DIV:
@@ -1416,8 +1577,9 @@ noce_operand_ok (op)
       default:
        switch (GET_RTX_CLASS (GET_CODE (op)))
          {
-         case 'c':
          case '1':
+           return ! may_trap_p (XEXP (op, 0));
+         case 'c':
          case '2':
            return ! may_trap_p (XEXP (op, 0)) && ! may_trap_p (XEXP (op, 1));
          }
@@ -1530,7 +1692,8 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
     {
       if (no_new_pseudos)
        return FALSE;
-      x = gen_reg_rtx (GET_MODE (x));
+      x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
+                                ? XEXP (x, 0) : x));
     }
 
   /* Don't operate on sources that may trap or are volatile.  */
@@ -1561,9 +1724,17 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
         that case don't do anything and let the code below delete INSN_A.  */
       if (insn_b && else_bb)
        {
+         rtx note;
+
          if (else_bb && insn_b == else_bb->end)
            else_bb->end = PREV_INSN (insn_b);
          reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
+
+         /* If there was a REG_EQUAL note, delete it since it may have been
+            true due to this insn being after a jump.  */
+         if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0)
+           remove_note (insn_b, note);
+
          insn_b = NULL_RTX;
        }
       /* If we have "x = b; if (...) x = a;", and x has side-effects, then
@@ -1601,9 +1772,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
@@ -1612,27 +1781,22 @@ noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
      the TEST block, it may in fact be loading data needed for the comparison.
      We'll let life_analysis remove the insn if it's really dead.  */
   if (insn_b && else_bb)
-    {
-      if (insn_b == else_bb->end)
-       else_bb->end = PREV_INSN (insn_b);
-      flow_delete_insn (insn_b);
-    }
+    delete_insn (insn_b);
 
   /* The new insns will have been inserted before cond_earliest.  We should
      be able to remove the jump with impunity, but the condition itself may
      have been modified by gcse to be shared across basic blocks.  */
-  test_bb->end = PREV_INSN (jump);
-  flow_delete_insn (jump);
+  delete_insn (jump);
 
   /* If we used a temporary, fix it up now.  */
   if (orig_x != x)
     {
       start_sequence ();
-      emit_move_insn (orig_x, x);
+      noce_emit_move_insn (orig_x, x);
       insn_b = gen_sequence ();
       end_sequence ();
 
-      test_bb->end = emit_insn_after (insn_b, test_bb->end);
+      emit_insn_after (insn_b, test_bb->end);
     }
 
   /* Merge the blocks!  */
@@ -1681,7 +1845,7 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
   /* First merge TEST block into THEN block.  This is a no-brainer since
      the THEN block did not have a code label to begin with.  */
 
-  if (combo_bb->global_live_at_end)
+  if (life_data_ok)
     COPY_REG_SET (combo_bb->global_live_at_end, then_bb->global_live_at_end);
   merge_blocks_nomove (combo_bb, then_bb);
   num_removed_blocks++;
@@ -1705,10 +1869,9 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
       if (combo_bb->succ == NULL_EDGE)
        abort ();
 
-      /* There should sill be a branch at the end of the THEN or ELSE
+      /* There should still be a branch at the end of the THEN or ELSE
          blocks taking us to our final destination.  */
-      if (! simplejump_p (combo_bb->end)
-          && ! returnjump_p (combo_bb->end))
+      if (GET_CODE (combo_bb->end) != JUMP_INSN)
        abort ();
     }
 
@@ -1718,10 +1881,12 @@ merge_if_block (test_bb, then_bb, else_bb, join_bb)
      is more than one remaining edge, it must come from elsewhere.  There
      may be zero incoming edges if the THEN block didn't actually join 
      back up (as with a call to abort).  */
-  else if (join_bb->pred == NULL || join_bb->pred->pred_next == NULL)
+  else if ((join_bb->pred == NULL
+           || join_bb->pred->pred_next == NULL)
+          && join_bb != EXIT_BLOCK_PTR)
     {
       /* We can merge the JOIN.  */
-      if (combo_bb->global_live_at_end)
+      if (life_data_ok)
        COPY_REG_SET (combo_bb->global_live_at_end,
                      join_bb->global_live_at_end);
       merge_blocks_nomove (combo_bb, join_bb);
@@ -1738,7 +1903,8 @@ 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.  */
@@ -1783,6 +1949,9 @@ find_if_header (test_bb)
 
   if (find_if_block (test_bb, then_edge, else_edge))
     goto success;
+  if (HAVE_trap && HAVE_conditional_trap
+      && find_cond_trap (test_bb, then_edge, else_edge))
+    goto success;
   if (post_dominators
       && (! HAVE_conditional_execution || reload_completed))
     {
@@ -1895,13 +2064,13 @@ find_if_block (test_bb, then_edge, else_edge)
   /* Make sure IF, THEN, and ELSE, blocks are adjacent.  Actually, we
      get the first condition for free, since we've already asserted that
      there's a fallthru edge from IF to THEN.  */
-  /* ??? As an enhancement, move the ELSE block.  Have to deal with EH and
+  /* ??? As an enhancement, move the ELSE block.  Have to deal with
      BLOCK notes, if by no other means than aborting the merge if they
      exist.  Sticky enough I don't want to think about it now.  */
   next_index = then_bb->index;
   if (else_bb && ++next_index != else_bb->index)
     return FALSE;
-  if (++next_index != join_bb->index)
+  if (++next_index != join_bb->index && join_bb->index != EXIT_BLOCK)
     {
       if (else_bb)
        join_bb = NULL;
@@ -1913,6 +2082,128 @@ find_if_block (test_bb, then_edge, else_edge)
   return process_if_block (test_bb, then_bb, else_bb, join_bb);
 }
 
+/* Convert a branch over a trap, or a branch to a trap,
+   into a conditional trap.  */
+
+static int
+find_cond_trap (test_bb, then_edge, else_edge)
+     basic_block test_bb;
+     edge then_edge, else_edge;
+{
+  basic_block then_bb, else_bb, join_bb, trap_bb;
+  rtx trap, jump, cond, cond_earliest, seq;
+  enum rtx_code code;
+
+  then_bb = then_edge->dest;
+  else_bb = else_edge->dest;
+  join_bb = NULL;
+
+  /* Locate the block with the trap instruction.  */
+  /* ??? While we look for no successors, we really ought to allow
+     EH successors.  Need to fix merge_if_block for that to work.  */
+  /* ??? We can't currently handle merging the blocks if they are not
+     already adjacent.  Prevent losage in merge_if_block by detecting
+     this now.  */
+  if (then_bb->succ == NULL)
+    {
+      trap_bb = then_bb;
+      if (else_bb->index != then_bb->index + 1)
+       return FALSE;
+      join_bb = else_bb;
+      else_bb = NULL;
+    }
+  else if (else_bb->succ == NULL)
+    {
+      trap_bb = else_bb;
+      if (else_bb->index != then_bb->index + 1)
+       else_bb = NULL;
+      else if (then_bb->succ
+         && ! then_bb->succ->succ_next
+         && ! (then_bb->succ->flags & EDGE_COMPLEX)
+         && then_bb->succ->dest->index == else_bb->index + 1)
+       join_bb = then_bb->succ->dest;
+    }
+  else
+    return FALSE;
+
+  /* Don't confuse a conditional return with something we want to
+     optimize here.  */
+  if (trap_bb == EXIT_BLOCK_PTR)
+    return FALSE;
+
+  /* The only instruction in the THEN block must be the trap.  */
+  trap = first_active_insn (trap_bb);
+  if (! (trap == trap_bb->end
+        && GET_CODE (PATTERN (trap)) == TRAP_IF
+         && TRAP_CONDITION (PATTERN (trap)) == const_true_rtx))
+    return FALSE;
+
+  if (rtl_dump_file)
+    {
+      if (trap_bb == then_bb)
+       fprintf (rtl_dump_file,
+                "\nTRAP-IF block found, start %d, trap %d",
+                test_bb->index, then_bb->index);
+      else
+       fprintf (rtl_dump_file,
+                "\nTRAP-IF block found, start %d, then %d, trap %d",
+                test_bb->index, then_bb->index, trap_bb->index);
+      if (join_bb)
+       fprintf (rtl_dump_file, ", join %d\n", join_bb->index);
+      else
+       fputc ('\n', rtl_dump_file);
+    }
+
+  /* If this is not a standard conditional jump, we can't parse it.  */
+  jump = test_bb->end;
+  cond = noce_get_condition (jump, &cond_earliest);
+  if (! cond)
+    return FALSE;
+
+  /* If the conditional jump is more than just a conditional jump,
+     then we can not do if-conversion on this block.  */
+  if (! onlyjump_p (jump))
+    return FALSE;
+
+  /* We must be comparing objects whose modes imply the size.  */
+  if (GET_MODE (XEXP (cond, 0)) == BLKmode)
+    return FALSE;
+
+  /* Reverse the comparison code, if necessary.  */
+  code = GET_CODE (cond);
+  if (then_bb == trap_bb)
+    {
+      code = reversed_comparison_code (cond, jump);
+      if (code == UNKNOWN)
+       return FALSE;
+    }
+
+  /* Attempt to generate the conditional trap.  */
+  seq = gen_cond_trap (code, XEXP (cond, 0), XEXP (cond, 1),
+                      TRAP_CODE (PATTERN (trap)));
+  if (seq == NULL)
+    return FALSE;
+
+  /* Emit the new insns before cond_earliest; delete the old jump
+     and trap insns.  */
+
+  emit_insn_before (seq, cond_earliest);
+
+  delete_insn (jump);
+
+  delete_insn (trap);
+
+  /* Merge the blocks!  */
+  if (trap_bb != then_bb && ! else_bb)
+    {
+      flow_delete_block (trap_bb);
+      num_removed_blocks++;
+    }
+  merge_if_block (test_bb, then_bb, else_bb, join_bb);
+
+  return TRUE;
+}
+
 /* Look for IF-THEN-ELSE cases in which one of THEN or ELSE is
    transformable, but not necessarily the other.  There need be no
    JOIN block.
@@ -1996,9 +2287,8 @@ find_if_case_1 (test_bb, then_edge, else_edge)
       edge then_edge, else_edge;
 {
   basic_block then_bb = then_edge->dest;
-  basic_block else_bb = else_edge->dest;
+  basic_block else_bb = else_edge->dest, new_bb;
   edge then_succ = then_bb->succ;
-  rtx new_lab;
 
   /* THEN has one successor.  */
   if (!then_succ || then_succ->succ_next != NULL)
@@ -2012,8 +2302,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++;
@@ -2026,18 +2316,9 @@ 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
@@ -2048,9 +2329,17 @@ find_if_case_1 (test_bb, then_edge, else_edge)
                    else_bb->global_live_at_start,
                    then_bb->global_live_at_end, BITMAP_IOR);
   
-  make_edge (NULL, test_bb, then_succ->dest, 0);
+  new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
+  /* Make rest of code believe that the newly created block is the THEN_BB
+     block we are going to remove.  */
+  if (new_bb)
+    {
+      new_bb->aux = then_bb->aux;
+      SET_UPDATE_LIFE (then_bb);
+    }
   flow_delete_block (then_bb);
-  tidy_fallthru_edge (else_edge, test_bb, else_bb);
+  /* We've possibly created jump to next insn, cleanup_cfg will solve that
+     later.  */
 
   num_removed_blocks++;
   num_updated_if_blocks++;
@@ -2068,7 +2357,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)
@@ -2107,27 +2396,8 @@ find_if_case_2 (test_bb, then_edge, else_edge)
   if (count_bb_insns (then_bb) > BRANCH_COST)
     return FALSE;
 
-  /* Find the label for ELSE's destination.  */
-  if (else_succ->dest == EXIT_BLOCK_PTR)
-    new_lab = NULL_RTX;
-  else
-    {
-      if (else_succ->flags & EDGE_FALLTHRU)
-       {
-         new_lab = else_succ->dest->head;
-         if (GET_CODE (new_lab) != CODE_LABEL)
-           abort ();
-       }
-      else
-       {
-         new_lab = JUMP_LABEL (else_bb->end);
-         if (! new_lab)
-           abort ();
-       }
-    }
-
   /* Registers set are dead, or are predicable.  */
-  if (! dead_or_predicable (test_bb, else_bb, then_bb, new_lab, 0))
+  if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0))
     return FALSE;
 
   /* Conversion went ok, including moving the insns and fixing up the
@@ -2138,8 +2408,6 @@ find_if_case_2 (test_bb, then_edge, else_edge)
                    then_bb->global_live_at_start,
                    else_bb->global_live_at_end, BITMAP_IOR);
   
-  remove_edge (else_edge);
-  make_edge (NULL, test_bb, else_succ->dest, 0);
   flow_delete_block (else_bb);
 
   num_removed_blocks++;
@@ -2173,19 +2441,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;
-
-  /* No code movement can occur if we'd be scrogging EH regions.
-     Within MERGE_BB, ensure that we've not got stray EH_BEG or EH_END
-     notes within the block.  Between the blocks, checking that the end
-     region numbers match ensures that we won't disrupt the nesting
-     between regions.  */
-  if (merge_bb->eh_beg != merge_bb->eh_end
-      || merge_bb->eh_end != test_bb->eh_end)
-    return FALSE;
+  rtx head, end, jump, earliest, old_dest, new_label;
 
   jump = test_bb->end;
 
@@ -2229,6 +2488,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)
@@ -2236,8 +2497,10 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 
       if (reversep)
        {
-         cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
-                                GET_MODE (cond), XEXP (cond, 0),
+         enum rtx_code rev = reversed_comparison_code (cond, jump);
+         if (rev == UNKNOWN)
+           return FALSE;
+         cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
                                 XEXP (cond, 1));
          if (prob_val)
            prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
@@ -2274,7 +2537,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;
@@ -2366,9 +2629,10 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
      change group management.  */
 
   old_dest = JUMP_LABEL (jump);
+  new_label = block_label (new_dest);
   if (reversep
-      ? ! invert_jump_1 (jump, new_dest)
-      : ! redirect_jump_1 (jump, new_dest))
+      ? ! invert_jump_1 (jump, new_label)
+      : ! redirect_jump_1 (jump, new_label))
     goto cancel;
 
   if (! apply_change_group ())
@@ -2376,15 +2640,24 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 
   if (old_dest)
     LABEL_NUSES (old_dest) -= 1;
-  if (new_dest)
-    LABEL_NUSES (new_dest) += 1;
-  JUMP_LABEL (jump) = new_dest;
+  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)
     {
-      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)));
+      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.  */
@@ -2393,19 +2666,8 @@ 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));
     }
@@ -2419,14 +2681,15 @@ dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
 /* Main entry point for all if-conversion.  */
 
 void
-if_convert (life_data_ok)
-     int life_data_ok;
+if_convert (x_life_data_ok)
+     int x_life_data_ok;
 {
   int block_num;
 
   num_possible_if_blocks = 0;
   num_updated_if_blocks = 0;
   num_removed_blocks = 0;
+  life_data_ok = (x_life_data_ok != 0);
 
   /* Free up basic_block_for_insn so that we don't have to keep it 
      up to date, either here or in merge_blocks_nomove.  */
@@ -2460,9 +2723,6 @@ if_convert (life_data_ok)
   if (rtl_dump_file)
     fflush (rtl_dump_file);
 
-  /* Rebuild basic_block_for_insn for update_life_info and for gcse.  */
-  compute_bb_for_insn (get_max_uid ());
-
   /* Rebuild life info for basic blocks that require it.  */
   if (num_removed_blocks && life_data_ok)
     {
@@ -2489,6 +2749,7 @@ if_convert (life_data_ok)
 
       sbitmap_free (update_life_blocks);
     }
+  clear_aux_for_blocks ();
 
   /* Write the final stats.  */
   if (rtl_dump_file && num_possible_if_blocks > 0)