OSDN Git Service

(assign_parms): Don't trust the callee to copy a TREE_ADDRESSABLE
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index d2df7d8..323db6b 100644 (file)
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This module is essentially the "combiner" phase of the U. of Arizona
@@ -120,7 +121,7 @@ static int combine_successes;
 
 static int total_attempts, total_merges, total_extras, total_successes;
 
-/* Define a defulat value for REVERSIBLE_CC_MODE.
+/* Define a default value for REVERSIBLE_CC_MODE.
    We can never assume that a condition code mode is safe to reverse unless
    the md tells us so.  */
 #ifndef REVERSIBLE_CC_MODE
@@ -173,6 +174,11 @@ static int last_call_cuid;
 
 static rtx subst_insn;
 
+/* This is an insn that belongs before subst_insn, but is not currently
+   on the insn chain.  */
+
+static rtx subst_prev_insn;
+
 /* This is the lowest CUID that `subst' is currently dealing with.
    get_last_value will not return a value if the register was set at or
    after this CUID.  If not for this mechanism, we could get confused if
@@ -415,7 +421,7 @@ static int merge_outer_ops  PROTO((enum rtx_code *, HOST_WIDE_INT *,
                                       enum machine_mode, int *));
 static rtx simplify_shift_const        PROTO((rtx, enum rtx_code, enum machine_mode,
                                       rtx, int));
-static int recog_for_combine   PROTO((rtx *, rtx, rtx *));
+static int recog_for_combine   PROTO((rtx *, rtx, rtx *, int *));
 static rtx gen_lowpart_for_combine  PROTO((enum machine_mode, rtx));
 static rtx gen_rtx_combine PVPROTO((enum rtx_code code, enum machine_mode mode,
                                  ...));
@@ -513,6 +519,10 @@ combine_instructions (f, nregs)
 
   label_tick = 1;
 
+  /* We need to initialize it here, because record_dead_and_set_regs may call
+     get_last_value.  */
+  subst_prev_insn = NULL_RTX;
+
   setup_incoming_promotions ();
 
   for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
@@ -1208,6 +1218,8 @@ try_combine (i3, i2, i1)
   int i3_subst_into_i2 = 0;
   /* Notes that I1, I2 or I3 is a MULT operation.  */
   int have_mult = 0;
+  /* Number of clobbers of SCRATCH we had to add.  */
+  int i3_scratches = 0, i2_scratches = 0, other_scratches = 0;
 
   int maxreg;
   rtx temp;
@@ -1358,8 +1370,9 @@ try_combine (i3, i2, i1)
             never appear in the insn stream so giving it the same INSN_UID
             as I2 will not cause a problem.  */
 
-         i1 = gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2,
-                       XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0);
+         subst_prev_insn = i1
+           = gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2,
+                      XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0);
 
          SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
          SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
@@ -1675,7 +1688,8 @@ try_combine (i3, i2, i1)
   mark_used_regs_combine (newpat);
 
   /* Is the result of combination a valid instruction?  */
-  insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+  insn_code_number
+    = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
 
   /* If the result isn't valid, see if it is a PARALLEL of two SETs where
      the second SET's destination is a register that is unused.  In that case,
@@ -1696,7 +1710,8 @@ try_combine (i3, i2, i1)
       && asm_noperands (newpat) < 0)
     {
       newpat = XVECEXP (newpat, 0, 0);
-      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+      insn_code_number
+       = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
     }
 
   else if (insn_code_number < 0 && GET_CODE (newpat) == PARALLEL
@@ -1709,7 +1724,8 @@ try_combine (i3, i2, i1)
           && asm_noperands (newpat) < 0)
     {
       newpat = XVECEXP (newpat, 0, 1);
-      insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+      insn_code_number
+       = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
     }
 
   /* If we were combining three insns and the result is a simple SET
@@ -1778,15 +1794,15 @@ try_combine (i3, i2, i1)
          if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
            SUBST (regno_reg_rtx[REGNO (i2dest)], ni2dest);
 
-         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes,
+                                             &i2_scratches);
 
          /* If I2 or I3 has multiple SETs, we won't know how to track
             register status, so don't use these insns.  */
 
          if (i2_code_number >= 0 && i2set && i3set)
-           insn_code_number = recog_for_combine (&newi3pat, i3,
-                                                 &new_i3_notes);
-
+           insn_code_number = recog_for_combine (&newi3pat, i3, &new_i3_notes,
+                                                 &i3_scratches); 
          if (insn_code_number >= 0)
            newpat = newi3pat;
 
@@ -1857,12 +1873,14 @@ try_combine (i3, i2, i1)
 
          newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
          SUBST (*split, newdest);
-         i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+         i2_code_number
+           = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
 
          /* If the split point was a MULT and we didn't have one before,
             don't use one now.  */
          if (i2_code_number >= 0 && ! (split_code == MULT && ! have_mult))
-           insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+           insn_code_number
+             = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
        }
     }
 
@@ -1916,9 +1934,12 @@ try_combine (i3, i2, i1)
       newpat = XVECEXP (newpat, 0, 1);
       SUBST (SET_SRC (newpat),
             gen_lowpart_for_combine (GET_MODE (SET_SRC (newpat)), ni2dest));
-      i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+      i2_code_number
+       = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+
       if (i2_code_number >= 0)
-       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+       insn_code_number
+         = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
 
       if (insn_code_number >= 0)
        {
@@ -1992,9 +2013,12 @@ try_combine (i3, i2, i1)
       newi2pat = XVECEXP (newpat, 0, 1);
       newpat = XVECEXP (newpat, 0, 0);
 
-      i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
+      i2_code_number
+       = recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
+
       if (i2_code_number >= 0)
-       insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+       insn_code_number
+         = recog_for_combine (&newpat, i3, &new_i3_notes, &i3_scratches);
     }
 
   /* If it still isn't recognized, fail and change things back the way they
@@ -2016,8 +2040,9 @@ try_combine (i3, i2, i1)
 
       CLEAR_HARD_REG_SET (newpat_used_regs);
 
-      other_code_number = recog_for_combine (&other_pat, undobuf.other_insn,
-                                            &new_other_notes);
+      other_code_number
+       = recog_for_combine (&other_pat, undobuf.other_insn,
+                            &new_other_notes, &other_scratches);
 
       if (other_code_number < 0 && ! check_asm_operands (other_pat))
        {
@@ -2319,6 +2344,12 @@ try_combine (i3, i2, i1)
     if (newi2pat)
       note_stores (newi2pat, set_nonzero_bits_and_sign_copies);
 
+    /* If we added any (clobber (scratch)), add them to the max for a
+       block.  This is a very pessimistic calculation, since we might
+       have had them already and this might not be the worst block, but
+       it's not worth doing any better.  */
+    max_scratch += i3_scratches + i2_scratches + other_scratches;
+
     /* If I3 is now an unconditional jump, ensure that it has a 
        BARRIER following it since it may have initially been a
        conditional jump.  It may also be the last nonnote insn.  */
@@ -2331,6 +2362,10 @@ try_combine (i3, i2, i1)
 
   combine_successes++;
 
+  /* Clear this here, so that subsequent get_last_value calls are not
+     affected.  */
+  subst_prev_insn = NULL_RTX;
+
   if (added_links_insn
       && (newi2pat == 0 || INSN_CUID (added_links_insn) < INSN_CUID (i2))
       && INSN_CUID (added_links_insn) < INSN_CUID (i3))
@@ -2358,6 +2393,10 @@ undo_all ()
 
   obfree (undobuf.storage);
   undobuf.num_undo = 0;
+
+  /* Clear this here, so that subsequent get_last_value calls are not
+     affected.  */
+  subst_prev_insn = NULL_RTX;
 }
 \f
 /* Find the innermost point within the rtx at LOC, possibly LOC itself,
@@ -2408,7 +2447,7 @@ find_split_point (loc, insn)
       /* If we have a PLUS whose second operand is a constant and the
         address is not valid, perhaps will can split it up using
         the machine-specific way to split large constants.  We use
-        the first psuedo-reg (one of the virtual regs) as a placeholder;
+        the first pseudo-reg (one of the virtual regs) as a placeholder;
         it will not remain in the result.  */
       if (GET_CODE (XEXP (x, 0)) == PLUS
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
@@ -3018,6 +3057,9 @@ simplify_rtx (x, op0_mode, last, in_dest)
          rtx cop1 = const0_rtx;
          enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
 
+         if (cond_code == NE && GET_RTX_CLASS (GET_CODE (cond)) == '<')
+           return x;
+
          /* Simplify the alternative arms; this may collapse the true and 
             false arms to store-flag values.  */
          true = subst (true, pc_rtx, pc_rtx, 0, 0);
@@ -3441,6 +3483,13 @@ simplify_rtx (x, op0_mode, last, in_dest)
        }
       break;
 
+    case TRUNCATE:
+      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+       SUBST (XEXP (x, 0),
+              force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
+                             GET_MODE_MASK (mode), NULL_RTX, 0));
+      break;
+
     case FLOAT_TRUNCATE:
       /* (float_truncate:SF (float_extend:DF foo:SF)) = foo:SF.  */
       if (GET_CODE (XEXP (x, 0)) == FLOAT_EXTEND
@@ -4261,8 +4310,9 @@ simplify_set (x)
              && exact_log2 (mask = nonzero_bits (op0, GET_MODE (op0))) >= 0)
            {
              rtx pat = PATTERN (other_insn), note = 0;
+             int scratches;
 
-             if ((recog_for_combine (&pat, other_insn, &note) < 0
+             if ((recog_for_combine (&pat, other_insn, &note, &scratches) < 0
                   && ! check_asm_operands (pat)))
                {
                  PUT_CODE (*cc_use, old_code);
@@ -4334,6 +4384,14 @@ simplify_set (x)
       && (GET_MODE_SIZE (GET_MODE (src))
          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
 #endif
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+      && ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER
+           && (TEST_HARD_REG_BIT
+               (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+                REGNO (dest)))
+           && (GET_MODE_SIZE (GET_MODE (src))
+               != GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))))
+#endif                           
       && (GET_CODE (dest) == REG
          || (GET_CODE (dest) == SUBREG
              && GET_CODE (SUBREG_REG (dest)) == REG)))
@@ -4489,6 +4547,10 @@ simplify_logical (x, last)
 
          if (GET_CODE (x) != AND)
            return x;
+
+         if (GET_RTX_CLASS (GET_CODE (x)) == 'c' 
+             || GET_RTX_CLASS (GET_CODE (x)) == '2')
+           op0 = XEXP (x, 0), op1 = XEXP (x, 1);
        }
 
       /* Convert (A | B) & A to A.  */
@@ -5401,7 +5463,7 @@ make_compound_operation (x, in_code)
        {
          new = make_compound_operation (XEXP (SUBREG_REG (XEXP (x, 0)), 0),
                                         next_code);
-         new = make_extraction (mode, new, 0,
+         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);
        }
@@ -5747,8 +5809,7 @@ force_to_mode (x, mode, mask, reg, just_select)
         whose constant is the AND of that constant with MASK.  If it
         remains an AND of MASK, delete it since it is redundant.  */
 
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
        {
          x = simplify_and_const_int (x, op_mode, XEXP (x, 0),
                                      mask & INTVAL (XEXP (x, 1)));
@@ -5767,7 +5828,8 @@ force_to_mode (x, mode, mask, reg, just_select)
             cheaper constant.  */
 
          if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
-             && GET_MODE_MASK (GET_MODE (x)) != mask)
+             && GET_MODE_MASK (GET_MODE (x)) != mask
+             && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
            {
              HOST_WIDE_INT cval = (INTVAL (XEXP (x, 1))
                                    | (GET_MODE_MASK (GET_MODE (x)) & ~ mask));
@@ -5795,13 +5857,26 @@ force_to_mode (x, mode, mask, reg, just_select)
         low-order bits (as in an alignment operation) and FOO is already
         aligned to that boundary, mask C1 to that boundary as well.
         This may eliminate that PLUS and, later, the AND.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && exact_log2 (- mask) >= 0
-         && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0
-         && (INTVAL (XEXP (x, 1)) & ~ mask) != 0)
-       return force_to_mode (plus_constant (XEXP (x, 0),
-                                            INTVAL (XEXP (x, 1)) & mask),
-                             mode, mask, reg, next_select);
+
+      {
+       int width = GET_MODE_BITSIZE (mode);
+       unsigned HOST_WIDE_INT smask = mask;
+
+       /* If MODE is narrower than HOST_WIDE_INT and mask is a negative
+          number, sign extend it.  */
+
+       if (width < HOST_BITS_PER_WIDE_INT
+           && (smask & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
+         smask |= (HOST_WIDE_INT) -1 << width;
+
+       if (GET_CODE (XEXP (x, 1)) == CONST_INT
+           && exact_log2 (- smask) >= 0
+           && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0
+           && (INTVAL (XEXP (x, 1)) & ~ mask) != 0)
+         return force_to_mode (plus_constant (XEXP (x, 0),
+                                              INTVAL (XEXP (x, 1)) & mask),
+                               mode, mask, reg, next_select);
+      }
 
       /* ... fall through ... */
 
@@ -5943,8 +6018,9 @@ force_to_mode (x, mode, mask, reg, just_select)
     case ASHIFTRT:
       /* If we are just looking for the sign bit, we don't need this shift at
         all, even if it has a variable count.  */
-      if (mask == ((HOST_WIDE_INT) 1
-                  << (GET_MODE_BITSIZE (GET_MODE (x)) - 1)))
+      if (GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+         && (mask == ((HOST_WIDE_INT) 1
+                      << (GET_MODE_BITSIZE (GET_MODE (x)) - 1))))
        return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
 
       /* If this is a shift by a constant, get a mask that contains those bits
@@ -6113,7 +6189,7 @@ if_then_else_cond (x, ptrue, pfalse)
     }
 
   /* If this is a COMPARE, do nothing, since the IF_THEN_ELSE we would
-     make can't possibly match and would supress other optimizations.  */
+     make can't possibly match and would suppress other optimizations.  */
   else if (code == COMPARE)
     ;
 
@@ -6536,7 +6612,7 @@ apply_distributive_law (x)
          || (GET_MODE_CLASS (GET_MODE (lhs))
              != GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs))))
          || (GET_MODE_SIZE (GET_MODE (lhs))
-             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))))
+             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))))
          || GET_MODE_SIZE (GET_MODE (SUBREG_REG (lhs))) > UNITS_PER_WORD)
        return x;
 
@@ -6598,6 +6674,7 @@ simplify_and_const_int (x, mode, varop, constop)
      unsigned HOST_WIDE_INT constop;
 {
   unsigned HOST_WIDE_INT nonzero;
+  int width = GET_MODE_BITSIZE (mode);
   int i;
 
   /* Simplify VAROP knowing that we will be only looking at some of the
@@ -6615,6 +6692,19 @@ simplify_and_const_int (x, mode, varop, constop)
 
   nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
 
+  /* If this would be an entire word for the target, but is not for
+     the host, then sign-extend on the host so that the number will look
+     the same way on the host that it would on the target.
+
+     For example, when building a 64 bit alpha hosted 32 bit sparc
+     targeted compiler, then we want the 32 bit unsigned value -1 to be
+     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+     The later confuses the sparc backend.  */
+
+  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
+      && (nonzero & ((HOST_WIDE_INT) 1 << (width - 1))))
+    nonzero |= ((HOST_WIDE_INT) (-1) << width);
+
   /* 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
      which is tested below.  */
@@ -6752,10 +6842,18 @@ nonzero_bits (x, mode)
          sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
 #endif
 
-         return nonzero & ~ (sp_alignment - 1);
+         nonzero &= ~ (sp_alignment - 1);
        }
 #endif
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+      /* If pointers extend unsigned and this is a pointer in Pmode, say that
+        all the bits above ptr_mode are known to be zero.  */
+      if (POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode
+         && REGNO_POINTER_FLAG (REGNO (x)))
+       nonzero &= GET_MODE_MASK (ptr_mode);
+#endif
+
       /* 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
@@ -7091,6 +7189,14 @@ num_sign_bit_copies (x, mode)
     {
     case REG:
 
+#ifdef POINTERS_EXTEND_UNSIGNED
+      /* If pointers extend signed and this is a pointer in Pmode, say that
+        all the bits above ptr_mode are known to be sign bit copies.  */
+      if (! POINTERS_EXTEND_UNSIGNED && GET_MODE (x) == Pmode && mode == Pmode
+         && REGNO_POINTER_FLAG (REGNO (x)))
+       return GET_MODE_BITSIZE (Pmode) - GET_MODE_BITSIZE (ptr_mode) + 1;
+#endif
+
       if (reg_last_set_value[REGNO (x)] != 0
          && reg_last_set_mode[REGNO (x)] == mode
          && (reg_n_sets[REGNO (x)] == 1
@@ -7392,6 +7498,7 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
 {
   enum rtx_code op0 = *pop0;
   HOST_WIDE_INT const0 = *pconst0;
+  int width = GET_MODE_BITSIZE (mode);
 
   const0 &= GET_MODE_MASK (mode);
   const1 &= GET_MODE_MASK (mode);
@@ -7481,6 +7588,19 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
   else if (const0 == GET_MODE_MASK (mode) && op0 == AND)
     op0 = NIL;
 
+  /* If this would be an entire word for the target, but is not for
+     the host, then sign-extend on the host so that the number will look
+     the same way on the host that it would on the target.
+
+     For example, when building a 64 bit alpha hosted 32 bit sparc
+     targeted compiler, then we want the 32 bit unsigned value -1 to be
+     represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+     The later confuses the sparc backend.  */
+
+  if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
+      && (const0 & ((HOST_WIDE_INT) 1 << (width - 1))))
+    const0 |= ((HOST_WIDE_INT) (-1) << width);
+
   *pop0 = op0;
   *pconst0 = const0;
 
@@ -7542,15 +7662,17 @@ simplify_shift_const (x, code, result_mode, varop, count)
       if (complement_p)
        break;
 
-      /* Convert ROTATETRT to ROTATE.  */
+      /* Convert ROTATERT to ROTATE.  */
       if (code == ROTATERT)
        code = ROTATE, count = GET_MODE_BITSIZE (result_mode) - count;
 
       /* We need to determine what mode we will do the shift in.  If the
-        shift is a ASHIFTRT or ROTATE, we must always do it in the mode it
-        was originally done in.  Otherwise, we can do it in MODE, the widest
-        mode encountered. */
-      shift_mode = (code == ASHIFTRT || code == ROTATE ? result_mode : mode);
+        shift is a right shift or a ROTATE, we must always do it in the mode
+        it was originally done in.  Otherwise, we can do it in MODE, the
+        widest mode encountered. */
+      shift_mode
+       = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
+          ? result_mode : mode);
 
       /* Handle cases where the count is greater than the size of the mode
         minus 1.  For ASHIFT, use the size minus one as the count (this can
@@ -7802,7 +7924,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
                 ASHIFTRT.
 
                 If the mode of this shift is not the mode of the outer shift,
-                we can't do this if either shift is ASHIFTRT or ROTATE.
+                we can't do this if either shift is a right shift or ROTATE.
 
                 Finally, we can't do any of these if the mode is too wide
                 unless the codes are the same.
@@ -7813,7 +7935,8 @@ simplify_shift_const (x, code, result_mode, varop, count)
              if (code == first_code)
                {
                  if (GET_MODE (varop) != result_mode
-                     && (code == ASHIFTRT || code == ROTATE))
+                     && (code == ASHIFTRT || code == LSHIFTRT
+                         || code == ROTATE))
                    break;
 
                  count += first_count;
@@ -7825,7 +7948,8 @@ simplify_shift_const (x, code, result_mode, varop, count)
                  || (code == ROTATE && first_code == ASHIFTRT)
                  || GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT
                  || (GET_MODE (varop) != result_mode
-                     && (first_code == ASHIFTRT || first_code == ROTATE
+                     && (first_code == ASHIFTRT || first_code == LSHIFTRT
+                         || first_code == ROTATE
                          || code == ROTATE)))
                break;
 
@@ -8091,11 +8215,13 @@ simplify_shift_const (x, code, result_mode, varop, count)
     }
 
   /* We need to determine what mode to do the shift in.  If the shift is
-     a ASHIFTRT or ROTATE, we must always do it in the mode it was originally
-     done in.  Otherwise, we can do it in MODE, the widest mode encountered.
-     The code we care about is that of the shift that will actually be done,
-     not the shift that was originally requested.  */
-  shift_mode = (code == ASHIFTRT || code == ROTATE ? result_mode : mode);
+     a right shift or ROTATE, we must always do it in the mode it was
+     originally done in.  Otherwise, we can do it in MODE, the widest mode
+     encountered.  The code we care about is that of the shift that will
+     actually be done, not the shift that was originally requested.  */
+  shift_mode
+    = (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
+       ? result_mode : mode);
 
   /* We have now finished analyzing the shift.  The result should be
      a shift of type CODE with SHIFT_MODE shifting VAROP COUNT places.  If
@@ -8163,7 +8289,24 @@ simplify_shift_const (x, code, result_mode, varop, count)
   if (outer_op != NIL)
     {
       if (GET_MODE_BITSIZE (result_mode) < HOST_BITS_PER_WIDE_INT)
-       outer_const &= GET_MODE_MASK (result_mode);
+       {
+         int width = GET_MODE_BITSIZE (result_mode);
+
+         outer_const &= GET_MODE_MASK (result_mode);
+
+         /* If this would be an entire word for the target, but is not for
+            the host, then sign-extend on the host so that the number will
+            look the same way on the host that it would on the target.
+
+            For example, when building a 64 bit alpha hosted 32 bit sparc
+            targeted compiler, then we want the 32 bit unsigned value -1 to be
+            represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+            The later confuses the sparc backend.  */
+
+         if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT && BITS_PER_WORD == width
+             && (outer_const & ((HOST_WIDE_INT) 1 << (width - 1))))
+           outer_const |= ((HOST_WIDE_INT) (-1) << width);
+       }
 
       if (outer_op == AND)
        x = simplify_and_const_int (NULL_RTX, result_mode, x, outer_const);
@@ -8190,14 +8333,18 @@ simplify_shift_const (x, code, result_mode, varop, count)
    PNOTES is a pointer to a location where any REG_UNUSED notes added for
    the CLOBBERs are placed.
 
+   PADDED_SCRATCHES is set to the number of (clobber (scratch)) patterns
+   we had to add.
+
    The value is the final insn code from the pattern ultimately matched,
    or -1.  */
 
 static int
-recog_for_combine (pnewpat, insn, pnotes)
+recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
      rtx *pnewpat;
      rtx insn;
      rtx *pnotes;
+     int *padded_scratches;
 {
   register rtx pat = *pnewpat;
   int insn_code_number;
@@ -8205,6 +8352,8 @@ recog_for_combine (pnewpat, insn, pnotes)
   int i;
   rtx notes = 0;
 
+  *padded_scratches = 0;
+
   /* If PAT is a PARALLEL, check to see if it contains the CLOBBER
      we use to indicate that something didn't match.  If we find such a
      thing, force rejection.  */
@@ -8266,6 +8415,8 @@ recog_for_combine (pnewpat, insn, pnotes)
          if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == REG
              && ! reg_dead_at_p (XEXP (XVECEXP (newpat, 0, i), 0), insn))
            return -1;
+         else if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == SCRATCH)
+           (*padded_scratches)++;
          notes = gen_rtx (EXPR_LIST, REG_UNUSED,
                           XEXP (XVECEXP (newpat, 0, i), 0), notes);
        }
@@ -8320,6 +8471,14 @@ gen_lowpart_for_combine (mode, x)
     }
 
   result = gen_lowpart_common (mode, x);
+  if (result != 0
+      && GET_CODE (result) == SUBREG
+      && GET_CODE (SUBREG_REG (result)) == REG
+      && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER
+      && (GET_MODE_SIZE (GET_MODE (result))
+         != GET_MODE_SIZE (GET_MODE (SUBREG_REG (result)))))
+    reg_changes_size[REGNO (SUBREG_REG (result))] = 1;
+
   if (result)
     return result;
 
@@ -9060,7 +9219,7 @@ simplify_comparison (code, pop0, pop1)
 
        case SUBREG:
          /* Check for the case where we are comparing A - C1 with C2,
-            both constants are smaller than 1/2 the maxium positive
+            both constants are smaller than 1/2 the maximum positive
             value in MODE, and the comparison is equality or unsigned.
             In that case, if A is either zero-extended to MODE or has
             sufficient sign bits so that the high-order bit in MODE
@@ -9853,19 +10012,32 @@ get_last_value (x)
   /* If the value was set in a later insn than the ones we are processing,
      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.  */
+     the case when the same pseudo is used by repeated insns.
+
+     This does not work if there exists an instruction which is temporarily
+     not on the insn chain.  */
 
   if (INSN_CUID (reg_last_set[regno]) >= subst_low_cuid)
     {
       rtx insn, set;
 
+      /* We can not do anything useful in this case, because there is
+        an instruction which is not on the insn chain.  */
+      if (subst_prev_insn)
+       return 0;
+
       /* Skip over USE insns.  They are not useful here, and they may have
         been made by combine, in which case they do not have a INSN_CUID
-        value.  */
-      for (insn = prev_real_insn (subst_insn);
-          insn && (GET_CODE (PATTERN (insn)) == USE
+        value.  We can't use prev_real_insn, because that would incorrectly
+        take us backwards across labels.  Skip over BARRIERs also, since
+        they could have been made by combine.  If we see one, we must be
+        optimizing dead code, so it doesn't matter what we do.  */
+      for (insn = prev_nonnote_insn (subst_insn);
+          insn && ((GET_CODE (insn) == INSN
+                    && GET_CODE (PATTERN (insn)) == USE)
+                   || GET_CODE (insn) == BARRIER
                    || INSN_CUID (insn) >= subst_low_cuid);
-          insn = prev_real_insn (insn))
+          insn = prev_nonnote_insn (insn))
        ;
 
       if (insn
@@ -9875,7 +10047,7 @@ get_last_value (x)
          value = SET_SRC (set);
 
          /* Make sure that VALUE doesn't reference X.  Replace any
-            expliit references with a CLOBBER.  If there are any remaining
+            explicit references with a CLOBBER.  If there are any remaining
             references (rare), don't use the value.  */
 
          if (reg_mentioned_p (x, value))
@@ -9963,7 +10135,7 @@ static int reg_dead_flag;
 
 /* Function called via note_stores from reg_dead_at_p.
 
-   If DEST is within [reg_dead_rengno, reg_dead_endregno), set 
+   If DEST is within [reg_dead_regno, reg_dead_endregno), set 
    reg_dead_flag to 1 if X is a CLOBBER and to -1 it is a SET.  */
 
 static void
@@ -10018,7 +10190,7 @@ reg_dead_at_p (reg, insn)
 
   /* Scan backwards until we find a REG_DEAD note, SET, CLOBBER, label, or
      beginning of function.  */
-  for (; insn && GET_CODE (insn) != CODE_LABEL;
+  for (; insn && GET_CODE (insn) != CODE_LABEL && GET_CODE (insn) != BARRIER;
        insn = prev_nonnote_insn (insn))
     {
       note_stores (PATTERN (insn), reg_dead_at_p_1);
@@ -10193,9 +10365,22 @@ move_deaths (x, from_cuid, to_insn, pnotes)
     {
       register int regno = REGNO (x);
       register rtx where_dead = reg_last_death[regno];
-
-      if (where_dead && INSN_CUID (where_dead) >= from_cuid
-         && INSN_CUID (where_dead) < INSN_CUID (to_insn))
+      register rtx before_dead, after_dead;
+
+      /* WHERE_DEAD could be a USE insn made by combine, so first we
+        make sure that we have insns with valid INSN_CUID values.  */
+      before_dead = where_dead;
+      while (before_dead && INSN_UID (before_dead) > max_uid_cuid)
+       before_dead = PREV_INSN (before_dead);
+      after_dead = where_dead;
+      while (after_dead && INSN_UID (after_dead) > max_uid_cuid)
+       after_dead = NEXT_INSN (after_dead);
+
+      if (before_dead && after_dead
+         && INSN_CUID (before_dead) >= from_cuid
+         && (INSN_CUID (after_dead) < INSN_CUID (to_insn)
+             || (where_dead != after_dead
+                 && INSN_CUID (after_dead) == INSN_CUID (to_insn))))
        {
          rtx note = remove_death (regno, where_dead);
 
@@ -10226,6 +10411,21 @@ move_deaths (x, from_cuid, to_insn, pnotes)
                               gen_rtx (REG, reg_raw_mode[i], i),
                               REG_NOTES (where_dead));
            }
+         /* If we didn't find any note, and we have a multi-reg hard
+            register, then to be safe we must check for REG_DEAD notes
+            for each register other than the first.  They could have
+            their own REG_DEAD notes lying around.  */
+         else if (note == 0 && regno < FIRST_PSEUDO_REGISTER
+                  && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+           {
+             int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
+             int i;
+             rtx oldnotes = 0;
+
+             for (i = regno + 1; i < ourend; i++)
+               move_deaths (gen_rtx (REG, reg_raw_mode[i], i),
+                            from_cuid, to_insn, &oldnotes);
+           }
 
          if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
            {
@@ -10546,7 +10746,10 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                         modified the register.  */
 
                      if (set != 0 && ! side_effects_p (SET_SRC (set))
-                         && rtx_equal_p (XEXP (note, 0), SET_DEST (set)))
+                         && (rtx_equal_p (XEXP (note, 0), SET_DEST (set))
+                             || (GET_CODE (SET_DEST (set)) == SUBREG
+                                 && rtx_equal_p (XEXP (note, 0),
+                                                 XEXP (SET_DEST (set), 0)))))
                        {
                          /* Move the notes and links of TEM elsewhere.
                             This might delete other dead insns recursively. 
@@ -10580,6 +10783,22 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
                             && find_reg_fusage (tem, USE, XEXP (note, 0))))
                  {
                    place = tem;
+
+                   /* If we are doing a 3->2 combination, and we have a
+                      register which formerly died in i3 and was not used
+                      by i2, which now no longer dies in i3 and is used in
+                      i2 but does not die in i2, and place is between i2
+                      and i3, then we may need to move a link from place to
+                      i2.  */
+                   if (i2 && INSN_UID (place) <= max_uid_cuid
+                       && INSN_CUID (place) > INSN_CUID (i2)
+                       && from_insn && INSN_CUID (from_insn) > INSN_CUID (i2)
+                       && reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
+                     {
+                       rtx links = LOG_LINKS (place);
+                       LOG_LINKS (place) = 0;
+                       distribute_links (links);
+                     }
                    break;
                  }
                }