OSDN Git Service

(c_sizeof, build_c_cast): Set TREE_OVERFLOW in addition
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index f0b24a0..6fb8579 100644 (file)
@@ -1,6 +1,6 @@
 /* Medium-level subroutines: convert bit-field store and extract
    and shifts, multiplies and divides to rtl instructions.
-   Copyright (C) 1987, 1988, 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -49,59 +49,102 @@ int mult_is_very_cheap;
 
 static int sdiv_pow2_cheap, smod_pow2_cheap;
 
-/* Cost of various pieces of RTL.  */
-static int add_cost, shift_cost, mult_cost, negate_cost, lea_cost;
+/* For compilers that support multiple targets with different word sizes,
+   MAX_BITS_PER_WORD contains the biggest value of BITS_PER_WORD.  An example
+   is the H8/300(H) compiler.  */
 
-/* Max scale factor for scaled address in lea instruction.  */
-static int lea_max_mul;
+#ifndef MAX_BITS_PER_WORD
+#define MAX_BITS_PER_WORD BITS_PER_WORD
+#endif
+
+/* Cost of various pieces of RTL.  */
+static int add_cost, mult_cost, negate_cost, zero_cost;
+static int shift_cost[MAX_BITS_PER_WORD];
+static int shiftadd_cost[MAX_BITS_PER_WORD];
+static int shiftsub_cost[MAX_BITS_PER_WORD];
 
 void
 init_expmed ()
 {
-  char *free_point = (char *) oballoc (1);
+  char *free_point;
   /* This is "some random pseudo register" for purposes of calling recog
      to see what insns exist.  */
   rtx reg = gen_rtx (REG, word_mode, FIRST_PSEUDO_REGISTER);
-  rtx pow2 = gen_rtx (CONST_INT, VOIDmode, 32);
-  rtx lea;
-  int i, dummy;
-
-  add_cost = rtx_cost (gen_rtx (PLUS, word_mode, reg, reg));
-  shift_cost = rtx_cost (gen_rtx (LSHIFT, word_mode, reg,
-                                 /* Using a constant gives better
-                                    estimate of typical costs.
-                                    1 or 2 might have quirks.  */
-                                 gen_rtx (CONST_INT, VOIDmode, 3)));
-  mult_cost = rtx_cost (gen_rtx (MULT, word_mode, reg, reg));
-  negate_cost = rtx_cost (gen_rtx (NEG, word_mode, reg));
+  rtx shift_insn, shiftadd_insn, shiftsub_insn;
+  int dummy;
+  int m;
 
-  mult_is_very_cheap
-    = (rtx_cost (gen_rtx (MULT, word_mode, reg,
-                         gen_rtx (CONST_INT, VOIDmode, 128)))
-       < rtx_cost (gen_rtx (LSHIFT, word_mode, reg,
-                           gen_rtx (CONST_INT, VOIDmode, 7))));
+  start_sequence ();
 
-  sdiv_pow2_cheap
-    = rtx_cost (gen_rtx (DIV, word_mode, reg, pow2)) <= 2 * add_cost;
-  smod_pow2_cheap
-    = rtx_cost (gen_rtx (MOD, word_mode, reg, pow2)) <= 2 * add_cost;
+  /* Since we are on the permanent obstack, we must be sure we save this
+     spot AFTER we call start_sequence, since it will reuse the rtl it
+     makes.  */
+
+  free_point = (char *) oballoc (0);
+
+  zero_cost = rtx_cost (const0_rtx, 0);
+  add_cost = rtx_cost (gen_rtx (PLUS, word_mode, reg, reg), SET);
+
+  shift_insn = emit_insn (gen_rtx (SET, VOIDmode, reg,
+                                  gen_rtx (ASHIFT, word_mode, reg,
+                                           const0_rtx)));
+
+  shiftadd_insn = emit_insn (gen_rtx (SET, VOIDmode, reg,
+                                     gen_rtx (PLUS, word_mode,
+                                              gen_rtx (MULT, word_mode,
+                                                       reg, const0_rtx),
+                                              reg)));
+
+  shiftsub_insn = emit_insn (gen_rtx (SET, VOIDmode, reg,
+                                     gen_rtx (MINUS, word_mode,
+                                              gen_rtx (MULT, word_mode,
+                                                        reg, const0_rtx),
+                                               reg)));
 
   init_recog ();
-  for (i = 2;; i <<= 1)
+
+  shift_cost[0] = 0;
+  shiftadd_cost[0] = shiftsub_cost[0] = add_cost;
+
+  for (m = 1; m < BITS_PER_WORD; m++)
     {
-      lea = gen_rtx (SET, VOIDmode, reg,
-                    gen_rtx (PLUS, word_mode, reg,
-                             gen_rtx (MULT, word_mode, reg,
-                                      gen_rtx (CONST_INT, VOIDmode, i))));
-      /* Using 0 as second argument is not quite right,
-        but what else is there to do?  */
-      if (recog (lea, 0, &dummy) < 0)
-       break;
-      lea_max_mul = i;
-      lea_cost = rtx_cost (SET_SRC (lea));
+      shift_cost[m] = shiftadd_cost[m] = shiftsub_cost[m] = 32000;
+
+      XEXP (SET_SRC (PATTERN (shift_insn)), 1) = GEN_INT (m);
+      if (recog (PATTERN (shift_insn), shift_insn, &dummy) >= 0)
+       shift_cost[m] = rtx_cost (SET_SRC (PATTERN (shift_insn)), SET);
+
+      XEXP (XEXP (SET_SRC (PATTERN (shiftadd_insn)), 0), 1)
+       = GEN_INT ((HOST_WIDE_INT) 1 << m);
+      if (recog (PATTERN (shiftadd_insn), shiftadd_insn, &dummy) >= 0)
+       shiftadd_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftadd_insn)), SET);
+
+      XEXP (XEXP (SET_SRC (PATTERN (shiftsub_insn)), 0), 1)
+       = GEN_INT ((HOST_WIDE_INT) 1 << m);
+      if (recog (PATTERN (shiftsub_insn), shiftsub_insn, &dummy) >= 0)
+       shiftsub_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftsub_insn)), SET);
     }
 
+  mult_cost = rtx_cost (gen_rtx (MULT, word_mode, reg, reg), SET);
+  /* For gcc 2.4 keep MULT_COST small to avoid really slow searches
+     in synth_mult.  */
+  mult_cost = MIN (12 * add_cost, mult_cost);
+  negate_cost = rtx_cost (gen_rtx (NEG, word_mode, reg), SET);
+
+  /* 999999 is chosen to avoid any plausible faster special case.  */
+  mult_is_very_cheap
+    = (rtx_cost (gen_rtx (MULT, word_mode, reg, GEN_INT (999999)), SET)
+       < rtx_cost (gen_rtx (ASHIFT, word_mode, reg, GEN_INT (7)), SET));
+
+  sdiv_pow2_cheap
+    = (rtx_cost (gen_rtx (DIV, word_mode, reg, GEN_INT (32)), SET)
+       <= 2 * add_cost);
+  smod_pow2_cheap
+    = (rtx_cost (gen_rtx (MOD, word_mode, reg, GEN_INT (32)), SET)
+       <= 2 * add_cost);
+
   /* Free the objects we just allocated.  */
+  end_sequence ();
   obfree (free_point);
 }
 
@@ -116,19 +159,19 @@ negate_rtx (mode, x)
 {
   if (GET_CODE (x) == CONST_INT)
     {
-      int val = - INTVAL (x);
-      if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_INT)
+      HOST_WIDE_INT val = - INTVAL (x);
+      if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT)
        {
          /* Sign extend the value from the bits that are significant.  */
-         if (val & (1 << (GET_MODE_BITSIZE (mode) - 1)))
-           val |= (-1) << GET_MODE_BITSIZE (mode);
+         if (val & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))
+           val |= (HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (mode);
          else
-           val &= (1 << GET_MODE_BITSIZE (mode)) - 1;
+           val &= ((HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (mode)) - 1;
        }
-      return gen_rtx (CONST_INT, VOIDmode, val);
+      return GEN_INT (val);
     }
   else
-    return expand_unop (GET_MODE (x), neg_optab, x, 0, 0);
+    return expand_unop (GET_MODE (x), neg_optab, x, NULL_RTX, 0);
 }
 \f
 /* Generate code to store value from rtx VALUE
@@ -198,13 +241,18 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
 
   /* Note that the adjustment of BITPOS above has no effect on whether
      BITPOS is 0 in a REG bigger than a word.  */
-  if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD && GET_CODE (op0) != MEM
+  if (GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
+      && (! STRICT_ALIGNMENT || GET_CODE (op0) != MEM)
       && bitpos == 0 && bitsize == GET_MODE_BITSIZE (fieldmode))
     {
       /* Storing in a full-word or multi-word field in a register
         can be done with just SUBREG.  */
       if (GET_MODE (op0) != fieldmode)
-       op0 = gen_rtx (SUBREG, fieldmode, op0, offset);
+       if (GET_CODE (op0) == REG)
+         op0 = gen_rtx (SUBREG, fieldmode, op0, offset);
+       else
+         op0 = change_address (op0, fieldmode,
+                               plus_constant (XEXP (op0, 0), offset));
       emit_move_insn (op0, value);
       return value;
     }
@@ -339,9 +387,8 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
          if (GET_MODE (op0) == BLKmode
              || GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (maxmode))
            bestmode
-             = get_best_mode (bitsize, bitnum,
-                              align * BITS_PER_UNIT, maxmode,
-                              GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0));
+             = get_best_mode (bitsize, bitnum, align * BITS_PER_UNIT, maxmode,
+                              MEM_VOLATILE_P (op0));
          else
            bestmode = GET_MODE (op0);
 
@@ -398,12 +445,18 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
          if (GET_MODE_BITSIZE (GET_MODE (value)) >= bitsize)
            {
              /* Optimization: Don't bother really extending VALUE
-                if it has all the bits we will actually use.  */
+                if it has all the bits we will actually use.  However,
+                if we must narrow it, be sure we do it correctly.  */
 
-             /* Avoid making subreg of a subreg, or of a mem.  */
-             if (GET_CODE (value1) != REG)
+             if (GET_MODE_SIZE (GET_MODE (value)) < GET_MODE_SIZE (maxmode))
+               {
+                 /* Avoid making subreg of a subreg, or of a mem.  */
+                 if (GET_CODE (value1) != REG)
                value1 = copy_to_reg (value1);
-             value1 = gen_rtx (SUBREG, maxmode, value1, 0);
+                 value1 = gen_rtx (SUBREG, maxmode, value1, 0);
+               }
+             else
+               value1 = gen_lowpart (maxmode, value1);
            }
          else if (!CONSTANT_P (value))
            /* Parse phase is supposed to make VALUE's data type
@@ -419,10 +472,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
             (value1, maxmode)))
        value1 = force_reg (maxmode, value1);
 
-      pat = gen_insv (xop0,
-                     gen_rtx (CONST_INT, VOIDmode, bitsize),
-                     gen_rtx (CONST_INT, VOIDmode, xbitpos),
-                     value1);
+      pat = gen_insv (xop0, GEN_INT (bitsize), GEN_INT (xbitpos), value1);
       if (pat)
        emit_insn (pat);
       else
@@ -540,15 +590,16 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align)
 
   if (GET_CODE (value) == CONST_INT)
     {
-      register int v = INTVAL (value);
+      register HOST_WIDE_INT v = INTVAL (value);
 
-      if (bitsize < HOST_BITS_PER_INT)
-       v &= (1 << bitsize) - 1;
+      if (bitsize < HOST_BITS_PER_WIDE_INT)
+       v &= ((HOST_WIDE_INT) 1 << bitsize) - 1;
 
       if (v == 0)
        all_zero = 1;
-      else if ((bitsize < HOST_BITS_PER_INT && v == (1 << bitsize) - 1)
-              || (bitsize == HOST_BITS_PER_INT && v == -1))
+      else if ((bitsize < HOST_BITS_PER_WIDE_INT
+               && v == ((HOST_WIDE_INT) 1 << bitsize) - 1)
+              || (bitsize == HOST_BITS_PER_WIDE_INT && v == -1))
        all_one = 1;
 
       value = lshift_value (mode, value, bitpos, bitsize);
@@ -581,10 +632,10 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align)
       if (must_and)
        value = expand_binop (mode, and_optab, value,
                              mask_rtx (mode, 0, bitsize, 0),
-                             0, 1, OPTAB_LIB_WIDEN);
+                             NULL_RTX, 1, OPTAB_LIB_WIDEN);
       if (bitpos > 0)
        value = expand_shift (LSHIFT_EXPR, mode, value,
-                             build_int_2 (bitpos, 0), 0, 1);
+                             build_int_2 (bitpos, 0), NULL_RTX, 1);
     }
 
   /* Now clear the chosen bits in OP0,
@@ -640,8 +691,13 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
 
   if (GET_MODE (value) != VOIDmode)
     value = convert_to_mode (word_mode, value, 1);
+
+  if (GET_CODE (value) == CONST_DOUBLE
+      && (part1 = gen_lowpart_common (word_mode, value)) != 0)
+    value = part1;
+
   if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT)
-    value = copy_to_reg (value);
+    value = copy_to_mode_reg (word_mode, value);
 
   /* Split the value into two parts:
      PART1 gets that which goes in the first word; PART2 the other.  */
@@ -649,35 +705,33 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
   /* PART1 gets the more significant part.  */
   if (GET_CODE (value) == CONST_INT)
     {
-      part1 = gen_rtx (CONST_INT, VOIDmode,
-                      (unsigned) (INTVAL (value)) >> bitsize_2);
-      part2 = gen_rtx (CONST_INT, VOIDmode,
-                      (unsigned) (INTVAL (value)) & ((1 << bitsize_2) - 1));
+      part1 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) >> bitsize_2);
+      part2 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value))
+                      & (((HOST_WIDE_INT) 1 << bitsize_2) - 1));
     }
   else
     {
       part1 = extract_fixed_bit_field (word_mode, value, 0, bitsize_1,
-                                      BITS_PER_WORD - bitsize, 0, 1,
+                                      BITS_PER_WORD - bitsize, NULL_RTX, 1,
                                       BITS_PER_WORD);
       part2 = extract_fixed_bit_field (word_mode, value, 0, bitsize_2,
-                                      BITS_PER_WORD - bitsize_2, 0, 1,
+                                      BITS_PER_WORD - bitsize_2, NULL_RTX, 1,
                                       BITS_PER_WORD);
     }
 #else
   /* PART1 gets the less significant part.  */
   if (GET_CODE (value) == CONST_INT)
     {
-      part1 = gen_rtx (CONST_INT, VOIDmode,
-                      (unsigned) (INTVAL (value)) & ((1 << bitsize_1) - 1));
-      part2 = gen_rtx (CONST_INT, VOIDmode,
-                      (unsigned) (INTVAL (value)) >> bitsize_1);
+      part1 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value))
+                      & (((HOST_WIDE_INT) 1 << bitsize_1) - 1));
+      part2 = GEN_INT ((unsigned HOST_WIDE_INT) (INTVAL (value)) >> bitsize_1);
     }
   else
     {
       part1 = extract_fixed_bit_field (word_mode, value, 0, bitsize_1, 0,
-                                      0, 1, BITS_PER_WORD);
+                                      NULL_RTX, 1, BITS_PER_WORD);
       part2 = extract_fixed_bit_field (word_mode, value, 0, bitsize_2,
-                                      bitsize_1, 0, 1, BITS_PER_WORD);
+                                      bitsize_1, NULL_RTX, 1, BITS_PER_WORD);
     }
 #endif
 
@@ -763,7 +817,6 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
 
   if (tmode == VOIDmode)
     tmode = mode;
-
   while (GET_CODE (op0) == SUBREG)
     {
       offset += SUBREG_WORD (op0);
@@ -912,8 +965,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
                          > GET_MODE_SIZE (maxmode)))
                    bestmode = get_best_mode (bitsize, bitnum,
                                              align * BITS_PER_UNIT, maxmode,
-                                             (GET_CODE (xop0) == MEM
-                                              && MEM_VOLATILE_P (xop0)));
+                                             MEM_VOLATILE_P (xop0));
                  else
                    bestmode = GET_MODE (xop0);
 
@@ -967,7 +1019,13 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
          if (GET_MODE (xtarget) != maxmode)
            {
              if (GET_CODE (xtarget) == REG)
-               xspec_target_subreg = xtarget = gen_lowpart (maxmode, xtarget);
+               {
+                 int wider = (GET_MODE_SIZE (maxmode)
+                              > GET_MODE_SIZE (GET_MODE (xtarget)));
+                 xtarget = gen_lowpart (maxmode, xtarget);
+                 if (wider)
+                   xspec_target_subreg = xtarget;
+               }
              else
                xtarget = gen_reg_rtx (maxmode);
            }
@@ -978,8 +1036,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
                 (xtarget, maxmode)))
            xtarget = gen_reg_rtx (maxmode);
 
-         bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize);
-         bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, xbitpos);
+         bitsize_rtx = GEN_INT (bitsize);
+         bitpos_rtx = GEN_INT (xbitpos);
 
          pat = gen_extzv (protect_from_queue (xtarget, 1),
                           xop0, bitsize_rtx, bitpos_rtx);
@@ -1040,8 +1098,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
                          > GET_MODE_SIZE (maxmode)))
                    bestmode = get_best_mode (bitsize, bitnum,
                                              align * BITS_PER_UNIT, maxmode,
-                                             (GET_CODE (xop0) == MEM
-                                              && MEM_VOLATILE_P (xop0)));
+                                             MEM_VOLATILE_P (xop0));
                  else
                    bestmode = GET_MODE (xop0);
 
@@ -1094,7 +1151,13 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
          if (GET_MODE (xtarget) != maxmode)
            {
              if (GET_CODE (xtarget) == REG)
-               xspec_target_subreg = xtarget = gen_lowpart (maxmode, xtarget);
+               {
+                 int wider = (GET_MODE_SIZE (maxmode)
+                              > GET_MODE_SIZE (GET_MODE (xtarget)));
+                 xtarget = gen_lowpart (maxmode, xtarget);
+                 if (wider)
+                   xspec_target_subreg = xtarget;
+               }
              else
                xtarget = gen_reg_rtx (maxmode);
            }
@@ -1105,8 +1168,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
                 (xtarget, maxmode)))
            xtarget = gen_reg_rtx (maxmode);
 
-         bitsize_rtx = gen_rtx (CONST_INT, VOIDmode, bitsize);
-         bitpos_rtx = gen_rtx (CONST_INT, VOIDmode, xbitpos);
+         bitsize_rtx = GEN_INT (bitsize);
+         bitpos_rtx = GEN_INT (xbitpos);
 
          pat = gen_extv (protect_from_queue (xtarget, 1),
                          xop0, bitsize_rtx, bitpos_rtx);
@@ -1210,6 +1273,16 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
 
       total_bits = GET_MODE_BITSIZE (mode);
 
+      /* Make sure bitpos is valid for the chosen mode.  Adjust BITPOS to
+        be be in the range 0 to total_bits-1, and put any excess bytes in
+        OFFSET.  */
+      if (bitpos >= total_bits)
+       {
+         offset += (bitpos / total_bits) * (total_bits / BITS_PER_UNIT);
+         bitpos -= ((bitpos / total_bits) * (total_bits / BITS_PER_UNIT)
+                    * BITS_PER_UNIT);
+       }
+
       /* Get ref to an aligned byte, halfword, or word containing the field.
         Adjust BITPOS to be position within a word,
         and OFFSET to be the offset of that word.
@@ -1311,23 +1384,25 @@ mask_rtx (mode, bitpos, bitsize, complement)
      enum machine_mode mode;
      int bitpos, bitsize, complement;
 {
-  int masklow, maskhigh;
+  HOST_WIDE_INT masklow, maskhigh;
 
-  if (bitpos < HOST_BITS_PER_INT)
-    masklow = -1 << bitpos;
+  if (bitpos < HOST_BITS_PER_WIDE_INT)
+    masklow = (HOST_WIDE_INT) -1 << bitpos;
   else
     masklow = 0;
 
-  if (bitpos + bitsize < HOST_BITS_PER_INT)
-    masklow &= (unsigned) -1 >> (HOST_BITS_PER_INT - bitpos - bitsize);
+  if (bitpos + bitsize < HOST_BITS_PER_WIDE_INT)
+    masklow &= ((unsigned HOST_WIDE_INT) -1
+               >> (HOST_BITS_PER_WIDE_INT - bitpos - bitsize));
   
-  if (bitpos <= HOST_BITS_PER_INT)
+  if (bitpos <= HOST_BITS_PER_WIDE_INT)
     maskhigh = -1;
   else
-    maskhigh = -1 << (bitpos - HOST_BITS_PER_INT);
+    maskhigh = (HOST_WIDE_INT) -1 << (bitpos - HOST_BITS_PER_WIDE_INT);
 
-  if (bitpos + bitsize > HOST_BITS_PER_INT)
-    maskhigh &= (unsigned) -1 >> (2 * HOST_BITS_PER_INT - bitpos - bitsize);
+  if (bitpos + bitsize > HOST_BITS_PER_WIDE_INT)
+    maskhigh &= ((unsigned HOST_WIDE_INT) -1
+                >> (2 * HOST_BITS_PER_WIDE_INT - bitpos - bitsize));
   else
     maskhigh = 0;
 
@@ -1349,21 +1424,21 @@ lshift_value (mode, value, bitpos, bitsize)
      rtx value;
      int bitpos, bitsize;
 {
-  unsigned v = INTVAL (value);
-  int low, high;
+  unsigned HOST_WIDE_INT v = INTVAL (value);
+  HOST_WIDE_INT low, high;
 
-  if (bitsize < HOST_BITS_PER_INT)
-    v &= ~(-1 << bitsize);
+  if (bitsize < HOST_BITS_PER_WIDE_INT)
+    v &= ~((HOST_WIDE_INT) -1 << bitsize);
 
-  if (bitpos < HOST_BITS_PER_INT)
+  if (bitpos < HOST_BITS_PER_WIDE_INT)
     {
       low = v << bitpos;
-      high = (bitpos > 0 ? (v >> (HOST_BITS_PER_INT - bitpos)) : 0);
+      high = (bitpos > 0 ? (v >> (HOST_BITS_PER_WIDE_INT - bitpos)) : 0);
     }
   else
     {
       low = 0;
-      high = v << (bitpos - HOST_BITS_PER_INT);
+      high = v << (bitpos - HOST_BITS_PER_WIDE_INT);
     }
 
   return immed_double_const (low, high, mode);
@@ -1401,7 +1476,8 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
          : operand_subword_force (op0, offset, GET_MODE (op0)));
   part1 = extract_fixed_bit_field (word_mode, word,
                                   GET_CODE (op0) == MEM ? offset : 0,
-                                  bitsize_1, bitpos % unit, 0, 1, align);
+                                  bitsize_1, bitpos % unit, NULL_RTX,
+                                  1, align);
 
   /* Offset op0 by 1 word to get to the following one.  */
   if (GET_CODE (op0) == SUBREG)
@@ -1417,7 +1493,7 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
                                   (GET_CODE (op0) == MEM
                                    ? CEIL (offset + 1, UNITS_PER_WORD) * UNITS_PER_WORD
                                    : 0),
-                                  bitsize_2, 0, 0, 1, align);
+                                  bitsize_2, 0, NULL_RTX, 1, align);
 
   /* Shift the more significant part up to fit above the other part.  */
 #if BYTES_BIG_ENDIAN
@@ -1430,7 +1506,7 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
 
   /* Combine the two parts with bitwise or.  This works
      because we extracted both parts as unsigned bit fields.  */
-  result = expand_binop (word_mode, ior_optab, part1, part2, 0, 1,
+  result = expand_binop (word_mode, ior_optab, part1, part2, NULL_RTX, 1,
                         OPTAB_LIB_WIDEN);
 
   /* Unsigned bit field: we are done.  */
@@ -1438,9 +1514,10 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
     return result;
   /* Signed bit field: sign-extend with two arithmetic shifts.  */
   result = expand_shift (LSHIFT_EXPR, word_mode, result,
-                        build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0);
+                        build_int_2 (BITS_PER_WORD - bitsize, 0),
+                        NULL_RTX, 0);
   return expand_shift (RSHIFT_EXPR, word_mode, result,
-                      build_int_2 (BITS_PER_WORD - bitsize, 0), 0, 0);
+                      build_int_2 (BITS_PER_WORD - bitsize, 0), NULL_RTX, 0);
 }
 \f
 /* Add INC into TARGET.  */
@@ -1494,7 +1571,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
      and shifted in the other direction; but that does not work
      on all machines.  */
 
-  op1 = expand_expr (amount, 0, VOIDmode, 0);
+  op1 = expand_expr (amount, NULL_RTX, VOIDmode, 0);
 
   if (op1 == const0_rtx)
     return shifted;
@@ -1516,11 +1593,56 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
          if (methods == OPTAB_WIDEN)
            continue;
          else if (methods == OPTAB_LIB_WIDEN)
-           methods = OPTAB_LIB;
+           {
+             /* If we are rotating by a constant that is valid and
+                we have been unable to open-code this by a rotation,
+                do it as the IOR of two shifts.  I.e., to rotate A
+                by N bits, compute (A << N) | ((unsigned) A >> (C - N))
+                where C is the bitsize of A.
+
+                It is theoretically possible that the target machine might
+                not be able to perform either shift and hence we would
+                be making two libcalls rather than just the one for the
+                shift (similarly if IOR could not be done).  We will allow
+                this extremely unlikely lossage to avoid complicating the
+                code below.  */
+
+             if (GET_CODE (op1) == CONST_INT && INTVAL (op1) > 0
+                 && INTVAL (op1) < GET_MODE_BITSIZE (mode))
+               {
+                 rtx subtarget = target == shifted ? 0 : target;
+                 rtx temp1;
+                 tree other_amount
+                   = build_int_2 (GET_MODE_BITSIZE (mode) - INTVAL (op1), 0);
+
+                 shifted = force_reg (mode, shifted);
+
+                 temp = expand_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR,
+                                      mode, shifted, amount, subtarget, 1);
+                 temp1 = expand_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR,
+                                       mode, shifted, other_amount, 0, 1);
+                 return expand_binop (mode, ior_optab, temp, temp1, target,
+                                      unsignedp, methods);
+               }
+             else
+               methods = OPTAB_LIB;
+           }
 
          temp = expand_binop (mode,
                               left ? rotl_optab : rotr_optab,
                               shifted, op1, target, unsignedp, methods);
+
+         /* If we don't have the rotate, but we are rotating by a constant
+            that is in range, try a rotate in the opposite direction.  */
+
+         if (temp == 0 && GET_CODE (op1) == CONST_INT
+             && INTVAL (op1) > 0 && INTVAL (op1) < GET_MODE_BITSIZE (mode))
+           temp = expand_binop (mode,
+                                left ? rotr_optab : rotl_optab,
+                                shifted, 
+                                GEN_INT (GET_MODE_BITSIZE (mode)
+                                         - INTVAL (op1)),
+                                target, unsignedp, methods);
        }
       else if (unsignedp)
        {
@@ -1567,8 +1689,9 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
              || (methods == OPTAB_WIDEN
                  && GET_MODE_SIZE (mode) < GET_MODE_SIZE (output_mode)))
            {
-             /* Note convert_to_mode does protect_from_queue.  */
-             rtx shifted1 = convert_to_mode (output_mode, shifted, 1);
+             rtx shifted1 = convert_to_mode (output_mode,
+                                             protect_from_queue (shifted, 0),
+                                             1);
              enum machine_mode length_mode
                = insn_operand_mode[(int) CODE_FOR_extzv][2];
              enum machine_mode pos_mode
@@ -1596,6 +1719,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
                        (target1, output_mode)))
                target1 = gen_reg_rtx (output_mode);
 
+             xop1 = protect_from_queue (xop1, 0);
              xop1 = convert_to_mode (pos_mode, xop1,
                                      TREE_UNSIGNED (TREE_TYPE (amount)));
 
@@ -1608,18 +1732,17 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
              /* WIDTH gets the width of the bit field to extract:
                 wordsize minus # bits to shift by.  */
              if (GET_CODE (xop1) == CONST_INT)
-               width = gen_rtx (CONST_INT, VOIDmode,
-                                (GET_MODE_BITSIZE (mode) - INTVAL (op1)));
+               width = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1));
              else
                {
                  /* Now get the width in the proper mode.  */
+                 op1 = protect_from_queue (op1, 0);
                  width = convert_to_mode (length_mode, op1,
                                           TREE_UNSIGNED (TREE_TYPE (amount)));
 
                  width = expand_binop (length_mode, sub_optab,
-                                       gen_rtx (CONST_INT, VOIDmode,
-                                                GET_MODE_BITSIZE (mode)),
-                                       width, 0, 0, OPTAB_LIB_WIDEN);
+                                       GEN_INT (GET_MODE_BITSIZE (mode)),
+                                       width, NULL_RTX, 0, OPTAB_LIB_WIDEN);
                }
 
              /* If this machine's extzv insists on a register for
@@ -1651,270 +1774,261 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
   return temp;
 }
 \f
-enum alg_code { alg_add, alg_subtract, alg_compound };
+enum alg_code { 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 };
 
 /* This structure records a sequence of operations.
    `ops' is the number of operations recorded.
    `cost' is their total cost.
    The operations are stored in `op' and the corresponding
-   integer coefficients in `coeff'.
-   These are the operations:
-   alg_add       Add to the total the multiplicand times the coefficient.
-   alg_subtract  Subtract the multiplicand times the coefficient.
-   alg_compound  This coefficient plus or minus the following one
-                 is multiplied into the total.  The following operation
-                 is alg_add or alg_subtract to indicate whether to add
-                or subtract the two coefficients.  */
+   logarithms of the integer coefficients in `log'.
 
-#ifndef MAX_BITS_PER_WORD
-#define MAX_BITS_PER_WORD BITS_PER_WORD
-#endif
+   These are the operations:
+   alg_zero            total := 0;
+   alg_m               total := multiplicand;
+   alg_shift           total := total * coeff
+   alg_add_t_m2                total := total + multiplicand * coeff;
+   alg_sub_t_m2                total := total - multiplicand * coeff;
+   alg_add_factor      total := total * coeff + total;
+   alg_sub_factor      total := total * coeff - total;
+   alg_add_t2_m                total := total * coeff + multiplicand;
+   alg_sub_t2_m                total := total * coeff - multiplicand;
+
+   The first operand must be either alg_zero or alg_m.  */
 
 struct algorithm
 {
-  int cost;
-  unsigned int ops;
+  short 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
+     consecutive ones or zeros, i.e., a multiplicand like 10101010101...
+     In that case we will generate shift-by-2, add, shift-by-2, add,...,
+     in total wordsize operations.  */
   enum alg_code op[MAX_BITS_PER_WORD];
-  unsigned int coeff[MAX_BITS_PER_WORD];
+  char log[MAX_BITS_PER_WORD];
 };
 
 /* Compute and return the best algorithm for multiplying by T.
-   Assume that add insns cost ADD_COST and shifts cost SHIFT_COST.
-   Return cost -1 if would cost more than MAX_COST.  */
+   The algorithm must cost less than cost_limit
+   If retval.cost >= COST_LIMIT, no algorithm was found and all
+   other field of the returned struct are undefined.  */
 
 static struct algorithm
-synth_mult (t, add_cost, shift_cost, max_cost)
-     unsigned int t;
-     int add_cost, shift_cost;
-     int max_cost;
+synth_mult (t, cost_limit)
+     unsigned HOST_WIDE_INT t;
+     int cost_limit;
 {
-  int m, n;
-  struct algorithm *best_alg = (struct algorithm *)alloca (sizeof (struct algorithm));
-  struct algorithm *alg_in = (struct algorithm *)alloca (sizeof (struct algorithm));
+  int m;
+  struct algorithm *best_alg
+    = (struct algorithm *)alloca (sizeof (struct algorithm));
+  struct algorithm *alg_in
+    = (struct algorithm *)alloca (sizeof (struct algorithm));
   unsigned int cost;
+  unsigned HOST_WIDE_INT q;
 
-  /* No matter what happens, we want to return a valid algorithm.  */
-  best_alg->cost = max_cost;
-  best_alg->ops = 0;
-
-  /* Is t an exponent of 2, so we can just do a shift?  */
+  /* Indicate that no algorithm is yet found.  If no algorithm
+     is found, this value will be returned and indicate failure.  */
+  best_alg->cost = cost_limit;
 
-  if ((t & -t) == t)
-    {
-      if (t > 1)
-       {
-         if (max_cost >= shift_cost)
-           {
-             best_alg->cost = shift_cost;
-             best_alg->ops = 1;
-             best_alg->op[0] = alg_add;
-             best_alg->coeff[0] = t;
-           }
-         else
-           best_alg->cost = -1;
-       }
-      else if (t == 1)
-       {
-         if (max_cost >= 0)
-           best_alg->cost = 0;
-       }
-      else
-       best_alg->cost = 0;
-
-      return *best_alg;
-    }
+  if (cost_limit <= 0)
+    return *best_alg;
 
-  /* If MAX_COST just permits as little as an addition (or less), we won't
-     succeed in synthesizing an algorithm for t.  Return immediately with
-     an indication of failure.  */
-  if (max_cost <= add_cost)
+  /* t == 1 can be done in zero cost.  */
+  if (t == 1)
     {
-      best_alg->cost = -1;
+      best_alg->ops = 1;
+      best_alg->cost = 0;
+      best_alg->op[0] = alg_m;
       return *best_alg;
     }
 
-  /* Look for factors of t of the form
-     t = q(2**m +- 1), 2 <= m <= floor(log2(t)) - 1.
-     If we find such a factor, we can multiply by t using an algorithm that
-     multiplies by q, shift the result by m and add/subtract it to itself.  */
+  /* t == 0 sometimes has a cost.  If it does and it exceeds our limit,
+     fail now.  */
 
-  for (m = floor_log2 (t) - 1; m >= 2; m--)
+  else if (t == 0)
     {
-      int m_exp_2 = 1 << m;
-      int d;
-
-      d = m_exp_2 + 1;
-      if (t % d == 0)
+      if (zero_cost >= cost_limit)
+       return *best_alg;
+      else
        {
-         int q = t / d;
-
-         cost = add_cost + shift_cost * 2;
-
-         *alg_in = synth_mult (q, add_cost, shift_cost,
-                               MIN (max_cost, best_alg->cost) - cost);
-
-         if (alg_in->cost >= 0)
-           {
-             cost += alg_in->cost;
-
-             if (cost < best_alg->cost)
-               {
-                 struct algorithm *x;
-                 x = alg_in;
-                 alg_in = best_alg;
-                 best_alg = x;
-                 best_alg->coeff[best_alg->ops] = m_exp_2;
-                 best_alg->op[best_alg->ops++] = alg_compound;
-                 best_alg->coeff[best_alg->ops] = 1;
-                 best_alg->op[best_alg->ops++] = alg_add;
-                 best_alg->cost = cost;
-               }
-           }
+         best_alg->ops = 1;
+         best_alg->cost = zero_cost;
+         best_alg->op[0] = alg_zero;
+         return *best_alg;
        }
+    }
 
-      d = m_exp_2 - 1;
-      if (t % d == 0)
-       {
-         int q = t / d;
-
-         cost = add_cost + shift_cost * 2;
+  /* 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.  */
 
-         *alg_in = synth_mult (q, add_cost, shift_cost,
-                               MIN (max_cost, best_alg->cost) - cost);
+  if ((t & 1) == 0)
+    {
+      m = floor_log2 (t & -t); /* m = number of low zero bits */
+      q = t >> m;
+      cost = shift_cost[m];
+      if (cost < cost_limit)
+       {
+         *alg_in = synth_mult (q, cost_limit - cost);
 
-         if (alg_in->cost >= 0)
+         cost += alg_in->cost;
+         if (cost < best_alg->cost)
            {
-             cost += alg_in->cost;
-
-             if (cost < best_alg->cost)
-               {
-                 struct algorithm *x;
-                 x = alg_in;
-                 alg_in = best_alg;
-                 best_alg = x;
-                 best_alg->coeff[best_alg->ops] = m_exp_2;
-                 best_alg->op[best_alg->ops++] = alg_compound;
-                 best_alg->coeff[best_alg->ops] = 1;
-                 best_alg->op[best_alg->ops++] = alg_subtract;
-                 best_alg->cost = cost;
-               }
+             struct algorithm *x;
+             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;
+             best_alg->cost = cost_limit = cost;
            }
        }
     }
 
-  /* Try load effective address instructions, i.e. do a*3, a*5, a*9.  */
-
-  {
-    int q;
-    int w;
-
-    q = t & -t;                        /* get out lsb */
-    w = (t - q) & -(t - q);    /* get out next lsb */
-
-    if (w / q <= lea_max_mul)
-      {
-       cost = lea_cost + (q != 1 ? shift_cost : 0);
-
-       *alg_in = synth_mult (t - q - w, add_cost, shift_cost,
-                             MIN (max_cost, best_alg->cost) - cost);
-
-       if (alg_in->cost >= 0)
-         {
-           cost += alg_in->cost;
-
-           /* Use <= to prefer this method to the factoring method
-              when the cost appears the same, because this method
-              uses fewer temporary registers.  */
-           if (cost <= best_alg->cost)
-             {
-               struct algorithm *x;
-               x = alg_in;
-               alg_in = best_alg;
-               best_alg = x;
-               best_alg->coeff[best_alg->ops] = w;
-               best_alg->op[best_alg->ops++] = alg_add;
-               best_alg->coeff[best_alg->ops] = q;
-               best_alg->op[best_alg->ops++] = alg_add;
-               best_alg->cost = cost;
-             }
-         }
-      }
-  }
-
-  /* Now, use the good old method to add or subtract at the leftmost
-     1-bit.  */
-
+  /* If we have an odd number, add or subtract one.  */
+  if ((t & 1) != 0)
   {
-    int q;
-    int w;
+    unsigned HOST_WIDE_INT w;
 
-    q = t & -t;                        /* get out lsb */
-    for (w = q; (w & t) != 0; w <<= 1)
+    for (w = 1; (w & t) != 0; w <<= 1)
       ;
-    if ((w > q << 1)
-       /* Reject the case where t has only two bits.
+    if (w > 2
+       /* Reject the case where t is 3.
           Thus we prefer addition in that case.  */
-       && !(t < w && w == q << 2))
+       && t != 3)
       {
-       /* There are many bits in a row.  Make 'em by subtraction.  */
+       /* T ends with ...111.  Multiply by (T + 1) and subtract 1.  */
 
        cost = add_cost;
-       if (q != 1)
-         cost += shift_cost;
-
-       *alg_in = synth_mult (t + q, add_cost, shift_cost,
-                             MIN (max_cost, best_alg->cost) - cost);
+       *alg_in = synth_mult (t + 1, cost_limit - cost);
 
-       if (alg_in->cost >= 0)
+       cost += alg_in->cost;
+       if (cost < best_alg->cost)
          {
-           cost += alg_in->cost;
-
-           /* Use <= to prefer this method to the factoring method
-              when the cost appears the same, because this method
-              uses fewer temporary registers.  */
-           if (cost <= best_alg->cost)
-             {
-               struct algorithm *x;
-               x = alg_in;
-               alg_in = best_alg;
-               best_alg = x;
-               best_alg->coeff[best_alg->ops] = q;
-               best_alg->op[best_alg->ops++] = alg_subtract;
-               best_alg->cost = cost;
-             }
+           struct algorithm *x;
+           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;
+           best_alg->cost = cost_limit = cost;
          }
       }
     else
       {
-       /* There's only one bit at the left.  Make it by addition.  */
+       /* T ends with ...01 or ...011.  Multiply by (T - 1) and add 1.  */
 
        cost = add_cost;
-       if (q != 1)
-         cost += shift_cost;
+       *alg_in = synth_mult (t - 1, cost_limit - cost);
 
-       *alg_in = synth_mult (t - q, add_cost, shift_cost,
-                             MIN (max_cost, best_alg->cost) - cost);
-
-       if (alg_in->cost >= 0)
+       cost += alg_in->cost;
+       if (cost < best_alg->cost)
          {
-           cost += alg_in->cost;
-
-           if (cost <= best_alg->cost)
-             {
-               struct algorithm *x;
-               x = alg_in;
-               alg_in = best_alg;
-               best_alg = x;
-               best_alg->coeff[best_alg->ops] = q;
-               best_alg->op[best_alg->ops++] = alg_add;
-               best_alg->cost = cost;
-             }
+           struct algorithm *x;
+           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;
+           best_alg->cost = cost_limit = cost;
          }
       }
   }
 
-  if (best_alg->cost >= max_cost)
-    best_alg->cost = -1;
+  /* Look for factors of t of the form
+     t = q(2**m +- 1), 2 <= m <= floor(log2(t - 1)).
+     If we find such a factor, we can multiply by t using an algorithm that
+     multiplies by q, shift the result by m and add/subtract it to itself.
+
+     We search for large factors first and loop down, even if large factors
+     are less probable than small; if we find a large factor we will find a
+     good sequence quickly, and therefore be able to prune (by decreasing
+     COST_LIMIT) the search.  */
+
+  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)
+       {
+         cost = MIN (shiftadd_cost[m], add_cost + shift_cost[m]);
+         *alg_in = synth_mult (t / d, cost_limit - cost);
+
+         cost += alg_in->cost;
+         if (cost < best_alg->cost)
+           {
+             struct algorithm *x;
+             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;
+             best_alg->cost = cost_limit = cost;
+           }
+       }
+
+      d = ((unsigned HOST_WIDE_INT) 1 << m) - 1;
+      if (t % d == 0 && t > d)
+       {
+         cost = MIN (shiftsub_cost[m], add_cost + shift_cost[m]);
+         *alg_in = synth_mult (t / d, cost_limit - cost);
+
+         cost += alg_in->cost;
+         if (cost < best_alg->cost)
+           {
+             struct algorithm *x;
+             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;
+             best_alg->cost = cost_limit = cost;
+           }
+       }
+    }
+
+  /* Try shift-and-add (load effective address) instructions,
+     i.e. do a*3, a*5, a*9.  */
+  if ((t & 1) != 0)
+    {
+      q = t - 1;
+      q = q & -q;
+      m = exact_log2 (q);
+      if (m >= 0)
+       {
+         cost = shiftadd_cost[m];
+         *alg_in = synth_mult ((t - 1) >> m, cost_limit - cost);
+
+         cost += alg_in->cost;
+         if (cost < best_alg->cost)
+           {
+             struct algorithm *x;
+             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;
+             best_alg->cost = cost_limit = cost;
+           }
+       }
+
+      q = t + 1;
+      q = q & -q;
+      m = exact_log2 (q);
+      if (m >= 0)
+       {
+         cost = shiftsub_cost[m];
+         *alg_in = synth_mult ((t + 1) >> m, cost_limit - cost);
+
+         cost += alg_in->cost;
+         if (cost < best_alg->cost)
+           {
+             struct algorithm *x;
+             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;
+             best_alg->cost = cost_limit = cost;
+           }
+       }
+    }
+
+  /* If we are getting a too long sequence for `struct algorithm'
+     to record, store a fake cost to make this search fail.  */
+  if (best_alg->ops == MAX_BITS_PER_WORD)
+    best_alg->cost = cost_limit;
+
   return *best_alg;
 }
 \f
@@ -1942,16 +2056,22 @@ expand_mult (mode, op0, op1, target, unsignedp)
     {
       if ((CONST_DOUBLE_HIGH (op1) == 0 && CONST_DOUBLE_LOW (op1) >= 0)
          || (CONST_DOUBLE_HIGH (op1) == -1 && CONST_DOUBLE_LOW (op1) < 0))
-       const_op1 = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (op1));
+       const_op1 = GEN_INT (CONST_DOUBLE_LOW (op1));
     }
 
-  if (GET_CODE (const_op1) == CONST_INT && ! mult_is_very_cheap && optimize)
+  /* 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 (GET_CODE (const_op1) == CONST_INT && ! mult_is_very_cheap)
     {
       struct algorithm alg;
       struct algorithm neg_alg;
       int negate = 0;
-      int absval = INTVAL (op1);
-      rtx last;
+      HOST_WIDE_INT val = INTVAL (op1);
+      HOST_WIDE_INT val_so_far;
+      rtx insn;
 
       /* Try to do the computation two ways: multiply by the negative of OP1
         and then negate, or do the multiplication directly.  The latter is
@@ -1960,20 +2080,19 @@ expand_mult (mode, op0, op1, target, unsignedp)
         has a factor of 2**m +/- 1, while the negated value does not or
         vice versa.  */
 
-      alg = synth_mult (absval, add_cost, shift_cost, mult_cost);
-      neg_alg = synth_mult (- absval, add_cost, shift_cost,
-                           mult_cost - negate_cost);
+      alg = synth_mult (val, mult_cost);
+      neg_alg = synth_mult (- val,
+                           (alg.cost < mult_cost ? alg.cost : mult_cost)
+                           - negate_cost);
 
-      if (neg_alg.cost >= 0 && neg_alg.cost + negate_cost < alg.cost)
-       alg = neg_alg, negate = 1, absval = - absval;
+      if (neg_alg.cost + negate_cost < alg.cost)
+       alg = neg_alg, negate = 1;
 
-      if (alg.cost >= 0)
+      if (alg.cost < mult_cost)
        {
-         /* If we found something, it must be cheaper than multiply.
-            So use it.  */
-         int opno = 0;
+         /* We found something cheaper than a multiply insn.  */
+         int opno;
          rtx accum, tem;
-         int factors_seen = 0;
 
          op0 = protect_from_queue (op0, 0);
 
@@ -1982,122 +2101,113 @@ expand_mult (mode, op0, op1, target, unsignedp)
          if (GET_CODE (op0) == MEM)
            op0 = force_reg (mode, op0);
 
-         if (alg.ops == 0)
-           accum = copy_to_mode_reg (mode, op0);
-         else
+         /* ACCUM starts out either as OP0 or as a zero, depending on
+            the first operation.  */
+
+         if (alg.op[0] == alg_zero)
            {
-             /* 1 if this is the last in a series of adds and subtracts.  */
-             int last = (1 == alg.ops || alg.op[1] == alg_compound);
-             int log = floor_log2 (alg.coeff[0]);
-             if (! factors_seen && ! last)
-               log -= floor_log2 (alg.coeff[1]);
-
-             if (alg.op[0] != alg_add)
-               abort ();
-             accum = expand_shift (LSHIFT_EXPR, mode, op0,
-                                   build_int_2 (log, 0),
-                                   0, 0);
+             accum = copy_to_mode_reg (mode, const0_rtx);
+             val_so_far = 0;
            }
-   
-         while (++opno < alg.ops)
+         else if (alg.op[0] == alg_m)
            {
-             int log = floor_log2 (alg.coeff[opno]);
-             /* 1 if this is the last in a series of adds and subtracts.  */
-             int last = (opno + 1 == alg.ops
-                         || alg.op[opno + 1] == alg_compound);
-
-             /* If we have not yet seen any separate factors (alg_compound)
-                then turn op0<<a1 + op0<<a2 + op0<<a3... into
-                (op0<<(a1-a2) + op0)<<(a2-a3) + op0...  */
+             accum  = copy_to_mode_reg (mode, op0);
+             val_so_far = 1;
+           }
+         else
+           abort ();
+
+         for (opno = 1; opno < alg.ops; opno++)
+           {
+             int log = alg.log[opno];
+             rtx shift_subtarget = preserve_subexpressions_p () ? 0 : accum;
+             rtx add_target = opno == alg.ops - 1 && target != 0 ? target : 0;
+
              switch (alg.op[opno])
                {
-               case alg_add:
-                 if (factors_seen)
-                   {
-                     tem = expand_shift (LSHIFT_EXPR, mode, op0,
-                                         build_int_2 (log, 0), 0, 0);
-                     accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
-                                            accum);
-                   }
-                 else
-                   {
-                     if (! last)
-                       log -= floor_log2 (alg.coeff[opno + 1]);
-                     accum = force_operand (gen_rtx (PLUS, mode, accum, op0),
-                                            accum);
-                     accum = expand_shift (LSHIFT_EXPR, mode, accum,
-                                           build_int_2 (log, 0), accum, 0);
-                   }
+               case alg_shift:
+                 accum = expand_shift (LSHIFT_EXPR, mode, accum,
+                                       build_int_2 (log, 0), NULL_RTX, 0);
+                 val_so_far <<= log;
                  break;
 
-               case alg_subtract:
-                 if (factors_seen)
-                   {
-                     tem = expand_shift (LSHIFT_EXPR, mode, op0,
-                                         build_int_2 (log, 0), 0, 0);
-                     accum = force_operand (gen_rtx (MINUS, mode, accum, tem),
-                                            accum);
-                   }
-                 else
-                   {
-                     if (! last)
-                       log -= floor_log2 (alg.coeff[opno + 1]);
-                     accum = force_operand (gen_rtx (MINUS, mode, accum, op0),
-                                            accum);
-                     accum = expand_shift (LSHIFT_EXPR, mode, accum,
-                                           build_int_2 (log, 0), accum, 0);
-                   }
+               case alg_add_t_m2:
+                 tem = expand_shift (LSHIFT_EXPR, mode, op0,
+                                     build_int_2 (log, 0), NULL_RTX, 0);
+                 accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+                                        add_target ? add_target : accum);
+                 val_so_far += (HOST_WIDE_INT) 1 << log;
+                 break;
 
+               case alg_sub_t_m2:
+                 tem = expand_shift (LSHIFT_EXPR, mode, op0,
+                                     build_int_2 (log, 0), NULL_RTX, 0);
+                 accum = force_operand (gen_rtx (MINUS, mode, accum, tem),
+                                        add_target ? add_target : accum);
+                 val_so_far -= (HOST_WIDE_INT) 1 << log;
                  break;
 
-               case alg_compound:
-                 factors_seen = 1;
-                 tem = expand_shift (LSHIFT_EXPR, mode, accum,
-                                     build_int_2 (log, 0), 0, 0);
+               case alg_add_t2_m:
+                 accum = expand_shift (LSHIFT_EXPR, mode, accum,
+                                       build_int_2 (log, 0), accum, 0);
+                 accum = force_operand (gen_rtx (PLUS, mode, accum, op0),
+                                        add_target ? add_target : accum);
+                 val_so_far = (val_so_far << log) + 1;
+                 break;
 
-                 log = floor_log2 (alg.coeff[opno + 1]);
+               case alg_sub_t2_m:
                  accum = expand_shift (LSHIFT_EXPR, mode, accum,
-                                       build_int_2 (log, 0), 0, 0);
-                 opno++;
-                 if (alg.op[opno] == alg_add)
-                   accum = force_operand (gen_rtx (PLUS, mode, tem, accum),
-                                          tem);
-                 else
-                   accum = force_operand (gen_rtx (MINUS, mode, tem, accum),
-                                          tem);
-               }
-           }
+                                       build_int_2 (log, 0), accum, 0);
+                 accum = force_operand (gen_rtx (MINUS, mode, accum, op0),
+                                        add_target ? add_target : accum);
+                 val_so_far = (val_so_far << log) - 1;
+                 break;
 
-         /* Write a REG_EQUAL note on the last insn so that we can cse 
-            multiplication sequences.  We need not do this if we were
-            multiplying by a power of two, since only one insn would have
-            been generated.
+               case alg_add_factor:
+                 tem = expand_shift (LSHIFT_EXPR, mode, accum,
+                                     build_int_2 (log, 0), NULL_RTX, 0);
+                 accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+                                        add_target ? add_target : accum);
+                 val_so_far += val_so_far << log;
+                 break;
 
-            ??? We could also write REG_EQUAL notes on the last insn of
-            each sequence that uses a single temporary, but it is not
-            clear how to calculate the partial product so far.
+               case alg_sub_factor:
+                 tem = expand_shift (LSHIFT_EXPR, mode, accum,
+                                     build_int_2 (log, 0), NULL_RTX, 0);
+                 accum = force_operand (gen_rtx (MINUS, mode, tem, accum),
+                                        add_target ? add_target : tem);
+                 val_so_far = (val_so_far << log) - val_so_far;
+                 break;
+
+               default:
+                 abort ();;
+               }
 
-            Torbjorn: Can you do this?  */
+             /* Write a REG_EQUAL note on the last insn so that we can cse
+                multiplication sequences.  */
 
-         if (exact_log2 (absval) < 0)
-           {
-             last = get_last_insn ();
-             REG_NOTES (last)
+             insn = get_last_insn ();
+             REG_NOTES (insn)
                = gen_rtx (EXPR_LIST, REG_EQUAL,
-                          gen_rtx (MULT, mode, op0, 
-                                   negate ? gen_rtx (CONST_INT,
-                                                     VOIDmode, absval)
-                                   : op1),
-                          REG_NOTES (last));
+                          gen_rtx (MULT, mode, op0, GEN_INT (val_so_far)),
+                          REG_NOTES (insn));
+           }
+
+         if (negate)
+           {
+             val_so_far = - val_so_far;
+             accum = expand_unop (mode, neg_optab, accum, target, 0);
            }
 
-         return (negate ? expand_unop (mode, neg_optab, accum, target, 0)
-                 : accum);
+         if (val != val_so_far)
+           abort ();
+
+         return accum;
        }
     }
 
   /* This used to use umul_optab if unsigned,
-     but I think that for non-widening multiply there is no difference
+     but for non-widening multiply there is no difference
      between signed and unsigned.  */
   op0 = expand_binop (mode, smul_optab,
                      op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
@@ -2134,11 +2244,18 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
   register rtx result = 0;
   enum machine_mode compute_mode;
   int log = -1;
+  int size;
   int can_clobber_op0;
   int mod_insn_no_good = 0;
   rtx adjusted_op0 = op0;
   optab optab1, optab2;
 
+  /* We shouldn't be called with op1 == const1_rtx, but some of the
+     code below will malfunction if we are, so check here and handle
+     the special case if so.  */
+  if (op1 == const1_rtx)
+    return rem_flag ? const0_rtx : op0;
+
   /* Don't use the function value register as a target
      since we have to read it as well as write it,
      and function-inlining gets confused by this.  */
@@ -2224,6 +2341,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
   if (compute_mode == VOIDmode)
     compute_mode = mode;
 
+  size = GET_MODE_BITSIZE (compute_mode);
+
   /* Now convert to the best mode to use.  Show we made a copy of OP0
      and hence we can clobber it (we cannot use a SUBREG to widen
      something.  */
@@ -2234,6 +2353,19 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
       op1 = convert_to_mode (compute_mode, op1, unsignedp);
     }
 
+  /* If we are computing the remainder and one of the operands is a volatile
+     MEM, copy it into a register.  */
+
+  if (rem_flag && GET_CODE (op0) == MEM && MEM_VOLATILE_P (op0))
+    adjusted_op0 = op0 = force_reg (compute_mode, op0), can_clobber_op0 = 1;
+  if (rem_flag && GET_CODE (op1) == MEM && MEM_VOLATILE_P (op1))
+    op1 = force_reg (compute_mode, op1);
+
+  /* If we are computing the remainder, op0 will be needed later to calculate
+     X - Y * (X / Y), therefore cannot be clobbered. */
+  if (rem_flag)
+    can_clobber_op0 = 0;
+
   if (target == 0 || GET_MODE (target) != compute_mode)
     target = gen_reg_rtx (compute_mode);
 
@@ -2243,18 +2375,47 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
     case TRUNC_DIV_EXPR:
       if (log >= 0 && ! unsignedp)
        {
-         rtx label = gen_label_rtx ();
-         if (! can_clobber_op0)
+         /* Here we need to add OP1-1 if OP0 is negative, 0 otherwise.
+            This can be computed without jumps by arithmetically shifting
+            OP0 right LOG-1 places and then shifting right logically
+            SIZE-LOG bits.  The resulting value is unconditionally added
+            to OP0.  */
+         if (log == 1 || BRANCH_COST >= 3)
            {
-             adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
-             /* Copy op0 to a reg, since emit_cmp_insn will call emit_queue
-                which will screw up mem refs for autoincrements.  */
-             op0 = force_reg (compute_mode, op0);
+             rtx temp = gen_reg_rtx (compute_mode);
+             if (! can_clobber_op0)
+               /* Copy op0 to a reg, to play safe,
+                  since this is done in the other path.  */
+               op0 = force_reg (compute_mode, op0);
+             temp = copy_to_suggested_reg (adjusted_op0, temp, compute_mode);
+             temp = expand_shift (RSHIFT_EXPR, compute_mode, temp,
+                                  build_int_2 (log - 1, 0), NULL_RTX, 0);
+             temp = expand_shift (RSHIFT_EXPR, compute_mode, temp,
+                                  build_int_2 (size - log, 0),
+                                  temp, 1);
+             /* We supply 0 as the target to make a new pseudo
+                for the value; that helps loop.c optimize the result.  */
+             adjusted_op0 = expand_binop (compute_mode, add_optab,
+                                          adjusted_op0, temp,
+                                          0, 0, OPTAB_LIB_WIDEN);
+           }
+         else
+           {
+             rtx label = gen_label_rtx ();
+             if (! can_clobber_op0)
+               {
+                 adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target,
+                                                       compute_mode);
+                 /* Copy op0 to a reg, since emit_cmp_insn will call emit_queue
+                    which will screw up mem refs for autoincrements.  */
+                 op0 = force_reg (compute_mode, op0);
+               }
+             emit_cmp_insn (adjusted_op0, const0_rtx, GE, 
+                            NULL_RTX, compute_mode, 0, 0);
+             emit_jump_insn (gen_bge (label));
+             expand_inc (adjusted_op0, plus_constant (op1, -1));
+             emit_label (label);
            }
-         emit_cmp_insn (adjusted_op0, const0_rtx, GE, 0, compute_mode, 0, 0);
-         emit_jump_insn (gen_bge (label));
-         expand_inc (adjusted_op0, plus_constant (op1, -1));
-         emit_label (label);
          mod_insn_no_good = 1;
        }
       break;
@@ -2266,12 +2427,14 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
          rtx label = gen_label_rtx ();
          if (! can_clobber_op0)
            {
-             adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
+             adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target,
+                                                   compute_mode);
              /* Copy op0 to a reg, since emit_cmp_insn will call emit_queue
                 which will screw up mem refs for autoincrements.  */
              op0 = force_reg (compute_mode, op0);
            }
-         emit_cmp_insn (adjusted_op0, const0_rtx, GE, 0, compute_mode, 0, 0);
+         emit_cmp_insn (adjusted_op0, const0_rtx, GE, 
+                        NULL_RTX, compute_mode, 0, 0);
          emit_jump_insn (gen_bge (label));
          expand_dec (adjusted_op0, op1);
          expand_inc (adjusted_op0, const1_rtx);
@@ -2284,7 +2447,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
     case CEIL_MOD_EXPR:
       if (! can_clobber_op0)
        {
-         adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
+         adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target,
+                                               compute_mode);
          /* Copy op0 to a reg, since emit_cmp_insn will call emit_queue
             which will screw up mem refs for autoincrements.  */
          op0 = force_reg (compute_mode, op0);
@@ -2295,7 +2459,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
          if (! unsignedp)
            {
              label = gen_label_rtx ();
-             emit_cmp_insn (adjusted_op0, const0_rtx, LE, 0, compute_mode, 0, 0);
+             emit_cmp_insn (adjusted_op0, const0_rtx, LE, 
+                            NULL_RTX, compute_mode, 0, 0);
              emit_jump_insn (gen_ble (label));
            }
          expand_inc (adjusted_op0, op1);
@@ -2307,7 +2472,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
        {
          adjusted_op0 = expand_binop (compute_mode, add_optab,
                                       adjusted_op0, plus_constant (op1, -1),
-                                      0, 0, OPTAB_LIB_WIDEN);
+                                      NULL_RTX, 0, OPTAB_LIB_WIDEN);
        }
       mod_insn_no_good = 1;
       break;
@@ -2316,7 +2481,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
     case ROUND_MOD_EXPR:
       if (! can_clobber_op0)
        {
-         adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target);
+         adjusted_op0 = copy_to_suggested_reg (adjusted_op0, target,
+                                               compute_mode);
          /* Copy op0 to a reg, since emit_cmp_insn will call emit_queue
             which will screw up mem refs for autoincrements.  */
          op0 = force_reg (compute_mode, op0);
@@ -2324,20 +2490,37 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
       if (log < 0)
        {
          op1 = expand_shift (RSHIFT_EXPR, compute_mode, op1,
-                             integer_one_node, 0, 0);
+                             integer_one_node, NULL_RTX, 0);
          if (! unsignedp)
            {
-             rtx label = gen_label_rtx ();
-             emit_cmp_insn (adjusted_op0, const0_rtx, GE, 0, compute_mode, 0, 0);
-             emit_jump_insn (gen_bge (label));
-             expand_unop (compute_mode, neg_optab, op1, op1, 0);
-             emit_label (label);
+             if (BRANCH_COST >= 2)
+               {
+                 /* Negate OP1 if OP0 < 0.  Do this by computing a temporary
+                    that has all bits equal to the sign bit and exclusive
+                    or-ing it with OP1.  */
+                 rtx temp = gen_reg_rtx (compute_mode);
+                 temp = copy_to_suggested_reg (adjusted_op0, temp, compute_mode);
+                 temp = expand_shift (RSHIFT_EXPR, compute_mode, temp,
+                                      build_int_2 (size - 1, 0),
+                                      NULL_RTX, 0);
+                 op1 = expand_binop (compute_mode, xor_optab, op1, temp, op1,
+                                     unsignedp, OPTAB_LIB_WIDEN);
+               }
+             else
+               {
+                 rtx label = gen_label_rtx ();
+                 emit_cmp_insn (adjusted_op0, const0_rtx, GE, NULL_RTX,
+                                compute_mode, 0, 0);
+                 emit_jump_insn (gen_bge (label));
+                 expand_unop (compute_mode, neg_optab, op1, op1, 0);
+                 emit_label (label);
+               }
            }
          expand_inc (adjusted_op0, op1);
        }
       else
        {
-         op1 = gen_rtx (CONST_INT, VOIDmode, (1 << log) / 2);
+         op1 = GEN_INT (((HOST_WIDE_INT) 1 << log) / 2);
          expand_inc (adjusted_op0, op1);
        }
       mod_insn_no_good = 1;
@@ -2349,8 +2532,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
       /* Try to produce the remainder directly */
       if (log >= 0)
        result = expand_binop (compute_mode, and_optab, adjusted_op0,
-                              gen_rtx (CONST_INT, VOIDmode,
-                                       (1 << log) - 1),
+                              GEN_INT (((HOST_WIDE_INT) 1 << log) - 1),
                               target, 1, OPTAB_LIB_WIDEN);
       else
        {
@@ -2366,7 +2548,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
              if (! expand_twoval_binop (unsignedp
                                         ? udivmod_optab : sdivmod_optab,
                                         adjusted_op0, op1,
-                                        0, result, unsignedp))
+                                        NULL_RTX, result, unsignedp))
                result = 0;
            }
        }
@@ -2384,12 +2566,14 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
        and a remainder subroutine would be ok,
        don't use a divide subroutine.  */
     result = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
-                               adjusted_op0, op1, 0, unsignedp, OPTAB_WIDEN);
+                               adjusted_op0, op1, NULL_RTX, unsignedp,
+                               OPTAB_WIDEN);
   else
     {
       /* Try a quotient insn, but not a library call.  */
       result = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
-                                 adjusted_op0, op1, rem_flag ? 0 : target,
+                                 adjusted_op0, op1,
+                                 rem_flag ? NULL_RTX : target,
                                  unsignedp, OPTAB_WIDEN);
       if (result == 0)
        {
@@ -2398,14 +2582,15 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
          result = gen_reg_rtx (mode);
          if (! expand_twoval_binop (unsignedp ? udivmod_optab : sdivmod_optab,
                                     adjusted_op0, op1,
-                                    result, 0, unsignedp))
+                                    result, NULL_RTX, unsignedp))
            result = 0;
        }
 
       /* If still no luck, use a library call.  */
       if (result == 0)
        result = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
-                                   adjusted_op0, op1, rem_flag ? 0 : target,
+                                   adjusted_op0, op1,
+                                   rem_flag ? NULL_RTX : target,
                                    unsignedp, OPTAB_LIB_WIDEN);
     }
 
@@ -2544,7 +2729,7 @@ expand_mult_add (x, target, mult, add, mode, unsignedp)
 {
   tree type = type_for_mode (mode, unsignedp);
   tree add_type = (GET_MODE (add) == VOIDmode
-                  ? type : type_for_mode (GET_MODE (add)));
+                  ? type : type_for_mode (GET_MODE (add), unsignedp));
   tree result =  fold (build (PLUS_EXPR, type,
                              fold (build (MULT_EXPR, type,
                                           make_tree (type, x),
@@ -2574,7 +2759,7 @@ expand_and (op0, op1, target)
   if (mode != VOIDmode)
     tem = expand_binop (mode, and_optab, op0, op1, target, 0, OPTAB_LIB_WIDEN);
   else if (GET_CODE (op0) == CONST_INT && GET_CODE (op1) == CONST_INT)
-    tem = gen_rtx (CONST_INT, VOIDmode, INTVAL (op0) & INTVAL (op1));
+    tem = GEN_INT (INTVAL (op0) & INTVAL (op1));
   else
     abort ();
 
@@ -2620,6 +2805,18 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
   if (mode == VOIDmode)
     mode = GET_MODE (op0);
 
+  /* If one operand is constant, make it the second one.  Only do this
+     if the other operand is not constant as well.  */
+
+  if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
+      || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+    {
+      tem = op0;
+      op0 = op1;
+      op1 = tem;
+      code = swap_condition (code);
+    }
+
   /* For some comparisons with 1 and -1, we can convert this to 
      comparisons with zero.  This will often produce more opportunities for
      store-flag insns. */
@@ -2660,16 +2857,18 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
   if (op1 == const0_rtx && (code == LT || code == GE)
       && GET_MODE_CLASS (mode) == MODE_INT
       && (normalizep || STORE_FLAG_VALUE == 1
-         || (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
-             && STORE_FLAG_VALUE == 1 << (GET_MODE_BITSIZE (mode) - 1))))
+         || (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+             && (STORE_FLAG_VALUE 
+                 == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))))
     {
-      rtx subtarget = target;
+      subtarget = target;
 
       /* If the result is to be wider than OP0, it is best to convert it
         first.  If it is to be narrower, it is *incorrect* to convert it
         first.  */
       if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (mode))
        {
+         op0 = protect_from_queue (op0, 0);
          op0 = convert_to_mode (target_mode, op0, 0);
          mode = target_mode;
        }
@@ -2705,13 +2904,21 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
       emit_queue ();
       last = get_last_insn ();
 
-      comparison = compare_from_rtx (op0, op1, code, unsignedp, mode, 0, 0);
+      comparison
+       = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX, 0);
       if (GET_CODE (comparison) == CONST_INT)
        return (comparison == const0_rtx ? const0_rtx
                : normalizep == 1 ? const1_rtx
                : normalizep == -1 ? constm1_rtx
                : const_true_rtx);
 
+      /* If the code of COMPARISON doesn't match CODE, something is
+        wrong; we can no longer be sure that we have the operation.  
+        We could handle this case, but it should not happen.  */
+
+      if (GET_CODE (comparison) != code)
+       abort ();
+
       /* Get a reference to the target in the proper mode for this insn.  */
       compare_mode = insn_operand_mode[(int) icode][0];
       subtarget = target;
@@ -2736,15 +2943,22 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
            {
              convert_move (target, subtarget,
                            (GET_MODE_BITSIZE (compare_mode)
-                            <= HOST_BITS_PER_INT)
+                            <= HOST_BITS_PER_WIDE_INT)
                            && 0 == (STORE_FLAG_VALUE
-                                    & (1 << (GET_MODE_BITSIZE (compare_mode) -1))));
+                                    & ((HOST_WIDE_INT) 1
+                                       << (GET_MODE_BITSIZE (compare_mode) -1))));
              op0 = target;
              compare_mode = target_mode;
            }
          else
            op0 = subtarget;
 
+         /* If we want to keep subexpressions around, don't reuse our
+            last target.  */
+
+         if (preserve_subexpressions_p ())
+           subtarget = 0;
+
          /* Now normalize to the proper value in COMPARE_MODE.  Sometimes
             we don't have to do anything.  */
          if (normalizep == 0 || normalizep == STORE_FLAG_VALUE)
@@ -2755,9 +2969,10 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
          /* We don't want to use STORE_FLAG_VALUE < 0 below since this
             makes it hard to use a value of just the sign bit due to
             ANSI integer constant typing rules.  */
-         else if (GET_MODE_BITSIZE (compare_mode) <= HOST_BITS_PER_INT
+         else if (GET_MODE_BITSIZE (compare_mode) <= HOST_BITS_PER_WIDE_INT
                   && (STORE_FLAG_VALUE
-                      & (1 << (GET_MODE_BITSIZE (compare_mode) - 1))))
+                      & ((HOST_WIDE_INT) 1
+                         << (GET_MODE_BITSIZE (compare_mode) - 1))))
            op0 = expand_shift (RSHIFT_EXPR, compare_mode, op0,
                                size_int (GET_MODE_BITSIZE (compare_mode) - 1),
                                subtarget, normalizep == 1);
@@ -2774,7 +2989,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
             conversion now.  */
          if (target_mode != compare_mode)
            {
-             convert_move (target, op0);
+             convert_move (target, op0, 0);
              return target;
            }
          else
@@ -2794,7 +3009,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
      comparison with zero.  Don't do any of these cases if branches are
      very cheap.  */
 
-  if (BRANCH_COST >= 0
+  if (BRANCH_COST > 0
       && GET_MODE_CLASS (mode) == MODE_INT && (code == EQ || code == NE)
       && op1 != const0_rtx)
     {
@@ -2831,8 +3046,9 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
       if (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
        normalizep = STORE_FLAG_VALUE;
 
-      else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_INT
-              && STORE_FLAG_VALUE == 1 << (GET_MODE_BITSIZE (mode) - 1))
+      else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+              && (STORE_FLAG_VALUE
+                  == (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))
        ;
       else
        return 0;
@@ -2884,7 +3100,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
 
         Two operations that can do the above actions are ABS and FFS, so try
         them.  If that doesn't work, and MODE is smaller than a full word,
-        we can use zero-extention to the wider mode (an unsigned conversion)
+        we can use zero-extension to the wider mode (an unsigned conversion)
         as the operation.  */
 
       if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
@@ -2894,6 +3110,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
       else if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        {
          mode = word_mode;
+         op0 = protect_from_queue (op0, 0);
          tem = convert_to_mode (mode, op0, 1);
        }
 
@@ -2913,6 +3130,9 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
 
       if (tem == 0 && (code == NE || BRANCH_COST > 1))
        {
+         if (rtx_equal_p (subtarget, op0))
+           subtarget = 0;
+
          tem = expand_unop (mode, neg_optab, op0, subtarget, 0);
          tem = expand_binop (mode, ior_optab, tem, op0, subtarget, 0,
                              OPTAB_WIDEN);