OSDN Git Service

* target.h (struct gcc_target): Add asm_out.exception_section,
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index bfa97b0..e16cb4d 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 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
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+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.  */
 
 /* This module is essentially the "combiner" phase of the U. of Arizona
    Portable Optimizer, but redone to work on our list-structured
@@ -84,7 +84,7 @@ Boston, MA 02111-1307, USA.  */
 #include "basic-block.h"
 #include "insn-config.h"
 #include "function.h"
-/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
+/* Include expr.h after insn-config.h so we get HAVE_conditional_move.  */
 #include "expr.h"
 #include "insn-attr.h"
 #include "recog.h"
@@ -478,12 +478,12 @@ combine_instructions (f, nregs)
      rtx f;
      unsigned int nregs;
 {
-  register rtx insn, next;
+  rtx insn, next;
 #ifdef HAVE_cc0
-  register rtx prev;
+  rtx prev;
 #endif
-  register int i;
-  register rtx links, nextlinks;
+  int i;
+  rtx links, nextlinks;
 
   int new_direct_jump_p = 0;
 
@@ -713,9 +713,10 @@ combine_instructions (f, nregs)
        }
     }
 
+  delete_noop_moves (f);
+
   if (need_refresh)
     {
-      compute_bb_for_insn (get_max_uid ());
       update_life_info (refresh_blocks, UPDATE_LIFE_GLOBAL_RM_NOTES,
                        PROP_DEATH_NOTES);
     }
@@ -1133,7 +1134,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
 
       for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
         if (INSN_P (p) && p != succ && volatile_refs_p (PATTERN (p)))
-       return 0;
+       return 0;
     }
 
   /* If INSN is an asm, and DEST is a hard register, reject, since it has
@@ -1245,7 +1246,7 @@ sets_function_arg_p (pat)
    This is NOT equivalent to:
 
          (parallel [(set (subreg:SI (reg:DI 100) 0) <foo>)
-                   (set (reg:DI 101) (reg:DI 100))])
+                   (set (reg:DI 101) (reg:DI 100))])
 
    Not only does this modify 100 (in which case it might still be valid
    if 100 were dead in I2), it sets 101 to the ORIGINAL value of 100.
@@ -1421,7 +1422,7 @@ cant_combine_insn_p (insn)
 {
   rtx set;
   rtx src, dest;
-  
+
   /* If this isn't really an insn, we can't do anything.
      This can occur when flow deletes an insn that it has merged into an
      auto-increment address.  */
@@ -1472,8 +1473,8 @@ cant_combine_insn_p (insn)
 
 static rtx
 try_combine (i3, i2, i1, new_direct_jump_p)
-     register rtx i3, i2, i1;
-     register int *new_direct_jump_p;
+     rtx i3, i2, i1;
+     int *new_direct_jump_p;
 {
   /* New patterns for I3 and I2, respectively.  */
   rtx newpat, newi2pat = 0;
@@ -1505,7 +1506,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 
   int maxreg;
   rtx temp;
-  register rtx link;
+  rtx link;
   int i;
 
   /* Exit early if one of the insns involved can't be used for
@@ -1771,7 +1772,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
   /* If I3 has an inc, then give up if I1 or I2 uses the reg that is inc'd.
      We used to do this EXCEPT in one case: I3 has a post-inc in an
      output operand.  However, that exception can give rise to insns like
-       mov r3,(r3)+
+       mov r3,(r3)+
      which is a famous insn on the PDP-11 where the value of r3 used as the
      source was model-dependent.  Avoid this sort of thing.  */
 
@@ -2131,12 +2132,18 @@ try_combine (i3, i2, i1, new_direct_jump_p)
            }
        }
 
+      /* If we've split a jump pattern, we'll wind up with a sequence even
+        with one instruction.  We can handle that below, so extract it.  */
+      if (m_split && GET_CODE (m_split) == SEQUENCE
+         && XVECLEN (m_split, 0) == 1)
+       m_split = PATTERN (XVECEXP (m_split, 0, 0));
+
       if (m_split && GET_CODE (m_split) != SEQUENCE)
        {
          insn_code_number = recog_for_combine (&m_split, i3, &new_i3_notes);
          if (insn_code_number >= 0)
            newpat = m_split;
-       } 
+       }
       else if (m_split && GET_CODE (m_split) == SEQUENCE
               && XVECLEN (m_split, 0) == 2
               && (next_real_insn (i2) == i3
@@ -2235,6 +2242,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
             appeared to be a memory address.  This is a kludge.  */
          if (split_code == MULT
              && GET_CODE (XEXP (*split, 1)) == CONST_INT
+             && INTVAL (XEXP (*split, 1)) > 0
              && (i = exact_log2 (INTVAL (XEXP (*split, 1)))) >= 0)
            {
              SUBST (*split, gen_rtx_ASHIFT (split_mode,
@@ -2466,7 +2474,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
     }
 #ifdef HAVE_cc0
   /* If I2 is the setter CC0 and I3 is the user CC0 then check whether
-     they are adjacent to each other or not. */
+     they are adjacent to each other or not.  */
   {
     rtx p = prev_nonnote_insn (i3);
     if (p && p != i2 && GET_CODE (p) == INSN && newi2pat
@@ -2768,6 +2776,12 @@ try_combine (i3, i2, i1, new_direct_jump_p)
            || GET_CODE (temp) != BARRIER)
          emit_barrier_after (i3);
       }
+    /* An NOOP jump does not need barrier, but it does need cleaning up
+       of CFG.  */
+    if (GET_CODE (newpat) == SET
+       && SET_SRC (newpat) == pc_rtx
+       && SET_DEST (newpat) == pc_rtx)
+      *new_direct_jump_p = 1;
   }
 
   combine_successes++;
@@ -3047,7 +3061,7 @@ find_split_point (loc, insn)
 
        case NE:
          /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
-            is known to be on, this can be converted into a NEG of a shift. */
+            is known to be on, this can be converted into a NEG of a shift.  */
          if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
              && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
              && 1 <= (pos = exact_log2
@@ -3253,14 +3267,14 @@ find_split_point (loc, insn)
 
 static rtx
 subst (x, from, to, in_dest, unique_copy)
-     register rtx x, from, to;
+     rtx x, from, to;
      int in_dest;
      int unique_copy;
 {
-  register enum rtx_code code = GET_CODE (x);
+  enum rtx_code code = GET_CODE (x);
   enum machine_mode op0_mode = VOIDmode;
-  register const char *fmt;
-  register int len, i;
+  const char *fmt;
+  int len, i;
   rtx new;
 
 /* Two expressions are equal if they are identical copies of a shared
@@ -3368,7 +3382,7 @@ subst (x, from, to, in_dest, unique_copy)
        {
          if (fmt[i] == 'E')
            {
-             register int j;
+             int j;
              for (j = XVECLEN (x, i) - 1; j >= 0; j--)
                {
                  if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
@@ -3627,7 +3641,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                 just make the comparison operation.  */
              if (true_rtx == const_true_rtx && false_rtx == const0_rtx)
                x = gen_binary (cond_code, mode, cond, cop1);
-             else if (true_rtx == const0_rtx && false_rtx == const_true_rtx)
+             else if (true_rtx == const0_rtx && false_rtx == const_true_rtx
+                      && reverse_condition (cond_code) != UNKNOWN)
                x = gen_binary (reverse_condition (cond_code),
                                mode, cond, cop1);
 
@@ -3702,7 +3717,12 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     }
 
   if (temp)
-    x = temp, code = GET_CODE (temp), op0_mode = VOIDmode;
+    {
+      x = temp;
+      code = GET_CODE (temp);
+      op0_mode = VOIDmode;
+      mode = GET_MODE (temp);
+    }
 
   /* First see if we can apply the inverse distributive law.  */
   if (code == PLUS || code == MINUS
@@ -3715,12 +3735,12 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
   /* If CODE is an associative operation not otherwise handled, see if we
      can associate some operands.  This can win if they are constants or
-     if they are logically related (i.e. (a & b) & a.  */
-  if ((code == PLUS || code == MINUS
-       || code == MULT || code == AND || code == IOR || code == XOR
-       || code == DIV || code == UDIV
+     if they are logically related (i.e. (a & b) & a).  */
+  if ((code == PLUS || code == MINUS || code == MULT || code == DIV
+       || code == AND || code == IOR || code == XOR
        || code == SMAX || code == SMIN || code == UMAX || code == UMIN)
-      && INTEGRAL_MODE_P (mode))
+      && ((INTEGRAL_MODE_P (mode) && code != DIV)
+         || (flag_unsafe_math_optimizations && FLOAT_MODE_P (mode))))
     {
       if (GET_CODE (XEXP (x, 0)) == code)
        {
@@ -3739,7 +3759,6 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
            }
          inner = simplify_binary_operation (code == MINUS ? PLUS
                                             : code == DIV ? MULT
-                                            : code == UDIV ? MULT
                                             : code,
                                             mode, inner_op0, inner_op1);
 
@@ -3774,13 +3793,13 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
 
       /* simplify_subreg can't use gen_lowpart_for_combine.  */
       if (CONSTANT_P (SUBREG_REG (x))
-         && subreg_lowpart_parts_p (mode, op0_mode, SUBREG_BYTE (x)))
+         && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x))
        return gen_lowpart_for_combine (mode, SUBREG_REG (x));
 
       {
        rtx temp;
        temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
-                               SUBREG_BYTE (x));
+                               SUBREG_BYTE (x));
        if (temp)
          return temp;
       }
@@ -3843,24 +3862,23 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
                                              XEXP (XEXP (x, 0), 1))))
        return reversed;
 
-      /* (ashiftrt foo C) where C is the number of bits in FOO minus 1
-        is (lt foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
+      /* (not (ashiftrt foo C)) where C is the number of bits in FOO minus 1
+        is (ge foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
         perform the above simplification.  */
 
       if (STORE_FLAG_VALUE == -1
          && GET_CODE (XEXP (x, 0)) == ASHIFTRT
-         && XEXP (x, 1) == const1_rtx
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
          && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
        return gen_rtx_GE (mode, XEXP (XEXP (x, 0), 0), const0_rtx);
 
       /* Apply De Morgan's laws to reduce number of patterns for machines
-        with negating logical insns (and-not, nand, etc.).  If result has
-        only one NOT, put it first, since that is how the patterns are
-        coded.  */
+        with negating logical insns (and-not, nand, etc.).  If result has
+        only one NOT, put it first, since that is how the patterns are
+        coded.  */
 
       if (GET_CODE (XEXP (x, 0)) == IOR || GET_CODE (XEXP (x, 0)) == AND)
-       {
+       {
          rtx in1 = XEXP (XEXP (x, 0), 0), in2 = XEXP (XEXP (x, 0), 1);
          enum machine_mode op_mode;
 
@@ -3916,16 +3934,13 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          temp = simplify_unary_operation (NEG, mode,
                                           XEXP (XEXP (x, 0), 0), mode);
          if (temp)
-           {
-             SUBST (XEXP (XEXP (x, 0), 0), temp);
-             return XEXP (x, 0);
-           }
+           return gen_binary (ASHIFT, mode, temp, XEXP (XEXP (x, 0), 1));
        }
 
       temp = expand_compound_operation (XEXP (x, 0));
 
       /* For C equal to the width of MODE minus 1, (neg (ashiftrt X C)) can be
-        replaced by (lshiftrt X C).  This will convert
+        replaced by (lshiftrt X C).  This will convert
         (neg (sign_extract X 1 Y)) to (zero_extract X 1 Y).  */
 
       if (GET_CODE (temp) == ASHIFTRT
@@ -4009,7 +4024,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          && num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
             >= GET_MODE_BITSIZE (mode) + 1
          && ! (GET_CODE (XEXP (x, 0)) == LSHIFTRT
-               && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
+               && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT))
        return gen_lowpart_for_combine (mode, XEXP (x, 0));
 
       /* A truncate of a comparison can be replaced with a subreg if
@@ -4225,6 +4240,16 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
          if (GET_CODE (x) != MULT)
            return x;
        }
+      /* Try simplify a*(b/c) as (a*b)/c.  */
+      if (FLOAT_MODE_P (mode) && flag_unsafe_math_optimizations
+         && GET_CODE (XEXP (x, 0)) == DIV)
+       {
+         rtx tem = simplify_binary_operation (MULT, mode,
+                                              XEXP (XEXP (x, 0), 0),
+                                              XEXP (x, 1));
+         if (tem)
+           return gen_binary (DIV, mode, tem, XEXP (XEXP (x, 0), 1));
+       }
       break;
 
     case UDIV:
@@ -4244,8 +4269,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     case GT:  case GTU:  case GE:  case GEU:
     case LT:  case LTU:  case LE:  case LEU:
     case UNEQ:  case LTGT:
-    case UNGT:  case UNGE:  
-    case UNLT:  case UNLE:  
+    case UNGT:  case UNGE:
+    case UNLT:  case UNLE:
     case UNORDERED: case ORDERED:
       /* If the first operand is a condition code, we can't do anything
         with it.  */
@@ -4521,7 +4546,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       }
 
       break;
-      
+
     default:
       break;
     }
@@ -5573,7 +5598,7 @@ expand_compound_operation (x)
          && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<'
          && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
              <= HOST_BITS_PER_WIDE_INT)
-         && ((HOST_WIDE_INT) STORE_FLAG_VALUE
+         && ((HOST_WIDE_INT) STORE_FLAG_VALUE
              & ~GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
        return XEXP (XEXP (x, 0), 0);
 
@@ -5862,8 +5887,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
           && GET_CODE (inner) != MEM
           && (! in_dest
               || (GET_CODE (inner) == REG
-                  && (movstrict_optab->handlers[(int) tmode].insn_code
-                      != CODE_FOR_nothing))))
+                  && have_insn_for (STRICT_LOW_PART, tmode))))
          || (GET_CODE (inner) == MEM && pos_rtx == 0
              && (pos
                  % (STRICT_ALIGNMENT ? GET_MODE_ALIGNMENT (tmode)
@@ -5884,15 +5908,15 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
       if (GET_CODE (inner) == MEM)
        {
-         int offset;
+         HOST_WIDE_INT offset;
+
          /* POS counts from lsb, but make OFFSET count in memory order.  */
          if (BYTES_BIG_ENDIAN)
            offset = (GET_MODE_BITSIZE (is_mode) - len - pos) / BITS_PER_UNIT;
          else
            offset = pos / BITS_PER_UNIT;
 
-         new = gen_rtx_MEM (tmode, plus_constant (XEXP (inner, 0), offset));
-         MEM_COPY_ATTRIBUTES (new, inner);
+         new = adjust_address_nv (inner, tmode, offset);
        }
       else if (GET_CODE (inner) == REG)
        {
@@ -5900,7 +5924,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
             a SUBREG and it would sometimes return a new hard register.  */
          if (tmode != inner_mode)
            {
-             int final_word = pos / BITS_PER_WORD;
+             HOST_WIDE_INT final_word = pos / BITS_PER_WORD;
 
              if (WORDS_BIG_ENDIAN
                  && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
@@ -5916,9 +5940,9 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
              new = gen_rtx_SUBREG (tmode, inner, final_word);
            }
-         else
-           new = inner;
-       }
+         else
+           new = inner;
+       }
       else
        new = force_to_mode (inner, tmode,
                             len >= HOST_BITS_PER_WIDE_INT
@@ -5985,59 +6009,28 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
   /* Get the mode to use should INNER not be a MEM, the mode for the position,
      and the mode for the result.  */
-#ifdef HAVE_insv
-  if (in_dest)
+  if (in_dest && mode_for_extraction(EP_insv, -1) != MAX_MACHINE_MODE)
     {
-      wanted_inner_reg_mode
-       = insn_data[(int) CODE_FOR_insv].operand[0].mode;
-      if (wanted_inner_reg_mode == VOIDmode)
-       wanted_inner_reg_mode = word_mode;
-
-      pos_mode = insn_data[(int) CODE_FOR_insv].operand[2].mode;
-      if (pos_mode == VOIDmode)
-       pos_mode = word_mode;
-
-      extraction_mode = insn_data[(int) CODE_FOR_insv].operand[3].mode;
-      if (extraction_mode == VOIDmode)
-       extraction_mode = word_mode;
+      wanted_inner_reg_mode = mode_for_extraction (EP_insv, 0);
+      pos_mode = mode_for_extraction (EP_insv, 2);
+      extraction_mode = mode_for_extraction (EP_insv, 3);
     }
-#endif
 
-#ifdef HAVE_extzv
-  if (! in_dest && unsignedp)
+  if (! in_dest && unsignedp
+      && mode_for_extraction (EP_extzv, -1) != MAX_MACHINE_MODE)
     {
-      wanted_inner_reg_mode
-       = insn_data[(int) CODE_FOR_extzv].operand[1].mode;
-      if (wanted_inner_reg_mode == VOIDmode)
-       wanted_inner_reg_mode = word_mode;
-
-      pos_mode = insn_data[(int) CODE_FOR_extzv].operand[3].mode;
-      if (pos_mode == VOIDmode)
-       pos_mode = word_mode;
-
-      extraction_mode = insn_data[(int) CODE_FOR_extzv].operand[0].mode;
-      if (extraction_mode == VOIDmode)
-       extraction_mode = word_mode;
+      wanted_inner_reg_mode = mode_for_extraction (EP_extzv, 1);
+      pos_mode = mode_for_extraction (EP_extzv, 3);
+      extraction_mode = mode_for_extraction (EP_extzv, 0);
     }
-#endif
 
-#ifdef HAVE_extv
-  if (! in_dest && ! unsignedp)
+  if (! in_dest && ! unsignedp
+      && mode_for_extraction (EP_extv, -1) != MAX_MACHINE_MODE)
     {
-      wanted_inner_reg_mode
-       = insn_data[(int) CODE_FOR_extv].operand[1].mode;
-      if (wanted_inner_reg_mode == VOIDmode)
-       wanted_inner_reg_mode = word_mode;
-
-      pos_mode = insn_data[(int) CODE_FOR_extv].operand[3].mode;
-      if (pos_mode == VOIDmode)
-       pos_mode = word_mode;
-
-      extraction_mode = insn_data[(int) CODE_FOR_extv].operand[0].mode;
-      if (extraction_mode == VOIDmode)
-       extraction_mode = word_mode;
+      wanted_inner_reg_mode = mode_for_extraction (EP_extv, 1);
+      pos_mode = mode_for_extraction (EP_extv, 3);
+      extraction_mode = mode_for_extraction (EP_extv, 0);
     }
-#endif
 
   /* Never narrow an object, since that might not be safe.  */
 
@@ -6120,13 +6113,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
                  - GET_MODE_SIZE (wanted_inner_mode) - offset);
 
       if (offset != 0 || inner_mode != wanted_inner_mode)
-       {
-         rtx newmem = gen_rtx_MEM (wanted_inner_mode,
-                                   plus_constant (XEXP (inner, 0), offset));
-
-         MEM_COPY_ATTRIBUTES (newmem, inner);
-         inner = newmem;
-       }
+       inner = adjust_address_nv (inner, wanted_inner_mode, offset);
     }
 
   /* If INNER is not memory, we can always get it into the proper mode.  If we
@@ -6252,7 +6239,7 @@ extract_left_shift (x, count)
 
    Return the new rtx, usually just X.
 
-   Also, for machines like the Vax that don't have logical shift insns,
+   Also, for machines like the VAX that don't have logical shift insns,
    try to convert logical to arithmetic shift operations in cases where
    they are equivalent.  This undoes the canonicalizations to logical
    shifts done elsewhere.
@@ -6369,10 +6356,9 @@ make_compound_operation (x, in_code)
       /* On machines without logical shifts, if the operand of the AND is
         a logical shift and our mask turns off all the propagated sign
         bits, we can replace the logical shift with an arithmetic shift.  */
-      else if (ashr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
-              && (lshr_optab->handlers[(int) mode].insn_code
-                  == CODE_FOR_nothing)
-              && GET_CODE (XEXP (x, 0)) == LSHIFTRT
+      else if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
+              && !have_insn_for (LSHIFTRT, mode)
+              && have_insn_for (ASHIFTRT, mode)
               && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
               && INTVAL (XEXP (XEXP (x, 0), 1)) >= 0
               && INTVAL (XEXP (XEXP (x, 0), 1)) < HOST_BITS_PER_WIDE_INT
@@ -6413,8 +6399,8 @@ make_compound_operation (x, in_code)
     case LSHIFTRT:
       /* If the sign bit is known to be zero, replace this with an
         arithmetic shift.  */
-      if (ashr_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing
-         && lshr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+      if (have_insn_for (ASHIFTRT, mode)
+         && ! have_insn_for (LSHIFTRT, mode)
          && mode_width <= HOST_BITS_PER_WIDE_INT
          && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
        {
@@ -6597,9 +6583,7 @@ force_to_mode (x, mode, mask, reg, just_select)
      that the operation is valid in MODE, in which case we do the operation
      in MODE.  */
   op_mode = ((GET_MODE_CLASS (mode) == GET_MODE_CLASS (GET_MODE (x))
-             && code_to_optab[(int) code] != 0
-             && (code_to_optab[(int) code]->handlers[(int) mode].insn_code
-                 != CODE_FOR_nothing))
+             && have_insn_for (code, mode))
             ? mode : GET_MODE (x));
 
   /* It is not valid to do a right-shift in a narrower mode
@@ -6861,7 +6845,7 @@ force_to_mode (x, mode, mask, reg, just_select)
 
     binop:
       /* For most binary operations, just propagate into the operation and
-        change the mode if we have an operation of that mode.   */
+        change the mode if we have an operation of that mode.  */
 
       op0 = gen_lowpart_for_combine (op_mode,
                                     force_to_mode (XEXP (x, 0), mode, mask,
@@ -7293,29 +7277,16 @@ if_then_else_cond (x, ptrue, pfalse)
        return cond0;
     }
 
-  /* If X is a normal SUBREG with both inner and outer modes integral,
-     we can narrow both the true and false values of the inner expression,
-     if there is a condition.  */
-  else if (code == SUBREG && GET_MODE_CLASS (mode) == MODE_INT
-          && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
-          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+  /* If X is a SUBREG, we can narrow both the true and false values
+     if the inner expression, if there is a condition.  */
+  else if (code == SUBREG
           && 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
                                               &true0, &false0)))
     {
-      if ((GET_CODE (SUBREG_REG (x)) == REG
-          || GET_CODE (SUBREG_REG (x)) == MEM
-          || CONSTANT_P (SUBREG_REG (x)))
-         && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
-         && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) >= UNITS_PER_WORD))
-       {
-         true0 = operand_subword (true0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
-                                  GET_MODE (SUBREG_REG (x)));
-         false0 = operand_subword (false0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
-                                   GET_MODE (SUBREG_REG (x)));
-       }
-      *ptrue = force_to_mode (true0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
-      *pfalse
-       = force_to_mode (false0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
+      *ptrue = simplify_gen_subreg (mode, true0,
+                                   GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+      *pfalse = simplify_gen_subreg (mode, false0,
+                                    GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
 
       return cond0;
     }
@@ -7431,7 +7402,7 @@ known_cond (x, cond, reg, val)
              /* Do not reverse the condition when it is NE or EQ.
                 This is because we cannot conclude anything about
                 the value of 'SMAX (x, y)' when x is not equal to y,
-                but we can when x equals y.  */ 
+                but we can when x equals y.  */
              if ((code == SMAX || code == UMAX)
                  && ! (cond == EQ || cond == NE))
                cond = reverse_condition (cond);
@@ -7909,7 +7880,7 @@ nonzero_bits (x, mode)
   switch (code)
     {
     case REG:
-#ifdef POINTERS_EXTEND_UNSIGNED
+#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
       /* If pointers extend unsigned and this is a pointer in Pmode, say that
         all the bits above ptr_mode are known to be zero.  */
       if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
@@ -8149,18 +8120,26 @@ nonzero_bits (x, mode)
            result_low = low0 + low1;
            break;
          case DIV:
+           if (width1 == 0)
+             break;
            if (! op0_maybe_minusp && ! op1_maybe_minusp)
              result_width = width0;
            break;
          case UDIV:
+           if (width1 == 0)
+             break;
            result_width = width0;
            break;
          case MOD:
+           if (width1 == 0)
+             break;
            if (! op0_maybe_minusp && ! op1_maybe_minusp)
              result_width = MIN (width0, width1);
            result_low = MIN (low0, low1);
            break;
          case UMOD:
+           if (width1 == 0)
+             break;
            result_width = MIN (width0, width1);
            result_low = MIN (low0, low1);
            break;
@@ -8178,7 +8157,7 @@ nonzero_bits (x, mode)
        /* If pointers extend unsigned and this is an addition or subtraction
           to a pointer in Pmode, all the bits above ptr_mode are known to be
           zero.  */
-       if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+       if (POINTERS_EXTEND_UNSIGNED > 0 && GET_MODE (x) == Pmode
            && (code == PLUS || code == MINUS)
            && GET_CODE (XEXP (x, 0)) == REG && REG_POINTER (XEXP (x, 0)))
          nonzero &= GET_MODE_MASK (ptr_mode);
@@ -8359,7 +8338,7 @@ num_sign_bit_copies (x, mode)
     {
     case REG:
 
-#ifdef POINTERS_EXTEND_UNSIGNED
+#if defined(POINTERS_EXTEND_UNSIGNED) && !defined(HAVE_ptr_extend)
       /* If pointers extend signed and this is a pointer in Pmode, say that
         all the bits above ptr_mode are known to be sign bit copies.  */
       if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode
@@ -8469,7 +8448,8 @@ num_sign_bit_copies (x, mode)
         of sign bit copies, we can just subtract that amount from the
         number.  */
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= 0 && INTVAL (XEXP (x, 1)) < bitwidth)
+         && INTVAL (XEXP (x, 1)) >= 0
+         && INTVAL (XEXP (x, 1)) < (int) bitwidth)
        {
          num0 = num_sign_bit_copies (XEXP (x, 0), mode);
          return MAX (1, num0 - (code == ROTATE ? INTVAL (XEXP (x, 1))
@@ -8601,7 +8581,7 @@ num_sign_bit_copies (x, mode)
       num0 = num_sign_bit_copies (XEXP (x, 0), mode);
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) > 0)
-       num0 = MIN (bitwidth, num0 + INTVAL (XEXP (x, 1)));
+       num0 = MIN ((int) bitwidth, num0 + INTVAL (XEXP (x, 1)));
 
       return num0;
 
@@ -8609,7 +8589,7 @@ num_sign_bit_copies (x, mode)
       /* Left shifts destroy copies.  */
       if (GET_CODE (XEXP (x, 1)) != CONST_INT
          || INTVAL (XEXP (x, 1)) < 0
-         || INTVAL (XEXP (x, 1)) >= bitwidth)
+         || INTVAL (XEXP (x, 1)) >= (int) bitwidth)
        return 1;
 
       num0 = num_sign_bit_copies (XEXP (x, 0), mode);
@@ -8850,7 +8830,7 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
   /* If we were given an invalid count, don't do anything except exactly
      what was requested.  */
 
-  if (input_count < 0 || input_count > (int) GET_MODE_BITSIZE (mode))
+  if (input_count < 0 || input_count >= (int) GET_MODE_BITSIZE (mode))
     {
       if (x)
        return x;
@@ -8944,7 +8924,7 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
       /* We simplify the tests below and elsewhere by converting
         ASHIFTRT to LSHIFTRT if we know the sign bit is clear.
         `make_compound_operation' will convert it to a ASHIFTRT for
-        those machines (such as Vax) that don't have a LSHIFTRT.  */
+        those machines (such as VAX) that don't have a LSHIFTRT.  */
       if (GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
          && code == ASHIFTRT
          && ((nonzero_bits (varop, shift_mode)
@@ -8976,14 +8956,10 @@ simplify_shift_const (x, code, result_mode, varop, input_count)
              && (tmode = mode_for_size (GET_MODE_BITSIZE (mode) - count,
                                         MODE_INT, 1)) != BLKmode)
            {
-             if (BYTES_BIG_ENDIAN)
-               new = gen_rtx_MEM (tmode, XEXP (varop, 0));
-             else
-               new = gen_rtx_MEM (tmode,
-                                  plus_constant (XEXP (varop, 0),
-                                                 count / BITS_PER_UNIT));
+             new = adjust_address_nv (varop, tmode,
+                                      BYTES_BIG_ENDIAN ? 0
+                                      : count / BITS_PER_UNIT);
 
-             MEM_COPY_ATTRIBUTES (new, varop);
              varop = gen_rtx_fmt_e (code == ASHIFTRT ? SIGN_EXTEND
                                     : ZERO_EXTEND, mode, new);
              count = 0;
@@ -9580,7 +9556,7 @@ recog_for_combine (pnewpat, insn, pnotes)
      rtx insn;
      rtx *pnotes;
 {
-  register rtx pat = *pnewpat;
+  rtx pat = *pnewpat;
   int insn_code_number;
   int num_clobbers_to_add = 0;
   int i;
@@ -9600,7 +9576,6 @@ recog_for_combine (pnewpat, insn, pnotes)
   old_notes = REG_NOTES (insn);
   REG_NOTES (insn) = 0;
 
-  /* Is the result of combination a valid instruction?  */
   insn_code_number = recog (pat, insn, &num_clobbers_to_add);
 
   /* If it isn't, there is the possibility that we previously had an insn
@@ -9629,6 +9604,10 @@ recog_for_combine (pnewpat, insn, pnotes)
       insn_code_number = recog (pat, insn, &num_clobbers_to_add);
     }
 
+  /* Recognize all noop sets, these will be killed by followup pass.  */
+  if (insn_code_number < 0 && GET_CODE (pat) == SET && set_noop_p (pat))
+    insn_code_number = NOOP_MOVE_INSN_CODE, num_clobbers_to_add = 0;
+
   REG_NOTES (insn) = old_notes;
 
   /* If we had any clobbers to add, make a new pattern than contains
@@ -9681,7 +9660,7 @@ recog_for_combine (pnewpat, insn, pnotes)
 static rtx
 gen_lowpart_for_combine (mode, x)
      enum machine_mode mode;
-     register rtx x;
+     rtx x;
 {
   rtx result;
 
@@ -9724,8 +9703,7 @@ gen_lowpart_for_combine (mode, x)
 
   if (GET_CODE (x) == MEM)
     {
-      register int offset = 0;
-      rtx new;
+      int offset = 0;
 
       /* Refuse to work on a volatile memory ref or one with a mode-dependent
         address.  */
@@ -9749,9 +9727,8 @@ gen_lowpart_for_combine (mode, x)
          offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
                     - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
        }
-      new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
-      MEM_COPY_ATTRIBUTES (new, x);
-      return new;
+
+      return adjust_address_nv (x, mode, offset);
     }
 
   /* If X is a comparison operator, rewrite it in a new mode.  This
@@ -9765,18 +9742,13 @@ gen_lowpart_for_combine (mode, x)
   else
     {
       int offset = 0;
+      rtx res;
 
-      if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
-         && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode))
-       {
-         int difference = (GET_MODE_SIZE (GET_MODE (x))
-                           - GET_MODE_SIZE (mode));
-         if (WORDS_BIG_ENDIAN)
-           offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-         if (BYTES_BIG_ENDIAN)
-           offset += difference % UNITS_PER_WORD;
-       }
-      return gen_rtx_SUBREG (mode, x, offset);
+      offset = subreg_lowpart_offset (mode, GET_MODE (x));
+      res = simplify_gen_subreg (mode, x, GET_MODE (x), offset);
+      if (res)
+       return res;
+      return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
     }
 }
 \f
@@ -10237,14 +10209,15 @@ simplify_comparison (code, pop0, pop1)
            {
              if (BITS_BIG_ENDIAN)
                {
-#ifdef HAVE_extzv
-                 mode = insn_data[(int) CODE_FOR_extzv].operand[1].mode;
-                 if (mode == VOIDmode)
-                   mode = word_mode;
-                 i = (GET_MODE_BITSIZE (mode) - 1 - i);
-#else
-                 i = BITS_PER_WORD - 1 - i;
-#endif
+                 enum machine_mode new_mode
+                   = mode_for_extraction (EP_extzv, 1);
+                 if (new_mode == MAX_MACHINE_MODE)
+                   i = BITS_PER_WORD - 1 - i;
+                 else
+                   {
+                     mode = new_mode;
+                     i = (GET_MODE_BITSIZE (mode) - 1 - i);
+                   }
                }
 
              op0 = XEXP (op0, 2);
@@ -10544,7 +10517,7 @@ simplify_comparison (code, pop0, pop1)
                new_code = GET_CODE (op0);
              else
                new_code = combine_reversed_comparison_code (op0);
-         
+
              if (new_code != UNKNOWN)
                {
                  code = new_code;
@@ -10861,6 +10834,7 @@ simplify_comparison (code, pop0, pop1)
 
   if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
       && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+      && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op0))) == MODE_INT
       && (code == NE || code == EQ)
       && ((GET_MODE_SIZE (GET_MODE (op0))
           > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))))
@@ -10871,6 +10845,7 @@ simplify_comparison (code, pop0, pop1)
 
   else if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
           && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+          && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op0))) == MODE_INT
           && (code == NE || code == EQ)
           && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
               <= HOST_BITS_PER_WIDE_INT)
@@ -10891,12 +10866,12 @@ simplify_comparison (code, pop0, pop1)
   mode = GET_MODE (op0);
   if (mode != VOIDmode && GET_MODE_CLASS (mode) == MODE_INT
       && GET_MODE_SIZE (mode) < UNITS_PER_WORD
-      && cmp_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+      && ! have_insn_for (COMPARE, mode))
     for (tmode = GET_MODE_WIDER_MODE (mode);
         (tmode != VOIDmode
          && GET_MODE_BITSIZE (tmode) <= HOST_BITS_PER_WIDE_INT);
         tmode = GET_MODE_WIDER_MODE (tmode))
-      if (cmp_optab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
+      if (have_insn_for (COMPARE, tmode))
        {
          /* If the only nonzero bits in OP0 and OP1 are those in the
             narrower mode and this is an equality or unsigned comparison,
@@ -10914,8 +10889,7 @@ simplify_comparison (code, pop0, pop1)
              /* If OP0 is an AND and we don't have an AND in MODE either,
                 make a new AND in the proper mode.  */
              if (GET_CODE (op0) == AND
-                 && (add_optab->handlers[(int) mode].insn_code
-                     == CODE_FOR_nothing))
+                 && !have_insn_for (AND, mode))
                op0 = gen_binary (AND, tmode,
                                  gen_lowpart_for_combine (tmode,
                                                           XEXP (op0, 0)),
@@ -10996,9 +10970,9 @@ static void
 update_table_tick (x)
      rtx x;
 {
-  register enum rtx_code code = GET_CODE (x);
-  register const char *fmt = GET_RTX_FORMAT (code);
-  register int i;
+  enum rtx_code code = GET_CODE (x);
+  const char *fmt = GET_RTX_FORMAT (code);
+  int i;
 
   if (code == REG)
     {
@@ -11180,7 +11154,7 @@ static void
 record_dead_and_set_regs (insn)
      rtx insn;
 {
-  register rtx link;
+  rtx link;
   unsigned int i;
 
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
@@ -11441,12 +11415,12 @@ get_last_value (x)
 
 static int
 use_crosses_set_p (x, from_cuid)
-     register rtx x;
+     rtx x;
      int from_cuid;
 {
-  register const char *fmt;
-  register int i;
-  register enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int i;
+  enum rtx_code code = GET_CODE (x);
 
   if (code == REG)
     {
@@ -11476,7 +11450,7 @@ use_crosses_set_p (x, from_cuid)
     {
       if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            if (use_crosses_set_p (XVECEXP (x, i, j), from_cuid))
              return 1;
@@ -11649,7 +11623,7 @@ mark_used_regs_combine (x)
       {
        /* If setting a MEM, or a SUBREG of a MEM, then note any hard regs in
           the address.  */
-       register rtx testreg = SET_DEST (x);
+       rtx testreg = SET_DEST (x);
 
        while (GET_CODE (testreg) == SUBREG
               || GET_CODE (testreg) == ZERO_EXTRACT
@@ -11671,7 +11645,7 @@ mark_used_regs_combine (x)
   /* Recursively scan the operands of this expression.  */
 
   {
-    register const char *fmt = GET_RTX_FORMAT (code);
+    const char *fmt = GET_RTX_FORMAT (code);
 
     for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
       {
@@ -11679,7 +11653,7 @@ mark_used_regs_combine (x)
          mark_used_regs_combine (XEXP (x, i));
        else if (fmt[i] == 'E')
          {
-           register int j;
+           int j;
 
            for (j = 0; j < XVECLEN (x, i); j++)
              mark_used_regs_combine (XVECEXP (x, i, j));
@@ -11697,7 +11671,7 @@ remove_death (regno, insn)
      unsigned int regno;
      rtx insn;
 {
-  register rtx note = find_regno_note (insn, REG_DEAD, regno);
+  rtx note = find_regno_note (insn, REG_DEAD, regno);
 
   if (note)
     {
@@ -11726,15 +11700,15 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
      rtx to_insn;
      rtx *pnotes;
 {
-  register const char *fmt;
-  register int len, i;
-  register enum rtx_code code = GET_CODE (x);
+  const char *fmt;
+  int len, i;
+  enum rtx_code code = GET_CODE (x);
 
   if (code == REG)
     {
       unsigned int regno = REGNO (x);
-      register rtx where_dead = reg_last_death[regno];
-      register rtx before_dead, after_dead;
+      rtx where_dead = reg_last_death[regno];
+      rtx before_dead, after_dead;
 
       /* Don't move the register if it gets killed in between from and to */
       if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
@@ -11878,7 +11852,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
     {
       if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = XVECLEN (x, i) - 1; j >= 0; j--)
            move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid,
                         to_insn, pnotes);
@@ -11970,6 +11944,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
       switch (REG_NOTE_KIND (note))
        {
        case REG_BR_PROB:
+       case REG_BR_PRED:
        case REG_EXEC_COUNT:
          /* Doesn't matter much where we put this, as long as it's somewhere.
             It is preferable to keep these notes on branches, which is most
@@ -11977,6 +11952,12 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
          place = i3;
          break;
 
+       case REG_VTABLE_REF:
+         /* ??? Should remain with *a particular* memory load.  Given the
+            nature of vtable data, the last insn seems relatively safe.  */
+         place = i3;
+         break;
+
        case REG_NON_LOCAL_GOTO:
          if (GET_CODE (i3) == JUMP_INSN)
            place = i3;
@@ -12006,8 +11987,8 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
            abort ();
          break;
 
-       case REG_EH_RETHROW:
        case REG_NORETURN:
+       case REG_SETJMP:
          /* These notes must remain with the call.  It should not be
             possible for both I2 and I3 to be a call.  */
          if (GET_CODE (i3) == CALL_INSN)
@@ -12353,6 +12334,15 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
            {
              unsigned int regno = REGNO (XEXP (note, 0));
 
+             /* Similarly, if the instruction on which we want to place
+                the note is a noop, we'll need do a global live update
+                after we remove them in delete_noop_moves.  */
+             if (noop_move_p (place))
+               {
+                 SET_BIT (refresh_blocks, this_basic_block);
+                 need_refresh = 1;
+               }
+
              if (dead_or_set_p (place, XEXP (note, 0))
                  || reg_bitfield_target_p (XEXP (note, 0), PATTERN (place)))
                {