OSDN Git Service

Make `solaris' reflect the most recent major release.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index aebb6b9..5b44d66 100644 (file)
@@ -1,5 +1,5 @@
 /* Optimize by combining instructions for GNU compiler.
-   Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -74,10 +74,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    combine anyway.  */
 
 #include "config.h"
+/* Must precede rtl.h for FFS.  */
+#include <stdio.h>
+
 #include "gvarargs.h"
 #include "rtl.h"
 #include "flags.h"
 #include "regs.h"
+#include "hard-reg-set.h"
 #include "expr.h"
 #include "basic-block.h"
 #include "insn-config.h"
@@ -86,12 +90,25 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "insn-attr.h"
 #include "recog.h"
 #include "real.h"
-#include <stdio.h>
 
 /* It is not safe to use ordinary gen_lowpart in combine.
    Use gen_lowpart_for_combine instead.  See comments there.  */
 #define gen_lowpart dont_use_gen_lowpart_you_dummy
 
+/* If byte loads either zero- or sign- extend, define BYTE_LOADS_EXTEND
+   for cases when we don't care which is true.  Define LOAD_EXTEND to
+   be ZERO_EXTEND or SIGN_EXTEND, depending on which was defined.  */
+
+#ifdef BYTE_LOADS_ZERO_EXTEND
+#define BYTE_LOADS_EXTEND
+#define LOAD_EXTEND ZERO_EXTEND
+#endif
+
+#ifdef BYTE_LOADS_SIGN_EXTEND
+#define BYTE_LOADS_EXTEND
+#define LOAD_EXTEND SIGN_EXTEND
+#endif
+
 /* Number of attempts to combine instructions in this function.  */
 
 static int combine_attempts;
@@ -222,12 +239,12 @@ static rtx *reg_last_set_value;
 /* Record the value of label_tick when the value for register n is placed in
    reg_last_set_value[n].  */
 
-static short *reg_last_set_label;
+static int *reg_last_set_label;
 
 /* Record the value of label_tick when an expression involving register n
    is placed in reg_last_set_value. */
 
-static short *reg_last_set_table_tick;
+static int *reg_last_set_table_tick;
 
 /* Set non-zero if references to register n in expressions should not be
    used.  */
@@ -236,36 +253,45 @@ static char *reg_last_set_invalid;
 
 /* Incremented for each label. */
 
-static short label_tick;
+static int label_tick;
 
 /* Some registers that are set more than once and used in more than one
    basic block are nevertheless always set in similar ways.  For example,
    a QImode register may be loaded from memory in two places on a machine
    where byte loads zero extend.
 
-   We record in the following array what we know about the significant
+   We record in the following array what we know about the nonzero
    bits of a register, specifically which bits are known to be zero.
 
    If an entry is zero, it means that we don't know anything special.  */
 
-static HOST_WIDE_INT *reg_significant;
+static unsigned HOST_WIDE_INT *reg_nonzero_bits;
 
-/* Mode used to compute significance in reg_significant.  It is the largest
+/* Mode used to compute significance in reg_nonzero_bits.  It is the largest
    integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
 
-static enum machine_mode significant_mode;
+static enum machine_mode nonzero_bits_mode;
 
 /* Nonzero if we know that a register has some leading bits that are always
    equal to the sign bit.  */
 
 static char *reg_sign_bit_copies;
 
-/* Nonzero when reg_significant and reg_sign_bit_copies can be safely used.
+/* Nonzero when reg_nonzero_bits and reg_sign_bit_copies can be safely used.
    It is zero while computing them and after combine has completed.  This
    former test prevents propagating values based on previously set values,
    which can be incorrect if a variable is modified in a loop.  */
 
-static int significant_valid;
+static int nonzero_sign_valid;
+
+/* These arrays are maintained in parallel with reg_last_set_value
+   and are used to store the mode in which the register was last set,
+   the bits that were known to be zero when it was last set, and the
+   number of sign bits copies it was known to have when it was last set.  */
+
+static enum machine_mode *reg_last_set_mode;
+static unsigned HOST_WIDE_INT *reg_last_set_nonzero_bits;
+static char *reg_last_set_sign_bit_copies;
 \f
 /* Record one modification to rtl structure
    to be undone by storing old_contents into *where.
@@ -339,7 +365,8 @@ static struct undobuf undobuf;
 
 static int n_occurrences;
 
-static void set_significant ();
+static void set_nonzero_bits_and_sign_copies ();
+static void setup_incoming_promotions ();
 static void move_deaths ();
 rtx remove_death ();
 static void record_value_for_reg ();
@@ -360,7 +387,7 @@ static rtx make_field_assignment ();
 static rtx make_compound_operation ();
 static rtx apply_distributive_law ();
 static rtx simplify_and_const_int ();
-static unsigned HOST_WIDE_INT significant_bits ();
+static unsigned HOST_WIDE_INT nonzero_bits ();
 static int num_sign_bit_copies ();
 static int merge_outer_ops ();
 static rtx simplify_shift_const ();
@@ -392,24 +419,37 @@ combine_instructions (f, nregs)
   combine_merges = 0;
   combine_extras = 0;
   combine_successes = 0;
+  undobuf.num_undo = previous_num_undos = 0;
 
   combine_max_regno = nregs;
 
   reg_last_death = (rtx *) alloca (nregs * sizeof (rtx));
   reg_last_set = (rtx *) alloca (nregs * sizeof (rtx));
   reg_last_set_value = (rtx *) alloca (nregs * sizeof (rtx));
-  reg_last_set_table_tick = (short *) alloca (nregs * sizeof (short));
-  reg_last_set_label = (short *) alloca (nregs * sizeof (short));
+  reg_last_set_table_tick = (int *) alloca (nregs * sizeof (int));
+  reg_last_set_label = (int *) alloca (nregs * sizeof (int));
   reg_last_set_invalid = (char *) alloca (nregs * sizeof (char));
-  reg_significant = (HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
+  reg_last_set_mode
+    = (enum machine_mode *) alloca (nregs * sizeof (enum machine_mode));
+  reg_last_set_nonzero_bits
+    = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
+  reg_last_set_sign_bit_copies
+    = (char *) alloca (nregs * sizeof (char));
+
+  reg_nonzero_bits
+    = (unsigned HOST_WIDE_INT *) alloca (nregs * sizeof (HOST_WIDE_INT));
   reg_sign_bit_copies = (char *) alloca (nregs * sizeof (char));
 
   bzero (reg_last_death, nregs * sizeof (rtx));
   bzero (reg_last_set, nregs * sizeof (rtx));
   bzero (reg_last_set_value, nregs * sizeof (rtx));
-  bzero (reg_last_set_table_tick, nregs * sizeof (short));
+  bzero (reg_last_set_table_tick, nregs * sizeof (int));
+  bzero (reg_last_set_label, nregs * sizeof (int));
   bzero (reg_last_set_invalid, nregs * sizeof (char));
-  bzero (reg_significant, nregs * sizeof (HOST_WIDE_INT));
+  bzero (reg_last_set_mode, nregs * sizeof (enum machine_mode));
+  bzero (reg_last_set_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
+  bzero (reg_last_set_sign_bit_copies, nregs * sizeof (char));
+  bzero (reg_nonzero_bits, nregs * sizeof (HOST_WIDE_INT));
   bzero (reg_sign_bit_copies, nregs * sizeof (char));
 
   init_recog_no_volatile ();
@@ -422,34 +462,59 @@ combine_instructions (f, nregs)
 
   uid_cuid = (int *) alloca ((i + 1) * sizeof (int));
 
-  significant_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
+  nonzero_bits_mode = mode_for_size (HOST_BITS_PER_WIDE_INT, MODE_INT, 0);
 
-  /* Don't use reg_significant when computing it.  This can cause problems
+  /* Don't use reg_nonzero_bits when computing it.  This can cause problems
      when, for example, we have j <<= 1 in a loop.  */
 
-  significant_valid = 0;
+  nonzero_sign_valid = 0;
 
   /* Compute the mapping from uids to cuids.
      Cuids are numbers assigned to insns, like uids,
      except that cuids increase monotonically through the code. 
 
      Scan all SETs and see if we can deduce anything about what
-     bits are significant for some registers.  */
+     bits are known to be zero for some registers and how many copies
+     of the sign bit are known to exist for those registers.
+
+     Also set any known values so that we can use it while searching
+     for what bits are known to be set.  */
+
+  label_tick = 1;
+
+  setup_incoming_promotions ();
 
   for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
     {
       INSN_CUID (insn) = ++i;
+      subst_low_cuid = i;
+      subst_insn = insn;
+
       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-       note_stores (PATTERN (insn), set_significant);
+       {
+         note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
+         record_dead_and_set_regs (insn);
+       }
+
+      if (GET_CODE (insn) == CODE_LABEL)
+       label_tick++;
     }
 
-  significant_valid = 1;
+  nonzero_sign_valid = 1;
 
   /* Now scan all the insns in forward order.  */
 
   label_tick = 1;
   last_call_cuid = 0;
   mem_last_set = 0;
+  bzero (reg_last_death, nregs * sizeof (rtx));
+  bzero (reg_last_set, nregs * sizeof (rtx));
+  bzero (reg_last_set_value, nregs * sizeof (rtx));
+  bzero (reg_last_set_table_tick, nregs * sizeof (int));
+  bzero (reg_last_set_label, nregs * sizeof (int));
+  bzero (reg_last_set_invalid, nregs * sizeof (char));
+
+  setup_incoming_promotions ();
 
   for (insn = f; insn; insn = next ? next : NEXT_INSN (insn))
     {
@@ -554,12 +619,34 @@ combine_instructions (f, nregs)
   total_extras += combine_extras;
   total_successes += combine_successes;
 
-  significant_valid = 0;
+  nonzero_sign_valid = 0;
+}
+\f
+/* Set up any promoted values for incoming argument registers.  */
+
+static void
+setup_incoming_promotions ()
+{
+#ifdef PROMOTE_FUNCTION_ARGS
+  int regno;
+  rtx reg;
+  enum machine_mode mode;
+  int unsignedp;
+  rtx first = get_insns ();
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (FUNCTION_ARG_REGNO_P (regno)
+       && (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
+      record_value_for_reg (reg, first,
+                           gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
+                                    GET_MODE (reg),
+                                    gen_rtx (CLOBBER, mode, const0_rtx)));
+#endif
 }
 \f
 /* Called via note_stores.  If X is a pseudo that is used in more than
    one basic block, is narrower that HOST_BITS_PER_WIDE_INT, and is being
-   set, record what bits are significant.  If we are clobbering X,
+   set, record what bits are known zero.  If we are clobbering X,
    ignore this "set" because the clobbered value won't be used. 
 
    If we are setting only a portion of X and we can't figure out what
@@ -571,7 +658,7 @@ combine_instructions (f, nregs)
    by any set of X.  */
 
 static void
-set_significant (x, set)
+set_nonzero_bits_and_sign_copies (x, set)
      rtx x;
      rtx set;
 {
@@ -581,18 +668,57 @@ set_significant (x, set)
       && REGNO (x) >= FIRST_PSEUDO_REGISTER
       && reg_n_sets[REGNO (x)] > 1
       && reg_basic_block[REGNO (x)] < 0
+      /* If this register is undefined at the start of the file, we can't
+        say what its contents were.  */
+      && ! (basic_block_live_at_start[0][REGNO (x) / REGSET_ELT_BITS]
+           & ((REGSET_ELT_TYPE) 1 << (REGNO (x) % REGSET_ELT_BITS)))
       && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
     {
       if (GET_CODE (set) == CLOBBER)
-       return;
+       {
+         reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
+         reg_sign_bit_copies[REGNO (x)] = 0;
+         return;
+       }
 
       /* If this is a complex assignment, see if we can convert it into a
         simple assignment.  */
       set = expand_field_assignment (set);
-      if (SET_DEST (set) == x)
+
+      /* If this is a simple assignment, or we have a paradoxical SUBREG,
+        set what we know about X.  */
+
+      if (SET_DEST (set) == x
+         || (GET_CODE (SET_DEST (set)) == SUBREG
+             && (GET_MODE_SIZE (GET_MODE (SET_DEST (set)))
+                 > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (set)))))
+             && SUBREG_REG (SET_DEST (set)) == x))
        {
-         reg_significant[REGNO (x)]
-           |= significant_bits (SET_SRC (set), significant_mode);
+         rtx src = SET_SRC (set);
+
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+         /* If X is narrower than a word and SRC is a non-negative
+            constant that would appear negative in the mode of X,
+            sign-extend it for use in reg_nonzero_bits because some
+            machines (maybe most) will actually do the sign-extension
+            and this is the conservative approach. 
+
+            ??? For 2.5, try to tighten up the MD files in this regard
+            instead of this kludge.  */
+
+         if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
+             && GET_CODE (src) == CONST_INT
+             && INTVAL (src) > 0
+             && 0 != (INTVAL (src)
+                      & ((HOST_WIDE_INT) 1
+                         << GET_MODE_BITSIZE (GET_MODE (x)))))
+           src = GEN_INT (INTVAL (src)
+                          | ((HOST_WIDE_INT) (-1)
+                             << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+
+         reg_nonzero_bits[REGNO (x)]
+           |= nonzero_bits (src, nonzero_bits_mode);
          num = num_sign_bit_copies (SET_SRC (set), GET_MODE (x));
          if (reg_sign_bit_copies[REGNO (x)] == 0
              || reg_sign_bit_copies[REGNO (x)] > num)
@@ -600,7 +726,7 @@ set_significant (x, set)
        }
       else
        {
-         reg_significant[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
+         reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
          reg_sign_bit_copies[REGNO (x)] = 0;
        }
     }
@@ -732,10 +858,12 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
         If the insns are adjacent, a use can't cross a set even though we
         think it might (this can happen for a sequence of insns each setting
         the same destination; reg_last_set of that register might point to
-        a NOTE).  Also, don't move a volatile asm across any other insns.  */
+        a NOTE).  Also, don't move a volatile asm or UNSPEC_VOLATILE across
+        any other insns.  */
       || (! all_adjacent
          && (use_crosses_set_p (src, INSN_CUID (insn))
-             || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))))
+             || (GET_CODE (src) == ASM_OPERANDS && MEM_VOLATILE_P (src))
+             || GET_CODE (src) == UNSPEC_VOLATILE))
       /* If there is a REG_NO_CONFLICT note for DEST in I3 or SUCC, we get
         better register allocation by not doing the combine.  */
       || find_reg_note (i3, REG_NO_CONFLICT, dest)
@@ -776,11 +904,15 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
   else if (GET_CODE (dest) != CC0)
     return 0;
 
-  /* Don't substitute for a register intended as a clobberable operand.  */
+  /* Don't substitute for a register intended as a clobberable operand.
+     Similarly, don't substitute an expression containing a register that
+     will be clobbered in I3.  */
   if (GET_CODE (PATTERN (i3)) == PARALLEL)
     for (i = XVECLEN (PATTERN (i3), 0) - 1; i >= 0; i--)
       if (GET_CODE (XVECEXP (PATTERN (i3), 0, i)) == CLOBBER
-         && rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest))
+         && (reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0),
+                                      src)
+             || rtx_equal_p (XEXP (XVECEXP (PATTERN (i3), 0, i), 0), dest)))
        return 0;
 
   /* If INSN contains anything volatile, or is an `asm' (whether volatile
@@ -944,9 +1076,18 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
        return 0;
 
       /* If DEST is used in I3, it is being killed in this insn,
-        so record that for later.  */
+        so record that for later. 
+        Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
+        STACK_POINTER_REGNUM, since these are always considered to be
+        live.  Similarly for ARG_POINTER_REGNUM if it is fixed.  */
       if (pi3dest_killed && GET_CODE (dest) == REG
-         && reg_referenced_p (dest, PATTERN (i3)))
+         && reg_referenced_p (dest, PATTERN (i3))
+         && REGNO (dest) != FRAME_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+         && (REGNO (dest) != ARG_POINTER_REGNUM
+             || ! fixed_regs [REGNO (dest)])
+#endif
+         && REGNO (dest) != STACK_POINTER_REGNUM)
        {
          if (*pi3dest_killed)
            return 0;
@@ -1531,7 +1672,15 @@ try_combine (i3, i2, i1)
         convert I2DEST to the mode of the source of NEWPAT if we can.  */
 
       m_split = split_insns (newpat, i3);
-      if (m_split == 0)
+
+      /* We can only use I2DEST as a scratch reg if it doesn't overlap any
+        inputs of NEWPAT.  */
+
+      /* ??? If I2DEST is not safe, and I1DEST exists, then it would be
+        possible to try that as a scratch reg.  This would require adding
+        more code to make it work though.  */
+
+      if (m_split == 0 && ! reg_overlap_mentioned_p (ni2dest, newpat))
        {
          /* If I2DEST is a hard register or the only use of a pseudo,
             we can change its mode.  */
@@ -1562,8 +1711,8 @@ try_combine (i3, i2, i1)
          rtx newi3pat = PATTERN (XVECEXP (m_split, 0, 1));
          newi2pat = PATTERN (XVECEXP (m_split, 0, 0));
 
-         i2set = single_set (XVECEXP (m_split, 0, 1));
-         i3set = single_set (XVECEXP (m_split, 0, 0));
+         i3set = single_set (XVECEXP (m_split, 0, 1));
+         i2set = single_set (XVECEXP (m_split, 0, 0));
 
          /* In case we changed the mode of I2DEST, replace it in the
             pseudo-register table here.  We can't do it above in case this
@@ -1676,11 +1825,13 @@ try_combine (i3, i2, i1)
           && ! find_reg_note (i3, REG_UNUSED,
                               SET_DEST (XVECEXP (newpat, 0, 0))))
     {
+      rtx ni2dest;
+
       newi2pat = XVECEXP (newpat, 0, 0);
+      ni2dest = SET_DEST (XVECEXP (newpat, 0, 0));
       newpat = XVECEXP (newpat, 0, 1);
       SUBST (SET_SRC (newpat),
-            gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)),
-                                     SET_DEST (newi2pat)));
+            gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
       i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
       if (i2_code_number >= 0)
        insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
@@ -1717,7 +1868,7 @@ try_combine (i3, i2, i1)
               insn = NEXT_INSN (insn))
            {
              if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-                 && reg_referenced_p (SET_DEST (newi2pat), PATTERN (insn)))
+                 && reg_referenced_p (ni2dest, PATTERN (insn)))
                {
                  for (link = LOG_LINKS (insn); link;
                       link = XEXP (link, 1))
@@ -2068,19 +2219,20 @@ try_combine (i3, i2, i1)
          }
       }
 
-    /* Update reg_significant et al for any changes that may have been made
+    /* Update reg_nonzero_bits et al for any changes that may have been made
        to this insn.  */
 
-    note_stores (newpat, set_significant);
+    note_stores (newpat, set_nonzero_bits_and_sign_copies);
     if (newi2pat)
-      note_stores (newi2pat, set_significant);
+      note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
 
     /* If I3 is now an unconditional jump, ensure that it has a 
        BARRIER following it since it may have initially been a
-       conditional jump.  */
+       conditional jump.  It may also be the last nonnote insn.  */
 
     if ((GET_CODE (newpat) == RETURN || simplejump_p (i3))
-       && GET_CODE (next_nonnote_insn (i3)) != BARRIER)
+       && ((temp = next_nonnote_insn (i3)) == NULL_RTX
+           || GET_CODE (temp) != BARRIER))
       emit_barrier_after (i3);
   }
 
@@ -2781,7 +2933,8 @@ subst (x, from, to, in_dest, unique_copy)
     x = temp, code = GET_CODE (temp);
 
   /* First see if we can apply the inverse distributive law.  */
-  if (code == PLUS || code == MINUS || code == IOR || code == XOR)
+  if (code == PLUS || code == MINUS
+      || code == AND || code == IOR || code == XOR)
     {
       x = apply_distributive_law (x);
       code = GET_CODE (x);
@@ -2794,7 +2947,7 @@ subst (x, from, to, in_dest, unique_copy)
        || code == MULT || code == AND || code == IOR || code == XOR
        || code == DIV || code == UDIV
        || code == SMAX || code == SMIN || code == UMAX || code == UMIN)
-      && GET_MODE_CLASS (mode) == MODE_INT)
+      && INTEGRAL_MODE_P (mode))
     {
       if (GET_CODE (XEXP (x, 0)) == code)
        {
@@ -2935,8 +3088,16 @@ subst (x, from, to, in_dest, unique_copy)
            return temp;
        }
        
+      /* If we want a subreg of a constant, at offset 0,
+        take the low bits.  On a little-endian machine, that's
+        always valid.  On a big-endian machine, it's valid
+        only if the constant's mode fits in one word.  */
       if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
-         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode))
+         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode)
+#if WORDS_BIG_ENDIAN
+         && GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD
+#endif
+         )
        return gen_lowpart_for_combine (mode, SUBREG_REG (x));
 
       /* If we are narrowing the object, we need to see if we can simplify
@@ -3012,6 +3173,16 @@ subst (x, from, to, in_dest, unique_copy)
        return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
                                mode, XEXP (XEXP (x, 0), 0),
                                XEXP (XEXP (x, 0), 1));
+
+      /* (ashiftrt foo C) where C is the number of bits in FOO minus 1
+        is (lt foo (const_int 0)), so we can perform the above
+        simplification.  */
+
+      if (XEXP (x, 1) == const1_rtx
+         && GET_CODE (XEXP (x, 0)) == ASHIFTRT
+         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+         && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
+       return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
 #endif
 
       /* Apply De Morgan's laws to reduce number of patterns for machines
@@ -3066,7 +3237,7 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* (neg (minus X Y)) can become (minus Y X).  */
       if (GET_CODE (XEXP (x, 0)) == MINUS
-         && (GET_MODE_CLASS (mode) != MODE_FLOAT
+         && (! FLOAT_MODE_P (mode)
              /* x-y != -(y-x) with IEEE floating point. */
              || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT))
        {
@@ -3077,7 +3248,7 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
       if (GET_CODE (XEXP (x, 0)) == XOR && XEXP (XEXP (x, 0), 1) == const1_rtx
-         && significant_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
+         && nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
        {
          x = gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
          goto restart;
@@ -3113,7 +3284,7 @@ subst (x, from, to, in_dest, unique_copy)
          goto restart;
        }
 
-      /* If X has only a single bit significant, say, bit I, convert
+      /* If X has only a single bit that might be nonzero, say, bit I, convert
         (neg X) to (ashiftrt (ashift X C-I) C-I) where C is the bitsize of
         MODE minus 1.  This will convert (neg (zero_extract X 1 Y)) to
         (sign_extract X 1 Y).  But only do this if TEMP isn't a register
@@ -3123,7 +3294,7 @@ subst (x, from, to, in_dest, unique_copy)
       if (GET_CODE (temp) != REG
          && ! (GET_CODE (temp) == SUBREG
                && GET_CODE (SUBREG_REG (temp)) == REG)
-         && (i = exact_log2 (significant_bits (temp, mode))) >= 0)
+         && (i = exact_log2 (nonzero_bits (temp, mode))) >= 0)
        {
          rtx temp1 = simplify_shift_const
            (NULL_RTX, ASHIFTRT, mode,
@@ -3161,7 +3332,7 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* In IEEE floating point, x-0 is not the same as x.  */
       if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-          || GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) == MODE_INT)
+          || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))))
          && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
        return XEXP (x, 0);
       break;
@@ -3225,7 +3396,22 @@ subst (x, from, to, in_dest, unique_copy)
          goto restart;
        }
 
-      /* If only the low-order bit of X is significant, (plus x -1)
+      /* (plus (comparison A B) C) can become (neg (rev-comp A B)) if
+        C is 1 and STORE_FLAG_VALUE is -1 or if C is -1 and STORE_FLAG_VALUE
+        is 1.  This produces better code than the alternative immediately
+        below.  */
+      if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+         && reversible_comparison_p (XEXP (x, 0))
+         && ((STORE_FLAG_VALUE == -1 && XEXP (x, 1) == const1_rtx)
+             || (STORE_FLAG_VALUE == 1 && XEXP (x, 1) == constm1_rtx)))
+       {
+         x = gen_binary (reverse_condition (GET_CODE (XEXP (x, 0))),
+                         mode, XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1));
+         x = gen_unary (NEG, mode, x);
+         goto restart;
+       }
+
+      /* If only the low-order bit of X is possibly nonzero, (plus x -1)
         can become (ashiftrt (ashift (xor x 1) C) C) where C is
         the bitsize of the mode - 1.  This allows simplification of
         "a = (b & 8) == 0;"  */
@@ -3233,7 +3419,7 @@ subst (x, from, to, in_dest, unique_copy)
          && GET_CODE (XEXP (x, 0)) != REG
          && ! (GET_CODE (XEXP (x,0)) == SUBREG
                && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG)
-         && significant_bits (XEXP (x, 0), mode) == 1)
+         && nonzero_bits (XEXP (x, 0), mode) == 1)
        {
          x = simplify_shift_const
            (NULL_RTX, ASHIFTRT, mode,
@@ -3250,8 +3436,9 @@ subst (x, from, to, in_dest, unique_copy)
         for example in cases like ((a & 1) + (a & 2)), which can
         become a & 3.  */
 
-      if ((significant_bits (XEXP (x, 0), mode)
-          & significant_bits (XEXP (x, 1), mode)) == 0)
+      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && (nonzero_bits (XEXP (x, 0), mode)
+             & nonzero_bits (XEXP (x, 1), mode)) == 0)
        {
          x = gen_binary (IOR, mode, XEXP (x, 0), XEXP (x, 1));
          goto restart;
@@ -3352,30 +3539,41 @@ subst (x, from, to, in_dest, unique_copy)
 
 #if STORE_FLAG_VALUE == 1
          /* If STORE_FLAG_VALUE is 1, we can convert (ne x 0) to simply X
-            if only the low-order bit is significant in X (such as when
+            if only the low-order bit is possibly nonzero in X (such as when
             X is a ZERO_EXTRACT of one bit.  Similarly, we can convert
-            EQ to (xor X 1).  */
+            EQ to (xor X 1).  Remove any ZERO_EXTRACT we made when thinking
+            this was a comparison.  It may now be simpler to use, e.g., an
+            AND.  If a ZERO_EXTRACT is indeed appropriate, it will
+            be placed back by the call to make_compound_operation in the
+            SET case.  */
          if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && op1 == const0_rtx
-             && significant_bits (op0, GET_MODE (op0)) == 1)
-           return gen_lowpart_for_combine (mode, op0);
+             && nonzero_bits (op0, GET_MODE (op0)) == 1)
+           return gen_lowpart_for_combine (mode,
+                                           expand_compound_operation (op0));
          else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
                   && op1 == const0_rtx
-                  && significant_bits (op0, GET_MODE (op0)) == 1)
-           return gen_rtx_combine (XOR, mode,
-                                   gen_lowpart_for_combine (mode, op0),
-                                   const1_rtx);
+                  && nonzero_bits (op0, GET_MODE (op0)) == 1)
+           {
+             op0 = expand_compound_operation (op0);
+
+             x = gen_rtx_combine (XOR, mode,
+                                  gen_lowpart_for_combine (mode, op0),
+                                  const1_rtx);
+             goto restart;
+           }
 #endif
 
 #if STORE_FLAG_VALUE == -1
          /* If STORE_FLAG_VALUE is -1, we can convert (ne x 0)
-            to (neg x) if only the low-order bit of X is significant.
+            to (neg x) if only the low-order bit of X can be nonzero.
             This converts (ne (zero_extract X 1 Y) 0) to
             (sign_extract X 1 Y).  */
          if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && op1 == const0_rtx
-             && significant_bits (op0, GET_MODE (op0)) == 1)
+             && nonzero_bits (op0, GET_MODE (op0)) == 1)
            {
+             op0 = expand_compound_operation (op0);
              x = gen_rtx_combine (NEG, mode,
                                   gen_lowpart_for_combine (mode, op0));
              goto restart;
@@ -3383,19 +3581,20 @@ subst (x, from, to, in_dest, unique_copy)
 #endif
 
          /* If STORE_FLAG_VALUE says to just test the sign bit and X has just
-            one significant bit, we can convert (ne x 0) to (ashift x c)
-            where C puts the bit in the sign bit.  Remove any AND with
-            STORE_FLAG_VALUE when we are done, since we are only going to
-            test the sign bit.  */
+            one bit that might be nonzero, we can convert (ne x 0) to
+            (ashift x c) where C puts the bit in the sign bit.  Remove any
+            AND with STORE_FLAG_VALUE when we are done, since we are only
+            going to test the sign bit.  */
          if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
              && (STORE_FLAG_VALUE
                  == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
              && op1 == const0_rtx
              && mode == GET_MODE (op0)
-             && (i = exact_log2 (significant_bits (op0, GET_MODE (op0)))) >= 0)
+             && (i = exact_log2 (nonzero_bits (op0, GET_MODE (op0)))) >= 0)
            {
-             x = simplify_shift_const (NULL_RTX, ASHIFT, mode, op0,
+             x = simplify_shift_const (NULL_RTX, ASHIFT, mode,
+                                       expand_compound_operation (op0),
                                        GET_MODE_BITSIZE (mode) - 1 - i);
              if (GET_CODE (x) == AND && XEXP (x, 1) == const_true_rtx)
                return XEXP (x, 0);
@@ -3424,7 +3623,7 @@ subst (x, from, to, in_dest, unique_copy)
          && reversible_comparison_p (XEXP (x, 0))
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG)
        {
-         HOST_WIDE_INT sig;
+         HOST_WIDE_INT nzb;
          rtx from = XEXP (XEXP (x, 0), 0);
          enum rtx_code true_code = GET_CODE (XEXP (x, 0));
          enum rtx_code false_code = reverse_condition (true_code);
@@ -3443,13 +3642,13 @@ subst (x, from, to, in_dest, unique_copy)
            }
 
          /* If we are comparing against zero and the expression being tested
-            has only a single significant bit, that is its value when it is 
-            not equal to zero.  Similarly if it is known to be -1 or 0.  */
+            has only a single bit that might be nonzero, that is its value
+            when it is not equal to zero.  Similarly if it is known to be
+            -1 or 0.  */
 
          if (true_code == EQ && true_val == const0_rtx
-             && exact_log2 (sig = significant_bits (from,
-                                                    GET_MODE (from))) >= 0)
-           false_code = EQ, false_val = GEN_INT (sig);
+             && exact_log2 (nzb = nonzero_bits (from, GET_MODE (from))) >= 0)
+           false_code = EQ, false_val = GEN_INT (nzb);
          else if (true_code == EQ && true_val == const0_rtx
                   && (num_sign_bit_copies (from, GET_MODE (from))
                       == GET_MODE_BITSIZE (GET_MODE (from))))
@@ -3521,7 +3720,7 @@ subst (x, from, to, in_dest, unique_copy)
 
       /* Look for MIN or MAX.  */
 
-      if (GET_MODE_CLASS (mode) == MODE_INT
+      if (! FLOAT_MODE_P (mode)
          && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
          && rtx_equal_p (XEXP (XEXP (x, 0), 0), XEXP (x, 1))
          && rtx_equal_p (XEXP (XEXP (x, 0), 1), XEXP (x, 2))
@@ -3556,14 +3755,14 @@ subst (x, from, to, in_dest, unique_copy)
       if (mode != VOIDmode
          && (GET_CODE (XEXP (x, 0)) == EQ || GET_CODE (XEXP (x, 0)) == NE)
          && XEXP (XEXP (x, 0), 1) == const0_rtx
-         && (significant_bits (XEXP (XEXP (x, 0), 0), mode) == 1
+         && (nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1
              || (num_sign_bit_copies (XEXP (XEXP (x, 0), 0), mode)
                  == GET_MODE_BITSIZE (mode))))
        {
          rtx nz = make_compound_operation (GET_CODE (XEXP (x, 0)) == NE
                                            ? XEXP (x, 1) : XEXP (x, 2));
          rtx z = GET_CODE (XEXP (x, 0)) == NE ? XEXP (x, 2) : XEXP (x, 1);
-         rtx dir = (significant_bits (XEXP (XEXP (x, 0), 0), mode) == 1
+         rtx dir = (nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1
                     ? const1_rtx : constm1_rtx);
          rtx c = 0;
          enum machine_mode m = mode;
@@ -3607,7 +3806,7 @@ subst (x, from, to, in_dest, unique_copy)
                   && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
                   && subreg_lowpart_p (XEXP (XEXP (nz, 0), 0))
                   && rtx_equal_p (SUBREG_REG (XEXP (XEXP (nz, 0), 0)), z)
-                  && ((significant_bits (z, GET_MODE (z))
+                  && ((nonzero_bits (z, GET_MODE (z))
                        & ~ GET_MODE_MASK (GET_MODE (XEXP (XEXP (nz, 0), 0))))
                       == 0))
            {
@@ -3633,6 +3832,25 @@ subst (x, from, to, in_dest, unique_copy)
              return temp;
            }
        }
+
+      /* If we have (if_then_else (ne A 0) C1 0) and either A is known to 
+        be 0 or 1 and C1 is a single bit or A is known to be 0 or -1 and
+        C1 is the negation of a single bit, we can convert this operation
+        to a shift.  We can actually do this in more general cases, but it
+        doesn't seem worth it.  */
+
+      if (GET_CODE (XEXP (x, 0)) == NE && XEXP (XEXP (x, 0), 1) == const0_rtx
+         && XEXP (x, 2) == const0_rtx && GET_CODE (XEXP (x, 1)) == CONST_INT
+         && ((1 == nonzero_bits (XEXP (XEXP (x, 0), 0), mode)
+              && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
+             || ((num_sign_bit_copies (XEXP (XEXP (x, 0), 0), mode)
+                  == GET_MODE_BITSIZE (mode))
+                 && (i = exact_log2 (- INTVAL (XEXP (x, 1)))) >= 0)))
+       return
+         simplify_shift_const (NULL_RTX, ASHIFT, mode,
+                               gen_lowpart_for_combine (mode,
+                                                        XEXP (XEXP (x, 0), 0)),
+                               i);
       break;
          
     case ZERO_EXTRACT:
@@ -3684,11 +3902,13 @@ subst (x, from, to, in_dest, unique_copy)
          /* Simplify our comparison, if possible.  */
          new_code = simplify_comparison (old_code, &op0, &op1);
 
-#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
+#ifdef EXTRA_CC_MODES
          /* If this machine has CC modes other than CCmode, check to see
             if we need to use a different CC mode here.  */
          compare_mode = SELECT_CC_MODE (new_code, op0, op1);
+#endif /* EXTRA_CC_MODES */
 
+#if !defined (HAVE_cc0) && defined (EXTRA_CC_MODES)
          /* If the mode changed, we have to change SET_DEST, the mode
             in the compare, and the mode in the place SET_DEST is used.
             If SET_DEST is a hard register, just build new versions with
@@ -3718,13 +3938,13 @@ subst (x, from, to, in_dest, unique_copy)
             in undobuf.other_insn.  */
          if (new_code != old_code)
            {
-             unsigned mask;
+             unsigned HOST_WIDE_INT mask;
 
              SUBST (*cc_use, gen_rtx_combine (new_code, GET_MODE (*cc_use),
                                               SET_DEST (x), const0_rtx));
 
              /* If the only change we made was to change an EQ into an
-                NE or vice versa, OP0 has only one significant bit,
+                NE or vice versa, OP0 has only one bit that might be nonzero,
                 and OP1 is zero, check if changing the user of the condition
                 code will produce a valid insn.  If it won't, we can keep
                 the original code in that insn by surrounding our operation
@@ -3735,13 +3955,12 @@ subst (x, from, to, in_dest, unique_copy)
                  && ! other_changed && op1 == const0_rtx
                  && (GET_MODE_BITSIZE (GET_MODE (op0))
                      <= HOST_BITS_PER_WIDE_INT)
-                 && (exact_log2 (mask = significant_bits (op0,
-                                                          GET_MODE (op0)))
+                 && (exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0)))
                      >= 0))
                {
                  rtx pat = PATTERN (other_insn), note = 0;
 
-                 if ((recog_for_combine (&pat, undobuf.other_insn, &note) < 0
+                 if ((recog_for_combine (&pat, other_insn, &note) < 0
                       && ! check_asm_operands (pat)))
                    {
                      PUT_CODE (*cc_use, old_code);
@@ -3794,8 +4013,8 @@ subst (x, from, to, in_dest, unique_copy)
         We can always do this if M1 is narrower than M2 because that
         means that we only care about the low bits of the result.
 
-        However, on most machines (those with BYTE_LOADS_ZERO_EXTEND
-        and BYTES_LOADS_SIGN_EXTEND not defined), we cannot perform a
+        However, on most machines (those with neither BYTE_LOADS_ZERO_EXTEND
+        nor BYTE_LOADS_SIGN_EXTEND defined), we cannot perform a
         narrower operation that requested since the high-order bits will
         be undefined.  On machine where BYTE_LOADS_*_EXTEND is defined,
         however, this transformation is safe as long as M1 and M2 have
@@ -3808,7 +4027,7 @@ subst (x, from, to, in_dest, unique_copy)
               / UNITS_PER_WORD)
              == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_SRC (x))))
                   + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))
-#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined (BYTE_LOADS_SIGN_EXTEND)
+#ifndef BYTE_LOADS_EXTEND
          && (GET_MODE_SIZE (GET_MODE (SET_SRC (x)))
              < GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_SRC (x)))))
 #endif
@@ -3822,18 +4041,19 @@ subst (x, from, to, in_dest, unique_copy)
          SUBST (SET_SRC (x), SUBREG_REG (SET_SRC (x)));
        }
 
-#ifdef BYTE_LOADS_ZERO_EXTEND
+#ifdef BYTE_LOADS_EXTEND
       /* If we have (set FOO (subreg:M (mem:N BAR) 0)) with
         M wider than N, this would require a paradoxical subreg.
         Replace the subreg with a zero_extend to avoid the reload that
         would otherwise be required. */
+
       if (GET_CODE (SET_SRC (x)) == SUBREG
          && subreg_lowpart_p (SET_SRC (x))
          && SUBREG_WORD (SET_SRC (x)) == 0
          && (GET_MODE_SIZE (GET_MODE (SET_SRC (x)))
              > GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_SRC (x)))))
          && GET_CODE (SUBREG_REG (SET_SRC (x))) == MEM)
-       SUBST (SET_SRC (x), gen_rtx_combine (ZERO_EXTEND,
+       SUBST (SET_SRC (x), gen_rtx_combine (LOAD_EXTEND,
                                             GET_MODE (SET_SRC (x)),
                                             XEXP (SET_SRC (x), 0)));
 #endif
@@ -3847,7 +4067,8 @@ subst (x, from, to, in_dest, unique_copy)
         IOR'ed together.  In practice, at most two will be nonzero.  Then
         we do the IOR's.  */
 
-      if (GET_CODE (SET_SRC (x)) == IF_THEN_ELSE
+      if (GET_CODE (SET_DEST (x)) != PC
+         && GET_CODE (SET_SRC (x)) == IF_THEN_ELSE
          && (GET_CODE (XEXP (SET_SRC (x), 0)) == EQ
              || GET_CODE (XEXP (SET_SRC (x), 0)) == NE)
          && XEXP (XEXP (SET_SRC (x), 0), 1) == const0_rtx
@@ -4058,10 +4279,10 @@ subst (x, from, to, in_dest, unique_copy)
       break;
 
     case IOR:
-      /* (ior A C) is C if all significant bits of A are on in C.  */
+      /* (ior A C) is C if all bits of A that might be nonzero are on in C.  */
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && (significant_bits (XEXP (x, 0), mode)
-             & ~ INTVAL (XEXP (x, 1))) == 0)
+         && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+         && (nonzero_bits (XEXP (x, 0), mode) & ~ INTVAL (XEXP (x, 1))) == 0)
        return XEXP (x, 1);
 
       /* Convert (A & B) | A to A.  */
@@ -4184,6 +4405,16 @@ subst (x, from, to, in_dest, unique_copy)
        return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
                                mode, XEXP (XEXP (x, 0), 0),
                                XEXP (XEXP (x, 0), 1));
+
+      /* (lshiftrt foo C) where C is the number of bits in FOO minus 1
+        is (lt foo (const_int 0)), so we can perform the above
+        simplification.  */
+
+      if (XEXP (x, 1) == const1_rtx
+         && GET_CODE (XEXP (x, 0)) == LSHIFTRT
+         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+         && INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
+       return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
 #endif
 
       /* (xor (comparison foo bar) (const_int sign-bit))
@@ -4208,7 +4439,7 @@ subst (x, from, to, in_dest, unique_copy)
       if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
          || ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
               <= HOST_BITS_PER_WIDE_INT)
-             && ((significant_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+             && ((nonzero_bits (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
                   & ((HOST_WIDE_INT) 1
                      << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1)))
                  == 0)))
@@ -4498,9 +4729,9 @@ expand_field_assignment (x)
   return x;
 }
 \f
-/* Return an RTX for a reference to LEN bits of INNER.  POS is the starting
-   bit position (counted from the LSB) if >= 0; otherwise POS_RTX represents
-   the starting bit position.
+/* Return an RTX for a reference to LEN bits of INNER.  If POS_RTX is nonzero,
+   it is an RTX that represents a variable starting position; otherwise,
+   POS is the (constant) starting bit position (counted from the LSB).
 
    INNER may be a USE.  This will occur when we started with a bitfield
    that went outside the boundary of the object in memory, which is
@@ -4533,6 +4764,9 @@ make_extraction (mode, inner, pos, pos_rtx, len,
      int unsignedp;
      int in_dest, in_compare;
 {
+  /* This mode describes the size of the storage area
+     to fetch the overall value from.  Within that, we
+     ignore the POS lowest bits, etc.  */
   enum machine_mode is_mode = GET_MODE (inner);
   enum machine_mode inner_mode;
   enum machine_mode wanted_mem_mode = byte_mode;
@@ -4541,19 +4775,30 @@ make_extraction (mode, inner, pos, pos_rtx, len,
   enum machine_mode tmode = mode_for_size (len, MODE_INT, 1);
   int spans_byte = 0;
   rtx new = 0;
+  rtx orig_pos_rtx = pos_rtx;
 
   /* Get some information about INNER and get the innermost object.  */
   if (GET_CODE (inner) == USE)
+    /* (use:SI (mem:QI foo)) stands for (mem:SI foo).  */
     /* We don't need to adjust the position because we set up the USE
        to pretend that it was a full-word object.  */
     spans_byte = 1, inner = XEXP (inner, 0);
   else if (GET_CODE (inner) == SUBREG && subreg_lowpart_p (inner))
-    inner = SUBREG_REG (inner);
+    {
+      /* If going from (subreg:SI (mem:QI ...)) to (mem:QI ...),
+        consider just the QI as the memory to extract from.
+        The subreg adds or removes high bits; its mode is
+        irrelevant to the meaning of this extraction,
+        since POS and LEN count from the lsb.  */
+      if (GET_CODE (SUBREG_REG (inner)) == MEM)
+       is_mode = GET_MODE (SUBREG_REG (inner));
+      inner = SUBREG_REG (inner);
+    }
 
   inner_mode = GET_MODE (inner);
 
   if (pos_rtx && GET_CODE (pos_rtx) == CONST_INT)
-    pos = INTVAL (pos_rtx);
+    pos = INTVAL (pos_rtx), pos_rtx = 0;
 
   /* See if this can be done without an extraction.  We never can if the
      width of the field is not the same as that of some integer mode. For
@@ -4570,12 +4815,12 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
   if (tmode != BLKmode
       && ! (spans_byte && inner_mode != tmode)
-      && ((pos == 0 && GET_CODE (inner) != MEM
+      && ((pos_rtx == 0 && pos == 0 && GET_CODE (inner) != MEM
           && (! in_dest
               || (GET_CODE (inner) == REG
                   && (movstrict_optab->handlers[(int) tmode].insn_code
                       != CODE_FOR_nothing))))
-         || (GET_CODE (inner) == MEM && pos >= 0
+         || (GET_CODE (inner) == MEM && pos_rtx == 0
              && (pos
                  % (STRICT_ALIGNMENT ? GET_MODE_ALIGNMENT (tmode)
                     : BITS_PER_UNIT)) == 0
@@ -4586,8 +4831,6 @@ make_extraction (mode, inner, pos, pos_rtx, len,
                  || (! mode_dependent_address_p (XEXP (inner, 0))
                      && ! MEM_VOLATILE_P (inner))))))
     {
-      int offset = pos / BITS_PER_UNIT;
-         
       /* If INNER is a MEM, make a new MEM that encompasses just the desired
         field.  If the original and current mode are the same, we need not
         adjust the offset.  Otherwise, we do if bytes big endian.  
@@ -4597,11 +4840,12 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
       if (GET_CODE (inner) == MEM)
        {
-#if BYTES_BIG_ENDIAN
-         if (inner_mode != tmode)
-           offset = (GET_MODE_SIZE (inner_mode)
-                     - GET_MODE_SIZE (tmode) - offset);
-#endif
+         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));
          RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (inner);
@@ -4613,10 +4857,10 @@ make_extraction (mode, inner, pos, pos_rtx, len,
           a SUBREG and it would sometimes return a new hard register.  */
        new = gen_rtx (SUBREG, tmode, inner,
                       (WORDS_BIG_ENDIAN
-                       && GET_MODE_SIZE (is_mode) > UNITS_PER_WORD)
-                      ? ((GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (tmode)
-                          / UNITS_PER_WORD))
-                      : 0);
+                       && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD
+                       ? ((GET_MODE_SIZE (inner_mode) - GET_MODE_SIZE (tmode))
+                          / UNITS_PER_WORD)
+                       : 0));
       else
        new = force_to_mode (inner, tmode, len, NULL_RTX);
 
@@ -4640,7 +4884,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
   /* Unless this is a COMPARE or we have a funny memory reference,
      don't do anything with zero-extending field extracts starting at
      the low-order bit since they are simple AND operations.  */
-  if (pos == 0 && ! in_dest && ! in_compare && ! spans_byte && unsignedp)
+  if (pos_rtx == 0 && pos == 0 && ! in_dest
+      && ! in_compare && ! spans_byte && unsignedp)
     return 0;
 
   /* Get the mode to use should INNER be a MEM, the mode for the position,
@@ -4693,7 +4938,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 #if BITS_BIG_ENDIAN
   /* If position is constant, compute new position.  Otherwise, build
      subtraction.  */
-  if (pos >= 0)
+  if (pos_rtx == 0)
     pos = (MAX (GET_MODE_BITSIZE (is_mode), GET_MODE_BITSIZE (wanted_mem_mode))
           - len - pos);
   else
@@ -4721,12 +4966,6 @@ make_extraction (mode, inner, pos, pos_rtx, len,
         endian in both bits and bytes or little endian in bits and bytes.
         If it is mixed, we must adjust.  */
             
-#if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
-      if (! spans_byte && is_mode != wanted_mem_mode)
-       offset = (GET_MODE_SIZE (is_mode)
-                 - GET_MODE_SIZE (wanted_mem_mode) - offset);
-#endif
-
       /* If bytes are big endian and we had a paradoxical SUBREG, we must
         adjust OFFSET to compensate. */
 #if BYTES_BIG_ENDIAN
@@ -4736,12 +4975,18 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 #endif
 
       /* If this is a constant position, we can move to the desired byte.  */
-      if (pos >= 0)
+      if (pos_rtx == 0)
        {
          offset += pos / BITS_PER_UNIT;
          pos %= GET_MODE_BITSIZE (wanted_mem_mode);
        }
 
+#if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
+      if (! spans_byte && is_mode != wanted_mem_mode)
+       offset = (GET_MODE_SIZE (is_mode)
+                 - GET_MODE_SIZE (wanted_mem_mode) - offset);
+#endif
+
       if (offset != 0 || inner_mode != wanted_mem_mode)
        {
          rtx newmem = gen_rtx (MEM, wanted_mem_mode,
@@ -4762,15 +5007,20 @@ make_extraction (mode, inner, pos, pos_rtx, len,
 
   /* Adjust mode of POS_RTX, if needed.  If we want a wider mode, we
      have to zero extend.  Otherwise, we can just use a SUBREG.  */
-  if (pos < 0
+  if (pos_rtx != 0
       && GET_MODE_SIZE (pos_mode) > GET_MODE_SIZE (GET_MODE (pos_rtx)))
     pos_rtx = gen_rtx_combine (ZERO_EXTEND, pos_mode, pos_rtx);
-  else if (pos < 0
+  else if (pos_rtx != 0
           && GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
     pos_rtx = gen_lowpart_for_combine (pos_mode, pos_rtx);
 
-  /* Make POS_RTX unless we already have it and it is correct.  */
-  if (pos_rtx == 0 || (pos >= 0 && INTVAL (pos_rtx) != pos))
+  /* Make POS_RTX unless we already have it and it is correct.  If we don't
+     have a POS_RTX but we do have an ORIG_POS_RTX, the latter must
+     be a CONST_INT. */
+  if (pos_rtx == 0 && orig_pos_rtx != 0 && INTVAL (orig_pos_rtx) == pos)
+    pos_rtx = orig_pos_rtx;
+
+  else if (pos_rtx == 0)
     pos_rtx = GEN_INT (pos);
 
   /* Make the required operation.  See if we can use existing rtx.  */
@@ -4811,6 +5061,7 @@ make_compound_operation (x, in_code)
   enum rtx_code next_code;
   int i, count;
   rtx new = 0;
+  rtx tem;
   char *fmt;
 
   /* Select the code to be used in recursive calls.  Once we are inside an
@@ -4834,9 +5085,12 @@ make_compound_operation (x, in_code)
       if (in_code == MEM && GET_CODE (XEXP (x, 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT
          && INTVAL (XEXP (x, 1)) >= 0)
-       new = gen_rtx_combine (MULT, mode, XEXP (x, 0),
-                              GEN_INT ((HOST_WIDE_INT) 1
-                                       << INTVAL (XEXP (x, 1))));
+       {
+         new = make_compound_operation (XEXP (x, 0), next_code);
+         new = gen_rtx_combine (MULT, mode, new,
+                                GEN_INT ((HOST_WIDE_INT) 1
+                                         << INTVAL (XEXP (x, 1))));
+       }
       break;
 
     case AND:
@@ -4849,20 +5103,24 @@ make_compound_operation (x, in_code)
         is a logical right shift, make an extraction.  */
       if (GET_CODE (XEXP (x, 0)) == LSHIFTRT
          && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
-       new = make_extraction (mode, XEXP (XEXP (x, 0), 0), -1,
-                              XEXP (XEXP (x, 0), 1), i, 1,
-                              0, in_code == COMPARE);
+       {
+         new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+         new = make_extraction (mode, new, 0, XEXP (XEXP (x, 0), 1), i, 1,
+                                0, in_code == COMPARE);
+       }
 
       /* Same as previous, but for (subreg (lshiftrt ...)) in first op.  */
       else if (GET_CODE (XEXP (x, 0)) == SUBREG
               && subreg_lowpart_p (XEXP (x, 0))
               && GET_CODE (SUBREG_REG (XEXP (x, 0))) == LSHIFTRT
               && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
-       new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))),
-                              XEXP (SUBREG_REG (XEXP (x, 0)), 0), -1,
-                              XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1,
-                              0, in_code == COMPARE);
-
+       {
+         new = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
+                                        next_code);
+         new = make_extraction (GET_MODE (SUBREG_REG (XEXP (x, 0))), new, 0,
+                                XEXP (SUBREG_REG (XEXP (x, 0)), 1), i, 1,
+                                0, in_code == COMPARE);
+       }
 
       /* If we are have (and (rotate X C) M) and C is larger than the number
         of bits in M, this is an extraction.  */
@@ -4871,10 +5129,13 @@ make_compound_operation (x, in_code)
               && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
               && (i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0
               && i <= INTVAL (XEXP (XEXP (x, 0), 1)))
-       new = make_extraction (mode, XEXP (XEXP (x, 0), 0),
-                              (GET_MODE_BITSIZE (mode)
-                               - INTVAL (XEXP (XEXP (x, 0), 1))),
-                              NULL_RTX, i, 1, 0, in_code == COMPARE);
+       {
+         new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+         new = make_extraction (mode, new,
+                                (GET_MODE_BITSIZE (mode)
+                                 - INTVAL (XEXP (XEXP (x, 0), 1))),
+                                NULL_RTX, i, 1, 0, in_code == COMPARE);
+       }
 
       /* On machines without logical shifts, if the operand of the AND is
         a logical shift and our mask turns off all the propagated sign
@@ -4893,7 +5154,9 @@ make_compound_operation (x, in_code)
          mask >>= INTVAL (XEXP (XEXP (x, 0), 1));
          if ((INTVAL (XEXP (x, 1)) & ~mask) == 0)
            SUBST (XEXP (x, 0),
-                  gen_rtx_combine (ASHIFTRT, mode, XEXP (XEXP (x, 0), 0),
+                  gen_rtx_combine (ASHIFTRT, mode,
+                                   make_compound_operation (XEXP (XEXP (x, 0), 0),
+                                                            next_code),
                                    XEXP (XEXP (x, 0), 1)));
        }
 
@@ -4902,14 +5165,19 @@ make_compound_operation (x, in_code)
         If it doesn't end up being a ZERO_EXTEND, we will ignore it unless
         we are in a COMPARE.  */
       else if ((i = exact_log2 (INTVAL (XEXP (x, 1)) + 1)) >= 0)
-       new = make_extraction (mode, XEXP (x, 0), 0, NULL_RTX, i, 1,
-                              0, in_code == COMPARE);
+       new = make_extraction (mode,
+                              make_compound_operation (XEXP (x, 0),
+                                                       next_code),
+                              0, NULL_RTX, i, 1, 0, in_code == COMPARE);
 
       /* If we are in a comparison and this is an AND with a power of two,
         convert this into the appropriate bit extract.  */
       else if (in_code == COMPARE
               && (i = exact_log2 (INTVAL (XEXP (x, 1)))) >= 0)
-       new = make_extraction (mode, XEXP (x, 0), i, NULL_RTX, 1, 1, 0, 1);
+       new = make_extraction (mode,
+                              make_compound_operation (XEXP (x, 0),
+                                                       next_code),
+                              i, NULL_RTX, 1, 1, 0, 1);
 
       break;
 
@@ -4919,10 +5187,12 @@ make_compound_operation (x, in_code)
       if (ashr_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing
          && lshr_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
          && mode_width <= HOST_BITS_PER_WIDE_INT
-         && (significant_bits (XEXP (x, 0), mode)
-             & (1 << (mode_width - 1))) == 0)
+         && (nonzero_bits (XEXP (x, 0), mode) & (1 << (mode_width - 1))) == 0)
        {
-         new = gen_rtx_combine (ASHIFTRT, mode, XEXP (x, 0), XEXP (x, 1));
+         new = gen_rtx_combine (ASHIFTRT, mode,
+                                make_compound_operation (XEXP (x, 0),
+                                                         next_code),
+                                XEXP (x, 1));
          break;
        }
 
@@ -4935,11 +5205,14 @@ make_compound_operation (x, in_code)
          && GET_CODE (XEXP (x, 0)) == ASHIFT
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (x, 0), 1)))
-       new = make_extraction (mode, XEXP (XEXP (x, 0), 0),
-                              (INTVAL (XEXP (x, 1))
-                               - INTVAL (XEXP (XEXP (x, 0), 1))),
-                              NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
-                              code == LSHIFTRT, 0, in_code == COMPARE);
+       {
+         new = make_compound_operation (XEXP (XEXP (x, 0), 0), next_code);
+         new = make_extraction (mode, new,
+                                (INTVAL (XEXP (x, 1))
+                                 - INTVAL (XEXP (XEXP (x, 0), 1))),
+                                NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
+                                code == LSHIFTRT, 0, in_code == COMPARE);
+       }
 
       /* Similarly if we have (ashifrt (OP (ashift foo C1) C3) C2).  In these
         cases, we are better off returning a SIGN_EXTEND of the operation.  */
@@ -4950,24 +5223,38 @@ make_compound_operation (x, in_code)
              || GET_CODE (XEXP (x, 0)) == PLUS)
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == ASHIFT
          && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))
          && INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)) < HOST_BITS_PER_WIDE_INT
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-         && (INTVAL (XEXP (XEXP (x, 0), 1))
-             & (((HOST_WIDE_INT) 1
-                 << INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))) - 1)) == 0)
+         && 0 == (INTVAL (XEXP (XEXP (x, 0), 1))
+                  & (((HOST_WIDE_INT) 1
+                      << (MIN (INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)),
+                               INTVAL (XEXP (x, 1)))
+                          - 1)))))
        {
-         HOST_WIDE_INT newop1
-           = (INTVAL (XEXP (XEXP (x, 0), 1))
-              >> INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)));
+         rtx c1 = XEXP (XEXP (XEXP (x, 0), 0), 1);
+         rtx c2 = XEXP (x, 1);
+         rtx c3 = XEXP (XEXP (x, 0), 1);
+         HOST_WIDE_INT newop1;
+         rtx inner = XEXP (XEXP (XEXP (x, 0), 0), 0);
+
+         /* If C1 > C2, INNER needs to have the shift performed on it
+            for C1-C2 bits.  */
+         if (INTVAL (c1) > INTVAL (c2))
+           {
+             inner = gen_binary (ASHIFT, mode, inner,
+                                 GEN_INT (INTVAL (c1) - INTVAL (c2)));
+             c1 = c2;
+           }
 
+         newop1 = INTVAL (c3) >> INTVAL (c1);
+         new = make_compound_operation (inner,
+                                        GET_CODE (XEXP (x, 0)) == PLUS
+                                        ? MEM : GET_CODE (XEXP (x, 0)));
          new = make_extraction (mode,
-                                gen_binary (GET_CODE (XEXP (x, 0)), mode,
-                                            XEXP (XEXP (XEXP (x, 0), 0), 0),
+                                gen_binary (GET_CODE (XEXP (x, 0)), mode, new,
                                             GEN_INT (newop1)),
-                                (INTVAL (XEXP (x, 1))
-                                 - INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))),
-                                NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
+                                INTVAL (c2) - INTVAL (c1),
+                                NULL_RTX, mode_width - INTVAL (c2),
                                 code == LSHIFTRT, 0, in_code == COMPARE);
        }
 
@@ -4977,14 +5264,39 @@ make_compound_operation (x, in_code)
          && GET_CODE (XEXP (XEXP (x, 0), 0)) == ASHIFT
          && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) >= INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1)))
-       new = make_extraction (mode,
-                              gen_unary (GET_CODE (XEXP (x, 0)), mode,
-                                         XEXP (XEXP (XEXP (x, 0), 0), 0)),
-                              (INTVAL (XEXP (x, 1))
-                               - INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))),
-                              NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
-                              code == LSHIFTRT, 0, in_code == COMPARE);
+       {
+         new = make_compound_operation (XEXP (XEXP (XEXP (x, 0), 0), 0),
+                                        next_code);
+         new = make_extraction (mode,
+                                gen_unary (GET_CODE (XEXP (x, 0)), mode,
+                                           new, 0),
+                                (INTVAL (XEXP (x, 1))
+                                 - INTVAL (XEXP (XEXP (XEXP (x, 0), 0), 1))),
+                                NULL_RTX, mode_width - INTVAL (XEXP (x, 1)),
+                                code == LSHIFTRT, 0, in_code == COMPARE);
+       }
       break;
+
+    case SUBREG:
+      /* Call ourselves recursively on the inner expression.  If we are
+        narrowing the object and it has a different RTL code from
+        what it originally did, do this SUBREG as a force_to_mode.  */
+
+      tem = make_compound_operation (SUBREG_REG (x), in_code);
+      if (GET_CODE (tem) != GET_CODE (SUBREG_REG (x))
+         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (tem))
+         && subreg_lowpart_p (x))
+       {
+         rtx newer = force_to_mode (tem, mode,
+                                    GET_MODE_BITSIZE (mode), NULL_RTX);
+
+         /* If we have something other than a SUBREG, we might have
+            done an expansion, so rerun outselves.  */
+         if (GET_CODE (newer) != SUBREG)
+           newer = make_compound_operation (newer, in_code);
+
+         return newer;
+       }
     }
 
   if (new)
@@ -5163,9 +5475,21 @@ force_to_mode (x, mode, bits, reg)
     case ASHIFT:
     case LSHIFT:
       /* For left shifts, do the same, but just for the first operand.
-        If the shift count is a constant, we need even fewer bits of the
-        first operand.  */
-
+        However, we cannot do anything with shifts where we cannot
+        guarantee that the counts are smaller than the size of the mode
+        because such a count will have a different meaning in a
+        wider mode.
+
+        If we can narrow the shift and know the count, we need even fewer
+        bits of the first operand.  */
+
+      if (! (GET_CODE (XEXP (x, 1)) == CONST_INT
+            && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode))
+         && ! (GET_MODE (XEXP (x, 1)) != VOIDmode
+               && (nonzero_bits (XEXP (x, 1), GET_MODE (XEXP (x, 1)))
+                   < (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode))))
+       break;
+       
       if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) < bits)
        bits -= INTVAL (XEXP (x, 1));
 
@@ -5185,8 +5509,8 @@ force_to_mode (x, mode, bits, reg)
 
     case LSHIFTRT:
       /* Here we can only do something if the shift count is a constant and
-        the count plus BITS is no larger than the width of MODE, we can do
-        the shift in MODE.  */
+        the count plus BITS is no larger than the width of MODE.  In that
+        case, we can do the shift in MODE.  */
 
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) + bits <= GET_MODE_BITSIZE (mode))
@@ -5370,7 +5694,7 @@ make_field_assignment (x)
          || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
          || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
     {
-      assign = make_extraction (VOIDmode, dest, -1, XEXP (XEXP (src, 0), 1),
+      assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
                                1, 1, 1, 0);
       return gen_rtx (SET, VOIDmode, assign, const0_rtx);
     }
@@ -5385,7 +5709,7 @@ make_field_assignment (x)
               || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
               || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
     {
-      assign = make_extraction (VOIDmode, dest, -1,
+      assign = make_extraction (VOIDmode, dest, 0,
                                XEXP (SUBREG_REG (XEXP (src, 0)), 1),
                                1, 1, 1, 0);
       return gen_rtx (SET, VOIDmode, assign, const0_rtx);
@@ -5399,7 +5723,7 @@ make_field_assignment (x)
               || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
               || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
     {
-      assign = make_extraction (VOIDmode, dest, -1, XEXP (XEXP (src, 0), 1),
+      assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
                                1, 1, 1, 0);
       return gen_rtx (SET, VOIDmode, assign, const1_rtx);
     }
@@ -5430,7 +5754,8 @@ make_field_assignment (x)
 
   pos = get_pos_from_mask (~c1, &len);
   if (pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (dest))
-      || (c1 & significant_bits (other, GET_MODE (other))) != 0)
+      || (GET_MODE_BITSIZE (GET_MODE (other)) <= HOST_BITS_PER_WIDE_INT
+         && (c1 & nonzero_bits (other, GET_MODE (other))) != 0))
     return x;
 
   assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
@@ -5462,6 +5787,12 @@ apply_distributive_law (x)
   rtx tem;
   enum rtx_code inner_code;
 
+  /* Distributivity is not true for floating point.
+     It can change the value.  So don't do it.
+     -- rms and moshier@world.std.com.  */
+  if (FLOAT_MODE_P (GET_MODE (x)))
+    return x;
+
   /* The outer operation can only be one of the following:  */
   if (code != IOR && code != AND && code != XOR
       && code != PLUS && code != MINUS)
@@ -5583,7 +5914,7 @@ simplify_and_const_int (x, mode, varop, constop)
 {
   register enum machine_mode tmode;
   register rtx temp;
-  unsigned HOST_WIDE_INT significant;
+  unsigned HOST_WIDE_INT nonzero;
 
   /* There is a large class of optimizations based on the principle that
      some operations produce results where certain bits are known to be zero,
@@ -5634,7 +5965,7 @@ simplify_and_const_int (x, mode, varop, constop)
                 constant masks to zero all the bits the mode doesn't have.  */
              && ((GET_MODE_SIZE (GET_MODE (varop))
                   < GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop))))
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
+#ifdef BYTE_LOADS_EXTEND
                  || (0 == (constop
                            & GET_MODE_MASK (GET_MODE (varop))
                            & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (varop)))))
@@ -5674,16 +6005,20 @@ simplify_and_const_int (x, mode, varop, constop)
        case XOR:
          /* If VAROP is (ior (lshiftrt FOO C1) C2), try to commute the IOR and
             LSHIFT so we end up with an (and (lshiftrt (ior ...) ...) ...)
-            operation which may be a bitfield extraction.  */
+            operation which may be a bitfield extraction.  Ensure
+            that the constant we form is not wider than the mode of
+            VAROP.  */
 
          if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT
              && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
              && INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0
              && INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT
              && GET_CODE (XEXP (varop, 1)) == CONST_INT
+             && ((INTVAL (XEXP (XEXP (varop, 0), 1))
+                 + floor_log2 (INTVAL (XEXP (varop, 1))))
+                 < GET_MODE_BITSIZE (GET_MODE (varop)))
              && (INTVAL (XEXP (varop, 1))
-                 & ~ significant_bits (XEXP (varop, 0),
-                                       GET_MODE (varop)) == 0))
+                 & ~ nonzero_bits (XEXP (varop, 0), GET_MODE (varop)) == 0))
            {
              temp = GEN_INT ((INTVAL (XEXP (varop, 1)) & constop)
                              << INTVAL (XEXP (XEXP (varop, 0), 1)));
@@ -5710,12 +6045,15 @@ simplify_and_const_int (x, mode, varop, constop)
                                         XEXP (varop, 1), constop))));
 
        case NOT:
-         /* (and (not FOO)) is (and (xor FOO CONST_OP)) so if FOO is an
-            LSHIFTRT we can do the same as above.  */
+         /* (and (not FOO)) is (and (xor FOO CONST)), so if FOO is an
+            LSHIFTRT, we can do the same as above.  Ensure that the constant
+            we form is not wider than the mode of VAROP.  */
 
          if (GET_CODE (XEXP (varop, 0)) == LSHIFTRT
              && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
              && INTVAL (XEXP (XEXP (varop, 0), 1)) >= 0
+             && (INTVAL (XEXP (XEXP (varop, 0), 1)) + floor_log2 (constop)
+                 < GET_MODE_BITSIZE (GET_MODE (varop)))
              && INTVAL (XEXP (XEXP (varop, 0), 1)) < HOST_BITS_PER_WIDE_INT)
            {
              temp = GEN_INT (constop << INTVAL (XEXP (XEXP (varop, 0), 1)));
@@ -5750,10 +6088,10 @@ simplify_and_const_int (x, mode, varop, constop)
            {
              int i = -1;
 
-             significant = GET_MODE_MASK (GET_MODE (varop));
-             significant >>= INTVAL (XEXP (varop, 1));
+             nonzero = GET_MODE_MASK (GET_MODE (varop));
+             nonzero >>= INTVAL (XEXP (varop, 1));
 
-             if ((constop & ~significant) == 0
+             if ((constop & ~ nonzero) == 0
                  || (i = exact_log2 (constop)) >= 0)
                {
                  varop = simplify_shift_const
@@ -5772,13 +6110,33 @@ simplify_and_const_int (x, mode, varop, constop)
                                     XEXP (varop, 0), XEXP (varop, 1));
          break;
 
+       case LSHIFTRT:
+         /* If we have (and (lshiftrt FOO C1) C2) where the combination of the
+            shift and AND produces only copies of the sign bit (C2 is one less
+            than a power of two), we can do this with just a shift.  */
+
+         if (GET_CODE (XEXP (varop, 1)) == CONST_INT
+             && ((INTVAL (XEXP (varop, 1))
+                  + num_sign_bit_copies (XEXP (varop, 0),
+                                         GET_MODE (XEXP (varop, 0))))
+                 >= GET_MODE_BITSIZE (GET_MODE (varop)))
+             && exact_log2 (constop + 1) >= 0
+             && (num_sign_bit_copies (XEXP (varop, 0),
+                                      GET_MODE (XEXP (varop, 0)))
+                 >= exact_log2 (constop + 1)))
+           varop
+             = gen_rtx_combine (LSHIFTRT, GET_MODE (varop), XEXP (varop, 0),
+                                GEN_INT (GET_MODE_BITSIZE (GET_MODE (varop))
+                                         - exact_log2 (constop + 1)));
+         break;
+
        case NE:
          /* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is
-            included in STORE_FLAG_VALUE and FOO has no significant bits
-            not in CONST.  */
+            included in STORE_FLAG_VALUE and FOO has no bits that might be
+            nonzero not in CONST.  */
          if ((constop & ~ STORE_FLAG_VALUE) == 0
              && XEXP (varop, 0) == const0_rtx
-             && (significant_bits (XEXP (varop, 0), mode) & ~ constop) == 0)
+             && (nonzero_bits (XEXP (varop, 0), mode) & ~ constop) == 0)
            {
              varop = XEXP (varop, 0);
              continue;
@@ -5792,7 +6150,7 @@ simplify_and_const_int (x, mode, varop, constop)
             and possibly the PLUS if it is now adding zero.  */
          if (GET_CODE (XEXP (varop, 1)) == CONST_INT
              && exact_log2 (-constop) >= 0
-             && (significant_bits (XEXP (varop, 0), mode) & ~ constop) == 0)
+             && (nonzero_bits (XEXP (varop, 0), mode) & ~ constop) == 0)
            {
              varop = plus_constant (XEXP (varop, 0),
                                     INTVAL (XEXP (varop, 1)) & constop);
@@ -5829,14 +6187,17 @@ simplify_and_const_int (x, mode, varop, constop)
   if (GET_CODE (varop) == CONST_INT)
     return GEN_INT (constop & INTVAL (varop));
 
-  /* See what bits are significant in VAROP.  */
-  significant = significant_bits (varop, mode);
+  /* See what bits may be nonzero in VAROP.  Unlike the general case of
+     a call to nonzero_bits, here we don't care about bits outside
+     MODE.  */
+
+  nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
 
   /* Turn off all bits in the constant that are known to already be zero.
-     Thus, if the AND isn't needed at all, we will have CONSTOP == SIGNIFICANT
+     Thus, if the AND isn't needed at all, we will have CONSTOP == NONZERO_BITS
      which is tested below.  */
 
-  constop &= significant;
+  constop &= nonzero;
 
   /* If we don't have any bits left, return zero.  */
   if (constop == 0)
@@ -5856,7 +6217,7 @@ simplify_and_const_int (x, mode, varop, constop)
     return x ? x : varop;
 
   /* If we are only masking insignificant bits, return VAROP.  */
-  if (constop == significant)
+  if (constop == nonzero)
     x = varop;
 
   /* Otherwise, return an AND.  See how much, if any, of X we can use.  */
@@ -5882,12 +6243,12 @@ simplify_and_const_int (x, mode, varop, constop)
    a shift, AND, or zero_extract, we can do better.  */
 
 static unsigned HOST_WIDE_INT
-significant_bits (x, mode)
+nonzero_bits (x, mode)
      rtx x;
      enum machine_mode mode;
 {
-  unsigned HOST_WIDE_INT significant = GET_MODE_MASK (mode);
-  unsigned HOST_WIDE_INT inner_sig;
+  unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
+  unsigned HOST_WIDE_INT inner_nz;
   enum rtx_code code;
   int mode_width = GET_MODE_BITSIZE (mode);
   rtx tem;
@@ -5896,14 +6257,14 @@ significant_bits (x, mode)
   if (GET_MODE_BITSIZE (GET_MODE (x)) > mode_width)
     {
       mode = GET_MODE (x);
-      significant = GET_MODE_MASK (mode);
+      nonzero = GET_MODE_MASK (mode);
       mode_width = GET_MODE_BITSIZE (mode);
     }
 
   if (mode_width > HOST_BITS_PER_WIDE_INT)
     /* Our only callers in this case look for single bit values.  So
        just return the mode mask.  Those tests will then be false.  */
-    return significant;
+    return nonzero;
 
   code = GET_CODE (x);
   switch (code)
@@ -5923,23 +6284,63 @@ significant_bits (x, mode)
          sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
 #endif
 
-         return significant & ~ (sp_alignment - 1);
+         return nonzero & ~ (sp_alignment - 1);
        }
 #endif
 
-      /* If X is a register whose value we can find, use that value.  
-        Otherwise, use the previously-computed significant bits for this
-        register.  */
+      /* If X is a register whose nonzero bits value is current, use it.
+        Otherwise, if X is a register whose value we can find, use that
+        value.  Otherwise, use the previously-computed global nonzero bits
+        for this register.  */
+
+      if (reg_last_set_value[REGNO (x)] != 0
+         && reg_last_set_mode[REGNO (x)] == mode
+         && (reg_n_sets[REGNO (x)] == 1
+             || reg_last_set_label[REGNO (x)] == label_tick)
+         && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
+       return reg_last_set_nonzero_bits[REGNO (x)];
 
       tem = get_last_value (x);
+
       if (tem)
-       return significant_bits (tem, mode);
-      else if (significant_valid && reg_significant[REGNO (x)])
-       return reg_significant[REGNO (x)] & significant;
+       {
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+         /* If X is narrower than MODE and TEM is a non-negative
+            constant that would appear negative in the mode of X,
+            sign-extend it for use in reg_nonzero_bits because some
+            machines (maybe most) will actually do the sign-extension
+            and this is the conservative approach. 
+
+            ??? For 2.5, try to tighten up the MD files in this regard
+            instead of this kludge.  */
+
+         if (GET_MODE_BITSIZE (GET_MODE (x)) < mode_width
+             && GET_CODE (tem) == CONST_INT
+             && INTVAL (tem) > 0
+             && 0 != (INTVAL (tem)
+                      & ((HOST_WIDE_INT) 1
+                         << GET_MODE_BITSIZE (GET_MODE (x)))))
+           tem = GEN_INT (INTVAL (tem)
+                          | ((HOST_WIDE_INT) (-1)
+                             << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+         return nonzero_bits (tem, mode);
+       }
+      else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
+       return reg_nonzero_bits[REGNO (x)] & nonzero;
       else
-       return significant;
+       return nonzero;
 
     case CONST_INT:
+#ifdef SHORT_IMMEDIATES_SIGN_EXTEND
+      /* If X is negative in MODE, sign-extend the value.  */
+      if (INTVAL (x) > 0
+         && 0 != (INTVAL (x)
+                  & ((HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (GET_MODE (x)))))
+       return (INTVAL (x)
+               | ((HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (GET_MODE (x))));
+#endif
+
       return INTVAL (x);
 
 #ifdef BYTE_LOADS_ZERO_EXTEND
@@ -5947,7 +6348,7 @@ significant_bits (x, mode)
       /* In many, if not most, RISC machines, reading a byte from memory
         zeros the rest of the register.  Noticing that fact saves a lot
         of extra zero-extends.  */
-      significant &= GET_MODE_MASK (GET_MODE (x));
+      nonzero &= GET_MODE_MASK (GET_MODE (x));
       break;
 #endif
 
@@ -5959,68 +6360,67 @@ significant_bits (x, mode)
     case LE:  case LEU:
 
       if (GET_MODE_CLASS (mode) == MODE_INT)
-       significant = 1;
+       nonzero = 1;
 
       /* A comparison operation only sets the bits given by its mode.  The
         rest are set undefined.  */
       if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
-       significant |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
+       nonzero |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
       break;
 #endif
 
     case NEG:
       if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
          == GET_MODE_BITSIZE (GET_MODE (x)))
-       significant = 1;
+       nonzero = 1;
 
       if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
-       significant |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
+       nonzero |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
       break;
 
     case ABS:
       if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
          == GET_MODE_BITSIZE (GET_MODE (x)))
-       significant = 1;
+       nonzero = 1;
       break;
 
     case TRUNCATE:
-      significant &= (significant_bits (XEXP (x, 0), mode)
-                     & GET_MODE_MASK (mode));
+      nonzero &= (nonzero_bits (XEXP (x, 0), mode) & GET_MODE_MASK (mode));
       break;
 
     case ZERO_EXTEND:
-      significant &= significant_bits (XEXP (x, 0), mode);
+      nonzero &= nonzero_bits (XEXP (x, 0), mode);
       if (GET_MODE (XEXP (x, 0)) != VOIDmode)
-       significant &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
+       nonzero &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
       break;
 
     case SIGN_EXTEND:
       /* If the sign bit is known clear, this is the same as ZERO_EXTEND.
         Otherwise, show all the bits in the outer mode but not the inner
         may be non-zero.  */
-      inner_sig = significant_bits (XEXP (x, 0), mode);
+      inner_nz = nonzero_bits (XEXP (x, 0), mode);
       if (GET_MODE (XEXP (x, 0)) != VOIDmode)
        {
-         inner_sig &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
-         if (inner_sig &
+         inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
+         if (inner_nz &
              (((HOST_WIDE_INT) 1
                << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
-           inner_sig |= (GET_MODE_MASK (mode)
+           inner_nz |= (GET_MODE_MASK (mode)
                          & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0))));
        }
 
-      significant &= inner_sig;
+      nonzero &= inner_nz;
       break;
 
     case AND:
-      significant &= (significant_bits (XEXP (x, 0), mode)
-                     & significant_bits (XEXP (x, 1), mode));
+      nonzero &= (nonzero_bits (XEXP (x, 0), mode)
+                 & nonzero_bits (XEXP (x, 1), mode));
       break;
 
     case XOR:   case IOR:
     case UMIN:  case UMAX:  case SMIN:  case SMAX:
-      significant &= (significant_bits (XEXP (x, 0), mode)
-                     | significant_bits (XEXP (x, 1), mode));
+      nonzero &= (nonzero_bits (XEXP (x, 0), mode)
+                 | nonzero_bits (XEXP (x, 1), mode));
       break;
 
     case PLUS:  case MINUS:
@@ -6032,14 +6432,14 @@ significant_bits (x, mode)
         computing the width (position of the highest-order non-zero bit)
         and the number of low-order zero bits for each value.  */
       {
-       unsigned HOST_WIDE_INT sig0 = significant_bits (XEXP (x, 0), mode);
-       unsigned HOST_WIDE_INT sig1 = significant_bits (XEXP (x, 1), mode);
-       int width0 = floor_log2 (sig0) + 1;
-       int width1 = floor_log2 (sig1) + 1;
-       int low0 = floor_log2 (sig0 & -sig0);
-       int low1 = floor_log2 (sig1 & -sig1);
-       int op0_maybe_minusp = (sig0 & (1 << (mode_width - 1)));
-       int op1_maybe_minusp = (sig1 & (1 << (mode_width - 1)));
+       unsigned HOST_WIDE_INT nz0 = nonzero_bits (XEXP (x, 0), mode);
+       unsigned HOST_WIDE_INT nz1 = nonzero_bits (XEXP (x, 1), mode);
+       int width0 = floor_log2 (nz0) + 1;
+       int width1 = floor_log2 (nz1) + 1;
+       int low0 = floor_log2 (nz0 & -nz0);
+       int low1 = floor_log2 (nz1 & -nz1);
+       int op0_maybe_minusp = (nz0 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
+       int op1_maybe_minusp = (nz1 & ((HOST_WIDE_INT) 1 << (mode_width - 1)));
        int result_width = mode_width;
        int result_low = 0;
 
@@ -6075,17 +6475,17 @@ significant_bits (x, mode)
          }
 
        if (result_width < mode_width)
-         significant &= ((HOST_WIDE_INT) 1 << result_width) - 1;
+         nonzero &= ((HOST_WIDE_INT) 1 << result_width) - 1;
 
        if (result_low > 0)
-         significant &= ~ (((HOST_WIDE_INT) 1 << result_low) - 1);
+         nonzero &= ~ (((HOST_WIDE_INT) 1 << result_low) - 1);
       }
       break;
 
     case ZERO_EXTRACT:
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
          && INTVAL (XEXP (x, 1)) < HOST_BITS_PER_WIDE_INT)
-       significant &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1;
+       nonzero &= ((HOST_WIDE_INT) 1 << INTVAL (XEXP (x, 1))) - 1;
       break;
 
     case SUBREG:
@@ -6094,25 +6494,25 @@ significant_bits (x, mode)
         are zero, though others might be too.  */
 
       if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x))
-       significant = (GET_MODE_MASK (GET_MODE (x))
-                      & significant_bits (SUBREG_REG (x), GET_MODE (x)));
+       nonzero = (GET_MODE_MASK (GET_MODE (x))
+                  & nonzero_bits (SUBREG_REG (x), GET_MODE (x)));
 
       /* If the inner mode is a single word for both the host and target
         machines, we can compute this from which bits of the inner
-        object are known significant.  */
+        object might be nonzero.  */
       if (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) <= BITS_PER_WORD
          && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
              <= HOST_BITS_PER_WIDE_INT))
        {
-         significant &= significant_bits (SUBREG_REG (x), mode);
-#if ! defined(BYTE_LOADS_ZERO_EXTEND) && ! defined(BYTE_LOADS_SIGN_EXTEND)
+         nonzero &= nonzero_bits (SUBREG_REG (x), mode);
+#ifndef BYTE_LOADS_EXTEND
          /* On many CISC machines, accessing an object in a wider mode
             causes the high-order bits to become undefined.  So they are
             not known to be zero.  */
          if (GET_MODE_SIZE (GET_MODE (x))
              > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-           significant |= (GET_MODE_MASK (GET_MODE (x))
-                           & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+           nonzero |= (GET_MODE_MASK (GET_MODE (x))
+                       & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
 #endif
        }
       break;
@@ -6122,9 +6522,9 @@ significant_bits (x, mode)
     case ASHIFT:
     case LSHIFT:
     case ROTATE:
-      /* The significant bits are in two classes: any bits within MODE
+      /* The nonzero bits are in two classes: any bits within MODE
         that aren't in GET_MODE (x) are always significant.  The rest of the
-        significant bits are those that are significant in the operand of
+        nonzero bits are those that are significant in the operand of
         the shift when shifted the appropriate number of bits.  This
         shows that high-order bits are cleared by the right shift and
         low-order bits by left shifts.  */
@@ -6136,13 +6536,12 @@ significant_bits (x, mode)
          int width = GET_MODE_BITSIZE (inner_mode);
          int count = INTVAL (XEXP (x, 1));
          unsigned HOST_WIDE_INT mode_mask = GET_MODE_MASK (inner_mode);
-         unsigned HOST_WIDE_INT op_significant
-           = significant_bits (XEXP (x, 0), mode);
-         unsigned HOST_WIDE_INT inner = op_significant & mode_mask;
+         unsigned HOST_WIDE_INT op_nonzero = nonzero_bits (XEXP (x, 0), mode);
+         unsigned HOST_WIDE_INT inner = op_nonzero & mode_mask;
          unsigned HOST_WIDE_INT outer = 0;
 
          if (mode_width > width)
-           outer = (op_significant & significant & ~ mode_mask);
+           outer = (op_nonzero & nonzero & ~ mode_mask);
 
          if (code == LSHIFTRT)
            inner >>= count;
@@ -6150,9 +6549,9 @@ significant_bits (x, mode)
            {
              inner >>= count;
 
-             /* If the sign bit was significant at before the shift, we
+             /* If the sign bit may have been nonzero before the shift, we
                 need to mark all the places it could have been copied to
-                by the shift significant.  */
+                by the shift as possibly nonzero.  */
              if (inner & ((HOST_WIDE_INT) 1 << (width - 1 - count)))
                inner |= (((HOST_WIDE_INT) 1 << count) - 1) << (width - count);
            }
@@ -6162,22 +6561,22 @@ significant_bits (x, mode)
            inner = ((inner << (count % width)
                      | (inner >> (width - (count % width)))) & mode_mask);
 
-         significant &= (outer | inner);
+         nonzero &= (outer | inner);
        }
       break;
 
     case FFS:
       /* This is at most the number of bits in the mode.  */
-      significant = ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width) + 1)) - 1;
+      nonzero = ((HOST_WIDE_INT) 1 << (floor_log2 (mode_width) + 1)) - 1;
       break;
 
     case IF_THEN_ELSE:
-      significant &= (significant_bits (XEXP (x, 1), mode)
-                     | significant_bits (XEXP (x, 2), mode));
+      nonzero &= (nonzero_bits (XEXP (x, 1), mode)
+                 | nonzero_bits (XEXP (x, 2), mode));
       break;
     }
 
-  return significant;
+  return nonzero;
 }
 \f
 /* Return the number of bits at the high-order end of X that are known to
@@ -6193,7 +6592,7 @@ num_sign_bit_copies (x, mode)
   enum rtx_code code = GET_CODE (x);
   int bitwidth;
   int num0, num1, result;
-  unsigned HOST_WIDE_INT sig;
+  unsigned HOST_WIDE_INT nonzero;
   rtx tem;
 
   /* If we weren't given a mode, use the mode of X.  If the mode is still
@@ -6203,19 +6602,27 @@ num_sign_bit_copies (x, mode)
     mode = GET_MODE (x);
 
   if (mode == VOIDmode)
-    return 0;
+    return 1;
 
   bitwidth = GET_MODE_BITSIZE (mode);
 
   switch (code)
     {
     case REG:
-      if (significant_valid && reg_sign_bit_copies[REGNO (x)] != 0)
-       return reg_sign_bit_copies[REGNO (x)];
+
+      if (reg_last_set_value[REGNO (x)] != 0
+         && reg_last_set_mode[REGNO (x)] == mode
+         && (reg_n_sets[REGNO (x)] == 1
+             || reg_last_set_label[REGNO (x)] == label_tick)
+         && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
+       return reg_last_set_sign_bit_copies[REGNO (x)];
 
       tem =  get_last_value (x);
       if (tem != 0)
        return num_sign_bit_copies (tem, mode);
+
+      if (nonzero_sign_valid && reg_sign_bit_copies[REGNO (x)] != 0)
+       return reg_sign_bit_copies[REGNO (x)];
       break;
 
 #ifdef BYTE_LOADS_SIGN_EXTEND
@@ -6227,11 +6634,12 @@ num_sign_bit_copies (x, mode)
     case CONST_INT:
       /* If the constant is negative, take its 1's complement and remask.
         Then see how many zero bits we have.  */
-      sig = INTVAL (x) & GET_MODE_MASK (mode);
-      if (sig & ((HOST_WIDE_INT) 1 << (bitwidth - 1)))
-       sig = (~ sig) & GET_MODE_MASK (mode);
+      nonzero = INTVAL (x) & GET_MODE_MASK (mode);
+      if (bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
+       nonzero = (~ nonzero) & GET_MODE_MASK (mode);
 
-      return (sig == 0 ? bitwidth : bitwidth - floor_log2 (sig) - 1);
+      return (nonzero == 0 ? bitwidth : bitwidth - floor_log2 (nonzero) - 1);
 
     case SUBREG:
       /* If this is a SUBREG for a promoted object that is sign-extended
@@ -6239,8 +6647,8 @@ num_sign_bit_copies (x, mode)
         high-order bits are known to be sign bit copies.  */
 
       if (SUBREG_PROMOTED_VAR_P (x) && ! SUBREG_PROMOTED_UNSIGNED_P (x))
-       return (GET_MODE_BITSIZE (mode) - GET_MODE_BITSIZE (GET_MODE (x))
-               + num_sign_bit_copies (SUBREG_REG (x), GET_MODE (x)));
+       return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1,
+                   num_sign_bit_copies (SUBREG_REG (x), mode));
 
       /* For a smaller object, just ignore the high bits. */
       if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
@@ -6251,7 +6659,7 @@ num_sign_bit_copies (x, mode)
                             - bitwidth)));
        }
 
-#if defined(BYTE_LOADS_ZERO_EXTEND) || defined(BYTE_LOADS_SIGN_EXTEND)
+#ifdef BYTE_LOADS_EXTEND
       /* For paradoxical SUBREGs, just look inside since, on machines with
         one of these defined, we assume that operations are actually 
         performed on the full register.  Note that we are passing MODE
@@ -6299,15 +6707,16 @@ num_sign_bit_copies (x, mode)
     case NEG:
       /* In general, this subtracts one sign bit copy.  But if the value
         is known to be positive, the number of sign bit copies is the
-        same as that of the input.  Finally, if the input has just one
-        significant bit, all the bits are copies of the sign bit.  */
-      sig = significant_bits (XEXP (x, 0), mode);
-      if (sig == 1)
+        same as that of the input.  Finally, if the input has just one bit
+        that might be nonzero, all the bits are copies of the sign bit.  */
+      nonzero = nonzero_bits (XEXP (x, 0), mode);
+      if (nonzero == 1)
        return bitwidth;
 
       num0 = num_sign_bit_copies (XEXP (x, 0), mode);
       if (num0 > 1
-         && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & sig))
+         && bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero))
        num0--;
 
       return num0;
@@ -6326,12 +6735,13 @@ num_sign_bit_copies (x, mode)
         be such a carry.  Furthermore, if the positive number is known to
         be 0 or 1, we know the result is either -1 or 0.  */
 
-      if (code == PLUS && XEXP (x, 1) == constm1_rtx)
+      if (code == PLUS && XEXP (x, 1) == constm1_rtx
+         && bitwidth <= HOST_BITS_PER_WIDE_INT)
        {
-         sig = significant_bits (XEXP (x, 0), mode);
-         if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & sig) == 0)
-           return (sig == 1 || sig == 0 ? bitwidth
-                   : bitwidth - floor_log2 (sig));
+         nonzero = nonzero_bits (XEXP (x, 0), mode);
+         if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0)
+           return (nonzero == 1 || nonzero == 0 ? bitwidth
+                   : bitwidth - floor_log2 (nonzero) - 1);
        }
 
       num0 = num_sign_bit_copies (XEXP (x, 0), mode);
@@ -6349,9 +6759,10 @@ num_sign_bit_copies (x, mode)
 
       result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
       if (result > 0
-         && ((significant_bits (XEXP (x, 0), mode)
+         && bitwidth <= HOST_BITS_PER_WIDE_INT
+         && ((nonzero_bits (XEXP (x, 0), mode)
               & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
-         && (significant_bits (XEXP (x, 1), mode)
+         && (nonzero_bits (XEXP (x, 1), mode)
              & ((HOST_WIDE_INT) 1 << (bitwidth - 1)) != 0))
        result--;
 
@@ -6371,7 +6782,8 @@ num_sign_bit_copies (x, mode)
         to add 1.  */
       result = num_sign_bit_copies (XEXP (x, 0), mode);
       if (result > 1
-         && (significant_bits (XEXP (x, 1), mode)
+         && bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (nonzero_bits (XEXP (x, 1), mode)
              & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
        result --;
 
@@ -6380,7 +6792,8 @@ num_sign_bit_copies (x, mode)
     case MOD:
       result = num_sign_bit_copies (XEXP (x, 1), mode);
       if (result > 1
-         && (significant_bits (XEXP (x, 1), mode)
+         && bitwidth <= HOST_BITS_PER_WIDE_INT
+         && (nonzero_bits (XEXP (x, 1), mode)
              & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
        result --;
 
@@ -6421,10 +6834,15 @@ num_sign_bit_copies (x, mode)
 
   /* If we haven't been able to figure it out by one of the above rules,
      see if some of the high-order bits are known to be zero.  If so,
-     count those bits and return one less than that amount.  */
+     count those bits and return one less than that amount.  If we can't
+     safely compute the mask for this mode, always return BITWIDTH.  */
 
-  sig = significant_bits (x, mode);
-  return sig == GET_MODE_MASK (mode) ? 1 : bitwidth - floor_log2 (sig) - 1;
+  if (bitwidth > HOST_BITS_PER_WIDE_INT)
+    return 1;
+
+  nonzero = nonzero_bits (x, mode);
+  return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
+         ? 1 : bitwidth - floor_log2 (nonzero) - 1);
 }
 \f
 /* Return the number of "extended" bits there are in X, when interpreted
@@ -6444,12 +6862,13 @@ extended_count (x, mode, unsignedp)
      enum machine_mode mode;
      int unsignedp;
 {
-  if (significant_valid == 0)
+  if (nonzero_sign_valid == 0)
     return 0;
 
   return (unsignedp
-         ? (GET_MODE_BITSIZE (mode) - 1
-            - floor_log2 (significant_bits (x, mode)))
+         ? (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+            && (GET_MODE_BITSIZE (mode) - 1
+                - floor_log2 (nonzero_bits (x, mode))))
          : num_sign_bit_copies (x, mode) - 1);
 }
 \f
@@ -6691,13 +7110,23 @@ simplify_shift_const (x, code, result_mode, varop, count)
          break;
        }
 
+      /* If we are doing an arithmetic right shift and discarding all but
+        the sign bit copies, this is equivalent to doing a shift by the
+        bitsize minus one.  Convert it into that shift because it will often
+        allow other simplifications.  */
+
+      if (code == ASHIFTRT
+         && (count + num_sign_bit_copies (varop, shift_mode)
+             >= GET_MODE_BITSIZE (shift_mode)))
+       count = GET_MODE_BITSIZE (shift_mode) - 1;
+
       /* 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.  */
       if (GET_MODE_BITSIZE (shift_mode) <= HOST_BITS_PER_WIDE_INT
          && code == ASHIFTRT
-         && ((significant_bits (varop, shift_mode)
+         && ((nonzero_bits (varop, shift_mode)
               & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (shift_mode) - 1)))
              == 0))
        code = LSHIFTRT;
@@ -6773,7 +7202,9 @@ simplify_shift_const (x, code, result_mode, varop, count)
          /* If VAROP is a SUBREG, strip it as long as the inner operand has
             the same number of words as what we've seen so far.  Then store
             the widest mode in MODE.  */
-         if (SUBREG_WORD (varop) == 0
+         if (subreg_lowpart_p (varop)
+             && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))
+                 > GET_MODE_SIZE (GET_MODE (varop)))
              && (((GET_MODE_SIZE (GET_MODE (SUBREG_REG (varop)))
                    + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
                  == mode_words))
@@ -6920,10 +7351,10 @@ simplify_shift_const (x, code, result_mode, varop, count)
                break;
 
              /* To compute the mask to apply after the shift, shift the
-                significant bits of the inner shift the same way the 
+                nonzero bits of the inner shift the same way the 
                 outer shift will.  */
 
-             mask_rtx = GEN_INT (significant_bits (varop, GET_MODE (varop)));
+             mask_rtx = GEN_INT (nonzero_bits (varop, GET_MODE (varop)));
 
              mask_rtx
                = simplify_binary_operation (code, result_mode, mask_rtx,
@@ -7047,7 +7478,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
          /* convert (lshift (eq FOO 0) C) to (xor FOO 1) if STORE_FLAG_VALUE
             says that the sign bit can be tested, FOO has mode MODE, C is
             GET_MODE_BITSIZE (MODE) - 1, and FOO has only the low-order bit
-            significant.  */
+            may be nonzero.  */
          if (code == LSHIFT
              && XEXP (varop, 1) == const0_rtx
              && GET_MODE (XEXP (varop, 0)) == result_mode
@@ -7055,7 +7486,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
              && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
              && ((STORE_FLAG_VALUE
                   & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (result_mode) - 1))))
-             && significant_bits (XEXP (varop, 0), result_mode) == 1
+             && nonzero_bits (XEXP (varop, 0), result_mode) == 1
              && merge_outer_ops (&outer_op, &outer_const, XOR,
                                  (HOST_WIDE_INT) 1, result_mode,
                                  &complement_p))
@@ -7070,7 +7501,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
          /* (lshiftrt (neg A) C) where A is either 0 or 1 and C is one less
             than the number of bits in the mode is equivalent to A.  */
          if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1
-             && significant_bits (XEXP (varop, 0), result_mode) == 1)
+             && nonzero_bits (XEXP (varop, 0), result_mode) == 1)
            {
              varop = XEXP (varop, 0);
              count = 0;
@@ -7095,7 +7526,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
             equivalent to (xor A 1).  */
          if (code == LSHIFTRT && count == GET_MODE_BITSIZE (result_mode) - 1
              && XEXP (varop, 1) == constm1_rtx
-             && significant_bits (XEXP (varop, 0), result_mode) == 1
+             && nonzero_bits (XEXP (varop, 0), result_mode) == 1
              && merge_outer_ops (&outer_op, &outer_const, XOR,
                                  (HOST_WIDE_INT) 1, result_mode,
                                  &complement_p))
@@ -7106,26 +7537,27 @@ simplify_shift_const (x, code, result_mode, varop, count)
            }
 
          /* If we have (xshiftrt (plus FOO BAR) C), and the only bits
-            significant in BAR are those being shifted out and those
+            that might be nonzero in BAR are those being shifted out and those
             bits are known zero in FOO, we can replace the PLUS with FOO.
             Similarly in the other operand order.  This code occurs when
             we are computing the size of a variable-size array.  */
 
          if ((code == ASHIFTRT || code == LSHIFTRT)
              && count < HOST_BITS_PER_WIDE_INT
-             && significant_bits (XEXP (varop, 1), result_mode) >> count == 0
-             && (significant_bits (XEXP (varop, 1), result_mode)
-                 & significant_bits (XEXP (varop, 0), result_mode)) == 0)
+             && nonzero_bits (XEXP (varop, 1), result_mode) >> count == 0
+             && (nonzero_bits (XEXP (varop, 1), result_mode)
+                 & nonzero_bits (XEXP (varop, 0), result_mode)) == 0)
            {
              varop = XEXP (varop, 0);
              continue;
            }
          else if ((code == ASHIFTRT || code == LSHIFTRT)
                   && count < HOST_BITS_PER_WIDE_INT
-                  && 0 == (significant_bits (XEXP (varop, 0), result_mode)
+                  && GET_MODE_BITSIZE (result_mode) <= HOST_BITS_PER_WIDE_INT
+                  && 0 == (nonzero_bits (XEXP (varop, 0), result_mode)
                            >> count)
-                  && 0 == (significant_bits (XEXP (varop, 0), result_mode)
-                           & significant_bits (XEXP (varop, 1),
+                  && 0 == (nonzero_bits (XEXP (varop, 0), result_mode)
+                           & nonzero_bits (XEXP (varop, 1),
                                                 result_mode)))
            {
              varop = XEXP (varop, 1);
@@ -7223,6 +7655,16 @@ simplify_shift_const (x, code, result_mode, varop, count)
       SUBST (XEXP (x, 1), const_rtx);
     }
 
+  /* If we have an outer operation and we just made a shift, it is
+     possible that we could have simplified the shift were it not
+     for the outer operation.  So try to do the simplification
+     recursively.  */
+
+  if (outer_op != NIL && GET_CODE (x) == code
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    x = simplify_shift_const (x, code, shift_mode, XEXP (x, 0),
+                             INTVAL (XEXP (x, 1)));
+
   /* If we were doing a LSHIFTRT in a wider mode than it was originally,
      turn off all the bits that the shift would have turned off.  */
   if (orig_code == LSHIFTRT && result_mode != shift_mode)
@@ -7367,7 +7809,14 @@ gen_lowpart_for_combine (mode, x)
   if (GET_MODE (x) == mode)
     return x;
 
-  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+  /* We can only support MODE being wider than a word if X is a
+     constant integer or has a mode the same size.  */
+
+  if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+      && ! ((GET_MODE (x) == VOIDmode
+            && (GET_CODE (x) == CONST_INT
+                || GET_CODE (x) == CONST_DOUBLE))
+           || GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
     return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
 
   /* X might be a paradoxical (subreg (mem)).  In that case, gen_lowpart
@@ -7591,7 +8040,7 @@ simplify_comparison (code, pop0, pop1)
     {
       /* If both operands are the same constant shift, see if we can ignore the
         shift.  We can if the shift is a rotate or if the bits shifted out of
-        this shift are not significant for either input and if the type of
+        this shift are known to be zero for both inputs and if the type of
         comparison is compatible with the shift.  */
       if (GET_CODE (op0) == GET_CODE (op1)
          && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
@@ -7616,8 +8065,8 @@ simplify_comparison (code, pop0, pop1)
          else if (GET_CODE (op0) == ASHIFT || GET_CODE (op0) == LSHIFT)
            mask = (mask & (mask << shift_count)) >> shift_count;
 
-         if ((significant_bits (XEXP (op0, 0), mode) & ~ mask) == 0
-             && (significant_bits (XEXP (op1, 0), mode) & ~ mask) == 0)
+         if ((nonzero_bits (XEXP (op0, 0), mode) & ~ mask) == 0
+             && (nonzero_bits (XEXP (op1, 0), mode) & ~ mask) == 0)
            op0 = XEXP (op0, 0), op1 = XEXP (op1, 0);
          else
            break;
@@ -7627,9 +8076,9 @@ simplify_comparison (code, pop0, pop1)
         SUBREGs are of the same mode, and, in both cases, the AND would
         be redundant if the comparison was done in the narrower mode,
         do the comparison in the narrower mode (e.g., we are AND'ing with 1
-        and the operand's significant bits are 0xffffff01; in that case if
-        we only care about QImode, we don't need the AND).  This case occurs
-        if the output mode of an scc insn is not SImode and
+        and the operand's possibly nonzero bits are 0xffffff01; in that case
+        if we only care about QImode, we don't need the AND).  This case
+        occurs if the output mode of an scc insn is not SImode and
         STORE_FLAG_VALUE == 1 (e.g., the 386).  */
 
       else if  (GET_CODE (op0) == AND && GET_CODE (op1) == AND
@@ -7641,10 +8090,12 @@ simplify_comparison (code, pop0, pop1)
                    > GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
                && (GET_MODE (SUBREG_REG (XEXP (op0, 0)))
                    == GET_MODE (SUBREG_REG (XEXP (op1, 0))))
-               && (significant_bits (SUBREG_REG (XEXP (op0, 0)),
+               && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
+                   <= HOST_BITS_PER_WIDE_INT)
+               && (nonzero_bits (SUBREG_REG (XEXP (op0, 0)),
                                      GET_MODE (SUBREG_REG (XEXP (op0, 0))))
                    & ~ INTVAL (XEXP (op0, 1))) == 0
-               && (significant_bits (SUBREG_REG (XEXP (op1, 0)),
+               && (nonzero_bits (SUBREG_REG (XEXP (op1, 0)),
                                      GET_MODE (SUBREG_REG (XEXP (op1, 0))))
                    & ~ INTVAL (XEXP (op1, 1))) == 0)
        {
@@ -7700,7 +8151,7 @@ simplify_comparison (code, pop0, pop1)
        const_op &= mask;
 
       /* If we are comparing against a constant power of two and the value
-        being compared has only that single significant bit (e.g., it was
+        being compared can only have that single bit nonzero (e.g., it was
         `and'ed with that bit), we can replace this with a comparison
         with zero.  */
       if (const_op
@@ -7708,7 +8159,7 @@ simplify_comparison (code, pop0, pop1)
              || code == LT || code == LTU)
          && mode_width <= HOST_BITS_PER_WIDE_INT
          && exact_log2 (const_op) >= 0
-         && significant_bits (op0, mode) == const_op)
+         && nonzero_bits (op0, mode) == const_op)
        {
          code = (code == EQ || code == GE || code == GEU ? NE : EQ);
          op1 = const0_rtx, const_op = 0;
@@ -7757,7 +8208,7 @@ simplify_comparison (code, pop0, pop1)
             a zero sign bit, we can replace this with == 0.  */
          else if (const_op == 0
                   && mode_width <= HOST_BITS_PER_WIDE_INT
-                  && (significant_bits (op0, mode)
+                  && (nonzero_bits (op0, mode)
                       & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
            code = EQ;
          break;
@@ -7787,7 +8238,7 @@ simplify_comparison (code, pop0, pop1)
             a zero sign bit, we can replace this with != 0.  */
          else if (const_op == 0
                   && mode_width <= HOST_BITS_PER_WIDE_INT
-                  && (significant_bits (op0, mode)
+                  && (nonzero_bits (op0, mode)
                       & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)
            code = NE;
          break;
@@ -7951,7 +8402,7 @@ simplify_comparison (code, pop0, pop1)
          if (sign_bit_comparison_p
              && (GET_CODE (XEXP (op0, 0)) == ABS
                  || (mode_width <= HOST_BITS_PER_WIDE_INT
-                     && (significant_bits (XEXP (op0, 0), mode)
+                     && (nonzero_bits (XEXP (op0, 0), mode)
                          & ((HOST_WIDE_INT) 1 << (mode_width - 1))) == 0)))
            {
              op0 = XEXP (op0, 0);
@@ -7959,28 +8410,9 @@ simplify_comparison (code, pop0, pop1)
              continue;
            }
 
-         /* If we have NEG of something that is the result of a
-            SIGN_EXTEND, SIGN_EXTRACT, or ASHIFTRT, we know that the
-            two high-order bits must be the same and hence that
-            "(-a) < 0" is equivalent to "a > 0".  Otherwise, we can't
-            do this.  */
-         if (GET_CODE (XEXP (op0, 0)) == SIGN_EXTEND
-             || (GET_CODE (XEXP (op0, 0)) == SIGN_EXTRACT
-                 && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
-                 && (INTVAL (XEXP (XEXP (op0, 0), 1))
-                     < GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (op0, 0), 0)))))
-             || (GET_CODE (XEXP (op0, 0)) == ASHIFTRT
-                 && GET_CODE (XEXP (XEXP (op0, 0), 1)) == CONST_INT
-                 && XEXP (XEXP (op0, 0), 1) != const0_rtx)
-             || ((tem = get_last_value (XEXP (op0, 0))) != 0
-                 && (GET_CODE (tem) == SIGN_EXTEND
-                     || (GET_CODE (tem) == SIGN_EXTRACT
-                         && GET_CODE (XEXP (tem, 1)) == CONST_INT
-                         && (INTVAL (XEXP (tem, 1))
-                             < GET_MODE_BITSIZE (GET_MODE (XEXP (tem, 0)))))
-                     || (GET_CODE (tem) == ASHIFTRT
-                         && GET_CODE (XEXP (tem, 1)) == CONST_INT
-                         && XEXP (tem, 1) != const0_rtx))))
+         /* If we have NEG of something whose two high-order bits are the
+            same, we know that "(-a) < 0" is equivalent to "a > 0". */
+         if (num_sign_bit_copies (op0, mode) >= 2)
            {
              op0 = XEXP (op0, 0);
              code = swap_condition (code);
@@ -8061,9 +8493,9 @@ simplify_comparison (code, pop0, pop1)
              && INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0
              && (- INTVAL (XEXP (SUBREG_REG (op0), 1))
                  < GET_MODE_MASK (mode) / 2)
-             && (unsigned) const_op < GET_MODE_MASK (mode) / 2
-             && (0 == (significant_bits (XEXP (SUBREG_REG (op0), 0),
-                                         GET_MODE (SUBREG_REG (op0)))
+             && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2
+             && (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0),
+                                     GET_MODE (SUBREG_REG (op0)))
                        & ~ GET_MODE_MASK (mode))
                  || (num_sign_bit_copies (XEXP (SUBREG_REG (op0), 0),
                                           GET_MODE (SUBREG_REG (op0)))
@@ -8097,12 +8529,12 @@ simplify_comparison (code, pop0, pop1)
          break;
 
        case PLUS:
-         /* (eq (plus X C1) C2) -> (eq X (minus C2 C1)).  We can only do
+         /* (eq (plus X A) B) -> (eq X (minus B A)).  We can only do
             this for equality comparisons due to pathological cases involving
             overflows.  */
-         if (equality_comparison_p && GET_CODE (XEXP (op0, 1)) == CONST_INT
-             && (tem = simplify_binary_operation (MINUS, mode, op1,
-                                                  XEXP (op0, 1))) != 0)
+         if (equality_comparison_p
+             && 0 != (tem = simplify_binary_operation (MINUS, mode,
+                                                       op1, XEXP (op0, 1))))
            {
              op0 = XEXP (op0, 0);
              op1 = tem;
@@ -8120,6 +8552,28 @@ simplify_comparison (code, pop0, pop1)
          break;
 
        case MINUS:
+         /* (eq (minus A B) C) -> (eq A (plus B C)) or
+            (eq B (minus A C)), whichever simplifies.  We can only do
+            this for equality comparisons due to pathological cases involving
+            overflows.  */
+         if (equality_comparison_p
+             && 0 != (tem = simplify_binary_operation (PLUS, mode,
+                                                       XEXP (op0, 1), op1)))
+           {
+             op0 = XEXP (op0, 0);
+             op1 = tem;
+             continue;
+           }
+
+         if (equality_comparison_p
+             && 0 != (tem = simplify_binary_operation (MINUS, mode,
+                                                       XEXP (op0, 0), op1)))
+           {
+             op0 = XEXP (op0, 1);
+             op1 = tem;
+             continue;
+           }
+
          /* The sign bit of (minus (ashiftrt X C) X), where C is the number
             of bits in X minus 1, is one iff X > 0.  */
          if (sign_bit_comparison_p && GET_CODE (XEXP (op0, 0)) == ASHIFTRT
@@ -8271,7 +8725,7 @@ simplify_comparison (code, pop0, pop1)
        case LSHIFT:
          /* If we have (compare (xshift FOO N) (const_int C)) and
             the high order N bits of FOO (N+1 if an inequality comparison)
-            are not significant, we can do this by comparing FOO with C
+            are known to be zero, we can do this by comparing FOO with C
             shifted right N bits so long as the low-order N bits of C are
             zero.  */
          if (GET_CODE (XEXP (op0, 1)) == CONST_INT
@@ -8279,9 +8733,9 @@ simplify_comparison (code, pop0, pop1)
              && ((INTVAL (XEXP (op0, 1)) + ! equality_comparison_p)
                  < HOST_BITS_PER_WIDE_INT)
              && ((const_op
-                  &  ((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1) == 0)
+                  & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0)
              && mode_width <= HOST_BITS_PER_WIDE_INT
-             && (significant_bits (XEXP (op0, 0), mode)
+             && (nonzero_bits (XEXP (op0, 0), mode)
                  & ~ (mask >> (INTVAL (XEXP (op0, 1))
                                + ! equality_comparison_p))) == 0)
            {
@@ -8336,7 +8790,7 @@ simplify_comparison (code, pop0, pop1)
              && GET_CODE (XEXP (op0, 0)) == ASHIFT
              && XEXP (op0, 1) == XEXP (XEXP (op0, 0), 1)
              && (tmode = mode_for_size (mode_width - INTVAL (XEXP (op0, 1)),
-                                        MODE_INT, 1)) != VOIDmode
+                                        MODE_INT, 1)) != BLKmode
              && ((unsigned HOST_WIDE_INT) const_op <= GET_MODE_MASK (tmode)
                  || ((unsigned HOST_WIDE_INT) - const_op
                      <= GET_MODE_MASK (tmode))))
@@ -8348,14 +8802,14 @@ simplify_comparison (code, pop0, pop1)
          /* ... fall through ... */
        case LSHIFTRT:
          /* If we have (compare (xshiftrt FOO N) (const_int C)) and
-            the low order N bits of FOO are not significant, we can do this
+            the low order N bits of FOO are known to be zero, we can do this
             by comparing FOO with C shifted left N bits so long as no
             overflow occurs.  */
          if (GET_CODE (XEXP (op0, 1)) == CONST_INT
              && INTVAL (XEXP (op0, 1)) >= 0
              && INTVAL (XEXP (op0, 1)) < HOST_BITS_PER_WIDE_INT
              && mode_width <= HOST_BITS_PER_WIDE_INT
-             && (significant_bits (XEXP (op0, 0), mode)
+             && (nonzero_bits (XEXP (op0, 0), mode)
                  & (((HOST_WIDE_INT) 1 << INTVAL (XEXP (op0, 1))) - 1)) == 0
              && (const_op == 0
                  || (floor_log2 (const_op) + INTVAL (XEXP (op0, 1))
@@ -8407,12 +8861,13 @@ simplify_comparison (code, pop0, pop1)
   else if (GET_CODE (op0) == SUBREG && subreg_lowpart_p (op0)
           && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
           && (code == NE || code == EQ)
-          && GET_MODE_BITSIZE (GET_MODE (op0)) <= HOST_BITS_PER_WIDE_INT
-          && (significant_bits (SUBREG_REG (op0), GET_MODE (SUBREG_REG (op0)))
+          && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+              <= HOST_BITS_PER_WIDE_INT)
+          && (nonzero_bits (SUBREG_REG (op0), GET_MODE (SUBREG_REG (op0)))
               & ~ GET_MODE_MASK (GET_MODE (op0))) == 0
           && (tem = gen_lowpart_for_combine (GET_MODE (SUBREG_REG (op0)),
                                              op1),
-              (significant_bits (tem, GET_MODE (SUBREG_REG (op0)))
+              (nonzero_bits (tem, GET_MODE (SUBREG_REG (op0)))
                & ~ GET_MODE_MASK (GET_MODE (op0))) == 0))
     op0 = SUBREG_REG (op0), op1 = tem;
 
@@ -8432,16 +8887,14 @@ simplify_comparison (code, pop0, pop1)
         tmode = GET_MODE_WIDER_MODE (tmode))
       if (cmp_optab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
        {
-         /* If the only significant bits in OP0 and OP1 are those in the
+         /* If the only nonzero bits in OP0 and OP1 are those in the
             narrower mode and this is an equality or unsigned comparison,
             we can use the wider mode.  Similarly for sign-extended
             values and equality or signed comparisons.  */
          if (((code == EQ || code == NE
                || code == GEU || code == GTU || code == LEU || code == LTU)
-              && ((significant_bits (op0, tmode) & ~ GET_MODE_MASK (mode))
-                  == 0)
-              && ((significant_bits (op1, tmode) & ~ GET_MODE_MASK (mode))
-                  == 0))
+              && (nonzero_bits (op0, tmode) & ~ GET_MODE_MASK (mode)) == 0
+              && (nonzero_bits (op1, tmode) & ~ GET_MODE_MASK (mode)) == 0)
              || ((code == EQ || code == NE
                   || code == GE || code == GT || code == LE || code == LT)
                  && (num_sign_bit_copies (op0, tmode)
@@ -8490,12 +8943,14 @@ reversible_comparison_p (x)
   switch (GET_MODE_CLASS (GET_MODE (XEXP (x, 0))))
     {
     case MODE_INT:
+    case MODE_PARTIAL_INT:
+    case MODE_COMPLEX_INT:
       return 1;
 
     case MODE_CC:
       x = get_last_value (XEXP (x, 0));
       return (x && GET_CODE (x) == COMPARE
-             && GET_MODE_CLASS (GET_MODE (XEXP (x, 0))) == MODE_INT);
+             && ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))));
     }
 
   return 0;
@@ -8534,8 +8989,8 @@ update_table_tick (x)
 
 /* Record that REG is set to VALUE in insn INSN.  If VALUE is zero, we
    are saying that the register is clobbered and we no longer know its
-   value.  If INSN is zero, don't update reg_last_set; this call is normally
-   done with VALUE also zero to invalidate the register.  */
+   value.  If INSN is zero, don't update reg_last_set; this is only permitted
+   with VALUE also zero and is used to invalidate the register.  */
 
 static void
 record_value_for_reg (reg, insn, value)
@@ -8605,9 +9060,19 @@ record_value_for_reg (reg, insn, value)
        value = 0;
     }
 
-  /* For the main register being modified, update the value.  */
+  /* For the main register being modified, update the value, the mode, the
+     nonzero bits, and the number of sign bit copies.  */
+
   reg_last_set_value[regno] = value;
 
+  if (value)
+    {
+      subst_low_cuid = INSN_CUID (insn);
+      reg_last_set_mode[regno] = GET_MODE (reg);
+      reg_last_set_nonzero_bits[regno] = nonzero_bits (value, GET_MODE (reg));
+      reg_last_set_sign_bit_copies[regno]
+       = num_sign_bit_copies (value, GET_MODE (reg));
+    }
 }
 
 /* Used for communication between the following two routines.  */
@@ -8656,16 +9121,37 @@ record_dead_and_set_regs (insn)
      rtx insn;
 {
   register rtx link;
+  int i;
+
   for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
     {
-      if (REG_NOTE_KIND (link) == REG_DEAD)
-       reg_last_death[REGNO (XEXP (link, 0))] = insn;
+      if (REG_NOTE_KIND (link) == REG_DEAD
+         && GET_CODE (XEXP (link, 0)) == REG)
+       {
+         int regno = REGNO (XEXP (link, 0));
+         int endregno
+           = regno + (regno < FIRST_PSEUDO_REGISTER
+                      ? HARD_REGNO_NREGS (regno, GET_MODE (XEXP (link, 0)))
+                      : 1);
+
+         for (i = regno; i < endregno; i++)
+           reg_last_death[i] = insn;
+       }
       else if (REG_NOTE_KIND (link) == REG_INC)
        record_value_for_reg (XEXP (link, 0), insn, NULL_RTX);
     }
 
   if (GET_CODE (insn) == CALL_INSN)
-    last_call_cuid = mem_last_set = INSN_CUID (insn);
+    {
+      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+       if (call_used_regs[i])
+         {
+           reg_last_set_value[i] = 0;
+           reg_last_death[i] = 0;
+         }
+
+      last_call_cuid = mem_last_set = INSN_CUID (insn);
+    }
 
   record_dead_insn = insn;
   note_stores (PATTERN (insn), record_dead_and_set_regs_1);
@@ -8756,16 +9242,15 @@ get_last_value (x)
 
   if (value == 0
       || (reg_n_sets[regno] != 1
-         && (reg_last_set_label[regno] != label_tick)))
+         && reg_last_set_label[regno] != label_tick))
     return 0;
 
   /* If the value was set in a later insn that the ones we are processing,
-     we can't use it, but make a quick check to see if the previous insn
-     set it to something.  This is commonly the case when the same pseudo
-     is used by repeated insns.  */
+     we can't use it even if the register was only set once, but make a quick
+     check to see if the previous insn set it to something.  This is commonly
+     the case when the same pseudo is used by repeated insns.  */
 
-  if (reg_n_sets[regno] != 1
-      && INSN_CUID (reg_last_set[regno]) >= subst_low_cuid)
+  if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid)
     {
       rtx insn, set;
 
@@ -8988,13 +9473,37 @@ move_deaths (x, from_cuid, to_insn, pnotes)
       if (where_dead && INSN_CUID (where_dead) >= from_cuid
          && INSN_CUID (where_dead) < INSN_CUID (to_insn))
        {
-         rtx note = remove_death (regno, reg_last_death[regno]);
+         rtx note = remove_death (regno, where_dead);
 
          /* It is possible for the call above to return 0.  This can occur
             when reg_last_death points to I2 or I1 that we combined with.
-            In that case make a new note.  */
+            In that case make a new note.
+
+            We must also check for the case where X is a hard register
+            and NOTE is a death note for a range of hard registers
+            including X.  In that case, we must put REG_DEAD notes for
+            the remaining registers in place of NOTE.  */
 
-         if (note)
+         if (note != 0 && regno < FIRST_PSEUDO_REGISTER
+             && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+                 != GET_MODE_SIZE (GET_MODE (x))))
+           {
+             int deadregno = REGNO (XEXP (note, 0));
+             int deadend
+               = (deadregno + HARD_REGNO_NREGS (deadregno,
+                                                GET_MODE (XEXP (note, 0))));
+             int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+             int i;
+
+             for (i = deadregno; i < deadend; i++)
+               if (i < regno || i >= ourend)
+                 REG_NOTES (where_dead)
+                   = gen_rtx (EXPR_LIST, REG_DEAD,
+                              gen_rtx (REG, word_mode, i),
+                              REG_NOTES (where_dead));
+           }
+
+         if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
            {
              XEXP (note, 1) = *pnotes;
              *pnotes = note;
@@ -9404,6 +9913,16 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                        all_used = 0;
                      }
 
+                 /* Check for the case where the register dying partially
+                    overlaps the register set by this insn.  */
+                 if (all_used)
+                   for (i = regno; i < endregno; i++)
+                     if (dead_or_set_regno_p (place, i))
+                         {
+                           all_used = 0;
+                           break;
+                         }
+
                  if (! all_used)
                    {
                      /* Put only REG_DEAD notes for pieces that are