OSDN Git Service

Fix numerous IA-64 C++ failures, IA-64 bootstrap trouble.
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index b44ba65..093791e 100644 (file)
@@ -1,7 +1,7 @@
 /* Medium-level subroutines: convert bit-field store and extract
    and shifts, multiplies and divides to rtl instructions.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -54,6 +54,9 @@ static void do_cmp_and_jump (rtx, rtx, enum rtx_code, enum machine_mode, rtx);
 static rtx expand_smod_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 static rtx expand_sdiv_pow2 (enum machine_mode, rtx, HOST_WIDE_INT);
 
+/* Test whether a value is zero of a power of two.  */
+#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
+
 /* Nonzero means divides or modulus operations are relatively cheap for
    powers of two, so don't use branches; emit the operation instead.
    Usually, this will mean that the MD file will emit non-branch
@@ -142,7 +145,8 @@ init_expmed (void)
   memset (&all, 0, sizeof all);
 
   PUT_CODE (&all.reg, REG);
-  REGNO (&all.reg) = 10000;
+  /* Avoid using hard regs in ways which may be unsupported.  */
+  REGNO (&all.reg) = LAST_VIRTUAL_REGISTER + 1;
 
   PUT_CODE (&all.plus, PLUS);
   XEXP (&all.plus, 0) = &all.reg;
@@ -298,7 +302,7 @@ mode_for_extraction (enum extraction_pattern pattern, int opno)
       return MAX_MACHINE_MODE;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   if (opno == -1)
@@ -334,10 +338,10 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 {
   unsigned int unit
     = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
-  unsigned HOST_WIDE_INT offset = bitnum / unit;
-  unsigned HOST_WIDE_INT bitpos = bitnum % unit;
+  unsigned HOST_WIDE_INT offset, bitpos;
   rtx op0 = str_rtx;
   int byte_offset;
+  rtx orig_value;
 
   enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
 
@@ -348,12 +352,16 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
         meaningful at a much higher level; when structures are copied
         between memory and regs, the higher-numbered regs
         always get higher addresses.  */
-      offset += (SUBREG_BYTE (op0) / UNITS_PER_WORD);
-      /* We used to adjust BITPOS here, but now we do the whole adjustment
-        right after the loop.  */
+      bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
       op0 = SUBREG_REG (op0);
     }
 
+  /* No action is needed if the target is a register and if the field
+     lies completely outside that register.  This can occur if the source
+     code contains an out-of-bounds access to a small array.  */
+  if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
+    return value;
+
   /* Use vec_set patterns for inserting parts of vectors whenever
      available.  */
   if (VECTOR_MODE_P (GET_MODE (op0))
@@ -386,10 +394,9 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
       /* We could handle this, but we should always be called with a pseudo
         for our targets and all insns should take them as outputs.  */
-      if (! (*insn_data[icode].operand[0].predicate) (dest, mode0)
-         || ! (*insn_data[icode].operand[1].predicate) (src, mode1)
-         || ! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
-       abort ();
+      gcc_assert ((*insn_data[icode].operand[0].predicate) (dest, mode0)
+                 && (*insn_data[icode].operand[1].predicate) (src, mode1)
+                 && (*insn_data[icode].operand[2].predicate) (rtxpos, mode2));
       pat = GEN_FCN (icode) (dest, src, rtxpos);
       seq = get_insns ();
       end_sequence ();
@@ -416,6 +423,8 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      done with a simple store.  For targets that support fast unaligned
      memory, any naturally sized, unit aligned field can be done directly.  */
 
+  offset = bitnum / unit;
+  bitpos = bitnum % unit;
   byte_offset = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
                 + (offset * UNITS_PER_WORD);
 
@@ -431,22 +440,11 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     {
       if (GET_MODE (op0) != fieldmode)
        {
-         if (GET_CODE (op0) == SUBREG)
-           {
-             if (GET_MODE (SUBREG_REG (op0)) == fieldmode
-                 || GET_MODE_CLASS (fieldmode) == MODE_INT
-                 || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT)
-               op0 = SUBREG_REG (op0);
-             else
-               /* Else we've got some float mode source being extracted into
-                  a different float mode destination -- this combination of
-                  subregs results in Severe Tire Damage.  */
-               abort ();
-           }
-         if (REG_P (op0))
-           op0 = gen_rtx_SUBREG (fieldmode, op0, byte_offset);
-         else
+         if (MEM_P (op0))
            op0 = adjust_address (op0, fieldmode, offset);
+         else
+           op0 = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
+                                      byte_offset);
        }
       emit_move_insn (op0, value);
       return value;
@@ -462,10 +460,11 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       {
        if (MEM_P (op0))
          op0 = adjust_address (op0, imode, 0);
-       else if (imode != BLKmode)
-         op0 = gen_lowpart (imode, op0);
        else
-         abort ();
+         {
+           gcc_assert (imode != BLKmode);
+           op0 = gen_lowpart (imode, op0);
+         }
       }
   }
 
@@ -510,15 +509,13 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
       if (GET_CODE (op0) == SUBREG)
        {
-         if (GET_MODE (SUBREG_REG (op0)) == fieldmode
-             || GET_MODE_CLASS (fieldmode) == MODE_INT
-             || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT)
-           op0 = SUBREG_REG (op0);
-         else
-           /* Else we've got some float mode source being extracted into
-              a different float mode destination -- this combination of
-              subregs results in Severe Tire Damage.  */
-           abort ();
+         /* Else we've got some float mode source being extracted into
+            a different float mode destination -- this combination of
+            subregs results in Severe Tire Damage.  */
+         gcc_assert (GET_MODE (SUBREG_REG (op0)) == fieldmode
+                     || GET_MODE_CLASS (fieldmode) == MODE_INT
+                     || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT);
+         op0 = SUBREG_REG (op0);
        }
 
       emit_insn (GEN_FCN (icode)
@@ -589,12 +586,10 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                 pseudo.  We can trivially remove a SUBREG that does not
                 change the size of the operand.  Such a SUBREG may have been
                 added above.  Otherwise, abort.  */
-             if (GET_CODE (op0) == SUBREG
-                 && (GET_MODE_SIZE (GET_MODE (op0))
-                     == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
-               op0 = SUBREG_REG (op0);
-             else
-               abort ();
+             gcc_assert (GET_CODE (op0) == SUBREG
+                         && (GET_MODE_SIZE (GET_MODE (op0))
+                             == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))));
+             op0 = SUBREG_REG (op0);
            }
          op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
                                op0, (offset * UNITS_PER_WORD));
@@ -602,15 +597,18 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       offset = 0;
     }
 
-  /* If VALUE is a floating-point mode, access it as an integer of the
-     corresponding size.  This can occur on a machine with 64 bit registers
-     that uses SFmode for float.  This can also occur for unaligned float
-     structure fields.  */
-  if (GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
+  /* If VALUE has a floating-point or complex mode, access it as an
+     integer of the corresponding size.  This can occur on a machine
+     with 64 bit registers that uses SFmode for float.  It can also
+     occur for unaligned float or complex fields.  */
+  orig_value = value;
+  if (GET_MODE (value) != VOIDmode
+      && GET_MODE_CLASS (GET_MODE (value)) != MODE_INT
       && GET_MODE_CLASS (GET_MODE (value)) != MODE_PARTIAL_INT)
-    value = gen_lowpart ((GET_MODE (value) == VOIDmode
-                         ? word_mode : int_mode_for_mode (GET_MODE (value))),
-                        value);
+    {
+      value = gen_reg_rtx (int_mode_for_mode (GET_MODE (value)));
+      emit_move_insn (gen_lowpart (GET_MODE (orig_value), value), orig_value);
+    }
 
   /* Now OFFSET is nonzero only if OP0 is memory
      and is therefore always measured in bytes.  */
@@ -672,7 +670,7 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
          /* Fetch that unit, store the bitfield in it, then store
             the unit.  */
          tempreg = copy_to_reg (op0);
-         store_bit_field (tempreg, bitsize, bitpos, fieldmode, value);
+         store_bit_field (tempreg, bitsize, bitpos, fieldmode, orig_value);
          emit_move_insn (op0, tempreg);
          return value;
        }
@@ -731,12 +729,12 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
            }
          else if (GET_CODE (value) == CONST_INT)
            value1 = gen_int_mode (INTVAL (value), maxmode);
-         else if (!CONSTANT_P (value))
+         else
            /* Parse phase is supposed to make VALUE's data type
               match that of the component reference, which is a type
               at least as wide as the field; so VALUE should have
               a mode that corresponds to that type.  */
-           abort ();
+           gcc_assert (CONSTANT_P (value));
        }
 
       /* If this machine's insv insists on a register,
@@ -790,8 +788,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
 
   if (REG_P (op0) || GET_CODE (op0) == SUBREG)
     {
-      if (offset != 0)
-       abort ();
+      gcc_assert (!offset);
       /* Special treatment for a bit field split across two registers.  */
       if (bitsize + bitpos > BITS_PER_WORD)
        {
@@ -899,8 +896,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
       if (bitpos > 0)
        value = expand_shift (LSHIFT_EXPR, mode, value,
-                             build_int_cst (NULL_TREE,
-                                            bitpos, 0), NULL_RTX, 1);
+                             build_int_cst (NULL_TREE, bitpos), NULL_RTX, 1);
     }
 
   /* Now clear the chosen bits in OP0,
@@ -1074,8 +1070,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 {
   unsigned int unit
     = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
-  unsigned HOST_WIDE_INT offset = bitnum / unit;
-  unsigned HOST_WIDE_INT bitpos = bitnum % unit;
+  unsigned HOST_WIDE_INT offset, bitpos;
   rtx op0 = str_rtx;
   rtx spec_target = target;
   rtx spec_target_subreg = 0;
@@ -1090,15 +1085,16 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
   while (GET_CODE (op0) == SUBREG)
     {
-      bitpos += SUBREG_BYTE (op0) * BITS_PER_UNIT;
-      if (bitpos > unit)
-       {
-         offset += (bitpos / unit);
-         bitpos %= unit;
-       }
+      bitnum += SUBREG_BYTE (op0) * BITS_PER_UNIT;
       op0 = SUBREG_REG (op0);
     }
 
+  /* If we have an out-of-bounds access to a register, just return an
+     uninitialized register of the required mode.  This can occur if the
+     source code contains an out-of-bounds access to a small array.  */
+  if (REG_P (op0) && bitnum >= GET_MODE_BITSIZE (GET_MODE (op0)))
+    return gen_reg_rtx (tmode);
+
   if (REG_P (op0)
       && mode == GET_MODE (op0)
       && bitnum == 0
@@ -1147,10 +1143,9 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
       /* We could handle this, but we should always be called with a pseudo
         for our targets and all insns should take them as outputs.  */
-      if (! (*insn_data[icode].operand[0].predicate) (dest, mode0)
-         || ! (*insn_data[icode].operand[1].predicate) (src, mode1)
-         || ! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
-       abort ();
+      gcc_assert ((*insn_data[icode].operand[0].predicate) (dest, mode0)
+                 && (*insn_data[icode].operand[1].predicate) (src, mode1)
+                 && (*insn_data[icode].operand[2].predicate) (rtxpos, mode2));
 
       pat = GEN_FCN (icode) (dest, src, rtxpos);
       seq = get_insns ();
@@ -1171,10 +1166,16 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       {
        if (MEM_P (op0))
          op0 = adjust_address (op0, imode, 0);
-       else if (imode != BLKmode)
-         op0 = gen_lowpart (imode, op0);
        else
-         abort ();
+         {
+           gcc_assert (imode != BLKmode);
+           op0 = gen_lowpart (imode, op0);
+
+           /* If we got a SUBREG, force it into a register since we
+              aren't going to be able to do another SUBREG on it.  */
+           if (GET_CODE (op0) == SUBREG)
+             op0 = force_reg (imode, op0);
+         }
       }
   }
 
@@ -1193,6 +1194,8 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      can also be extracted with a SUBREG.  For this, we need the
      byte offset of the value in op0.  */
 
+  bitpos = bitnum % unit;
+  offset = bitnum / unit;
   byte_offset = bitpos / BITS_PER_UNIT + offset * UNITS_PER_WORD;
 
   /* If OP0 is a register, BITPOS must count within a word.
@@ -1238,22 +1241,16 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     {
       if (mode1 != GET_MODE (op0))
        {
-         if (GET_CODE (op0) == SUBREG)
+         if (MEM_P (op0))
+           op0 = adjust_address (op0, mode1, offset);
+         else
            {
-             if (GET_MODE (SUBREG_REG (op0)) == mode1
-                 || GET_MODE_CLASS (mode1) == MODE_INT
-                 || GET_MODE_CLASS (mode1) == MODE_PARTIAL_INT)
-               op0 = SUBREG_REG (op0);
-             else
-               /* Else we've got some float mode source being extracted into
-                  a different float mode destination -- this combination of
-                  subregs results in Severe Tire Damage.  */
+             rtx sub = simplify_gen_subreg (mode1, op0, GET_MODE (op0),
+                                            byte_offset);
+             if (sub == NULL)
                goto no_subreg_mode_swap;
+             op0 = sub;
            }
-         if (REG_P (op0))
-           op0 = gen_rtx_SUBREG (mode1, op0, byte_offset);
-         else
-           op0 = adjust_address (op0, mode1, offset);
        }
       if (mode1 != mode)
        return convert_to_mode (tmode, op0, unsignedp);
@@ -1300,8 +1297,7 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
                                 bitnum + bit_offset, 1, target_part, mode,
                                 word_mode);
 
-         if (target_part == 0)
-           abort ();
+         gcc_assert (target_part);
 
          if (result_part != target_part)
            emit_move_insn (target_part, result_part);
@@ -1329,13 +1325,11 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       /* Signed bit field: sign-extend with two arithmetic shifts.  */
       target = expand_shift (LSHIFT_EXPR, mode, target,
                             build_int_cst (NULL_TREE,
-                                           GET_MODE_BITSIZE (mode) - bitsize,
-                                           0),
+                                           GET_MODE_BITSIZE (mode) - bitsize),
                             NULL_RTX, 0);
       return expand_shift (RSHIFT_EXPR, mode, target,
                           build_int_cst (NULL_TREE,
-                                         GET_MODE_BITSIZE (mode) - bitsize,
-                                         0),
+                                         GET_MODE_BITSIZE (mode) - bitsize),
                           NULL_RTX, 0);
     }
 
@@ -1349,13 +1343,11 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   int_mode = int_mode_for_mode (tmode);
   if (int_mode == BLKmode)
     int_mode = int_mode_for_mode (mode);
-  if (int_mode == BLKmode)
-    abort ();    /* Should probably push op0 out to memory and then
-                   do a load.  */
+  /* Should probably push op0 out to memory and then do a load.  */
+  gcc_assert (int_mode != BLKmode);
 
   /* OFFSET is the number of words or bytes (UNIT says which)
      from STR_RTX to the first word or byte containing part of the field.  */
-
   if (!MEM_P (op0))
     {
       if (offset != 0
@@ -1638,19 +1630,19 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     return spec_target;
   if (GET_MODE (target) != tmode && GET_MODE (target) != mode)
     {
-      /* If the target mode is floating-point, first convert to the
+      /* If the target mode is not a scalar integral, first convert to the
         integer mode of that size and then access it as a floating-point
         value via a SUBREG.  */
-      if (GET_MODE_CLASS (tmode) != MODE_INT
-         && GET_MODE_CLASS (tmode) != MODE_PARTIAL_INT)
+      if (!SCALAR_INT_MODE_P (tmode))
        {
-         target = convert_to_mode (mode_for_size (GET_MODE_BITSIZE (tmode),
-                                                  MODE_INT, 0),
-                                   target, unsignedp);
+         enum machine_mode smode
+           = mode_for_size (GET_MODE_BITSIZE (tmode), MODE_INT, 0);
+         target = convert_to_mode (smode, target, unsignedp);
+         target = force_reg (smode, target);
          return gen_lowpart (tmode, target);
        }
-      else
-       return convert_to_mode (tmode, target, unsignedp);
+
+      return convert_to_mode (tmode, target, unsignedp);
     }
   return target;
 }
@@ -1740,7 +1732,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
        {
          /* If the field does not already start at the lsb,
             shift it so it does.  */
-         tree amount = build_int_cst (NULL_TREE, bitpos, 0);
+         tree amount = build_int_cst (NULL_TREE, bitpos);
          /* Maybe propagate the target for the shift.  */
          /* But not if we will return it--could confuse integrate.c.  */
          rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
@@ -1781,7 +1773,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
     {
       tree amount
        = build_int_cst (NULL_TREE,
-                        GET_MODE_BITSIZE (mode) - (bitsize + bitpos), 0);
+                        GET_MODE_BITSIZE (mode) - (bitsize + bitpos));
       /* Maybe propagate the target for the shift.  */
       rtx subtarget = (target != 0 && REG_P (target) ? target : 0);
       op0 = expand_shift (LSHIFT_EXPR, mode, op0, amount, subtarget, 1);
@@ -1789,7 +1781,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
 
   return expand_shift (RSHIFT_EXPR, mode, op0,
                       build_int_cst (NULL_TREE,
-                                     GET_MODE_BITSIZE (mode) - bitsize, 0),
+                                     GET_MODE_BITSIZE (mode) - bitsize),
                       target, 0);
 }
 \f
@@ -1863,6 +1855,152 @@ lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
   return immed_double_const (low, high, mode);
 }
 \f
+/* Extract a bit field from a memory by forcing the alignment of the
+   memory.  This efficient only if the field spans at least 4 boundaries.
+
+   OP0 is the MEM.
+   BITSIZE is the field width; BITPOS is the position of the first bit.
+   UNSIGNEDP is true if the result should be zero-extended.  */
+
+static rtx
+extract_force_align_mem_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
+                                  unsigned HOST_WIDE_INT bitpos,
+                                  int unsignedp)
+{
+  enum machine_mode mode, dmode;
+  unsigned int m_bitsize, m_size;
+  unsigned int sign_shift_up, sign_shift_dn;
+  rtx base, a1, a2, v1, v2, comb, shift, result, start;
+
+  /* Choose a mode that will fit BITSIZE.  */
+  mode = smallest_mode_for_size (bitsize, MODE_INT);
+  m_size = GET_MODE_SIZE (mode);
+  m_bitsize = GET_MODE_BITSIZE (mode);
+
+  /* Choose a mode twice as wide.  Fail if no such mode exists.  */
+  dmode = mode_for_size (m_bitsize * 2, MODE_INT, false);
+  if (dmode == BLKmode)
+    return NULL;
+
+  do_pending_stack_adjust ();
+  start = get_last_insn ();
+
+  /* At the end, we'll need an additional shift to deal with sign/zero
+     extension.  By default this will be a left+right shift of the
+     appropriate size.  But we may be able to eliminate one of them.  */
+  sign_shift_up = sign_shift_dn = m_bitsize - bitsize;
+
+  if (STRICT_ALIGNMENT)
+    {
+      base = plus_constant (XEXP (op0, 0), bitpos / BITS_PER_UNIT);
+      bitpos %= BITS_PER_UNIT;
+
+      /* We load two values to be concatenate.  There's an edge condition
+        that bears notice -- an aligned value at the end of a page can
+        only load one value lest we segfault.  So the two values we load
+        are at "base & -size" and "(base + size - 1) & -size".  If base
+        is unaligned, the addresses will be aligned and sequential; if
+        base is aligned, the addresses will both be equal to base.  */
+
+      a1 = expand_simple_binop (Pmode, AND, force_operand (base, NULL),
+                               GEN_INT (-(HOST_WIDE_INT)m_size),
+                               NULL, true, OPTAB_LIB_WIDEN);
+      mark_reg_pointer (a1, m_bitsize);
+      v1 = gen_rtx_MEM (mode, a1);
+      set_mem_align (v1, m_bitsize);
+      v1 = force_reg (mode, validize_mem (v1));
+
+      a2 = plus_constant (base, GET_MODE_SIZE (mode) - 1);
+      a2 = expand_simple_binop (Pmode, AND, force_operand (a2, NULL),
+                               GEN_INT (-(HOST_WIDE_INT)m_size),
+                               NULL, true, OPTAB_LIB_WIDEN);
+      v2 = gen_rtx_MEM (mode, a2);
+      set_mem_align (v2, m_bitsize);
+      v2 = force_reg (mode, validize_mem (v2));
+
+      /* Combine these two values into a double-word value.  */
+      if (m_bitsize == BITS_PER_WORD)
+       {
+         comb = gen_reg_rtx (dmode);
+         emit_insn (gen_rtx_CLOBBER (VOIDmode, comb));
+         emit_move_insn (gen_rtx_SUBREG (mode, comb, 0), v1);
+         emit_move_insn (gen_rtx_SUBREG (mode, comb, m_size), v2);
+       }
+      else
+       {
+         if (BYTES_BIG_ENDIAN)
+           comb = v1, v1 = v2, v2 = comb;
+         v1 = convert_modes (dmode, mode, v1, true);
+         if (v1 == NULL)
+           goto fail;
+         v2 = convert_modes (dmode, mode, v2, true);
+         v2 = expand_simple_binop (dmode, ASHIFT, v2, GEN_INT (m_bitsize),
+                                   NULL, true, OPTAB_LIB_WIDEN);
+         if (v2 == NULL)
+           goto fail;
+         comb = expand_simple_binop (dmode, IOR, v1, v2, NULL,
+                                     true, OPTAB_LIB_WIDEN);
+         if (comb == NULL)
+           goto fail;
+       }
+
+      shift = expand_simple_binop (Pmode, AND, base, GEN_INT (m_size - 1),
+                                  NULL, true, OPTAB_LIB_WIDEN);
+      shift = expand_mult (Pmode, shift, GEN_INT (BITS_PER_UNIT), NULL, 1);
+
+      if (bitpos != 0)
+       {
+         if (sign_shift_up <= bitpos)
+           bitpos -= sign_shift_up, sign_shift_up = 0;
+         shift = expand_simple_binop (Pmode, PLUS, shift, GEN_INT (bitpos),
+                                      NULL, true, OPTAB_LIB_WIDEN);
+       }
+    }
+  else
+    {
+      unsigned HOST_WIDE_INT offset = bitpos / BITS_PER_UNIT;
+      bitpos %= BITS_PER_UNIT;
+
+      /* When strict alignment is not required, we can just load directly
+        from memory without masking.  If the remaining BITPOS offset is
+        small enough, we may be able to do all operations in MODE as 
+        opposed to DMODE.  */
+      if (bitpos + bitsize <= m_bitsize)
+       dmode = mode;
+      comb = adjust_address (op0, dmode, offset);
+
+      if (sign_shift_up <= bitpos)
+       bitpos -= sign_shift_up, sign_shift_up = 0;
+      shift = GEN_INT (bitpos);
+    }
+
+  /* Shift down the double-word such that the requested value is at bit 0.  */
+  if (shift != const0_rtx)
+    comb = expand_simple_binop (dmode, unsignedp ? LSHIFTRT : ASHIFTRT,
+                               comb, shift, NULL, unsignedp, OPTAB_LIB_WIDEN);
+  if (comb == NULL)
+    goto fail;
+
+  /* If the field exactly matches MODE, then all we need to do is return the
+     lowpart.  Otherwise, shift to get the sign bits set properly.  */
+  result = force_reg (mode, gen_lowpart (mode, comb));
+
+  if (sign_shift_up)
+    result = expand_simple_binop (mode, ASHIFT, result,
+                                 GEN_INT (sign_shift_up),
+                                 NULL_RTX, 0, OPTAB_LIB_WIDEN);
+  if (sign_shift_dn)
+    result = expand_simple_binop (mode, unsignedp ? LSHIFTRT : ASHIFTRT,
+                                 result, GEN_INT (sign_shift_dn),
+                                 NULL_RTX, 0, OPTAB_LIB_WIDEN);
+
+  return result;
+
+ fail:
+  delete_insns_since (start);
+  return NULL;
+}
+
 /* Extract a bit field that is split across two words
    and return an RTX for the result.
 
@@ -1884,7 +2022,16 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
   if (REG_P (op0) || GET_CODE (op0) == SUBREG)
     unit = BITS_PER_WORD;
   else
-    unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
+    {
+      unit = MIN (MEM_ALIGN (op0), BITS_PER_WORD);
+      if (0 && bitsize / unit > 2)
+       {
+         rtx tmp = extract_force_align_mem_bit_field (op0, bitsize, bitpos,
+                                                      unsignedp);
+         if (tmp)
+           return tmp;
+       }
+    }
 
   while (bitsdone < bitsize)
     {
@@ -1937,15 +2084,15 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
        {
          if (bitsize != bitsdone)
            part = expand_shift (LSHIFT_EXPR, word_mode, part,
-                                build_int_cst (NULL_TREE,
-                                               bitsize - bitsdone, 0), 0, 1);
+                                build_int_cst (NULL_TREE, bitsize - bitsdone),
+                                0, 1);
        }
       else
        {
          if (bitsdone != thissize)
            part = expand_shift (LSHIFT_EXPR, word_mode, part,
                                 build_int_cst (NULL_TREE,
-                                               bitsdone - thissize, 0), 0, 1);
+                                               bitsdone - thissize), 0, 1);
        }
 
       if (first)
@@ -1964,12 +2111,11 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
     return result;
   /* Signed bit field: sign-extend with two arithmetic shifts.  */
   result = expand_shift (LSHIFT_EXPR, word_mode, result,
-                        build_int_cst (NULL_TREE,
-                                       BITS_PER_WORD - bitsize, 0),
+                        build_int_cst (NULL_TREE, BITS_PER_WORD - bitsize),
                         NULL_RTX, 0);
   return expand_shift (RSHIFT_EXPR, word_mode, result,
-                      build_int_cst (NULL_TREE,
-                                     BITS_PER_WORD - bitsize, 0), NULL_RTX, 0);
+                      build_int_cst (NULL_TREE, BITS_PER_WORD - bitsize),
+                      NULL_RTX, 0);
 }
 \f
 /* Add INC into TARGET.  */
@@ -2086,9 +2232,8 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
              tree type = TREE_TYPE (amount);
              tree new_amount = make_tree (type, op1);
              tree other_amount
-               = fold (build2 (MINUS_EXPR, type, convert
-                               (type, build_int_cst
-                                (NULL_TREE, GET_MODE_BITSIZE (mode), 0)),
+               = fold (build2 (MINUS_EXPR, type, 
+                               build_int_cst (type, GET_MODE_BITSIZE (mode)),
                                amount));
 
              shifted = force_reg (mode, shifted);
@@ -2149,16 +2294,44 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
         define_expand for lshrsi3 was added to vax.md.  */
     }
 
-  if (temp == 0)
-    abort ();
+  gcc_assert (temp);
   return temp;
 }
 \f
-enum alg_code { alg_zero, alg_m, alg_shift,
+enum alg_code { alg_unknown, alg_zero, alg_m, alg_shift,
                  alg_add_t_m2, alg_sub_t_m2,
                  alg_add_factor, alg_sub_factor,
-                 alg_add_t2_m, alg_sub_t2_m,
-                 alg_add, alg_subtract, alg_factor, alg_shiftop };
+                 alg_add_t2_m, alg_sub_t2_m };
+
+/* This structure holds the "cost" of a multiply sequence.  The
+   "cost" field holds the total rtx_cost of every operator in the
+   synthetic multiplication sequence, hence cost(a op b) is defined
+   as rtx_cost(op) + cost(a) + cost(b), where cost(leaf) is zero.
+   The "latency" field holds the minimum possible latency of the
+   synthetic multiply, on a hypothetical infinitely parallel CPU.
+   This is the critical path, or the maximum height, of the expression
+   tree which is the sum of rtx_costs on the most expensive path from
+   any leaf to the root.  Hence latency(a op b) is defined as zero for
+   leaves and rtx_cost(op) + max(latency(a), latency(b)) otherwise.  */
+
+struct mult_cost {
+  short cost;     /* Total rtx_cost of the multiplication sequence.  */
+  short latency;  /* The latency of the multiplication sequence.  */
+};
+
+/* This macro is used to compare a pointer to a mult_cost against an
+   single integer "rtx_cost" value.  This is equivalent to the macro
+   CHEAPER_MULT_COST(X,Z) where Z = {Y,Y}.  */
+#define MULT_COST_LESS(X,Y) ((X)->cost < (Y)   \
+                            || ((X)->cost == (Y) && (X)->latency < (Y)))
+
+/* This macro is used to compare two pointers to mult_costs against
+   each other.  The macro returns true if X is cheaper than Y.
+   Currently, the cheaper of two mult_costs is the one with the
+   lower "cost".  If "cost"s are tied, the lower latency is cheaper.  */
+#define CHEAPER_MULT_COST(X,Y)  ((X)->cost < (Y)->cost         \
+                                || ((X)->cost == (Y)->cost     \
+                                    && (X)->latency < (Y)->latency))
 
 /* This structure records a sequence of operations.
    `ops' is the number of operations recorded.
@@ -2181,7 +2354,7 @@ enum alg_code { alg_zero, alg_m, alg_shift,
 
 struct algorithm
 {
-  short cost;
+  struct mult_cost cost;
   short ops;
   /* The size of the OP and LOG fields are not directly related to the
      word size, but the worst-case algorithms will be if we have few
@@ -2192,6 +2365,26 @@ struct algorithm
   char log[MAX_BITS_PER_WORD];
 };
 
+/* The entry for our multiplication cache/hash table.  */
+struct alg_hash_entry {
+  /* The number we are multiplying by.  */
+  unsigned int t;
+
+  /* The mode in which we are multiplying something by T.  */
+  enum machine_mode mode;
+
+  /* The best multiplication algorithm for t.  */
+  enum alg_code alg;
+};
+
+/* The number of cache/hash entries.  */
+#define NUM_ALG_HASH_ENTRIES 307
+
+/* Each entry of ALG_HASH caches alg_code for some integer.  This is
+   actually a hash table.  If we have a collision, that the older
+   entry is kicked out.  */
+static struct alg_hash_entry alg_hash[NUM_ALG_HASH_ENTRIES];
+
 /* Indicates the type of fixup needed after a constant multiplication.
    BASIC_VARIANT means no fixup is needed, NEGATE_VARIANT means that
    the result should be negated, and ADD_VARIANT means that the
@@ -2199,16 +2392,16 @@ struct algorithm
 enum mult_variant {basic_variant, negate_variant, add_variant};
 
 static void synth_mult (struct algorithm *, unsigned HOST_WIDE_INT,
-                       int, enum machine_mode mode);
+                       const struct mult_cost *, enum machine_mode mode);
 static bool choose_mult_variant (enum machine_mode, HOST_WIDE_INT,
                                 struct algorithm *, enum mult_variant *, int);
 static rtx expand_mult_const (enum machine_mode, rtx, HOST_WIDE_INT, rtx,
                              const struct algorithm *, enum mult_variant);
 static unsigned HOST_WIDE_INT choose_multiplier (unsigned HOST_WIDE_INT, int,
-                                                int, unsigned HOST_WIDE_INT *,
-                                                int *, int *);
+                                                int, rtx *, int *, int *);
 static unsigned HOST_WIDE_INT invert_mod2n (unsigned HOST_WIDE_INT, int);
 static rtx extract_high_half (enum machine_mode, rtx);
+static rtx expand_mult_highpart (enum machine_mode, rtx, rtx, rtx, int, int);
 static rtx expand_mult_highpart_optab (enum machine_mode, rtx, rtx, rtx,
                                       int, int);
 /* Compute and return the best algorithm for multiplying by T.
@@ -2219,19 +2412,26 @@ static rtx expand_mult_highpart_optab (enum machine_mode, rtx, rtx, rtx,
 
 static void
 synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
-           int cost_limit, enum machine_mode mode)
+           const struct mult_cost *cost_limit, enum machine_mode mode)
 {
   int m;
   struct algorithm *alg_in, *best_alg;
-  int cost;
+  struct mult_cost best_cost;
+  struct mult_cost new_limit;
+  int op_cost, op_latency;
   unsigned HOST_WIDE_INT q;
   int maxm = MIN (BITS_PER_WORD, GET_MODE_BITSIZE (mode));
+  int hash_index;
+  bool cache_hit = false;
+  enum alg_code cache_alg = alg_zero;
 
   /* Indicate that no algorithm is yet found.  If no algorithm
      is found, this value will be returned and indicate failure.  */
-  alg_out->cost = cost_limit;
+  alg_out->cost.cost = cost_limit->cost + 1;
+  alg_out->cost.latency = cost_limit->latency + 1;
 
-  if (cost_limit <= 0)
+  if (cost_limit->cost < 0
+      || (cost_limit->cost == 0 && cost_limit->latency <= 0))
     return;
 
   /* Restrict the bits of "t" to the multiplication's mode.  */
@@ -2241,7 +2441,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
   if (t == 1)
     {
       alg_out->ops = 1;
-      alg_out->cost = 0;
+      alg_out->cost.cost = 0;
+      alg_out->cost.latency = 0;
       alg_out->op[0] = alg_m;
       return;
     }
@@ -2250,12 +2451,13 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
      fail now.  */
   if (t == 0)
     {
-      if (zero_cost >= cost_limit)
+      if (MULT_COST_LESS (cost_limit, zero_cost))
        return;
       else
        {
          alg_out->ops = 1;
-         alg_out->cost = zero_cost;
+         alg_out->cost.cost = zero_cost;
+         alg_out->cost.latency = zero_cost;
          alg_out->op[0] = alg_zero;
          return;
        }
@@ -2265,12 +2467,48 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
 
   alg_in = alloca (sizeof (struct algorithm));
   best_alg = alloca (sizeof (struct algorithm));
+  best_cost = *cost_limit;
+
+  /* Compute the hash index.  */
+  hash_index = (t ^ (unsigned int) mode) % NUM_ALG_HASH_ENTRIES;
+
+  /* See if we already know what to do for T.  */
+  if (alg_hash[hash_index].t == t
+      && alg_hash[hash_index].mode == mode
+      && alg_hash[hash_index].alg != alg_unknown)
+    {
+      cache_hit = true;
+      cache_alg = alg_hash[hash_index].alg;
+      switch (cache_alg)
+       {
+       case alg_shift:
+         goto do_alg_shift;
+
+       case alg_add_t_m2:
+       case alg_sub_t_m2:
+         goto do_alg_addsub_t_m2;
+
+       case alg_add_factor:
+       case alg_sub_factor:
+         goto do_alg_addsub_factor;
+
+       case alg_add_t2_m:
+         goto do_alg_add_t2_m;
+
+       case alg_sub_t2_m:
+         goto do_alg_sub_t2_m;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
 
   /* If we have a group of zero bits at the low-order part of T, try
      multiplying by the remaining bits and then doing a shift.  */
 
   if ((t & 1) == 0)
     {
+    do_alg_shift:
       m = floor_log2 (t & -t); /* m = number of low zero bits */
       if (m < maxm)
        {
@@ -2278,21 +2516,26 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
          /* The function expand_shift will choose between a shift and
             a sequence of additions, so the observed cost is given as
             MIN (m * add_cost[mode], shift_cost[mode][m]).  */
-         cost = m * add_cost[mode];
-         if (shift_cost[mode][m] < cost)
-           cost = shift_cost[mode][m];
-         synth_mult (alg_in, q, cost_limit - cost, mode);
-
-         cost += alg_in->cost;
-         if (cost < cost_limit)
+         op_cost = m * add_cost[mode];
+         if (shift_cost[mode][m] < op_cost)
+           op_cost = shift_cost[mode][m];
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_cost;
+         synth_mult (alg_in, q, &new_limit, mode);
+
+         alg_in->cost.cost += op_cost;
+         alg_in->cost.latency += op_cost;
+         if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
            {
              struct algorithm *x;
+             best_cost = alg_in->cost;
              x = alg_in, alg_in = best_alg, best_alg = x;
              best_alg->log[best_alg->ops] = m;
              best_alg->op[best_alg->ops] = alg_shift;
-             cost_limit = cost;
            }
        }
+      if (cache_hit)
+       goto done;
     }
 
   /* If we have an odd number, add or subtract one.  */
@@ -2300,6 +2543,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
     {
       unsigned HOST_WIDE_INT w;
 
+    do_alg_addsub_t_m2:
       for (w = 1; (w & t) != 0; w <<= 1)
        ;
       /* If T was -1, then W will be zero after the loop.  This is another
@@ -2315,36 +2559,44 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
        {
          /* T ends with ...111.  Multiply by (T + 1) and subtract 1.  */
 
-         cost = add_cost[mode];
-         synth_mult (alg_in, t + 1, cost_limit - cost, mode);
+         op_cost = add_cost[mode];
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_cost;
+         synth_mult (alg_in, t + 1, &new_limit, mode);
 
-         cost += alg_in->cost;
-         if (cost < cost_limit)
+         alg_in->cost.cost += op_cost;
+         alg_in->cost.latency += op_cost;
+         if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
            {
              struct algorithm *x;
+             best_cost = alg_in->cost;
              x = alg_in, alg_in = best_alg, best_alg = x;
              best_alg->log[best_alg->ops] = 0;
              best_alg->op[best_alg->ops] = alg_sub_t_m2;
-             cost_limit = cost;
            }
        }
       else
        {
          /* T ends with ...01 or ...011.  Multiply by (T - 1) and add 1.  */
 
-         cost = add_cost[mode];
-         synth_mult (alg_in, t - 1, cost_limit - cost, mode);
+         op_cost = add_cost[mode];
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_cost;
+         synth_mult (alg_in, t - 1, &new_limit, mode);
 
-         cost += alg_in->cost;
-         if (cost < cost_limit)
+         alg_in->cost.cost += op_cost;
+         alg_in->cost.latency += op_cost;
+         if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
            {
              struct algorithm *x;
+             best_cost = alg_in->cost;
              x = alg_in, alg_in = best_alg, best_alg = x;
              best_alg->log[best_alg->ops] = 0;
              best_alg->op[best_alg->ops] = alg_add_t_m2;
-             cost_limit = cost;
            }
        }
+      if (cache_hit)
+       goto done;
     }
 
   /* Look for factors of t of the form
@@ -2357,100 +2609,159 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
      good sequence quickly, and therefore be able to prune (by decreasing
      COST_LIMIT) the search.  */
 
+ do_alg_addsub_factor:
   for (m = floor_log2 (t - 1); m >= 2; m--)
     {
       unsigned HOST_WIDE_INT d;
 
       d = ((unsigned HOST_WIDE_INT) 1 << m) + 1;
-      if (t % d == 0 && t > d && m < maxm)
+      if (t % d == 0 && t > d && m < maxm
+         && (!cache_hit || cache_alg == alg_add_factor))
        {
-         cost = add_cost[mode] + shift_cost[mode][m];
-         if (shiftadd_cost[mode][m] < cost)
-           cost = shiftadd_cost[mode][m];
-         synth_mult (alg_in, t / d, cost_limit - cost, mode);
+         /* If the target has a cheap shift-and-add instruction use
+            that in preference to a shift insn followed by an add insn.
+            Assume that the shift-and-add is "atomic" with a latency
+            equal to its cost, otherwise assume that on superscalar
+            hardware the shift may be executed concurrently with the
+            earlier steps in the algorithm.  */
+         op_cost = add_cost[mode] + shift_cost[mode][m];
+         if (shiftadd_cost[mode][m] < op_cost)
+           {
+             op_cost = shiftadd_cost[mode][m];
+             op_latency = op_cost;
+           }
+         else
+           op_latency = add_cost[mode];
+
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_latency;
+         synth_mult (alg_in, t / d, &new_limit, mode);
 
-         cost += alg_in->cost;
-         if (cost < cost_limit)
+         alg_in->cost.cost += op_cost;
+         alg_in->cost.latency += op_latency;
+         if (alg_in->cost.latency < op_cost)
+           alg_in->cost.latency = op_cost;
+         if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
            {
              struct algorithm *x;
+             best_cost = alg_in->cost;
              x = alg_in, alg_in = best_alg, best_alg = x;
              best_alg->log[best_alg->ops] = m;
              best_alg->op[best_alg->ops] = alg_add_factor;
-             cost_limit = cost;
            }
          /* Other factors will have been taken care of in the recursion.  */
          break;
        }
 
       d = ((unsigned HOST_WIDE_INT) 1 << m) - 1;
-      if (t % d == 0 && t > d && m < maxm)
+      if (t % d == 0 && t > d && m < maxm
+         && (!cache_hit || cache_alg == alg_sub_factor))
        {
-         cost = add_cost[mode] + shift_cost[mode][m];
-         if (shiftsub_cost[mode][m] < cost)
-           cost = shiftsub_cost[mode][m];
-         synth_mult (alg_in, t / d, cost_limit - cost, mode);
+         /* If the target has a cheap shift-and-subtract insn use
+            that in preference to a shift insn followed by a sub insn.
+            Assume that the shift-and-sub is "atomic" with a latency
+            equal to it's cost, otherwise assume that on superscalar
+            hardware the shift may be executed concurrently with the
+            earlier steps in the algorithm.  */
+         op_cost = add_cost[mode] + shift_cost[mode][m];
+         if (shiftsub_cost[mode][m] < op_cost)
+           {
+             op_cost = shiftsub_cost[mode][m];
+             op_latency = op_cost;
+           }
+         else
+           op_latency = add_cost[mode];
 
-         cost += alg_in->cost;
-         if (cost < cost_limit)
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_latency;
+         synth_mult (alg_in, t / d, &new_limit, mode);
+
+         alg_in->cost.cost += op_cost;
+         alg_in->cost.latency += op_latency;
+         if (alg_in->cost.latency < op_cost)
+           alg_in->cost.latency = op_cost;
+         if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
            {
              struct algorithm *x;
+             best_cost = alg_in->cost;
              x = alg_in, alg_in = best_alg, best_alg = x;
              best_alg->log[best_alg->ops] = m;
              best_alg->op[best_alg->ops] = alg_sub_factor;
-             cost_limit = cost;
            }
          break;
        }
     }
+  if (cache_hit)
+    goto done;
 
   /* Try shift-and-add (load effective address) instructions,
      i.e. do a*3, a*5, a*9.  */
   if ((t & 1) != 0)
     {
+    do_alg_add_t2_m:
       q = t - 1;
       q = q & -q;
       m = exact_log2 (q);
       if (m >= 0 && m < maxm)
        {
-         cost = shiftadd_cost[mode][m];
-         synth_mult (alg_in, (t - 1) >> m, cost_limit - cost, mode);
-
-         cost += alg_in->cost;
-         if (cost < cost_limit)
+         op_cost = shiftadd_cost[mode][m];
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_cost;
+         synth_mult (alg_in, (t - 1) >> m, &new_limit, mode);
+
+         alg_in->cost.cost += op_cost;
+         alg_in->cost.latency += op_cost;
+         if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
            {
              struct algorithm *x;
+             best_cost = alg_in->cost;
              x = alg_in, alg_in = best_alg, best_alg = x;
              best_alg->log[best_alg->ops] = m;
              best_alg->op[best_alg->ops] = alg_add_t2_m;
-             cost_limit = cost;
            }
        }
+      if (cache_hit)
+       goto done;
 
+    do_alg_sub_t2_m:
       q = t + 1;
       q = q & -q;
       m = exact_log2 (q);
       if (m >= 0 && m < maxm)
        {
-         cost = shiftsub_cost[mode][m];
-         synth_mult (alg_in, (t + 1) >> m, cost_limit - cost, mode);
-
-         cost += alg_in->cost;
-         if (cost < cost_limit)
+         op_cost = shiftsub_cost[mode][m];
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_cost;
+         synth_mult (alg_in, (t + 1) >> m, &new_limit, mode);
+
+         alg_in->cost.cost += op_cost;
+         alg_in->cost.latency += op_cost;
+         if (CHEAPER_MULT_COST (&alg_in->cost, &best_cost))
            {
              struct algorithm *x;
+             best_cost = alg_in->cost;
              x = alg_in, alg_in = best_alg, best_alg = x;
              best_alg->log[best_alg->ops] = m;
              best_alg->op[best_alg->ops] = alg_sub_t2_m;
-             cost_limit = cost;
            }
        }
+      if (cache_hit)
+       goto done;
     }
 
-  /* If cost_limit has not decreased since we stored it in alg_out->cost,
-     we have not found any algorithm.  */
-  if (cost_limit == alg_out->cost)
+ done:
+  /* If best_cost has not decreased, we have not found any algorithm.  */
+  if (!CHEAPER_MULT_COST (&best_cost, cost_limit))
     return;
 
+  /* Cache the result.  */
+  if (!cache_hit)
+    {
+      alg_hash[hash_index].t = t;
+      alg_hash[hash_index].mode = mode;
+      alg_hash[hash_index].alg = best_alg->op[best_alg->ops];
+    }
+
   /* If we are getting a too long sequence for `struct algorithm'
      to record, make this search fail.  */
   if (best_alg->ops == MAX_BITS_PER_WORD)
@@ -2460,7 +2771,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
      We avoid using structure assignment because the majority of
      best_alg is normally undefined, and this is a critical function.  */
   alg_out->ops = best_alg->ops + 1;
-  alg_out->cost = cost_limit;
+  alg_out->cost = best_cost;
   memcpy (alg_out->op, best_alg->op,
          alg_out->ops * sizeof *alg_out->op);
   memcpy (alg_out->log, best_alg->log,
@@ -2483,29 +2794,57 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
                     int mult_cost)
 {
   struct algorithm alg2;
+  struct mult_cost limit;
+  int op_cost;
 
   *variant = basic_variant;
-  synth_mult (alg, val, mult_cost, mode);
+  limit.cost = mult_cost;
+  limit.latency = mult_cost;
+  synth_mult (alg, val, &limit, mode);
 
   /* This works only if the inverted value actually fits in an
      `unsigned int' */
   if (HOST_BITS_PER_INT >= GET_MODE_BITSIZE (mode))
     {
-      synth_mult (&alg2, -val, MIN (alg->cost, mult_cost) - neg_cost[mode],
-                 mode);
-      alg2.cost += neg_cost[mode];
-      if (alg2.cost < alg->cost)
+      op_cost = neg_cost[mode];
+      if (MULT_COST_LESS (&alg->cost, mult_cost))
+       {
+         limit.cost = alg->cost.cost - op_cost;
+         limit.latency = alg->cost.latency - op_cost;
+       }
+      else
+       {
+         limit.cost = mult_cost - op_cost;
+         limit.latency = mult_cost - op_cost;
+       }
+
+      synth_mult (&alg2, -val, &limit, mode);
+      alg2.cost.cost += op_cost;
+      alg2.cost.latency += op_cost;
+      if (CHEAPER_MULT_COST (&alg2.cost, &alg->cost))
        *alg = alg2, *variant = negate_variant;
     }
 
   /* This proves very useful for division-by-constant.  */
-  synth_mult (&alg2, val - 1, MIN (alg->cost, mult_cost) - add_cost[mode],
-             mode);
-  alg2.cost += add_cost[mode];
-  if (alg2.cost < alg->cost)
+  op_cost = add_cost[mode];
+  if (MULT_COST_LESS (&alg->cost, mult_cost))
+    {
+      limit.cost = alg->cost.cost - op_cost;
+      limit.latency = alg->cost.latency - op_cost;
+    }
+  else
+    {
+      limit.cost = mult_cost - op_cost;
+      limit.latency = mult_cost - op_cost;
+    }
+
+  synth_mult (&alg2, val - 1, &limit, mode);
+  alg2.cost.cost += op_cost;
+  alg2.cost.latency += op_cost;
+  if (CHEAPER_MULT_COST (&alg2.cost, &alg->cost))
     *alg = alg2, *variant = add_variant;
 
-  return alg->cost < mult_cost;
+  return MULT_COST_LESS (&alg->cost, mult_cost);
 }
 
 /* A subroutine of expand_mult, used for constant multiplications.
@@ -2542,7 +2881,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
       val_so_far = 1;
     }
   else
-    abort ();
+    gcc_unreachable ();
 
   for (opno = 1; opno < alg->ops; opno++)
     {
@@ -2558,14 +2897,14 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
        {
        case alg_shift:
          accum = expand_shift (LSHIFT_EXPR, mode, accum,
-                               build_int_cst (NULL_TREE, log, 0),
+                               build_int_cst (NULL_TREE, log),
                                NULL_RTX, 0);
          val_so_far <<= log;
          break;
 
        case alg_add_t_m2:
          tem = expand_shift (LSHIFT_EXPR, mode, op0,
-                             build_int_cst (NULL_TREE, log, 0),
+                             build_int_cst (NULL_TREE, log),
                              NULL_RTX, 0);
          accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
@@ -2574,7 +2913,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
 
        case alg_sub_t_m2:
          tem = expand_shift (LSHIFT_EXPR, mode, op0,
-                             build_int_cst (NULL_TREE, log, 0),
+                             build_int_cst (NULL_TREE, log),
                              NULL_RTX, 0);
          accum = force_operand (gen_rtx_MINUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
@@ -2583,7 +2922,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
 
        case alg_add_t2_m:
          accum = expand_shift (LSHIFT_EXPR, mode, accum,
-                               build_int_cst (NULL_TREE, log, 0),
+                               build_int_cst (NULL_TREE, log),
                                shift_subtarget,
                                0);
          accum = force_operand (gen_rtx_PLUS (mode, accum, op0),
@@ -2593,7 +2932,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
 
        case alg_sub_t2_m:
          accum = expand_shift (LSHIFT_EXPR, mode, accum,
-                               build_int_cst (NULL_TREE, log, 0),
+                               build_int_cst (NULL_TREE, log),
                                shift_subtarget, 0);
          accum = force_operand (gen_rtx_MINUS (mode, accum, op0),
                                 add_target ? add_target : accum_target);
@@ -2602,7 +2941,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
 
        case alg_add_factor:
          tem = expand_shift (LSHIFT_EXPR, mode, accum,
-                             build_int_cst (NULL_TREE, log, 0),
+                             build_int_cst (NULL_TREE, log),
                              NULL_RTX, 0);
          accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
@@ -2611,7 +2950,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
 
        case alg_sub_factor:
          tem = expand_shift (LSHIFT_EXPR, mode, accum,
-                             build_int_cst (NULL_TREE, log, 0),
+                             build_int_cst (NULL_TREE, log),
                              NULL_RTX, 0);
          accum = force_operand (gen_rtx_MINUS (mode, tem, accum),
                                 (add_target
@@ -2620,7 +2959,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       /* Write a REG_EQUAL note on the last insn so that we can cse
@@ -2655,8 +2994,7 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
      in the result mode, to avoid sign-/zero-extension confusion.  */
   val &= GET_MODE_MASK (mode);
   val_so_far &= GET_MODE_MASK (mode);
-  if (val != val_so_far)
-    abort ();
+  gcc_assert (val == val_so_far);
 
   return accum;
 }
@@ -2673,43 +3011,96 @@ rtx
 expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
             int unsignedp)
 {
-  rtx const_op1 = op1;
   enum mult_variant variant;
   struct algorithm algorithm;
+  int max_cost;
 
-  /* synth_mult does an `unsigned int' multiply.  As long as the mode is
-     less than or equal in size to `unsigned int' this doesn't matter.
-     If the mode is larger than `unsigned int', then synth_mult works only
-     if the constant value exactly fits in an `unsigned int' without any
-     truncation.  This means that multiplying by negative values does
-     not work; results are off by 2^32 on a 32 bit machine.  */
-
-  /* If we are multiplying in DImode, it may still be a win
-     to try to work with shifts and adds.  */
-  if (GET_CODE (op1) == CONST_DOUBLE
-      && GET_MODE_CLASS (GET_MODE (op1)) == MODE_INT
-      && HOST_BITS_PER_INT >= BITS_PER_WORD
-      && CONST_DOUBLE_HIGH (op1) == 0)
-    const_op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
-  else if (HOST_BITS_PER_INT < GET_MODE_BITSIZE (mode)
-          && GET_CODE (op1) == CONST_INT
-          && INTVAL (op1) < 0)
-    const_op1 = 0;
-
-  /* We used to test optimize here, on the grounds that it's better to
-     produce a smaller program when -O is not used.
-     But this causes such a terrible slowdown sometimes
-     that it seems better to use synth_mult always.  */
-
-  if (const_op1 && GET_CODE (const_op1) == CONST_INT
+  /* Handling const0_rtx here allows us to use zero as a rogue value for
+     coeff below.  */
+  if (op1 == const0_rtx)
+    return const0_rtx;
+  if (op1 == const1_rtx)
+    return op0;
+  if (op1 == constm1_rtx)
+    return expand_unop (mode,
+                       GET_MODE_CLASS (mode) == MODE_INT
+                       && !unsignedp && flag_trapv
+                       ? negv_optab : neg_optab,
+                       op0, target, 0);
+
+  /* These are the operations that are potentially turned into a sequence
+     of shifts and additions.  */
+  if (GET_MODE_CLASS (mode) == MODE_INT
       && (unsignedp || !flag_trapv))
     {
-      int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+      HOST_WIDE_INT coeff = 0;
 
-      if (choose_mult_variant (mode, INTVAL (const_op1), &algorithm, &variant,
-                              mult_cost))
-       return expand_mult_const (mode, op0, INTVAL (const_op1), target,
-                                 &algorithm, variant);
+      /* synth_mult does an `unsigned int' multiply.  As long as the mode is
+        less than or equal in size to `unsigned int' this doesn't matter.
+        If the mode is larger than `unsigned int', then synth_mult works
+        only if the constant value exactly fits in an `unsigned int' without
+        any truncation.  This means that multiplying by negative values does
+        not work; results are off by 2^32 on a 32 bit machine.  */
+
+      if (GET_CODE (op1) == CONST_INT)
+       {
+         /* Attempt to handle multiplication of DImode values by negative
+            coefficients, by performing the multiplication by a positive
+            multiplier and then inverting the result.  */
+         if (INTVAL (op1) < 0
+             && GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
+           {
+             /* Its safe to use -INTVAL (op1) even for INT_MIN, as the
+                result is interpreted as an unsigned coefficient.  */
+             max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET)
+                        - neg_cost[mode];
+             if (max_cost > 0
+                 && choose_mult_variant (mode, -INTVAL (op1), &algorithm,
+                                         &variant, max_cost))
+               {
+                 rtx temp = expand_mult_const (mode, op0, -INTVAL (op1),
+                                               NULL_RTX, &algorithm,
+                                               variant);
+                 return expand_unop (mode, neg_optab, temp, target, 0);
+               }
+           }
+         else coeff = INTVAL (op1);
+       }
+      else if (GET_CODE (op1) == CONST_DOUBLE)
+       {
+         /* If we are multiplying in DImode, it may still be a win
+            to try to work with shifts and adds.  */
+         if (CONST_DOUBLE_HIGH (op1) == 0)
+           coeff = CONST_DOUBLE_LOW (op1);
+         else if (CONST_DOUBLE_LOW (op1) == 0
+                  && EXACT_POWER_OF_2_OR_ZERO_P (CONST_DOUBLE_HIGH (op1)))
+           {
+             int shift = floor_log2 (CONST_DOUBLE_HIGH (op1))
+                         + HOST_BITS_PER_WIDE_INT;
+             return expand_shift (LSHIFT_EXPR, mode, op0,
+                                  build_int_cst (NULL_TREE, shift),
+                                  target, unsignedp);
+           }
+       }
+        
+      /* We used to test optimize here, on the grounds that it's better to
+        produce a smaller program when -O is not used.  But this causes
+        such a terrible slowdown sometimes that it seems better to always
+        use synth_mult.  */
+      if (coeff != 0)
+       {
+         /* Special case powers of two.  */
+         if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+           return expand_shift (LSHIFT_EXPR, mode, op0,
+                                build_int_cst (NULL_TREE, floor_log2 (coeff)),
+                                target, unsignedp);
+
+         max_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
+         if (choose_mult_variant (mode, coeff, &algorithm, &variant,
+                                  max_cost))
+           return expand_mult_const (mode, op0, coeff, target,
+                                     &algorithm, variant);
+       }
     }
 
   if (GET_CODE (op0) == CONST_DOUBLE)
@@ -2741,8 +3132,7 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
                      && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
                      ? smulv_optab : smul_optab,
                      op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
-  if (op0 == 0)
-    abort ();
+  gcc_assert (op0);
   return op0;
 }
 \f
@@ -2773,8 +3163,7 @@ ceil_log2 (unsigned HOST_WIDE_INT x)
 static
 unsigned HOST_WIDE_INT
 choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
-                  unsigned HOST_WIDE_INT *multiplier_ptr,
-                  int *post_shift_ptr, int *lgup_ptr)
+                  rtx *multiplier_ptr, int *post_shift_ptr, int *lgup_ptr)
 {
   HOST_WIDE_INT mhigh_hi, mlow_hi;
   unsigned HOST_WIDE_INT mhigh_lo, mlow_lo;
@@ -2786,18 +3175,15 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
   /* lgup = ceil(log2(divisor)); */
   lgup = ceil_log2 (d);
 
-  if (lgup > n)
-    abort ();
+  gcc_assert (lgup <= n);
 
   pow = n + lgup;
   pow2 = n + lgup - precision;
 
-  if (pow == 2 * HOST_BITS_PER_WIDE_INT)
-    {
-      /* We could handle this with some effort, but this case is much better
-        handled directly with a scc insn, so rely on caller using that.  */
-      abort ();
-    }
+  /* We could handle this with some effort, but this case is much
+     better handled directly with a scc insn, so rely on caller using
+     that.  */
+  gcc_assert (pow != 2 * HOST_BITS_PER_WIDE_INT);
 
   /* mlow = 2^(N + lgup)/d */
  if (pow >= HOST_BITS_PER_WIDE_INT)
@@ -2821,13 +3207,11 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
   div_and_round_double (TRUNC_DIV_EXPR, 1, nl, nh, d, (HOST_WIDE_INT) 0,
                        &mhigh_lo, &mhigh_hi, &dummy1, &dummy2);
 
-  if (mhigh_hi && nh - d >= d)
-    abort ();
-  if (mhigh_hi > 1 || mlow_hi > 1)
-    abort ();
+  gcc_assert (!mhigh_hi || nh - d < d);
+  gcc_assert (mhigh_hi <= 1 && mlow_hi <= 1);
   /* Assert that mlow < mhigh.  */
-  if (! (mlow_hi < mhigh_hi || (mlow_hi == mhigh_hi && mlow_lo < mhigh_lo)))
-    abort ();
+  gcc_assert (mlow_hi < mhigh_hi
+             || (mlow_hi == mhigh_hi && mlow_lo < mhigh_lo));
 
   /* If precision == N, then mlow, mhigh exceed 2^N
      (but they do not exceed 2^(N+1)).  */
@@ -2851,12 +3235,12 @@ choose_multiplier (unsigned HOST_WIDE_INT d, int n, int precision,
   if (n < HOST_BITS_PER_WIDE_INT)
     {
       unsigned HOST_WIDE_INT mask = ((unsigned HOST_WIDE_INT) 1 << n) - 1;
-      *multiplier_ptr = mhigh_lo & mask;
+      *multiplier_ptr = GEN_INT (mhigh_lo & mask);
       return mhigh_lo >= mask;
     }
   else
     {
-      *multiplier_ptr = mhigh_lo;
+      *multiplier_ptr = GEN_INT (mhigh_lo);
       return mhigh_hi;
     }
 }
@@ -2907,8 +3291,7 @@ expand_mult_highpart_adjust (enum machine_mode mode, rtx adj_operand, rtx op0,
   enum rtx_code adj_code = unsignedp ? PLUS : MINUS;
 
   tem = expand_shift (RSHIFT_EXPR, mode, op0,
-                     build_int_cst (NULL_TREE,
-                                    GET_MODE_BITSIZE (mode) - 1, 0),
+                     build_int_cst (NULL_TREE, GET_MODE_BITSIZE (mode) - 1),
                      NULL_RTX, 0);
   tem = expand_and (mode, tem, op1, NULL_RTX);
   adj_operand
@@ -2916,8 +3299,7 @@ expand_mult_highpart_adjust (enum machine_mode mode, rtx adj_operand, rtx op0,
                     adj_operand);
 
   tem = expand_shift (RSHIFT_EXPR, mode, op1,
-                     build_int_cst (NULL_TREE,
-                                    GET_MODE_BITSIZE (mode) - 1, 0),
+                     build_int_cst (NULL_TREE, GET_MODE_BITSIZE (mode) - 1),
                      NULL_RTX, 0);
   tem = expand_and (mode, tem, op0, NULL_RTX);
   target = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
@@ -2938,8 +3320,7 @@ extract_high_half (enum machine_mode mode, rtx op)
 
   wider_mode = GET_MODE_WIDER_MODE (mode);
   op = expand_shift (RSHIFT_EXPR, wider_mode, op,
-                    build_int_cst (NULL_TREE,
-                                   GET_MODE_BITSIZE (mode), 0), 0, 1);
+                    build_int_cst (NULL_TREE, GET_MODE_BITSIZE (mode)), 0, 1);
   return convert_modes (mode, wider_mode, op, 0);
 }
 
@@ -2997,15 +3378,29 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
     }
 
   /* Try widening the mode and perform a non-widening multiplication.  */
-  moptab = smul_optab;
   if (smul_optab->handlers[wider_mode].insn_code != CODE_FOR_nothing
       && size - 1 < BITS_PER_WORD
       && mul_cost[wider_mode] + shift_cost[mode][size-1] < max_cost)
     {
-      tem = expand_binop (wider_mode, moptab, op0, op1, 0,
+      rtx insns, wop0, wop1;
+
+      /* We need to widen the operands, for example to ensure the
+        constant multiplier is correctly sign or zero extended.
+        Use a sequence to clean-up any instructions emitted by
+        the conversions if things don't work out.  */
+      start_sequence ();
+      wop0 = convert_modes (wider_mode, mode, op0, unsignedp);
+      wop1 = convert_modes (wider_mode, mode, op1, unsignedp);
+      tem = expand_binop (wider_mode, smul_optab, wop0, wop1, 0,
                          unsignedp, OPTAB_WIDEN);
+      insns = get_insns ();
+      end_sequence ();
+
       if (tem)
-       return extract_high_half (mode, tem);
+       {
+         emit_insn (insns);
+         return extract_high_half (mode, tem);
+       }
     }
 
   /* Try widening multiplication of opposite signedness, and adjust.  */
@@ -3029,9 +3424,10 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
   return 0;
 }
 
-/* Emit code to multiply OP0 and CNST1, putting the high half of the result
-   in TARGET if that is convenient, and return where the result is.  If the
-   operation can not be performed, 0 is returned.
+/* Emit code to multiply OP0 and OP1 (where OP1 is an integer constant),
+   putting the high half of the result in TARGET if that is convenient,
+   and return where the result is.  If the operation can not be performed,
+   0 is returned.
 
    MODE is the mode of operation and result.
 
@@ -3039,24 +3435,22 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
 
    MAX_COST is the total allowed cost for the expanded RTL.  */
 
-rtx
-expand_mult_highpart (enum machine_mode mode, rtx op0,
-                     unsigned HOST_WIDE_INT cnst1, rtx target,
-                     int unsignedp, int max_cost)
+static rtx
+expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
+                     rtx target, int unsignedp, int max_cost)
 {
   enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+  unsigned HOST_WIDE_INT cnst1;
   int extra_cost;
   bool sign_adjust = false;
   enum mult_variant variant;
   struct algorithm alg;
-  rtx op1, tem;
+  rtx tem;
 
   /* We can't support modes wider than HOST_BITS_PER_INT.  */
-  if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-    abort ();
+  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT);
 
-  op1 = gen_int_mode (cnst1, wider_mode);
-  cnst1 &= GET_MODE_MASK (mode);
+  cnst1 = INTVAL (op1) & GET_MODE_MASK (mode);
 
   /* We can't optimize modes wider than BITS_PER_WORD. 
      ??? We might be able to perform double-word arithmetic if 
@@ -3081,8 +3475,8 @@ expand_mult_highpart (enum machine_mode mode, rtx op0,
     {
       /* See whether the specialized multiplication optabs are
         cheaper than the shift/add version.  */
-      tem = expand_mult_highpart_optab (mode, op0, op1, target,
-                                       unsignedp, alg.cost + extra_cost);
+      tem = expand_mult_highpart_optab (mode, op0, op1, target, unsignedp,
+                                       alg.cost.cost + extra_cost);
       if (tem)
        return tem;
 
@@ -3106,7 +3500,7 @@ expand_mult_highpart (enum machine_mode mode, rtx op0,
 static rtx
 expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
-  unsigned HOST_WIDE_INT mask;
+  unsigned HOST_WIDE_INT masklow, maskhigh;
   rtx result, temp, shift, label;
   int logd;
 
@@ -3122,14 +3516,14 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
       if (signmask)
        {
          signmask = force_reg (mode, signmask);
-         mask = ((HOST_WIDE_INT) 1 << logd) - 1;
+         masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
          shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
 
          /* Use the rtx_cost of a LSHIFTRT instruction to determine
             which instruction sequence to use.  If logical right shifts
             are expensive the use 2 XORs, 2 SUBs and an AND, otherwise
             use a LSHIFTRT, 1 ADD, 1 SUB and an AND.  */
-            
+
          temp = gen_rtx_LSHIFTRT (mode, result, shift);
          if (lshr_optab->handlers[mode].insn_code == CODE_FOR_nothing
              || rtx_cost (temp, SET) > COSTS_N_INSNS (2))
@@ -3138,7 +3532,7 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, sub_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
-             temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+             temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, xor_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -3153,7 +3547,7 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
              temp = expand_binop (mode, add_optab, op0, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
-             temp = expand_binop (mode, and_optab, temp, GEN_INT (mask),
+             temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp = expand_binop (mode, sub_optab, temp, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -3167,11 +3561,19 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
      can avoid an explicit compare operation in the following comparison
      against zero.  */
 
-  mask = (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1)
-        | (((HOST_WIDE_INT) 1 << logd) - 1);
+  masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
+  if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+    {
+      masklow |= (HOST_WIDE_INT) -1 << (GET_MODE_BITSIZE (mode) - 1);
+      maskhigh = -1;
+    }
+  else
+    maskhigh = (HOST_WIDE_INT) -1
+                << (GET_MODE_BITSIZE (mode) - HOST_BITS_PER_WIDE_INT - 1);
 
-  temp = expand_binop (mode, and_optab, op0, GEN_INT (mask), result,
-                      1, OPTAB_LIB_WIDEN);
+  temp = expand_binop (mode, and_optab, op0,
+                      immed_double_const (masklow, maskhigh, mode),
+                      result, 1, OPTAB_LIB_WIDEN);
   if (temp != result)
     emit_move_insn (result, temp);
 
@@ -3180,9 +3582,11 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 
   temp = expand_binop (mode, sub_optab, result, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
-  mask = (HOST_WIDE_INT) -1 << logd;
-  temp = expand_binop (mode, ior_optab, temp, GEN_INT (mask), result,
-                      1, OPTAB_LIB_WIDEN);
+  masklow = (HOST_WIDE_INT) -1 << logd;
+  maskhigh = -1;
+  temp = expand_binop (mode, ior_optab, temp,
+                      immed_double_const (masklow, maskhigh, mode),
+                      result, 1, OPTAB_LIB_WIDEN);
   temp = expand_binop (mode, add_optab, temp, const1_rtx, result,
                       0, OPTAB_LIB_WIDEN);
   if (temp != result)
@@ -3202,7 +3606,7 @@ expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
   int logd;
 
   logd = floor_log2 (d);
-  shift = build_int_cst (NULL_TREE, logd, 0);
+  shift = build_int_cst (NULL_TREE, logd);
 
   if (d == 2 && BRANCH_COST >= 1)
     {
@@ -3218,6 +3622,11 @@ expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
     {
       rtx temp2;
 
+      /* ??? emit_conditional_move forces a stack adjustment via
+        compare_from_rtx so, if the sequence is discarded, it will
+        be lost.  Do it now instead.  */
+      do_pending_stack_adjust ();
+
       start_sequence ();
       temp2 = copy_to_mode_reg (mode, op0);
       temp = expand_binop (mode, add_optab, temp2, GEN_INT (d-1),
@@ -3249,7 +3658,7 @@ expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
                             NULL_RTX, 0, OPTAB_LIB_WIDEN);
       else
        temp = expand_shift (RSHIFT_EXPR, mode, temp,
-                            build_int_cst (NULL_TREE, ushift, 0),
+                            build_int_cst (NULL_TREE, ushift),
                             NULL_RTX, 1);
       temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
                           0, OPTAB_LIB_WIDEN);
@@ -3302,8 +3711,6 @@ expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
    (x mod 12) == (((x & 1023) + ((x >> 8) & ~3)) * 0x15555558 >> 2 * 3) >> 28
    */
 
-#define EXACT_POWER_OF_2_OR_ZERO_P(x) (((x) & ((x) - 1)) == 0)
-
 rtx
 expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
               rtx op0, rtx op1, rtx target, int unsignedp)
@@ -3506,9 +3913,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
          {
            if (unsignedp)
              {
-               unsigned HOST_WIDE_INT mh, ml;
+               unsigned HOST_WIDE_INT mh;
                int pre_shift, post_shift;
                int dummy;
+               rtx ml;
                unsigned HOST_WIDE_INT d = (INTVAL (op1)
                                            & GET_MODE_MASK (compute_mode));
 
@@ -3527,7 +3935,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                      }
                    quotient = expand_shift (RSHIFT_EXPR, compute_mode, op0,
                                             build_int_cst (NULL_TREE,
-                                                           pre_shift, 0),
+                                                           pre_shift),
                                             tquotient, 1);
                  }
                else if (size <= HOST_BITS_PER_WIDE_INT)
@@ -3558,8 +3966,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                            mh = choose_multiplier (d >> pre_shift, size,
                                                    size - pre_shift,
                                                    &ml, &post_shift, &dummy);
-                           if (mh)
-                             abort ();
+                           gcc_assert (!mh);
                          }
                        else
                          pre_shift = 0;
@@ -3585,15 +3992,14 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                                                NULL_RTX);
                            t3 = expand_shift
                              (RSHIFT_EXPR, compute_mode, t2,
-                              build_int_cst (NULL_TREE, 1, 0),
+                              build_int_cst (NULL_TREE, 1),
                               NULL_RTX,1);
                            t4 = force_operand (gen_rtx_PLUS (compute_mode,
                                                              t1, t3),
                                                NULL_RTX);
                            quotient = expand_shift
                              (RSHIFT_EXPR, compute_mode, t4,
-                              build_int_cst (NULL_TREE,
-                                             post_shift - 1, 0),
+                              build_int_cst (NULL_TREE, post_shift - 1),
                               tquotient, 1);
                          }
                        else
@@ -3606,7 +4012,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 
                            t1 = expand_shift
                              (RSHIFT_EXPR, compute_mode, op0,
-                              build_int_cst (NULL_TREE, pre_shift, 0),
+                              build_int_cst (NULL_TREE, pre_shift),
                               NULL_RTX, 1);
                            extra_cost
                              = (shift_cost[compute_mode][pre_shift]
@@ -3618,8 +4024,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                              goto fail1;
                            quotient = expand_shift
                              (RSHIFT_EXPR, compute_mode, t2,
-                              build_int_cst (NULL_TREE,
-                                             post_shift, 0),
+                              build_int_cst (NULL_TREE, post_shift),
                               tquotient, 1);
                          }
                      }
@@ -3639,6 +4044,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
              {
                unsigned HOST_WIDE_INT ml;
                int lgup, post_shift;
+               rtx mlr;
                HOST_WIDE_INT d = INTVAL (op1);
                unsigned HOST_WIDE_INT abs_d = d >= 0 ? d : -d;
 
@@ -3681,7 +4087,19 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                        if (remainder)
                          return gen_lowpart (mode, remainder);
                      }
-                   quotient = expand_sdiv_pow2 (compute_mode, op0, abs_d);
+
+                   if (sdiv_pow2_cheap[compute_mode]
+                       && ((sdiv_optab->handlers[compute_mode].insn_code
+                            != CODE_FOR_nothing)
+                           || (sdivmod_optab->handlers[compute_mode].insn_code
+                               != CODE_FOR_nothing)))
+                     quotient = expand_divmod (0, TRUNC_DIV_EXPR,
+                                               compute_mode, op0,
+                                               gen_int_mode (abs_d,
+                                                             compute_mode),
+                                               NULL_RTX, 0);
+                   else
+                     quotient = expand_sdiv_pow2 (compute_mode, op0, abs_d);
 
                    /* We have computed OP0 / abs(OP1).  If OP1 is negative,
                       negate the quotient.  */
@@ -3709,7 +4127,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                else if (size <= HOST_BITS_PER_WIDE_INT)
                  {
                    choose_multiplier (abs_d, size, size - 1,
-                                      &ml, &post_shift, &lgup);
+                                      &mlr, &post_shift, &lgup);
+                   ml = (unsigned HOST_WIDE_INT) INTVAL (mlr);
                    if (ml < (unsigned HOST_WIDE_INT) 1 << (size - 1))
                      {
                        rtx t1, t2, t3;
@@ -3721,18 +4140,18 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                        extra_cost = (shift_cost[compute_mode][post_shift]
                                      + shift_cost[compute_mode][size - 1]
                                      + add_cost[compute_mode]);
-                       t1 = expand_mult_highpart (compute_mode, op0, ml,
+                       t1 = expand_mult_highpart (compute_mode, op0, mlr,
                                                   NULL_RTX, 0,
                                                   max_cost - extra_cost);
                        if (t1 == 0)
                          goto fail1;
                        t2 = expand_shift
                          (RSHIFT_EXPR, compute_mode, t1,
-                          build_int_cst (NULL_TREE, post_shift, 0),
+                          build_int_cst (NULL_TREE, post_shift),
                           NULL_RTX, 0);
                        t3 = expand_shift
                          (RSHIFT_EXPR, compute_mode, op0,
-                          build_int_cst (NULL_TREE, size - 1, 0),
+                          build_int_cst (NULL_TREE, size - 1),
                           NULL_RTX, 0);
                        if (d < 0)
                          quotient
@@ -3754,10 +4173,11 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                          goto fail1;
 
                        ml |= (~(unsigned HOST_WIDE_INT) 0) << (size - 1);
+                       mlr = gen_int_mode (ml, compute_mode);
                        extra_cost = (shift_cost[compute_mode][post_shift]
                                      + shift_cost[compute_mode][size - 1]
                                      + 2 * add_cost[compute_mode]);
-                       t1 = expand_mult_highpart (compute_mode, op0, ml,
+                       t1 = expand_mult_highpart (compute_mode, op0, mlr,
                                                   NULL_RTX, 0,
                                                   max_cost - extra_cost);
                        if (t1 == 0)
@@ -3767,11 +4187,11 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                                            NULL_RTX);
                        t3 = expand_shift
                          (RSHIFT_EXPR, compute_mode, t2,
-                          build_int_cst (NULL_TREE, post_shift, 0),
+                          build_int_cst (NULL_TREE, post_shift),
                           NULL_RTX, 0);
                        t4 = expand_shift
                          (RSHIFT_EXPR, compute_mode, op0,
-                          build_int_cst (NULL_TREE, size - 1, 0),
+                          build_int_cst (NULL_TREE, size - 1),
                           NULL_RTX, 0);
                        if (d < 0)
                          quotient
@@ -3807,9 +4227,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
       /* We will come here only for signed operations.  */
        if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size)
          {
-           unsigned HOST_WIDE_INT mh, ml;
+           unsigned HOST_WIDE_INT mh;
            int pre_shift, lgup, post_shift;
            HOST_WIDE_INT d = INTVAL (op1);
+           rtx ml;
 
            if (d > 0)
              {
@@ -3828,7 +4249,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                      }
                    quotient = expand_shift
                      (RSHIFT_EXPR, compute_mode, op0,
-                      build_int_cst (NULL_TREE, pre_shift, 0),
+                      build_int_cst (NULL_TREE, pre_shift),
                       tquotient, 0);
                  }
                else
@@ -3837,15 +4258,14 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 
                    mh = choose_multiplier (d, size, size - 1,
                                            &ml, &post_shift, &lgup);
-                   if (mh)
-                     abort ();
+                   gcc_assert (!mh);
 
                    if (post_shift < BITS_PER_WORD
                        && size - 1 < BITS_PER_WORD)
                      {
                        t1 = expand_shift
                          (RSHIFT_EXPR, compute_mode, op0,
-                          build_int_cst (NULL_TREE, size - 1, 0),
+                          build_int_cst (NULL_TREE, size - 1),
                           NULL_RTX, 0);
                        t2 = expand_binop (compute_mode, xor_optab, op0, t1,
                                           NULL_RTX, 0, OPTAB_WIDEN);
@@ -3859,7 +4279,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                          {
                            t4 = expand_shift
                              (RSHIFT_EXPR, compute_mode, t3,
-                              build_int_cst (NULL_TREE, post_shift, 0),
+                              build_int_cst (NULL_TREE, post_shift),
                               NULL_RTX, 1);
                            quotient = expand_binop (compute_mode, xor_optab,
                                                     t4, t1, tquotient, 0,
@@ -3877,7 +4297,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                                   0, OPTAB_WIDEN);
                nsign = expand_shift
                  (RSHIFT_EXPR, compute_mode, t2,
-                  build_int_cst (NULL_TREE, size - 1, 0),
+                  build_int_cst (NULL_TREE, size - 1),
                   NULL_RTX, 0);
                t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
                                    NULL_RTX);
@@ -3992,8 +4412,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                rtx t1, t2, t3;
                unsigned HOST_WIDE_INT d = INTVAL (op1);
                t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
-                                  build_int_cst (NULL_TREE,
-                                                 floor_log2 (d), 0),
+                                  build_int_cst (NULL_TREE, floor_log2 (d)),
                                   tquotient, 1);
                t2 = expand_binop (compute_mode, and_optab, op0,
                                   GEN_INT (d - 1),
@@ -4091,8 +4510,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                rtx t1, t2, t3;
                unsigned HOST_WIDE_INT d = INTVAL (op1);
                t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
-                                  build_int_cst (NULL_TREE,
-                                                 floor_log2 (d), 0),
+                                  build_int_cst (NULL_TREE, floor_log2 (d)),
                                   tquotient, 0);
                t2 = expand_binop (compute_mode, and_optab, op0,
                                   GEN_INT (d - 1),
@@ -4214,7 +4632,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
            pre_shift = floor_log2 (d & -d);
            ml = invert_mod2n (d >> pre_shift, size);
            t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
-                              build_int_cst (NULL_TREE, pre_shift, 0),
+                              build_int_cst (NULL_TREE, pre_shift),
                               NULL_RTX, unsignedp);
            quotient = expand_mult (compute_mode, t1,
                                    gen_int_mode (ml, compute_mode),
@@ -4249,7 +4667,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
              }
            tem = plus_constant (op1, -1);
            tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
-                               build_int_cst (NULL_TREE, 1, 0),
+                               build_int_cst (NULL_TREE, 1),
                                NULL_RTX, 1);
            do_cmp_and_jump (remainder, tem, LEU, compute_mode, label);
            expand_inc (quotient, const1_rtx);
@@ -4275,13 +4693,13 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
            abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0);
            abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0);
            tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
-                               build_int_cst (NULL_TREE, 1, 0),
+                               build_int_cst (NULL_TREE, 1),
                                NULL_RTX, 1);
            do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label);
            tem = expand_binop (compute_mode, xor_optab, op0, op1,
                                NULL_RTX, 0, OPTAB_WIDEN);
            mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
-                                build_int_cst (NULL_TREE, size - 1, 0),
+                                build_int_cst (NULL_TREE, size - 1),
                                 NULL_RTX, 0);
            tem = expand_binop (compute_mode, xor_optab, mask, const1_rtx,
                                NULL_RTX, 0, OPTAB_WIDEN);
@@ -4298,7 +4716,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
        return gen_lowpart (mode, rem_flag ? remainder : quotient);
 
       default:
-       abort ();
+       gcc_unreachable ();
       }
 
   if (quotient == 0)
@@ -4434,14 +4852,15 @@ make_tree (tree type, rtx x)
                     < HOST_BITS_PER_WIDE_INT)))
          hi = -1;
       
-       t = build_int_cst (type, INTVAL (x), hi);
+       t = build_int_cst_wide (type, INTVAL (x), hi);
        
        return t;
       }
       
     case CONST_DOUBLE:
       if (GET_MODE (x) == VOIDmode)
-       t = build_int_cst (type, CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
+       t = build_int_cst_wide (type,
+                               CONST_DOUBLE_LOW (x), CONST_DOUBLE_HIGH (x));
       else
        {
          REAL_VALUE_TYPE d;
@@ -4491,17 +4910,15 @@ make_tree (tree type, rtx x)
 
     case LSHIFTRT:
       t = lang_hooks.types.unsigned_type (type);
-      return fold (convert (type,
-                           build2 (RSHIFT_EXPR, t,
-                                   make_tree (t, XEXP (x, 0)),
-                                   make_tree (type, XEXP (x, 1)))));
+      return fold_convert (type, build2 (RSHIFT_EXPR, t,
+                                        make_tree (t, XEXP (x, 0)),
+                                        make_tree (type, XEXP (x, 1))));
 
     case ASHIFTRT:
       t = lang_hooks.types.signed_type (type);
-      return fold (convert (type,
-                           build2 (RSHIFT_EXPR, t,
-                                   make_tree (t, XEXP (x, 0)),
-                                   make_tree (type, XEXP (x, 1)))));
+      return fold_convert (type, build2 (RSHIFT_EXPR, t,
+                                        make_tree (t, XEXP (x, 0)),
+                                        make_tree (type, XEXP (x, 1))));
 
     case DIV:
       if (TREE_CODE (type) != REAL_TYPE)
@@ -4509,22 +4926,20 @@ make_tree (tree type, rtx x)
       else
        t = type;
 
-      return fold (convert (type,
-                           build2 (TRUNC_DIV_EXPR, t,
-                                   make_tree (t, XEXP (x, 0)),
-                                   make_tree (t, XEXP (x, 1)))));
+      return fold_convert (type, build2 (TRUNC_DIV_EXPR, t,
+                                        make_tree (t, XEXP (x, 0)),
+                                        make_tree (t, XEXP (x, 1))));
     case UDIV:
       t = lang_hooks.types.unsigned_type (type);
-      return fold (convert (type,
-                           build2 (TRUNC_DIV_EXPR, t,
-                                   make_tree (t, XEXP (x, 0)),
-                                   make_tree (t, XEXP (x, 1)))));
+      return fold_convert (type, build2 (TRUNC_DIV_EXPR, t,
+                                        make_tree (t, XEXP (x, 0)),
+                                        make_tree (t, XEXP (x, 1))));
 
     case SIGN_EXTEND:
     case ZERO_EXTEND:
       t = lang_hooks.types.type_for_mode (GET_MODE (XEXP (x, 0)),
                                          GET_CODE (x) == ZERO_EXTEND);
-      return fold (convert (type, make_tree (t, XEXP (x, 0))));
+      return fold_convert (type, make_tree (t, XEXP (x, 0)));
 
     default:
       t = build_decl (VAR_DECL, NULL_TREE, type);
@@ -4550,7 +4965,8 @@ make_tree (tree type, rtx x)
    UNSIGNEDP is nonzero to do unsigned multiplication.  */
 
 bool
-const_mult_add_overflow_p (rtx x, rtx mult, rtx add, enum machine_mode mode, int unsignedp)
+const_mult_add_overflow_p (rtx x, rtx mult, rtx add,
+                          enum machine_mode mode, int unsignedp)
 {
   tree type, mult_type, add_type, result;
 
@@ -4561,7 +4977,9 @@ const_mult_add_overflow_p (rtx x, rtx mult, rtx add, enum machine_mode mode, int
   mult_type = type;
   if (unsignedp)
     {
-      mult_type = copy_node (type);
+      /* FIXME:It would be nice if we could step directly from this
+        type to its sizetype equivalent.  */
+      mult_type = build_distinct_type_copy (type);
       TYPE_IS_SIZETYPE (mult_type) = 1;
     }
 
@@ -4795,20 +5213,23 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
        = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX);
       if (CONSTANT_P (comparison))
        {
-         if (GET_CODE (comparison) == CONST_INT)
+         switch (GET_CODE (comparison))
            {
+           case CONST_INT:
              if (comparison == const0_rtx)
                return const0_rtx;
-           }
+             break;
+             
 #ifdef FLOAT_STORE_FLAG_VALUE
-         else if (GET_CODE (comparison) == CONST_DOUBLE)
-           {
+           case CONST_DOUBLE:
              if (comparison == CONST0_RTX (GET_MODE (comparison)))
                return const0_rtx;
-           }
+             break;
 #endif
-         else
-           abort ();
+           default:
+             gcc_unreachable ();
+           }
+         
          if (normalizep == 1)
            return const1_rtx;
          if (normalizep == -1)
@@ -4883,14 +5304,14 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
            op0 = expand_shift (RSHIFT_EXPR, compare_mode, op0,
                                size_int (GET_MODE_BITSIZE (compare_mode) - 1),
                                subtarget, normalizep == 1);
-         else if (STORE_FLAG_VALUE & 1)
+         else
            {
+             gcc_assert (STORE_FLAG_VALUE & 1);
+             
              op0 = expand_and (compare_mode, op0, const1_rtx, subtarget);
              if (normalizep == -1)
                op0 = expand_unop (compare_mode, neg_optab, op0, op0, 0);
            }
-         else
-           abort ();
 
          /* If we were converting to a smaller mode, do the
             conversion now.  */
@@ -5158,19 +5579,17 @@ do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, enum machine_mode mode,
          /* do_jump_by_parts_equality_rtx compares with zero.  Luckily
             that's the only equality operations we do */
        case EQ:
-         if (arg2 != const0_rtx || mode != GET_MODE(arg1))
-           abort ();
+         gcc_assert (arg2 == const0_rtx && mode == GET_MODE(arg1));
          do_jump_by_parts_equality_rtx (arg1, label2, label);
          break;
 
        case NE:
-         if (arg2 != const0_rtx || mode != GET_MODE(arg1))
-           abort ();
+         gcc_assert (arg2 == const0_rtx && mode == GET_MODE(arg1));
          do_jump_by_parts_equality_rtx (arg1, label, label2);
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       emit_label (label2);