OSDN Git Service

Make `solaris' reflect the most recent major release.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index b99b8e9..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,7 +90,6 @@ 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.  */
@@ -101,7 +104,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #define LOAD_EXTEND ZERO_EXTEND
 #endif
 
-#ifdef BYTE_LOAD_SIGN_EXTEND
+#ifdef BYTE_LOADS_SIGN_EXTEND
 #define BYTE_LOADS_EXTEND
 #define LOAD_EXTEND SIGN_EXTEND
 #endif
@@ -236,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.  */
@@ -250,7 +253,7 @@ 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,
@@ -262,7 +265,7 @@ static short label_tick;
 
    If an entry is zero, it means that we don't know anything special.  */
 
-static HOST_WIDE_INT *reg_nonzero_bits;
+static unsigned HOST_WIDE_INT *reg_nonzero_bits;
 
 /* Mode used to compute significance in reg_nonzero_bits.  It is the largest
    integer mode that can fit in HOST_BITS_PER_WIDE_INT.  */
@@ -280,6 +283,15 @@ static char *reg_sign_bit_copies;
    which can be incorrect if a variable is modified in a loop.  */
 
 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.
@@ -354,6 +366,7 @@ static struct undobuf undobuf;
 static int n_occurrences;
 
 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 ();
@@ -406,24 +419,36 @@ 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_nonzero_bits = (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_label, 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_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));
 
@@ -450,13 +475,29 @@ combine_instructions (f, nregs)
 
      Scan all SETs and see if we can deduce anything about what
      bits are known to be zero for some registers and how many copies
-     of the sign bit are known to exist for those registers.  */
+     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_nonzero_bits_and_sign_copies);
+       {
+         note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
+         record_dead_and_set_regs (insn);
+       }
+
+      if (GET_CODE (insn) == CODE_LABEL)
+       label_tick++;
     }
 
   nonzero_sign_valid = 1;
@@ -466,6 +507,14 @@ combine_instructions (f, nregs)
   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))
     {
@@ -573,6 +622,28 @@ combine_instructions (f, nregs)
   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 known zero.  If we are clobbering X,
@@ -597,18 +668,57 @@ set_nonzero_bits_and_sign_copies (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))
        {
+         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 (SET_SRC (set), nonzero_bits_mode);
+           |= 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)
@@ -748,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)
@@ -964,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;
@@ -2812,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);
@@ -2825,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)
        {
@@ -2966,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
@@ -3043,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
@@ -3097,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))
        {
@@ -3192,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;
@@ -3256,7 +3396,22 @@ subst (x, from, to, in_dest, unique_copy)
          goto restart;
        }
 
-      /* If only the low-order bit of X is possible nonzero, (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;"  */
@@ -3565,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))
@@ -3677,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:
@@ -3728,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
@@ -3838,7 +4014,7 @@ subst (x, from, to, in_dest, unique_copy)
         means that we only care about the low bits of the result.
 
         However, on most machines (those with neither BYTE_LOADS_ZERO_EXTEND
-        nor BYTES_LOADS_SIGN_EXTEND defined), we cannot perform a
+        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
@@ -4229,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))
@@ -4780,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
@@ -4801,6 +4981,12 @@ make_extraction (mode, inner, pos, pos_rtx, len,
          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,
@@ -4875,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
@@ -4898,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:
@@ -4913,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), 0,
-                              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), 0,
-                              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.  */
@@ -4935,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
@@ -4957,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)));
        }
 
@@ -4966,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;
 
@@ -4985,7 +5189,10 @@ make_compound_operation (x, in_code)
          && mode_width <= HOST_BITS_PER_WIDE_INT
          && (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;
        }
 
@@ -4998,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.  */
@@ -5013,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);
        }
 
@@ -5040,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)
@@ -5226,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));
 
@@ -5248,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))
@@ -5526,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)
@@ -5738,13 +6005,18 @@ 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))
                  & ~ nonzero_bits (XEXP (varop, 0), GET_MODE (varop)) == 0))
            {
@@ -5773,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)));
@@ -5835,6 +6110,26 @@ 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 bits that might be
@@ -5892,8 +6187,11 @@ simplify_and_const_int (x, mode, varop, constop)
   if (GET_CODE (varop) == CONST_INT)
     return GEN_INT (constop & INTVAL (varop));
 
-  /* See what bits may be nonzero in VAROP.  */
-  nonzero = nonzero_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 == NONZERO_BITS
@@ -5990,19 +6288,59 @@ nonzero_bits (x, mode)
        }
 #endif
 
-      /* If X is a register whose value we can find, use that value.  
-        Otherwise, use the previously-computed nonzero 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 nonzero_bits (tem, mode);
+       {
+#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 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
@@ -6271,12 +6609,20 @@ num_sign_bit_copies (x, mode)
   switch (code)
     {
     case REG:
-      if (nonzero_sign_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
@@ -6301,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))))
@@ -6390,7 +6736,7 @@ num_sign_bit_copies (x, mode)
         be 0 or 1, we know the result is either -1 or 0.  */
 
       if (code == PLUS && XEXP (x, 1) == constm1_rtx
-         && bitwidth <= HOST_BITS_PER_INT)
+         && bitwidth <= HOST_BITS_PER_WIDE_INT)
        {
          nonzero = nonzero_bits (XEXP (x, 0), mode);
          if ((((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero) == 0)
@@ -6413,7 +6759,7 @@ num_sign_bit_copies (x, mode)
 
       result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
       if (result > 0
-         && bitwidth <= HOST_BITS_PER_INT
+         && bitwidth <= HOST_BITS_PER_WIDE_INT
          && ((nonzero_bits (XEXP (x, 0), mode)
               & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
          && (nonzero_bits (XEXP (x, 1), mode)
@@ -6495,7 +6841,7 @@ num_sign_bit_copies (x, mode)
     return 1;
 
   nonzero = nonzero_bits (x, mode);
-  return (nonzero == GET_MODE_MASK (mode)
+  return (nonzero & ((HOST_WIDE_INT) 1 << (bitwidth - 1))
          ? 1 : bitwidth - floor_log2 (nonzero) - 1);
 }
 \f
@@ -6764,6 +7110,16 @@ 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
@@ -7299,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)
@@ -8127,7 +8493,7 @@ 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
+             && (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))
@@ -8163,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;
@@ -8186,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
@@ -8345,7 +8733,7 @@ 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
              && (nonzero_bits (XEXP (op0, 0), mode)
                  & ~ (mask >> (INTVAL (XEXP (op0, 1))
@@ -8555,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;
@@ -8599,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)
@@ -8670,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.  */
@@ -8721,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);
@@ -8821,7 +9242,7 @@ 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,
@@ -9052,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;
@@ -9468,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