OSDN Git Service

* params.h (ALLOW_STORE_DATA_RACES): New.
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index ab5057a..92167f1 100644 (file)
@@ -1,7 +1,8 @@
 /* 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, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -25,7 +26,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "rtl.h"
 #include "tree.h"
 #include "tm_p.h"
@@ -33,21 +34,32 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-config.h"
 #include "expr.h"
 #include "optabs.h"
-#include "real.h"
 #include "recog.h"
 #include "langhooks.h"
 #include "df.h"
 #include "target.h"
+#include "expmed.h"
+
+struct target_expmed default_target_expmed;
+#if SWITCHABLE_TARGET
+struct target_expmed *this_target_expmed = &default_target_expmed;
+#endif
 
 static void store_fixed_bit_field (rtx, unsigned HOST_WIDE_INT,
                                   unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT, rtx);
+                                  unsigned HOST_WIDE_INT,
+                                  unsigned HOST_WIDE_INT,
+                                  unsigned HOST_WIDE_INT,
+                                  rtx);
 static void store_split_bit_field (rtx, unsigned HOST_WIDE_INT,
-                                  unsigned HOST_WIDE_INT, rtx);
+                                  unsigned HOST_WIDE_INT,
+                                  unsigned HOST_WIDE_INT,
+                                  unsigned HOST_WIDE_INT,
+                                  rtx);
 static rtx extract_fixed_bit_field (enum machine_mode, rtx,
                                    unsigned HOST_WIDE_INT,
                                    unsigned HOST_WIDE_INT,
-                                   unsigned HOST_WIDE_INT, rtx, int);
+                                   unsigned HOST_WIDE_INT, rtx, int, bool);
 static rtx mask_rtx (enum machine_mode, int, int, int);
 static rtx lshift_value (enum machine_mode, rtx, int, int);
 static rtx extract_split_bit_field (rtx, unsigned HOST_WIDE_INT,
@@ -59,25 +71,10 @@ 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
-   sequences.  */
-
-static bool sdiv_pow2_cheap[NUM_MACHINE_MODES];
-static bool smod_pow2_cheap[NUM_MACHINE_MODES];
-
 #ifndef SLOW_UNALIGNED_ACCESS
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
 #endif
 
-/* 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.  */
-
-#ifndef MAX_BITS_PER_WORD
-#define MAX_BITS_PER_WORD BITS_PER_WORD
-#endif
 
 /* Reduce conditional compilation elsewhere.  */
 #ifndef HAVE_insv
@@ -96,20 +93,6 @@ static bool smod_pow2_cheap[NUM_MACHINE_MODES];
 #define gen_extzv(a,b,c,d) NULL_RTX
 #endif
 
-/* Cost of various pieces of RTL.  Note that some of these are indexed by
-   shift count and some by mode.  */
-static int zero_cost;
-static int add_cost[NUM_MACHINE_MODES];
-static int neg_cost[NUM_MACHINE_MODES];
-static int shift_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
-static int shiftadd_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
-static int shiftsub_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
-static int mul_cost[NUM_MACHINE_MODES];
-static int sdiv_cost[NUM_MACHINE_MODES];
-static int udiv_cost[NUM_MACHINE_MODES];
-static int mul_widen_cost[NUM_MACHINE_MODES];
-static int mul_highpart_cost[NUM_MACHINE_MODES];
-
 void
 init_expmed (void)
 {
@@ -130,22 +113,22 @@ init_expmed (void)
     struct rtx_def shift;      rtunion shift_fld1;
     struct rtx_def shift_mult; rtunion shift_mult_fld1;
     struct rtx_def shift_add;  rtunion shift_add_fld1;
-    struct rtx_def shift_sub;  rtunion shift_sub_fld1;
+    struct rtx_def shift_sub0; rtunion shift_sub0_fld1;
+    struct rtx_def shift_sub1; rtunion shift_sub1_fld1;
   } all;
 
   rtx pow2[MAX_BITS_PER_WORD];
   rtx cint[MAX_BITS_PER_WORD];
   int m, n;
   enum machine_mode mode, wider_mode;
+  int speed;
 
-  zero_cost = rtx_cost (const0_rtx, 0);
 
   for (m = 1; m < MAX_BITS_PER_WORD; m++)
     {
       pow2[m] = GEN_INT ((HOST_WIDE_INT) 1 << m);
       cint[m] = GEN_INT (m);
     }
-
   memset (&all, 0, sizeof all);
 
   PUT_CODE (&all.reg, REG);
@@ -202,65 +185,85 @@ init_expmed (void)
   XEXP (&all.shift_add, 0) = &all.shift_mult;
   XEXP (&all.shift_add, 1) = &all.reg;
 
-  PUT_CODE (&all.shift_sub, MINUS);
-  XEXP (&all.shift_sub, 0) = &all.shift_mult;
-  XEXP (&all.shift_sub, 1) = &all.reg;
+  PUT_CODE (&all.shift_sub0, MINUS);
+  XEXP (&all.shift_sub0, 0) = &all.shift_mult;
+  XEXP (&all.shift_sub0, 1) = &all.reg;
 
-  for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
-       mode != VOIDmode;
-       mode = GET_MODE_WIDER_MODE (mode))
+  PUT_CODE (&all.shift_sub1, MINUS);
+  XEXP (&all.shift_sub1, 0) = &all.reg;
+  XEXP (&all.shift_sub1, 1) = &all.shift_mult;
+
+  for (speed = 0; speed < 2; speed++)
     {
-      PUT_MODE (&all.reg, mode);
-      PUT_MODE (&all.plus, mode);
-      PUT_MODE (&all.neg, mode);
-      PUT_MODE (&all.mult, mode);
-      PUT_MODE (&all.sdiv, mode);
-      PUT_MODE (&all.udiv, mode);
-      PUT_MODE (&all.sdiv_32, mode);
-      PUT_MODE (&all.smod_32, mode);
-      PUT_MODE (&all.wide_trunc, mode);
-      PUT_MODE (&all.shift, mode);
-      PUT_MODE (&all.shift_mult, mode);
-      PUT_MODE (&all.shift_add, mode);
-      PUT_MODE (&all.shift_sub, mode);
-
-      add_cost[mode] = rtx_cost (&all.plus, SET);
-      neg_cost[mode] = rtx_cost (&all.neg, SET);
-      mul_cost[mode] = rtx_cost (&all.mult, SET);
-      sdiv_cost[mode] = rtx_cost (&all.sdiv, SET);
-      udiv_cost[mode] = rtx_cost (&all.udiv, SET);
-
-      sdiv_pow2_cheap[mode] = (rtx_cost (&all.sdiv_32, SET)
-                              <= 2 * add_cost[mode]);
-      smod_pow2_cheap[mode] = (rtx_cost (&all.smod_32, SET)
-                              <= 4 * add_cost[mode]);
-
-      wider_mode = GET_MODE_WIDER_MODE (mode);
-      if (wider_mode != VOIDmode)
-       {
-         PUT_MODE (&all.zext, wider_mode);
-         PUT_MODE (&all.wide_mult, wider_mode);
-         PUT_MODE (&all.wide_lshr, wider_mode);
-         XEXP (&all.wide_lshr, 1) = GEN_INT (GET_MODE_BITSIZE (mode));
+      crtl->maybe_hot_insn_p = speed;
+      zero_cost[speed] = rtx_cost (const0_rtx, SET, speed);
 
-         mul_widen_cost[wider_mode] = rtx_cost (&all.wide_mult, SET);
-         mul_highpart_cost[mode] = rtx_cost (&all.wide_trunc, SET);
-       }
+      for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+          mode != VOIDmode;
+          mode = GET_MODE_WIDER_MODE (mode))
+       {
+         PUT_MODE (&all.reg, mode);
+         PUT_MODE (&all.plus, mode);
+         PUT_MODE (&all.neg, mode);
+         PUT_MODE (&all.mult, mode);
+         PUT_MODE (&all.sdiv, mode);
+         PUT_MODE (&all.udiv, mode);
+         PUT_MODE (&all.sdiv_32, mode);
+         PUT_MODE (&all.smod_32, mode);
+         PUT_MODE (&all.wide_trunc, mode);
+         PUT_MODE (&all.shift, mode);
+         PUT_MODE (&all.shift_mult, mode);
+         PUT_MODE (&all.shift_add, mode);
+         PUT_MODE (&all.shift_sub0, mode);
+         PUT_MODE (&all.shift_sub1, mode);
+
+         add_cost[speed][mode] = rtx_cost (&all.plus, SET, speed);
+         neg_cost[speed][mode] = rtx_cost (&all.neg, SET, speed);
+         mul_cost[speed][mode] = rtx_cost (&all.mult, SET, speed);
+         sdiv_cost[speed][mode] = rtx_cost (&all.sdiv, SET, speed);
+         udiv_cost[speed][mode] = rtx_cost (&all.udiv, SET, speed);
+
+         sdiv_pow2_cheap[speed][mode] = (rtx_cost (&all.sdiv_32, SET, speed)
+                                         <= 2 * add_cost[speed][mode]);
+         smod_pow2_cheap[speed][mode] = (rtx_cost (&all.smod_32, SET, speed)
+                                         <= 4 * add_cost[speed][mode]);
+
+         wider_mode = GET_MODE_WIDER_MODE (mode);
+         if (wider_mode != VOIDmode)
+           {
+             PUT_MODE (&all.zext, wider_mode);
+             PUT_MODE (&all.wide_mult, wider_mode);
+             PUT_MODE (&all.wide_lshr, wider_mode);
+             XEXP (&all.wide_lshr, 1) = GEN_INT (GET_MODE_BITSIZE (mode));
+
+             mul_widen_cost[speed][wider_mode]
+               = rtx_cost (&all.wide_mult, SET, speed);
+             mul_highpart_cost[speed][mode]
+               = rtx_cost (&all.wide_trunc, SET, speed);
+           }
 
-      shift_cost[mode][0] = 0;
-      shiftadd_cost[mode][0] = shiftsub_cost[mode][0] = add_cost[mode];
+         shift_cost[speed][mode][0] = 0;
+         shiftadd_cost[speed][mode][0] = shiftsub0_cost[speed][mode][0]
+           = shiftsub1_cost[speed][mode][0] = add_cost[speed][mode];
 
-      n = MIN (MAX_BITS_PER_WORD, GET_MODE_BITSIZE (mode));
-      for (m = 1; m < n; m++)
-       {
-         XEXP (&all.shift, 1) = cint[m];
-         XEXP (&all.shift_mult, 1) = pow2[m];
+         n = MIN (MAX_BITS_PER_WORD, GET_MODE_BITSIZE (mode));
+         for (m = 1; m < n; m++)
+           {
+             XEXP (&all.shift, 1) = cint[m];
+             XEXP (&all.shift_mult, 1) = pow2[m];
 
-         shift_cost[mode][m] = rtx_cost (&all.shift, SET);
-         shiftadd_cost[mode][m] = rtx_cost (&all.shift_add, SET);
-         shiftsub_cost[mode][m] = rtx_cost (&all.shift_sub, SET);
+             shift_cost[speed][mode][m] = rtx_cost (&all.shift, SET, speed);
+             shiftadd_cost[speed][mode][m] = rtx_cost (&all.shift_add, SET, speed);
+             shiftsub0_cost[speed][mode][m] = rtx_cost (&all.shift_sub0, SET, speed);
+             shiftsub1_cost[speed][mode][m] = rtx_cost (&all.shift_sub1, SET, speed);
+           }
        }
     }
+  if (alg_hash_used_p)
+    memset (alg_hash, 0, sizeof (alg_hash));
+  else
+    alg_hash_used_p = true;
+  default_rtl_profile ();
 }
 
 /* Return an rtx representing minus the value of X.
@@ -285,7 +288,7 @@ negate_rtx (enum machine_mode mode, rtx x)
 enum machine_mode
 mode_for_extraction (enum extraction_pattern pattern, int opno)
 {
-  const struct insn_data *data;
+  const struct insn_data_d *data;
 
   switch (pattern)
     {
@@ -326,22 +329,6 @@ mode_for_extraction (enum extraction_pattern pattern, int opno)
     return word_mode;
   return data->operand[opno].mode;
 }
-
-/* Return true if X, of mode MODE, matches the predicate for operand
-   OPNO of instruction ICODE.  Allow volatile memories, regardless of
-   the ambient volatile_ok setting.  */
-
-static bool
-check_predicate_volatile_ok (enum insn_code icode, int opno,
-                            rtx x, enum machine_mode mode)
-{
-  bool save_volatile_ok, result;
-
-  save_volatile_ok = volatile_ok;
-  result = insn_data[(int) icode].operand[opno].predicate (x, mode);
-  volatile_ok = save_volatile_ok;
-  return result;
-}
 \f
 /* A subroutine of store_bit_field, with the same arguments.  Return true
    if the operation could be implemented.
@@ -352,7 +339,10 @@ check_predicate_volatile_ok (enum insn_code icode, int opno,
 
 static bool
 store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                  unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
+                  unsigned HOST_WIDE_INT bitnum,
+                  unsigned HOST_WIDE_INT bitregion_start,
+                  unsigned HOST_WIDE_INT bitregion_end,
+                  enum machine_mode fieldmode,
                   rtx value, bool fallback_p)
 {
   unsigned int unit
@@ -373,7 +363,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
         always get higher addresses.  */
       int inner_mode_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)));
       int outer_mode_size = GET_MODE_SIZE (GET_MODE (op0));
-      
+
       byte_offset = 0;
 
       /* Paradoxical subregs need special handling on big endian machines.  */
@@ -403,46 +393,22 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      available.  */
   if (VECTOR_MODE_P (GET_MODE (op0))
       && !MEM_P (op0)
-      && (optab_handler (vec_set_optab, GET_MODE (op0))->insn_code
-         != CODE_FOR_nothing)
+      && optab_handler (vec_set_optab, GET_MODE (op0)) != CODE_FOR_nothing
       && fieldmode == GET_MODE_INNER (GET_MODE (op0))
       && bitsize == GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
       && !(bitnum % GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
     {
+      struct expand_operand ops[3];
       enum machine_mode outermode = GET_MODE (op0);
       enum machine_mode innermode = GET_MODE_INNER (outermode);
-      int icode = (int) optab_handler (vec_set_optab, outermode)->insn_code;
+      enum insn_code icode = optab_handler (vec_set_optab, outermode);
       int pos = bitnum / GET_MODE_BITSIZE (innermode);
-      rtx rtxpos = GEN_INT (pos);
-      rtx src = value;
-      rtx dest = op0;
-      rtx pat, seq;
-      enum machine_mode mode0 = insn_data[icode].operand[0].mode;
-      enum machine_mode mode1 = insn_data[icode].operand[1].mode;
-      enum machine_mode mode2 = insn_data[icode].operand[2].mode;
 
-      start_sequence ();
-
-      if (! (*insn_data[icode].operand[1].predicate) (src, mode1))
-       src = copy_to_mode_reg (mode1, src);
-
-      if (! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
-       rtxpos = copy_to_mode_reg (mode1, rtxpos);
-
-      /* We could handle this, but we should always be called with a pseudo
-        for our targets and all insns should take them as outputs.  */
-      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 ();
-      if (pat)
-       {
-         emit_insn (seq);
-         emit_insn (pat);
-         return true;
-       }
+      create_fixed_operand (&ops[0], op0);
+      create_input_operand (&ops[1], value, innermode);
+      create_integer_operand (&ops[2], pos);
+      if (maybe_expand_insn (icode, 3, ops))
+       return true;
     }
 
   /* If the target is a register, overwriting the entire object, or storing
@@ -461,8 +427,10 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       && bitsize == GET_MODE_BITSIZE (fieldmode)
       && (!MEM_P (op0)
          ? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD
-            || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode))
-            && byte_offset % GET_MODE_SIZE (fieldmode) == 0)
+             || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode))
+            && ((GET_MODE (op0) == fieldmode && byte_offset == 0)
+                || validate_subreg (fieldmode, GET_MODE (op0), op0,
+                                    byte_offset)))
          : (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0))
             || (offset * BITS_PER_UNIT % bitsize == 0
                 && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0))))
@@ -496,6 +464,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
   /* We may be accessing data outside the field, which means
      we can alias adjacent data.  */
+  /* ?? not always for C++0x memory model ?? */
   if (MEM_P (op0))
     {
       op0 = shallow_copy_rtx (op0);
@@ -517,40 +486,36 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (!MEM_P (op0)
       && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0)
       && bitsize == GET_MODE_BITSIZE (fieldmode)
-      && (optab_handler (movstrict_optab, fieldmode)->insn_code
-         != CODE_FOR_nothing))
+      && optab_handler (movstrict_optab, fieldmode) != CODE_FOR_nothing)
     {
-      int icode = optab_handler (movstrict_optab, fieldmode)->insn_code;
+      struct expand_operand ops[2];
+      enum insn_code icode = optab_handler (movstrict_optab, fieldmode);
+      rtx arg0 = op0;
+      unsigned HOST_WIDE_INT subreg_off;
 
-      /* Get appropriate low part of the value being stored.  */
-      if (GET_CODE (value) == CONST_INT || REG_P (value))
-       value = gen_lowpart (fieldmode, value);
-      else if (!(GET_CODE (value) == SYMBOL_REF
-                || GET_CODE (value) == LABEL_REF
-                || GET_CODE (value) == CONST))
-       value = convert_to_mode (fieldmode, value, 0);
-
-      if (! (*insn_data[icode].operand[1].predicate) (value, fieldmode))
-       value = copy_to_mode_reg (fieldmode, value);
-
-      if (GET_CODE (op0) == SUBREG)
+      if (GET_CODE (arg0) == SUBREG)
        {
          /* 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
+         gcc_assert (GET_MODE (SUBREG_REG (arg0)) == fieldmode
                      || GET_MODE_CLASS (fieldmode) == MODE_INT
                      || GET_MODE_CLASS (fieldmode) == MODE_PARTIAL_INT);
-         op0 = SUBREG_REG (op0);
+         arg0 = SUBREG_REG (arg0);
        }
 
-      emit_insn (GEN_FCN (icode)
-                (gen_rtx_SUBREG (fieldmode, op0,
-                                 (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
-                                 + (offset * UNITS_PER_WORD)),
-                                 value));
+      subreg_off = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
+                  + (offset * UNITS_PER_WORD);
+      if (validate_subreg (fieldmode, GET_MODE (arg0), arg0, subreg_off))
+       {
+         arg0 = gen_rtx_SUBREG (fieldmode, arg0, subreg_off);
 
-      return true;
+         create_fixed_operand (&ops[0], arg0);
+         /* Shrink the source operand to FIELDMODE.  */
+         create_convert_operand_to (&ops[1], value, fieldmode, false);
+         if (maybe_expand_insn (icode, 2, ops))
+           return true;
+       }
     }
 
   /* Handle fields bigger than a word.  */
@@ -592,7 +557,9 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
          if (!store_bit_field_1 (op0, MIN (BITS_PER_WORD,
                                            bitsize - i * BITS_PER_WORD),
-                                 bitnum + bit_offset, word_mode,
+                                 bitnum + bit_offset,
+                                 bitregion_start, bitregion_end,
+                                 word_mode,
                                  value_word, fallback_p))
            {
              delete_insns_since (last);
@@ -651,16 +618,14 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       && bitsize > 0
       && GET_MODE_BITSIZE (op_mode) >= bitsize
       && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
-           && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
-      && insn_data[CODE_FOR_insv].operand[1].predicate (GEN_INT (bitsize),
-                                                       VOIDmode)
-      && check_predicate_volatile_ok (CODE_FOR_insv, 0, op0, VOIDmode))
+           && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode))))
     {
+      struct expand_operand ops[4];
       int xbitpos = bitpos;
       rtx value1;
       rtx xop0 = op0;
       rtx last = get_last_insn ();
-      rtx pat;
+      bool copy_back = false;
 
       /* Add OFFSET into OP0's address.  */
       if (MEM_P (xop0))
@@ -673,7 +638,23 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
           and we will need the original value of op0 if insv fails.  */
        xop0 = gen_rtx_SUBREG (op_mode, SUBREG_REG (xop0), SUBREG_BYTE (xop0));
       if (REG_P (xop0) && GET_MODE (xop0) != op_mode)
-       xop0 = gen_rtx_SUBREG (op_mode, xop0, 0);
+       xop0 = gen_lowpart_SUBREG (op_mode, xop0);
+
+      /* If the destination is a paradoxical subreg such that we need a
+        truncate to the inner mode, perform the insertion on a temporary and
+        truncate the result to the original destination.  Note that we can't
+        just truncate the paradoxical subreg as (truncate:N (subreg:W (reg:N
+        X) 0)) is (reg:N X).  */
+      if (GET_CODE (xop0) == SUBREG
+         && REG_P (SUBREG_REG (xop0))
+         && (!TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (SUBREG_REG (xop0)),
+                                             op_mode)))
+       {
+         rtx tem = gen_reg_rtx (op_mode);
+         emit_move_insn (tem, xop0);
+         xop0 = tem;
+         copy_back = true;
+       }
 
       /* On big-endian machines, we count bits from the most significant.
         If the bit field insn does not, we must invert.  */
@@ -713,7 +694,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
              else
                value1 = gen_lowpart (op_mode, value1);
            }
-         else if (GET_CODE (value) == CONST_INT)
+         else if (CONST_INT_P (value))
            value1 = gen_int_mode (INTVAL (value), op_mode);
          else
            /* Parse phase is supposed to make VALUE's data type
@@ -723,16 +704,14 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
            gcc_assert (CONSTANT_P (value));
        }
 
-      /* If this machine's insv insists on a register,
-        get VALUE1 into a register.  */
-      if (! ((*insn_data[(int) CODE_FOR_insv].operand[3].predicate)
-            (value1, op_mode)))
-       value1 = force_reg (op_mode, value1);
-
-      pat = gen_insv (xop0, GEN_INT (bitsize), GEN_INT (xbitpos), value1);
-      if (pat)
+      create_fixed_operand (&ops[0], xop0);
+      create_integer_operand (&ops[1], bitsize);
+      create_integer_operand (&ops[2], xbitpos);
+      create_input_operand (&ops[3], value1, op_mode);
+      if (maybe_expand_insn (CODE_FOR_insv, 4, ops))
        {
-         emit_insn (pat);
+         if (copy_back)
+           convert_move (op0, xop0, true);
          return true;
        }
       delete_insns_since (last);
@@ -743,6 +722,10 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (HAVE_insv && MEM_P (op0))
     {
       enum machine_mode bestmode;
+      unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
+
+      if (bitregion_end)
+       maxbits = bitregion_end - bitregion_start + 1;
 
       /* Get the mode to use for inserting into this field.  If OP0 is
         BLKmode, get the smallest mode consistent with the alignment. If
@@ -750,9 +733,12 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
         mode. Otherwise, use the smallest mode containing the field.  */
 
       if (GET_MODE (op0) == BLKmode
+         || GET_MODE_BITSIZE (GET_MODE (op0)) > maxbits
          || (op_mode != MAX_MACHINE_MODE
              && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (op_mode)))
-       bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0),
+       bestmode = get_best_mode  (bitsize, bitnum,
+                                 bitregion_start, bitregion_end,
+                                 MEM_ALIGN (op0),
                                  (op_mode == MAX_MACHINE_MODE
                                   ? VOIDmode : op_mode),
                                  MEM_VOLATILE_P (op0));
@@ -781,6 +767,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
             the unit.  */
          tempreg = copy_to_reg (xop0);
          if (store_bit_field_1 (tempreg, bitsize, xbitpos,
+                                bitregion_start, bitregion_end,
                                 fieldmode, orig_value, false))
            {
              emit_move_insn (xop0, tempreg);
@@ -793,21 +780,59 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   if (!fallback_p)
     return false;
 
-  store_fixed_bit_field (op0, offset, bitsize, bitpos, value);
+  store_fixed_bit_field (op0, offset, bitsize, bitpos,
+                        bitregion_start, bitregion_end, value);
   return true;
 }
 
 /* Generate code to store value from rtx VALUE
    into a bit-field within structure STR_RTX
    containing BITSIZE bits starting at bit BITNUM.
+
+   BITREGION_START is bitpos of the first bitfield in this region.
+   BITREGION_END is the bitpos of the ending bitfield in this region.
+   These two fields are 0, if the C++ memory model does not apply,
+   or we are not interested in keeping track of bitfield regions.
+
    FIELDMODE is the machine-mode of the FIELD_DECL node for this field.  */
 
 void
 store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                unsigned HOST_WIDE_INT bitnum, enum machine_mode fieldmode,
+                unsigned HOST_WIDE_INT bitnum,
+                unsigned HOST_WIDE_INT bitregion_start,
+                unsigned HOST_WIDE_INT bitregion_end,
+                enum machine_mode fieldmode,
                 rtx value)
 {
-  if (!store_bit_field_1 (str_rtx, bitsize, bitnum, fieldmode, value, true))
+  /* Under the C++0x memory model, we must not touch bits outside the
+     bit region.  Adjust the address to start at the beginning of the
+     bit region.  */
+  if (MEM_P (str_rtx)
+      && bitregion_start > 0)
+    {
+      enum machine_mode bestmode;
+      enum machine_mode op_mode;
+      unsigned HOST_WIDE_INT offset;
+
+      op_mode = mode_for_extraction (EP_insv, 3);
+      if (op_mode == MAX_MACHINE_MODE)
+       op_mode = VOIDmode;
+
+      offset = bitregion_start / BITS_PER_UNIT;
+      bitnum -= bitregion_start;
+      bitregion_end -= bitregion_start;
+      bitregion_start = 0;
+      bestmode = get_best_mode (bitsize, bitnum,
+                               bitregion_start, bitregion_end,
+                               MEM_ALIGN (str_rtx),
+                               op_mode,
+                               MEM_VOLATILE_P (str_rtx));
+      str_rtx = adjust_address (str_rtx, bestmode, offset);
+    }
+
+  if (!store_bit_field_1 (str_rtx, bitsize, bitnum,
+                         bitregion_start, bitregion_end,
+                         fieldmode, value, true))
     gcc_unreachable ();
 }
 \f
@@ -823,7 +848,10 @@ store_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 static void
 store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
                       unsigned HOST_WIDE_INT bitsize,
-                      unsigned HOST_WIDE_INT bitpos, rtx value)
+                      unsigned HOST_WIDE_INT bitpos,
+                      unsigned HOST_WIDE_INT bitregion_start,
+                      unsigned HOST_WIDE_INT bitregion_end,
+                      rtx value)
 {
   enum machine_mode mode;
   unsigned int total_bits = BITS_PER_WORD;
@@ -844,12 +872,19 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
       /* Special treatment for a bit field split across two registers.  */
       if (bitsize + bitpos > BITS_PER_WORD)
        {
-         store_split_bit_field (op0, bitsize, bitpos, value);
+         store_split_bit_field (op0, bitsize, bitpos,
+                                bitregion_start, bitregion_end,
+                                value);
          return;
        }
     }
   else
     {
+      unsigned HOST_WIDE_INT maxbits = MAX_FIXED_MODE_SIZE;
+
+      if (bitregion_end)
+       maxbits = bitregion_end - bitregion_start + 1;
+
       /* Get the proper mode to use for this field.  We want a mode that
         includes the entire field.  If such a mode would be larger than
         a word, we won't be doing the extraction the normal way.
@@ -859,15 +894,23 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
       if (GET_MODE_BITSIZE (mode) == 0
          || GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (word_mode))
        mode = word_mode;
-      mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
-                           MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
+
+      if (MEM_VOLATILE_P (op0)
+          && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
+         && GET_MODE_BITSIZE (GET_MODE (op0)) <= maxbits
+         && flag_strict_volatile_bitfields > 0)
+       mode = GET_MODE (op0);
+      else
+       mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
+                             bitregion_start, bitregion_end,
+                             MEM_ALIGN (op0), mode, MEM_VOLATILE_P (op0));
 
       if (mode == VOIDmode)
        {
          /* The only way this should occur is if the field spans word
             boundaries.  */
          store_split_bit_field (op0, bitsize, bitpos + offset * BITS_PER_UNIT,
-                                value);
+                                bitregion_start, bitregion_end, value);
          return;
        }
 
@@ -912,7 +955,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
   /* Shift VALUE left by BITPOS bits.  If VALUE is not constant,
      we must first convert its mode to MODE.  */
 
-  if (GET_CODE (value) == CONST_INT)
+  if (CONST_INT_P (value))
     {
       HOST_WIDE_INT v = INTVAL (value);
 
@@ -934,13 +977,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
                      && bitpos + bitsize != GET_MODE_BITSIZE (mode));
 
       if (GET_MODE (value) != mode)
-       {
-         if ((REG_P (value) || GET_CODE (value) == SUBREG)
-             && GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (value)))
-           value = gen_lowpart (mode, value);
-         else
-           value = convert_to_mode (mode, value, 1);
-       }
+       value = convert_to_mode (mode, value, 1);
 
       if (must_and)
        value = expand_binop (mode, and_optab, value,
@@ -948,7 +985,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), NULL_RTX, 1);
+                             bitpos, NULL_RTX, 1);
     }
 
   /* Now clear the chosen bits in OP0,
@@ -993,7 +1030,10 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT offset,
 
 static void
 store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
-                      unsigned HOST_WIDE_INT bitpos, rtx value)
+                      unsigned HOST_WIDE_INT bitpos,
+                      unsigned HOST_WIDE_INT bitregion_start,
+                      unsigned HOST_WIDE_INT bitregion_end,
+                      rtx value)
 {
   unsigned int unit;
   unsigned int bitsdone = 0;
@@ -1008,7 +1048,7 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
   /* If VALUE is a constant other than a CONST_INT, get it into a register in
      WORD_MODE.  If we can do this using gen_lowpart_common, do so.  Note
      that VALUE might be a floating-point constant.  */
-  if (CONSTANT_P (value) && GET_CODE (value) != CONST_INT)
+  if (CONSTANT_P (value) && !CONST_INT_P (value))
     {
       rtx word = gen_lowpart_common (word_mode, value);
 
@@ -1050,7 +1090,7 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
            total_bits = GET_MODE_BITSIZE (GET_MODE (value));
 
          /* Fetch successively less significant portions.  */
-         if (GET_CODE (value) == CONST_INT)
+         if (CONST_INT_P (value))
            part = GEN_INT (((unsigned HOST_WIDE_INT) (INTVAL (value))
                             >> (bitsize - bitsdone - thissize))
                            & (((HOST_WIDE_INT) 1 << thissize) - 1));
@@ -1060,18 +1100,18 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
               endianness compensation) to fetch the piece we want.  */
            part = extract_fixed_bit_field (word_mode, value, 0, thissize,
                                            total_bits - bitsize + bitsdone,
-                                           NULL_RTX, 1);
+                                           NULL_RTX, 1, false);
        }
       else
        {
          /* Fetch successively more significant portions.  */
-         if (GET_CODE (value) == CONST_INT)
+         if (CONST_INT_P (value))
            part = GEN_INT (((unsigned HOST_WIDE_INT) (INTVAL (value))
                             >> bitsdone)
                            & (((HOST_WIDE_INT) 1 << thissize) - 1));
          else
            part = extract_fixed_bit_field (word_mode, value, 0, thissize,
-                                           bitsdone, NULL_RTX, 1);
+                                           bitsdone, NULL_RTX, 1, false);
        }
 
       /* If OP0 is a register, then handle OFFSET here.
@@ -1083,22 +1123,32 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
       if (GET_CODE (op0) == SUBREG)
        {
          int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset;
-         word = operand_subword_force (SUBREG_REG (op0), word_offset,
-                                       GET_MODE (SUBREG_REG (op0)));
+         enum machine_mode sub_mode = GET_MODE (SUBREG_REG (op0));
+         if (sub_mode != BLKmode && GET_MODE_SIZE (sub_mode) < UNITS_PER_WORD)
+           word = word_offset ? const0_rtx : op0;
+         else
+           word = operand_subword_force (SUBREG_REG (op0), word_offset,
+                                         GET_MODE (SUBREG_REG (op0)));
          offset = 0;
        }
       else if (REG_P (op0))
        {
-         word = operand_subword_force (op0, offset, GET_MODE (op0));
+         enum machine_mode op0_mode = GET_MODE (op0);
+         if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD)
+           word = offset ? const0_rtx : op0;
+         else
+           word = operand_subword_force (op0, offset, GET_MODE (op0));
          offset = 0;
        }
       else
        word = op0;
 
       /* OFFSET is in UNITs, and UNIT is in bits.
-         store_fixed_bit_field wants offset in bytes.  */
-      store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize,
-                            thispos, part);
+        store_fixed_bit_field wants offset in bytes.  If WORD is const0_rtx,
+        it is just an out-of-bounds access.  Ignore it.  */
+      if (word != const0_rtx)
+       store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize,
+                              thispos, bitregion_start, bitregion_end, part);
       bitsdone += thissize;
     }
 }
@@ -1137,7 +1187,8 @@ convert_extracted_bit_field (rtx x, enum machine_mode mode,
 
 static rtx
 extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                    unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
+                    unsigned HOST_WIDE_INT bitnum,
+                    int unsignedp, bool packedp, rtx target,
                     enum machine_mode mode, enum machine_mode tmode,
                     bool fallback_p)
 {
@@ -1148,7 +1199,6 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
   enum machine_mode int_mode;
   enum machine_mode ext_mode;
   enum machine_mode mode1;
-  enum insn_code icode;
   int byte_offset;
 
   if (tmode == VOIDmode)
@@ -1181,7 +1231,6 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       && GET_MODE_INNER (GET_MODE (op0)) != tmode)
     {
       enum machine_mode new_mode;
-      int nunits = GET_MODE_NUNITS (GET_MODE (op0));
 
       if (GET_MODE_CLASS (tmode) == MODE_FLOAT)
        new_mode = MIN_MODE_VECTOR_FLOAT;
@@ -1197,8 +1246,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
        new_mode = MIN_MODE_VECTOR_INT;
 
       for (; new_mode != VOIDmode ; new_mode = GET_MODE_WIDER_MODE (new_mode))
-       if (GET_MODE_NUNITS (new_mode) == nunits
-           && GET_MODE_INNER (new_mode) == tmode
+       if (GET_MODE_SIZE (new_mode) == GET_MODE_SIZE (GET_MODE (op0))
            && targetm.vector_mode_supported_p (new_mode))
          break;
       if (new_mode != VOIDmode)
@@ -1209,55 +1257,25 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      available.  */
   if (VECTOR_MODE_P (GET_MODE (op0))
       && !MEM_P (op0)
-      && (optab_handler (vec_extract_optab, GET_MODE (op0))->insn_code
-         != CODE_FOR_nothing)
+      && optab_handler (vec_extract_optab, GET_MODE (op0)) != CODE_FOR_nothing
       && ((bitnum + bitsize - 1) / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))
          == bitnum / GET_MODE_BITSIZE (GET_MODE_INNER (GET_MODE (op0)))))
     {
+      struct expand_operand ops[3];
       enum machine_mode outermode = GET_MODE (op0);
       enum machine_mode innermode = GET_MODE_INNER (outermode);
-      int icode = (int) optab_handler (vec_extract_optab, outermode)->insn_code;
+      enum insn_code icode = optab_handler (vec_extract_optab, outermode);
       unsigned HOST_WIDE_INT pos = bitnum / GET_MODE_BITSIZE (innermode);
-      rtx rtxpos = GEN_INT (pos);
-      rtx src = op0;
-      rtx dest = NULL, pat, seq;
-      enum machine_mode mode0 = insn_data[icode].operand[0].mode;
-      enum machine_mode mode1 = insn_data[icode].operand[1].mode;
-      enum machine_mode mode2 = insn_data[icode].operand[2].mode;
-
-      if (innermode == tmode || innermode == mode)
-       dest = target;
 
-      if (!dest)
-       dest = gen_reg_rtx (innermode);
-
-      start_sequence ();
-
-      if (! (*insn_data[icode].operand[0].predicate) (dest, mode0))
-       dest = copy_to_mode_reg (mode0, dest);
-
-      if (! (*insn_data[icode].operand[1].predicate) (src, mode1))
-       src = copy_to_mode_reg (mode1, src);
-
-      if (! (*insn_data[icode].operand[2].predicate) (rtxpos, mode2))
-       rtxpos = copy_to_mode_reg (mode1, rtxpos);
-
-      /* We could handle this, but we should always be called with a pseudo
-        for our targets and all insns should take them as outputs.  */
-      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 ();
-      if (pat)
+      create_output_operand (&ops[0], target, innermode);
+      create_input_operand (&ops[1], op0, outermode);
+      create_integer_operand (&ops[2], pos);
+      if (maybe_expand_insn (icode, 3, ops))
        {
-         emit_insn (seq);
-         emit_insn (pat);
-         if (mode0 != mode)
-           return gen_lowpart (tmode, dest);
-         return dest;
+         target = ops[0].value;
+         if (GET_MODE (target) != mode)
+           return gen_lowpart (tmode, target);
+         return target;
        }
     }
 
@@ -1269,9 +1287,8 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       {
        if (MEM_P (op0))
          op0 = adjust_address (op0, imode, 0);
-       else
+       else if (imode != BLKmode)
          {
-           gcc_assert (imode != BLKmode);
            op0 = gen_lowpart (imode, op0);
 
            /* If we got a SUBREG, force it into a register since we
@@ -1279,6 +1296,24 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
            if (GET_CODE (op0) == SUBREG)
              op0 = force_reg (imode, op0);
          }
+       else if (REG_P (op0))
+         {
+           rtx reg, subreg;
+           imode = smallest_mode_for_size (GET_MODE_BITSIZE (GET_MODE (op0)),
+                                           MODE_INT);
+           reg = gen_reg_rtx (imode);
+           subreg = gen_lowpart_SUBREG (GET_MODE (op0), reg);
+           emit_move_insn (subreg, op0);
+           op0 = reg;
+           bitnum += SUBREG_BYTE (subreg) * BITS_PER_UNIT;
+         }
+       else
+         {
+           rtx mem = assign_stack_temp (GET_MODE (op0),
+                                        GET_MODE_SIZE (GET_MODE (op0)), 0);
+           emit_move_insn (mem, op0);
+           op0 = adjust_address (mem, BLKmode, 0);
+         }
       }
   }
 
@@ -1322,6 +1357,14 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
            ? mode_for_size (bitsize, GET_MODE_CLASS (tmode), 0)
            : mode);
 
+  /* If the bitfield is volatile, we need to make sure the access
+     remains on a type-aligned boundary.  */
+  if (GET_CODE (op0) == MEM
+      && MEM_VOLATILE_P (op0)
+      && GET_MODE_BITSIZE (GET_MODE (op0)) > 0
+      && flag_strict_volatile_bitfields > 0)
+    goto no_subreg_mode_swap;
+
   if (((bitsize >= BITS_PER_WORD && bitsize == GET_MODE_BITSIZE (mode)
        && bitpos % BITS_PER_WORD == 0)
        || (mode1 != BLKmode
@@ -1333,8 +1376,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
               ? bitpos + bitsize == BITS_PER_WORD
               : bitpos == 0)))
       && ((!MEM_P (op0)
-          && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
-                                    GET_MODE_BITSIZE (GET_MODE (op0)))
+          && TRULY_NOOP_TRUNCATION_MODES_P (mode1, GET_MODE (op0))
           && GET_MODE_SIZE (mode1) != 0
           && byte_offset % GET_MODE_SIZE (mode1) == 0)
          || (MEM_P (op0)
@@ -1370,11 +1412,11 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       unsigned int nwords = (bitsize + (BITS_PER_WORD - 1)) / BITS_PER_WORD;
       unsigned int i;
 
-      if (target == 0 || !REG_P (target))
+      if (target == 0 || !REG_P (target) || !valid_multiword_target_p (target))
        target = gen_reg_rtx (mode);
 
       /* Indicate for flow that the entire target reg is being set.  */
-      emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+      emit_clobber (target);
 
       for (i = 0; i < nwords; i++)
        {
@@ -1394,7 +1436,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
          rtx result_part
            = extract_bit_field (op0, MIN (BITS_PER_WORD,
                                           bitsize - i * BITS_PER_WORD),
-                                bitnum + bit_offset, 1, target_part, mode,
+                                bitnum + bit_offset, 1, false, target_part, mode,
                                 word_mode);
 
          gcc_assert (target_part);
@@ -1424,13 +1466,9 @@ extract_bit_field_1 (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),
-                            NULL_RTX, 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),
-                          NULL_RTX, 0);
+                          GET_MODE_BITSIZE (mode) - bitsize, NULL_RTX, 0);
     }
 
   /* From here on we know the desired field is smaller than a word.  */
@@ -1463,7 +1501,6 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
   /* Now OFFSET is nonzero only for memory operands.  */
   ext_mode = mode_for_extraction (unsignedp ? EP_extzv : EP_extv, 0);
-  icode = unsignedp ? CODE_FOR_extzv : CODE_FOR_extv;
   if (ext_mode != MAX_MACHINE_MODE
       && bitsize > 0
       && GET_MODE_BITSIZE (ext_mode) >= bitsize
@@ -1471,22 +1508,19 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
         acceptable to the format of ext(z)v.  */
       && !(GET_CODE (op0) == SUBREG && GET_MODE (op0) != ext_mode)
       && !((REG_P (op0) || GET_CODE (op0) == SUBREG)
-          && (bitsize + bitpos > GET_MODE_BITSIZE (ext_mode)))
-      && check_predicate_volatile_ok (icode, 1, op0, GET_MODE (op0)))
+          && (bitsize + bitpos > GET_MODE_BITSIZE (ext_mode))))
     {
+      struct expand_operand ops[4];
       unsigned HOST_WIDE_INT xbitpos = bitpos, xoffset = offset;
-      rtx bitsize_rtx, bitpos_rtx;
-      rtx last = get_last_insn ();
       rtx xop0 = op0;
       rtx xtarget = target;
       rtx xspec_target = target;
       rtx xspec_target_subreg = 0;
-      rtx pat;
 
       /* If op0 is a register, we need it in EXT_MODE to make it
         acceptable to the format of ext(z)v.  */
       if (REG_P (xop0) && GET_MODE (xop0) != ext_mode)
-       xop0 = gen_rtx_SUBREG (ext_mode, xop0, 0);
+       xop0 = gen_lowpart_SUBREG (ext_mode, xop0);
       if (MEM_P (xop0))
        /* Get ref to first byte containing part of the field.  */
        xop0 = adjust_address (xop0, byte_mode, xoffset);
@@ -1507,38 +1541,36 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
       if (GET_MODE (xtarget) != ext_mode)
        {
-         if (REG_P (xtarget))
+         /* Don't use LHS paradoxical subreg if explicit truncation is needed
+            between the mode of the extraction (word_mode) and the target
+            mode.  Instead, create a temporary and use convert_move to set
+            the target.  */
+         if (REG_P (xtarget)
+             && TRULY_NOOP_TRUNCATION_MODES_P (GET_MODE (xtarget), ext_mode))
            {
              xtarget = gen_lowpart (ext_mode, xtarget);
-             if (GET_MODE_SIZE (ext_mode)
-                 > GET_MODE_SIZE (GET_MODE (xspec_target)))
+             if (GET_MODE_PRECISION (ext_mode)
+                 > GET_MODE_PRECISION (GET_MODE (xspec_target)))
                xspec_target_subreg = xtarget;
            }
          else
            xtarget = gen_reg_rtx (ext_mode);
        }
 
-      /* If this machine's ext(z)v insists on a register target,
-        make sure we have one.  */
-      if (!insn_data[(int) icode].operand[0].predicate (xtarget, ext_mode))
-       xtarget = gen_reg_rtx (ext_mode);
-
-      bitsize_rtx = GEN_INT (bitsize);
-      bitpos_rtx = GEN_INT (xbitpos);
-
-      pat = (unsignedp
-            ? gen_extzv (xtarget, xop0, bitsize_rtx, bitpos_rtx)
-            : gen_extv (xtarget, xop0, bitsize_rtx, bitpos_rtx));
-      if (pat)
+      create_output_operand (&ops[0], xtarget, ext_mode);
+      create_fixed_operand (&ops[1], xop0);
+      create_integer_operand (&ops[2], bitsize);
+      create_integer_operand (&ops[3], xbitpos);
+      if (maybe_expand_insn (unsignedp ? CODE_FOR_extzv : CODE_FOR_extv,
+                            4, ops))
        {
-         emit_insn (pat);
+         xtarget = ops[0].value;
          if (xtarget == xspec_target)
            return xtarget;
          if (xtarget == xspec_target_subreg)
            return xspec_target;
          return convert_extracted_bit_field (xtarget, mode, tmode, unsignedp);
        }
-      delete_insns_since (last);
     }
 
   /* If OP0 is a memory, try copying it to a register and seeing if a
@@ -1556,7 +1588,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
       if (GET_MODE (op0) == BLKmode
          || (ext_mode != MAX_MACHINE_MODE
              && GET_MODE_SIZE (GET_MODE (op0)) > GET_MODE_SIZE (ext_mode)))
-       bestmode = get_best_mode (bitsize, bitnum, MEM_ALIGN (op0),
+       bestmode = get_best_mode (bitsize, bitnum, 0, 0, MEM_ALIGN (op0),
                                  (ext_mode == MAX_MACHINE_MODE
                                   ? VOIDmode : ext_mode),
                                  MEM_VOLATILE_P (op0));
@@ -1587,7 +1619,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
              xop0 = adjust_address (op0, bestmode, xoffset);
              xop0 = force_reg (bestmode, xop0);
              result = extract_bit_field_1 (xop0, bitsize, xbitpos,
-                                           unsignedp, target,
+                                           unsignedp, packedp, target,
                                            mode, tmode, false);
              if (result)
                return result;
@@ -1601,7 +1633,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
     return NULL;
 
   target = extract_fixed_bit_field (int_mode, op0, offset, bitsize,
-                                   bitpos, target, unsignedp);
+                                   bitpos, target, unsignedp, packedp);
   return convert_extracted_bit_field (target, mode, tmode, unsignedp);
 }
 
@@ -1612,6 +1644,7 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
    STR_RTX is the structure containing the byte (a REG or MEM).
    UNSIGNEDP is nonzero if this is an unsigned bit field.
+   PACKEDP is nonzero if the field has the packed attribute.
    MODE is the natural mode of the field value once extracted.
    TMODE is the mode the caller would like the value to have;
    but the value may be returned with type MODE instead.
@@ -1623,10 +1656,10 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
 
 rtx
 extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
-                  unsigned HOST_WIDE_INT bitnum, int unsignedp, rtx target,
-                  enum machine_mode mode, enum machine_mode tmode)
+                  unsigned HOST_WIDE_INT bitnum, int unsignedp, bool packedp,
+                  rtx target, enum machine_mode mode, enum machine_mode tmode)
 {
-  return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp,
+  return extract_bit_field_1 (str_rtx, bitsize, bitnum, unsignedp, packedp,
                              target, mode, tmode, true);
 }
 \f
@@ -1642,6 +1675,8 @@ extract_bit_field (rtx str_rtx, unsigned HOST_WIDE_INT bitsize,
      which is significant on bigendian machines.)
 
    UNSIGNEDP is nonzero for an unsigned bit field (don't sign-extend value).
+   PACKEDP is true if the field has the packed attribute.
+
    If TARGET is nonzero, attempts to store the value there
    and return TARGET, but this is not guaranteed.
    If TARGET is not used, create a pseudo-reg of mode TMODE for the value.  */
@@ -1651,7 +1686,7 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
                         unsigned HOST_WIDE_INT offset,
                         unsigned HOST_WIDE_INT bitsize,
                         unsigned HOST_WIDE_INT bitpos, rtx target,
-                        int unsignedp)
+                        int unsignedp, bool packedp)
 {
   unsigned int total_bits = BITS_PER_WORD;
   enum machine_mode mode;
@@ -1668,8 +1703,19 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
         includes the entire field.  If such a mode would be larger than
         a word, we won't be doing the extraction the normal way.  */
 
-      mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT,
-                           MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0));
+      if (MEM_VOLATILE_P (op0)
+         && flag_strict_volatile_bitfields > 0)
+       {
+         if (GET_MODE_BITSIZE (GET_MODE (op0)) > 0)
+           mode = GET_MODE (op0);
+         else if (target && GET_MODE_BITSIZE (GET_MODE (target)) > 0)
+           mode = GET_MODE (target);
+         else
+           mode = tmode;
+       }
+      else
+       mode = get_best_mode (bitsize, bitpos + offset * BITS_PER_UNIT, 0, 0,
+                             MEM_ALIGN (op0), word_mode, MEM_VOLATILE_P (op0));
 
       if (mode == VOIDmode)
        /* The only way this should occur is if the field spans word
@@ -1690,12 +1736,67 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
                     * 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.
-        Then alter OP0 to refer to that word.  */
-      bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
-      offset -= (offset % (total_bits / BITS_PER_UNIT));
+      /* If we're accessing a volatile MEM, we can't do the next
+        alignment step if it results in a multi-word access where we
+        otherwise wouldn't have one.  So, check for that case
+        here.  */
+      if (MEM_P (op0)
+         && MEM_VOLATILE_P (op0)
+         && flag_strict_volatile_bitfields > 0
+         && bitpos + bitsize <= total_bits
+         && bitpos + bitsize + (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT > total_bits)
+       {
+         if (STRICT_ALIGNMENT)
+           {
+             static bool informed_about_misalignment = false;
+             bool warned;
+
+             if (packedp)
+               {
+                 if (bitsize == total_bits)
+                   warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
+                                        "multiple accesses to volatile structure member"
+                                        " because of packed attribute");
+                 else
+                   warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
+                                        "multiple accesses to volatile structure bitfield"
+                                        " because of packed attribute");
+
+                 return extract_split_bit_field (op0, bitsize,
+                                                 bitpos + offset * BITS_PER_UNIT,
+                                                 unsignedp);
+               }
+
+             if (bitsize == total_bits)
+               warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
+                                    "mis-aligned access used for structure member");
+             else
+               warned = warning_at (input_location, OPT_fstrict_volatile_bitfields,
+                                    "mis-aligned access used for structure bitfield");
+
+             if (! informed_about_misalignment && warned)
+               {
+                 informed_about_misalignment = true;
+                 inform (input_location,
+                         "when a volatile object spans multiple type-sized locations,"
+                         " the compiler must choose between using a single mis-aligned access to"
+                         " preserve the volatility, or using multiple aligned accesses to avoid"
+                         " runtime faults; this code may fail at runtime if the hardware does"
+                         " not allow this access");
+               }
+           }
+       }
+      else
+       {
+
+         /* 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.
+            Then alter OP0 to refer to that word.  */
+         bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
+         offset -= (offset % (total_bits / BITS_PER_UNIT));
+       }
+
       op0 = adjust_address (op0, mode, offset);
     }
 
@@ -1715,12 +1816,11 @@ 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);
          /* 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);
          if (tmode != mode) subtarget = 0;
-         op0 = expand_shift (RSHIFT_EXPR, mode, op0, amount, subtarget, 1);
+         op0 = expand_shift (RSHIFT_EXPR, mode, op0, bitpos, subtarget, 1);
        }
       /* Convert the value to the desired mode.  */
       if (mode != tmode)
@@ -1739,8 +1839,6 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
   /* To extract a signed bit-field, first shift its msb to the msb of the word,
      then arithmetic-shift its lsb to the lsb of the word.  */
   op0 = force_reg (mode, op0);
-  if (mode != tmode)
-    target = 0;
 
   /* Find the narrowest integer mode that contains the field.  */
 
@@ -1752,20 +1850,19 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
        break;
       }
 
+  if (mode != tmode)
+    target = 0;
+
   if (GET_MODE_BITSIZE (mode) != (bitsize + bitpos))
     {
-      tree amount
-       = build_int_cst (NULL_TREE,
-                        GET_MODE_BITSIZE (mode) - (bitsize + bitpos));
+      int amount = 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);
     }
 
   return expand_shift (RSHIFT_EXPR, mode, op0,
-                      build_int_cst (NULL_TREE,
-                                     GET_MODE_BITSIZE (mode) - bitsize),
-                      target, 0);
+                      GET_MODE_BITSIZE (mode) - bitsize, target, 0);
 }
 \f
 /* Return a constant integer (CONST_INT or CONST_DOUBLE) mask value
@@ -1777,39 +1874,15 @@ extract_fixed_bit_field (enum machine_mode tmode, rtx op0,
 static rtx
 mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
 {
-  HOST_WIDE_INT masklow, maskhigh;
+  double_int mask;
 
-  if (bitsize == 0)
-    masklow = 0;
-  else if (bitpos < HOST_BITS_PER_WIDE_INT)
-    masklow = (HOST_WIDE_INT) -1 << bitpos;
-  else
-    masklow = 0;
-
-  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_WIDE_INT)
-    maskhigh = -1;
-  else
-    maskhigh = (HOST_WIDE_INT) -1 << (bitpos - HOST_BITS_PER_WIDE_INT);
-
-  if (bitsize == 0)
-    maskhigh = 0;
-  else 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;
+  mask = double_int_mask (bitsize);
+  mask = double_int_lshift (mask, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
 
   if (complement)
-    {
-      maskhigh = ~maskhigh;
-      masklow = ~masklow;
-    }
+    mask = double_int_not (mask);
 
-  return immed_double_const (masklow, maskhigh, mode);
+  return immed_double_int_const (mask, mode);
 }
 
 /* Return a constant integer (CONST_INT or CONST_DOUBLE) rtx with the value
@@ -1818,24 +1891,12 @@ mask_rtx (enum machine_mode mode, int bitpos, int bitsize, int complement)
 static rtx
 lshift_value (enum machine_mode mode, rtx value, int bitpos, int bitsize)
 {
-  unsigned HOST_WIDE_INT v = INTVAL (value);
-  HOST_WIDE_INT low, high;
-
-  if (bitsize < HOST_BITS_PER_WIDE_INT)
-    v &= ~((HOST_WIDE_INT) -1 << bitsize);
-
-  if (bitpos < HOST_BITS_PER_WIDE_INT)
-    {
-      low = v << bitpos;
-      high = (bitpos > 0 ? (v >> (HOST_BITS_PER_WIDE_INT - bitpos)) : 0);
-    }
-  else
-    {
-      low = 0;
-      high = v << (bitpos - HOST_BITS_PER_WIDE_INT);
-    }
+  double_int val;
+  
+  val = double_int_zext (uhwi_to_double_int (INTVAL (value)), bitsize);
+  val = double_int_lshift (val, bitpos, HOST_BITS_PER_DOUBLE_INT, false);
 
-  return immed_double_const (low, high, mode);
+  return immed_double_int_const (val, mode);
 }
 \f
 /* Extract a bit field that is split across two words
@@ -1904,7 +1965,7 @@ extract_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize,
         extract_fixed_bit_field wants offset in bytes.  */
       part = extract_fixed_bit_field (word_mode, word,
                                      offset * unit / BITS_PER_UNIT,
-                                     thissize, thispos, 0, 1);
+                                     thissize, thispos, 0, 1, false);
       bitsdone += thissize;
 
       /* Shift this part into place for the result.  */
@@ -1912,15 +1973,13 @@ 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, 1);
+                                bitsize - bitsdone, 0, 1);
        }
       else
        {
          if (bitsdone != thissize)
            part = expand_shift (LSHIFT_EXPR, word_mode, part,
-                                build_int_cst (NULL_TREE,
-                                               bitsdone - thissize), 0, 1);
+                                bitsdone - thissize, 0, 1);
        }
 
       if (first)
@@ -1939,11 +1998,9 @@ 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),
-                        NULL_RTX, 0);
+                        BITS_PER_WORD - bitsize, NULL_RTX, 0);
   return expand_shift (RSHIFT_EXPR, word_mode, result,
-                      build_int_cst (NULL_TREE, BITS_PER_WORD - bitsize),
-                      NULL_RTX, 0);
+                      BITS_PER_WORD - bitsize, NULL_RTX, 0);
 }
 \f
 /* Try to read the low bits of SRC as an rvalue of mode MODE, preserving
@@ -1976,8 +2033,22 @@ extract_low_bits (enum machine_mode mode, enum machine_mode src_mode, rtx src)
     return src;
 
   if (CONSTANT_P (src))
-    return simplify_gen_subreg (mode, src, src_mode,
-                               subreg_lowpart_offset (mode, src_mode));
+    {
+      /* simplify_gen_subreg can't be used here, as if simplify_subreg
+        fails, it will happily create (subreg (symbol_ref)) or similar
+        invalid SUBREGs.  */
+      unsigned int byte = subreg_lowpart_offset (mode, src_mode);
+      rtx ret = simplify_subreg (mode, src, src_mode, byte);
+      if (ret)
+       return ret;
+
+      if (GET_MODE (src) == VOIDmode
+         || !validate_subreg (mode, src_mode, src, byte))
+       return NULL_RTX;
+
+      src = force_reg (GET_MODE (src), src);
+      return gen_rtx_SUBREG (mode, src, byte);
+    }
 
   if (GET_MODE_CLASS (mode) == MODE_CC || GET_MODE_CLASS (src_mode) == MODE_CC)
     return NULL_RTX;
@@ -2032,14 +2103,14 @@ expand_dec (rtx target, rtx dec)
 \f
 /* Output a shift instruction for expression code CODE,
    with SHIFTED being the rtx for the value to shift,
-   and AMOUNT the tree for the amount to shift by.
+   and AMOUNT the rtx for the amount to shift by.
    Store the result in the rtx TARGET, if that is convenient.
    If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic.
    Return the rtx for where the value is.  */
 
-rtx
-expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
-             tree amount, rtx target, int unsignedp)
+static rtx
+expand_shift_1 (enum tree_code code, enum machine_mode mode, rtx shifted,
+               rtx amount, rtx target, int unsignedp)
 {
   rtx op1, temp = 0;
   int left = (code == LSHIFT_EXPR || code == LROTATE_EXPR);
@@ -2050,9 +2121,10 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
   optab lrotate_optab = rotl_optab;
   optab rrotate_optab = rotr_optab;
   enum machine_mode op1_mode;
-  int try;
+  int attempt;
+  bool speed = optimize_insn_for_speed_p ();
 
-  op1 = expand_normal (amount);
+  op1 = amount;
   op1_mode = GET_MODE (op1);
 
   /* Determine whether the shift/rotate amount is a vector, or scalar.  If the
@@ -2072,13 +2144,14 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
 
   if (SHIFT_COUNT_TRUNCATED)
     {
-      if (GET_CODE (op1) == CONST_INT
+      if (CONST_INT_P (op1)
          && ((unsigned HOST_WIDE_INT) INTVAL (op1) >=
              (unsigned HOST_WIDE_INT) GET_MODE_BITSIZE (mode)))
        op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
                       % GET_MODE_BITSIZE (mode));
       else if (GET_CODE (op1) == SUBREG
-              && subreg_lowpart_p (op1))
+              && subreg_lowpart_p (op1)
+              && INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (op1))))
        op1 = SUBREG_REG (op1);
     }
 
@@ -2088,12 +2161,12 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
   /* Check whether its cheaper to implement a left shift by a constant
      bit count by a sequence of additions.  */
   if (code == LSHIFT_EXPR
-      && GET_CODE (op1) == CONST_INT
+      && CONST_INT_P (op1)
       && INTVAL (op1) > 0
-      && INTVAL (op1) < GET_MODE_BITSIZE (mode)
+      && INTVAL (op1) < GET_MODE_PRECISION (mode)
       && INTVAL (op1) < MAX_BITS_PER_WORD
-      && shift_cost[mode][INTVAL (op1)] > INTVAL (op1) * add_cost[mode]
-      && shift_cost[mode][INTVAL (op1)] != MAX_COST)
+      && shift_cost[speed][mode][INTVAL (op1)] > INTVAL (op1) * add_cost[speed][mode]
+      && shift_cost[speed][mode][INTVAL (op1)] != MAX_COST)
     {
       int i;
       for (i = 0; i < INTVAL (op1); i++)
@@ -2105,13 +2178,13 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
       return shifted;
     }
 
-  for (try = 0; temp == 0 && try < 3; try++)
+  for (attempt = 0; temp == 0 && attempt < 3; attempt++)
     {
       enum optab_methods methods;
 
-      if (try == 0)
+      if (attempt == 0)
        methods = OPTAB_DIRECT;
-      else if (try == 1)
+      else if (attempt == 1)
        methods = OPTAB_WIDEN;
       else
        methods = OPTAB_LIB_WIDEN;
@@ -2136,24 +2209,26 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
                 code below.  */
 
              rtx subtarget = target == shifted ? 0 : target;
-             tree new_amount, other_amount;
+             rtx new_amount, other_amount;
              rtx temp1;
-             tree type = TREE_TYPE (amount);
-             if (GET_MODE (op1) != TYPE_MODE (type)
-                 && GET_MODE (op1) != VOIDmode)
-               op1 = convert_to_mode (TYPE_MODE (type), op1, 1);
-             new_amount = make_tree (type, op1);
-             other_amount
-               = fold_build2 (MINUS_EXPR, type,
-                              build_int_cst (type, GET_MODE_BITSIZE (mode)),
-                              new_amount);
+
+             new_amount = op1;
+             if (CONST_INT_P (op1))
+               other_amount = GEN_INT (GET_MODE_BITSIZE (mode)
+                                       - INTVAL (op1));
+             else
+               other_amount
+                 = simplify_gen_binary (MINUS, GET_MODE (op1),
+                                        GEN_INT (GET_MODE_PRECISION (mode)),
+                                        op1);
 
              shifted = force_reg (mode, shifted);
 
-             temp = expand_shift (left ? LSHIFT_EXPR : RSHIFT_EXPR,
-                                  mode, shifted, new_amount, 0, 1);
-             temp1 = expand_shift (left ? RSHIFT_EXPR : LSHIFT_EXPR,
-                                   mode, shifted, other_amount, subtarget, 1);
+             temp = expand_shift_1 (left ? LSHIFT_EXPR : RSHIFT_EXPR,
+                                    mode, shifted, new_amount, 0, 1);
+             temp1 = expand_shift_1 (left ? RSHIFT_EXPR : LSHIFT_EXPR,
+                                     mode, shifted, other_amount,
+                                     subtarget, 1);
              return expand_binop (mode, ior_optab, temp, temp1, target,
                                   unsignedp, methods);
            }
@@ -2196,111 +2271,38 @@ expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
   gcc_assert (temp);
   return temp;
 }
-\f
-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_impossible
-};
-
-/* 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.
-   `cost' is their total cost.
-   The operations are stored in `op' and the corresponding
-   logarithms of the integer coefficients in `log'.
-
-   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
-{
-  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
-     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];
-  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 HOST_WIDE_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;
+/* Output a shift instruction for expression code CODE,
+   with SHIFTED being the rtx for the value to shift,
+   and AMOUNT the amount to shift by.
+   Store the result in the rtx TARGET, if that is convenient.
+   If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic.
+   Return the rtx for where the value is.  */
 
-  /* The cost of multiplication if ALG_CODE is not alg_impossible.
-     Otherwise, the cost within which multiplication by T is
-     impossible.  */
-  struct mult_cost cost;
-};
+rtx
+expand_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
+             int amount, rtx target, int unsignedp)
+{
+  return expand_shift_1 (code, mode,
+                        shifted, GEN_INT (amount), target, unsignedp);
+}
 
-/* The number of cache/hash entries.  */
-#if HOST_BITS_PER_WIDE_INT == 64
-#define NUM_ALG_HASH_ENTRIES 1031
-#else
-#define NUM_ALG_HASH_ENTRIES 307
-#endif
+/* Output a shift instruction for expression code CODE,
+   with SHIFTED being the rtx for the value to shift,
+   and AMOUNT the tree for the amount to shift by.
+   Store the result in the rtx TARGET, if that is convenient.
+   If UNSIGNEDP is nonzero, do a logical shift; otherwise, arithmetic.
+   Return the rtx for where the value is.  */
 
-/* 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];
+rtx
+expand_variable_shift (enum tree_code code, enum machine_mode mode, rtx shifted,
+                      tree amount, rtx target, int unsignedp)
+{
+  return expand_shift_1 (code, mode,
+                        shifted, expand_normal (amount), target, unsignedp);
+}
 
+\f
 /* 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
@@ -2335,11 +2337,13 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
   struct mult_cost best_cost;
   struct mult_cost new_limit;
   int op_cost, op_latency;
+  unsigned HOST_WIDE_INT orig_t = t;
   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;
+  bool speed = optimize_insn_for_speed_p ();
 
   /* Indicate that no algorithm is yet found.  If no algorithm
      is found, this value will be returned and indicate failure.  */
@@ -2367,13 +2371,13 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
      fail now.  */
   if (t == 0)
     {
-      if (MULT_COST_LESS (cost_limit, zero_cost))
+      if (MULT_COST_LESS (cost_limit, zero_cost[speed]))
        return;
       else
        {
          alg_out->ops = 1;
-         alg_out->cost.cost = zero_cost;
-         alg_out->cost.latency = zero_cost;
+         alg_out->cost.cost = zero_cost[speed];
+         alg_out->cost.latency = zero_cost[speed];
          alg_out->op[0] = alg_zero;
          return;
        }
@@ -2381,16 +2385,18 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
 
   /* We'll be needing a couple extra algorithm structures now.  */
 
-  alg_in = alloca (sizeof (struct algorithm));
-  best_alg = alloca (sizeof (struct algorithm));
+  alg_in = XALLOCA (struct algorithm);
+  best_alg = XALLOCA (struct algorithm);
   best_cost = *cost_limit;
 
   /* Compute the hash index.  */
-  hash_index = (t ^ (unsigned int) mode) % NUM_ALG_HASH_ENTRIES;
+  hash_index = (t ^ (unsigned int) mode ^ (speed * 256)) % 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].mode == mode
+      && alg_hash[hash_index].speed == speed
       && alg_hash[hash_index].alg != alg_unknown)
     {
       cache_alg = alg_hash[hash_index].alg;
@@ -2459,10 +2465,10 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
          q = t >> m;
          /* 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]).  */
-         op_cost = m * add_cost[mode];
-         if (shift_cost[mode][m] < op_cost)
-           op_cost = shift_cost[mode][m];
+            MIN (m * add_cost[speed][mode], shift_cost[speed][mode][m]).  */
+         op_cost = m * add_cost[speed][mode];
+         if (shift_cost[speed][mode][m] < op_cost)
+           op_cost = shift_cost[speed][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);
@@ -2477,6 +2483,38 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
              best_alg->log[best_alg->ops] = m;
              best_alg->op[best_alg->ops] = alg_shift;
            }
+
+         /* See if treating ORIG_T as a signed number yields a better
+            sequence.  Try this sequence only for a negative ORIG_T
+            as it would be useless for a non-negative ORIG_T.  */
+         if ((HOST_WIDE_INT) orig_t < 0)
+           {
+             /* Shift ORIG_T as follows because a right shift of a
+                negative-valued signed type is implementation
+                defined.  */
+             q = ~(~orig_t >> m);
+             /* 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[speed][mode],
+                shift_cost[speed][mode][m]).  */
+             op_cost = m * add_cost[speed][mode];
+             if (shift_cost[speed][mode][m] < op_cost)
+               op_cost = shift_cost[speed][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;
+               }
+           }
        }
       if (cache_hit)
        goto done;
@@ -2503,7 +2541,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
        {
          /* T ends with ...111.  Multiply by (T + 1) and subtract 1.  */
 
-         op_cost = add_cost[mode];
+         op_cost = add_cost[speed][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);
@@ -2523,7 +2561,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
        {
          /* T ends with ...01 or ...011.  Multiply by (T - 1) and add 1.  */
 
-         op_cost = add_cost[mode];
+         op_cost = add_cost[speed][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);
@@ -2539,6 +2577,29 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
              best_alg->op[best_alg->ops] = alg_add_t_m2;
            }
        }
+
+      /* We may be able to calculate a * -7, a * -15, a * -31, etc
+        quickly with a - a * n for some appropriate constant n.  */
+      m = exact_log2 (-orig_t + 1);
+      if (m >= 0 && m < maxm)
+       {
+         op_cost = shiftsub1_cost[speed][mode][m];
+         new_limit.cost = best_cost.cost - op_cost;
+         new_limit.latency = best_cost.latency - op_cost;
+         synth_mult (alg_in, (unsigned HOST_WIDE_INT) (-orig_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_t_m2;
+           }
+       }
+
       if (cache_hit)
        goto done;
     }
@@ -2568,14 +2629,14 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
             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 = add_cost[speed][mode] + shift_cost[speed][mode][m];
+         if (shiftadd_cost[speed][mode][m] < op_cost)
            {
-             op_cost = shiftadd_cost[mode][m];
+             op_cost = shiftadd_cost[speed][mode][m];
              op_latency = op_cost;
            }
          else
-           op_latency = add_cost[mode];
+           op_latency = add_cost[speed][mode];
 
          new_limit.cost = best_cost.cost - op_cost;
          new_limit.latency = best_cost.latency - op_latency;
@@ -2607,14 +2668,14 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
             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 = add_cost[speed][mode] + shift_cost[speed][mode][m];
+         if (shiftsub0_cost[speed][mode][m] < op_cost)
            {
-             op_cost = shiftsub_cost[mode][m];
+             op_cost = shiftsub0_cost[speed][mode][m];
              op_latency = op_cost;
            }
          else
-           op_latency = add_cost[mode];
+           op_latency = add_cost[speed][mode];
 
          new_limit.cost = best_cost.cost - op_cost;
          new_limit.latency = best_cost.latency - op_latency;
@@ -2648,7 +2709,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
       m = exact_log2 (q);
       if (m >= 0 && m < maxm)
        {
-         op_cost = shiftadd_cost[mode][m];
+         op_cost = shiftadd_cost[speed][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);
@@ -2673,7 +2734,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
       m = exact_log2 (q);
       if (m >= 0 && m < maxm)
        {
-         op_cost = shiftsub_cost[mode][m];
+         op_cost = shiftsub0_cost[speed][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);
@@ -2704,6 +2765,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
         caller.  */
       alg_hash[hash_index].t = t;
       alg_hash[hash_index].mode = mode;
+      alg_hash[hash_index].speed = speed;
       alg_hash[hash_index].alg = alg_impossible;
       alg_hash[hash_index].cost = *cost_limit;
       return;
@@ -2714,6 +2776,7 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t,
     {
       alg_hash[hash_index].t = t;
       alg_hash[hash_index].mode = mode;
+      alg_hash[hash_index].speed = speed;
       alg_hash[hash_index].alg = best_alg->op[best_alg->ops];
       alg_hash[hash_index].cost.cost = best_cost.cost;
       alg_hash[hash_index].cost.latency = best_cost.latency;
@@ -2753,6 +2816,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
   struct algorithm alg2;
   struct mult_cost limit;
   int op_cost;
+  bool speed = optimize_insn_for_speed_p ();
 
   /* Fail quickly for impossible bounds.  */
   if (mult_cost < 0)
@@ -2761,7 +2825,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
   /* Ensure that mult_cost provides a reasonable upper bound.
      Any constant multiplication can be performed with less
      than 2 * bits additions.  */
-  op_cost = 2 * GET_MODE_BITSIZE (mode) * add_cost[mode];
+  op_cost = 2 * GET_MODE_BITSIZE (mode) * add_cost[speed][mode];
   if (mult_cost > op_cost)
     mult_cost = op_cost;
 
@@ -2774,7 +2838,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
      `unsigned int' */
   if (HOST_BITS_PER_INT >= GET_MODE_BITSIZE (mode))
     {
-      op_cost = neg_cost[mode];
+      op_cost = neg_cost[speed][mode];
       if (MULT_COST_LESS (&alg->cost, mult_cost))
        {
          limit.cost = alg->cost.cost - op_cost;
@@ -2794,7 +2858,7 @@ choose_mult_variant (enum machine_mode mode, HOST_WIDE_INT val,
     }
 
   /* This proves very useful for division-by-constant.  */
-  op_cost = add_cost[mode];
+  op_cost = add_cost[speed][mode];
   if (MULT_COST_LESS (&alg->cost, mult_cost))
     {
       limit.cost = alg->cost.cost - op_cost;
@@ -2863,25 +2927,21 @@ expand_mult_const (enum machine_mode mode, rtx op0, HOST_WIDE_INT val,
       switch (alg->op[opno])
        {
        case alg_shift:
-         accum = expand_shift (LSHIFT_EXPR, mode, accum,
-                               build_int_cst (NULL_TREE, log),
-                               NULL_RTX, 0);
+         tem = expand_shift (LSHIFT_EXPR, mode, accum, log, NULL_RTX, 0);
+         /* REG_EQUAL note will be attached to the following insn.  */
+         emit_move_insn (accum, tem);
          val_so_far <<= log;
          break;
 
        case alg_add_t_m2:
-         tem = expand_shift (LSHIFT_EXPR, mode, op0,
-                             build_int_cst (NULL_TREE, log),
-                             NULL_RTX, 0);
+         tem = expand_shift (LSHIFT_EXPR, mode, op0, log, NULL_RTX, 0);
          accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
          val_so_far += (HOST_WIDE_INT) 1 << log;
          break;
 
        case alg_sub_t_m2:
-         tem = expand_shift (LSHIFT_EXPR, mode, op0,
-                             build_int_cst (NULL_TREE, log),
-                             NULL_RTX, 0);
+         tem = expand_shift (LSHIFT_EXPR, mode, op0, log, NULL_RTX, 0);
          accum = force_operand (gen_rtx_MINUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
          val_so_far -= (HOST_WIDE_INT) 1 << log;
@@ -2889,9 +2949,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),
-                               shift_subtarget,
-                               0);
+                               log, shift_subtarget, 0);
          accum = force_operand (gen_rtx_PLUS (mode, accum, op0),
                                 add_target ? add_target : accum_target);
          val_so_far = (val_so_far << log) + 1;
@@ -2899,26 +2957,21 @@ 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),
-                               shift_subtarget, 0);
+                               log, shift_subtarget, 0);
          accum = force_operand (gen_rtx_MINUS (mode, accum, op0),
                                 add_target ? add_target : accum_target);
          val_so_far = (val_so_far << log) - 1;
          break;
 
        case alg_add_factor:
-         tem = expand_shift (LSHIFT_EXPR, mode, accum,
-                             build_int_cst (NULL_TREE, log),
-                             NULL_RTX, 0);
+         tem = expand_shift (LSHIFT_EXPR, mode, accum, log, NULL_RTX, 0);
          accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
                                 add_target ? add_target : accum_target);
          val_so_far += val_so_far << log;
          break;
 
        case alg_sub_factor:
-         tem = expand_shift (LSHIFT_EXPR, mode, accum,
-                             build_int_cst (NULL_TREE, log),
-                             NULL_RTX, 0);
+         tem = expand_shift (LSHIFT_EXPR, mode, accum, log, NULL_RTX, 0);
          accum = force_operand (gen_rtx_MINUS (mode, tem, accum),
                                 (add_target
                                  ? add_target : (optimize ? 0 : tem)));
@@ -2982,6 +3035,7 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   enum mult_variant variant;
   struct algorithm algorithm;
   int max_cost;
+  bool speed = optimize_insn_for_speed_p ();
 
   /* Handling const0_rtx here allows us to use zero as a rogue value for
      coeff below.  */
@@ -3011,7 +3065,7 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
         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)
+      if (CONST_INT_P (op1))
        {
          /* Attempt to handle multiplication of DImode values by negative
             coefficients, by performing the multiplication by a positive
@@ -3023,8 +3077,8 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
                 result is interpreted as an unsigned coefficient.
                 Exclude cost of op0 from max_cost to match the cost
                 calculation of the synth_mult.  */
-             max_cost = rtx_cost (gen_rtx_MULT (mode, fake_reg, op1), SET)
-                        - neg_cost[mode];
+             max_cost = rtx_cost (gen_rtx_MULT (mode, fake_reg, op1), SET, speed)
+                        - neg_cost[speed][mode];
              if (max_cost > 0
                  && choose_mult_variant (mode, -INTVAL (op1), &algorithm,
                                          &variant, max_cost))
@@ -3041,7 +3095,8 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
        {
          /* 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)
+         if (CONST_DOUBLE_HIGH (op1) == 0
+             && CONST_DOUBLE_LOW (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)))
@@ -3049,11 +3104,10 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
              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);
+                                  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
@@ -3063,12 +3117,11 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
          /* 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);
+                                floor_log2 (coeff), target, unsignedp);
 
          /* Exclude cost of op0 from max_cost to match the cost
             calculation of the synth_mult.  */
-         max_cost = rtx_cost (gen_rtx_MULT (mode, fake_reg, op1), SET);
+         max_cost = rtx_cost (gen_rtx_MULT (mode, fake_reg, op1), SET, speed);
          if (choose_mult_variant (mode, coeff, &algorithm, &variant,
                                   max_cost))
            return expand_mult_const (mode, op0, coeff, target,
@@ -3108,6 +3161,59 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   gcc_assert (op0);
   return op0;
 }
+
+/* Perform a widening multiplication and return an rtx for the result.
+   MODE is mode of value; OP0 and OP1 are what to multiply (rtx's);
+   TARGET is a suggestion for where to store the result (an rtx).
+   THIS_OPTAB is the optab we should use, it must be either umul_widen_optab
+   or smul_widen_optab.
+
+   We check specially for a constant integer as OP1, comparing the
+   cost of a widening multiply against the cost of a sequence of shifts
+   and adds.  */
+
+rtx
+expand_widening_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+                     int unsignedp, optab this_optab)
+{
+  bool speed = optimize_insn_for_speed_p ();
+  rtx cop1;
+
+  if (CONST_INT_P (op1)
+      && GET_MODE (op0) != VOIDmode
+      && (cop1 = convert_modes (mode, GET_MODE (op0), op1,
+                               this_optab == umul_widen_optab))
+      && CONST_INT_P (cop1)
+      && (INTVAL (cop1) >= 0
+         || HWI_COMPUTABLE_MODE_P (mode)))
+    {
+      HOST_WIDE_INT coeff = INTVAL (cop1);
+      int max_cost;
+      enum mult_variant variant;
+      struct algorithm algorithm;
+
+      /* Special case powers of two.  */
+      if (EXACT_POWER_OF_2_OR_ZERO_P (coeff))
+       {
+         op0 = convert_to_mode (mode, op0, this_optab == umul_widen_optab);
+         return expand_shift (LSHIFT_EXPR, mode, op0,
+                              floor_log2 (coeff), target, unsignedp);
+       }
+
+      /* Exclude cost of op0 from max_cost to match the cost
+        calculation of the synth_mult.  */
+      max_cost = mul_widen_cost[speed][mode];
+      if (choose_mult_variant (mode, coeff, &algorithm, &variant,
+                              max_cost))
+       {
+         op0 = convert_to_mode (mode, op0, this_optab == umul_widen_optab);
+         return expand_mult_const (mode, op0, coeff, target,
+                                   &algorithm, variant);
+       }
+    }
+  return expand_binop (mode, this_optab, op0, op1, target,
+                      unsignedp, OPTAB_LIB_WIDEN);
+}
 \f
 /* Return the smallest n such that 2**n >= X.  */
 
@@ -3264,16 +3370,14 @@ 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),
-                     NULL_RTX, 0);
+                     GET_MODE_BITSIZE (mode) - 1, NULL_RTX, 0);
   tem = expand_and (mode, tem, op1, NULL_RTX);
   adj_operand
     = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
                     adj_operand);
 
   tem = expand_shift (RSHIFT_EXPR, mode, op1,
-                     build_int_cst (NULL_TREE, GET_MODE_BITSIZE (mode) - 1),
-                     NULL_RTX, 0);
+                     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),
                          target);
@@ -3295,7 +3399,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, 1);
+                    GET_MODE_BITSIZE (mode), 0, 1);
   return convert_modes (mode, wider_mode, op, 0);
 }
 
@@ -3311,6 +3415,7 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
   optab moptab;
   rtx tem;
   int size;
+  bool speed = optimize_insn_for_speed_p ();
 
   gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
 
@@ -3319,7 +3424,7 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
 
   /* Firstly, try using a multiplication insn that only generates the needed
      high part of the product, and in the sign flavor of unsignedp.  */
-  if (mul_highpart_cost[mode] < max_cost)
+  if (mul_highpart_cost[speed][mode] < max_cost)
     {
       moptab = unsignedp ? umul_highpart_optab : smul_highpart_optab;
       tem = expand_binop (mode, moptab, op0, narrow_op1, target,
@@ -3331,8 +3436,8 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
   /* Secondly, same as above, but use sign flavor opposite of unsignedp.
      Need to adjust the result after the multiplication.  */
   if (size - 1 < BITS_PER_WORD
-      && (mul_highpart_cost[mode] + 2 * shift_cost[mode][size-1]
-         + 4 * add_cost[mode] < max_cost))
+      && (mul_highpart_cost[speed][mode] + 2 * shift_cost[speed][mode][size-1]
+         + 4 * add_cost[speed][mode] < max_cost))
     {
       moptab = unsignedp ? smul_highpart_optab : umul_highpart_optab;
       tem = expand_binop (mode, moptab, op0, narrow_op1, target,
@@ -3345,8 +3450,8 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
 
   /* Try widening multiplication.  */
   moptab = unsignedp ? umul_widen_optab : smul_widen_optab;
-  if (optab_handler (moptab, wider_mode)->insn_code != CODE_FOR_nothing
-      && mul_widen_cost[wider_mode] < max_cost)
+  if (optab_handler (moptab, wider_mode) != CODE_FOR_nothing
+      && mul_widen_cost[speed][wider_mode] < max_cost)
     {
       tem = expand_binop (wider_mode, moptab, op0, narrow_op1, 0,
                          unsignedp, OPTAB_WIDEN);
@@ -3355,9 +3460,9 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
     }
 
   /* Try widening the mode and perform a non-widening multiplication.  */
-  if (optab_handler (smul_optab, wider_mode)->insn_code != CODE_FOR_nothing
+  if (optab_handler (smul_optab, wider_mode) != CODE_FOR_nothing
       && size - 1 < BITS_PER_WORD
-      && mul_cost[wider_mode] + shift_cost[mode][size-1] < max_cost)
+      && mul_cost[speed][wider_mode] + shift_cost[speed][mode][size-1] < max_cost)
     {
       rtx insns, wop0, wop1;
 
@@ -3382,10 +3487,10 @@ expand_mult_highpart_optab (enum machine_mode mode, rtx op0, rtx op1,
 
   /* Try widening multiplication of opposite signedness, and adjust.  */
   moptab = unsignedp ? smul_widen_optab : umul_widen_optab;
-  if (optab_handler (moptab, wider_mode)->insn_code != CODE_FOR_nothing
+  if (optab_handler (moptab, wider_mode) != CODE_FOR_nothing
       && size - 1 < BITS_PER_WORD
-      && (mul_widen_cost[wider_mode] + 2 * shift_cost[mode][size-1]
-         + 4 * add_cost[mode] < max_cost))
+      && (mul_widen_cost[speed][wider_mode] + 2 * shift_cost[speed][mode][size-1]
+         + 4 * add_cost[speed][mode] < max_cost))
     {
       tem = expand_binop (wider_mode, moptab, op0, narrow_op1,
                          NULL_RTX, ! unsignedp, OPTAB_WIDEN);
@@ -3423,28 +3528,29 @@ expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
   enum mult_variant variant;
   struct algorithm alg;
   rtx tem;
+  bool speed = optimize_insn_for_speed_p ();
 
   gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
   /* We can't support modes wider than HOST_BITS_PER_INT.  */
-  gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT);
+  gcc_assert (HWI_COMPUTABLE_MODE_P (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 
+  /* We can't optimize modes wider than BITS_PER_WORD.
+     ??? We might be able to perform double-word arithmetic if
      mode == word_mode, however all the cost calculations in
      synth_mult etc. assume single-word operations.  */
   if (GET_MODE_BITSIZE (wider_mode) > BITS_PER_WORD)
     return expand_mult_highpart_optab (mode, op0, op1, target,
                                       unsignedp, max_cost);
 
-  extra_cost = shift_cost[mode][GET_MODE_BITSIZE (mode) - 1];
+  extra_cost = shift_cost[speed][mode][GET_MODE_BITSIZE (mode) - 1];
 
   /* Check whether we try to multiply by a negative constant.  */
   if (!unsignedp && ((cnst1 >> (GET_MODE_BITSIZE (mode) - 1)) & 1))
     {
       sign_adjust = true;
-      extra_cost += add_cost[mode];
+      extra_cost += add_cost[speed][mode];
     }
 
   /* See whether shift/add multiplication is cheap enough.  */
@@ -3486,8 +3592,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
   result = gen_reg_rtx (mode);
 
   /* Avoid conditional branches when they're expensive.  */
-  if (BRANCH_COST >= 2
-      && !optimize_size)
+  if (BRANCH_COST (optimize_insn_for_speed_p (), false) >= 2
+      && optimize_insn_for_speed_p ())
     {
       rtx signmask = emit_store_flag (result, LT, op0, const0_rtx,
                                      mode, 0, -1);
@@ -3503,8 +3609,8 @@ expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
             use a LSHIFTRT, 1 ADD, 1 SUB and an AND.  */
 
          temp = gen_rtx_LSHIFTRT (mode, result, shift);
-         if (optab_handler (lshr_optab, mode)->insn_code == CODE_FOR_nothing
-             || rtx_cost (temp, SET) > COSTS_N_INSNS (2))
+         if (optab_handler (lshr_optab, mode) == CODE_FOR_nothing
+             || rtx_cost (temp, SET, optimize_insn_for_speed_p ()) > COSTS_N_INSNS (2))
            {
              temp = expand_binop (mode, xor_optab, op0, signmask,
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -3580,23 +3686,24 @@ static rtx
 expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
 {
   rtx temp, label;
-  tree shift;
   int logd;
 
   logd = floor_log2 (d);
-  shift = build_int_cst (NULL_TREE, logd);
 
-  if (d == 2 && BRANCH_COST >= 1)
+  if (d == 2
+      && BRANCH_COST (optimize_insn_for_speed_p (),
+                     false) >= 1)
     {
       temp = gen_reg_rtx (mode);
       temp = emit_store_flag (temp, LT, op0, const0_rtx, mode, 0, 1);
       temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
                           0, OPTAB_LIB_WIDEN);
-      return expand_shift (RSHIFT_EXPR, mode, temp, shift, NULL_RTX, 0);
+      return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
     }
 
 #ifdef HAVE_conditional_move
-  if (BRANCH_COST >= 2)
+  if (BRANCH_COST (optimize_insn_for_speed_p (), false)
+      >= 2)
     {
       rtx temp2;
 
@@ -3619,28 +3726,28 @@ expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
          rtx seq = get_insns ();
          end_sequence ();
          emit_insn (seq);
-         return expand_shift (RSHIFT_EXPR, mode, temp2, shift, NULL_RTX, 0);
+         return expand_shift (RSHIFT_EXPR, mode, temp2, logd, NULL_RTX, 0);
        }
       end_sequence ();
     }
 #endif
 
-  if (BRANCH_COST >= 2)
+  if (BRANCH_COST (optimize_insn_for_speed_p (),
+                  false) >= 2)
     {
       int ushift = GET_MODE_BITSIZE (mode) - logd;
 
       temp = gen_reg_rtx (mode);
       temp = emit_store_flag (temp, LT, op0, const0_rtx, mode, 0, -1);
-      if (shift_cost[mode][ushift] > COSTS_N_INSNS (1))
+      if (shift_cost[optimize_insn_for_speed_p ()][mode][ushift] > COSTS_N_INSNS (1))
        temp = expand_binop (mode, and_optab, temp, GEN_INT (d - 1),
                             NULL_RTX, 0, OPTAB_LIB_WIDEN);
       else
        temp = expand_shift (RSHIFT_EXPR, mode, temp,
-                            build_int_cst (NULL_TREE, ushift),
-                            NULL_RTX, 1);
+                            ushift, NULL_RTX, 1);
       temp = expand_binop (mode, add_optab, temp, op0, NULL_RTX,
                           0, OPTAB_LIB_WIDEN);
-      return expand_shift (RSHIFT_EXPR, mode, temp, shift, NULL_RTX, 0);
+      return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
     }
 
   label = gen_label_rtx ();
@@ -3648,7 +3755,7 @@ expand_sdiv_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
   do_cmp_and_jump (temp, const0_rtx, GE, mode, label);
   expand_inc (temp, GEN_INT (d - 1));
   emit_label (label);
-  return expand_shift (RSHIFT_EXPR, mode, temp, shift, NULL_RTX, 0);
+  return expand_shift (RSHIFT_EXPR, mode, temp, logd, NULL_RTX, 0);
 }
 \f
 /* Emit the code to divide OP0 by OP1, putting the result in TARGET
@@ -3704,8 +3811,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
   int max_cost, extra_cost;
   static HOST_WIDE_INT last_div_const = 0;
   static HOST_WIDE_INT ext_op1;
+  bool speed = optimize_insn_for_speed_p ();
 
-  op1_is_constant = GET_CODE (op1) == CONST_INT;
+  op1_is_constant = CONST_INT_P (op1);
   if (op1_is_constant)
     {
       ext_op1 = INTVAL (op1);
@@ -3802,8 +3910,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 
   for (compute_mode = mode; compute_mode != VOIDmode;
        compute_mode = GET_MODE_WIDER_MODE (compute_mode))
-    if (optab_handler (optab1, compute_mode)->insn_code != CODE_FOR_nothing
-       || optab_handler (optab2, compute_mode)->insn_code != CODE_FOR_nothing)
+    if (optab_handler (optab1, compute_mode) != CODE_FOR_nothing
+       || optab_handler (optab2, compute_mode) != CODE_FOR_nothing)
       break;
 
   if (compute_mode == VOIDmode)
@@ -3834,10 +3942,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
   /* Only deduct something for a REM if the last divide done was
      for a different constant.   Then set the constant of the last
      divide.  */
-  max_cost = unsignedp ? udiv_cost[compute_mode] : sdiv_cost[compute_mode];
+  max_cost = unsignedp ? udiv_cost[speed][compute_mode] : sdiv_cost[speed][compute_mode];
   if (rem_flag && ! (last_div_const != 0 && op1_is_constant
                     && INTVAL (op1) == last_div_const))
-    max_cost -= mul_cost[compute_mode] + add_cost[compute_mode];
+    max_cost -= mul_cost[speed][compute_mode] + add_cost[speed][compute_mode];
 
   last_div_const = ! rem_flag && op1_is_constant ? INTVAL (op1) : 0;
 
@@ -3849,7 +3957,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 
       /* convert_modes may have placed op1 into a register, so we
         must recompute the following.  */
-      op1_is_constant = GET_CODE (op1) == CONST_INT;
+      op1_is_constant = CONST_INT_P (op1);
       op1_is_pow2 = (op1_is_constant
                     && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
                          || (! unsignedp
@@ -3911,9 +4019,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                          return gen_lowpart (mode, remainder);
                      }
                    quotient = expand_shift (RSHIFT_EXPR, compute_mode, op0,
-                                            build_int_cst (NULL_TREE,
-                                                           pre_shift),
-                                            tquotient, 1);
+                                            pre_shift, tquotient, 1);
                  }
                else if (size <= HOST_BITS_PER_WIDE_INT)
                  {
@@ -3921,10 +4027,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                      {
                        /* Most significant bit of divisor is set; emit an scc
                           insn.  */
-                       quotient = emit_store_flag (tquotient, GEU, op0, op1,
-                                                   compute_mode, 1, 1);
-                       if (quotient == 0)
-                         goto fail1;
+                       quotient = emit_store_flag_force (tquotient, GEU, op0, op1,
+                                                         compute_mode, 1, 1);
                      }
                    else
                      {
@@ -3956,9 +4060,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                              goto fail1;
 
                            extra_cost
-                             = (shift_cost[compute_mode][post_shift - 1]
-                                + shift_cost[compute_mode][1]
-                                + 2 * add_cost[compute_mode]);
+                             = (shift_cost[speed][compute_mode][post_shift - 1]
+                                + shift_cost[speed][compute_mode][1]
+                                + 2 * add_cost[speed][compute_mode]);
                            t1 = expand_mult_highpart (compute_mode, op0, ml,
                                                       NULL_RTX, 1,
                                                       max_cost - extra_cost);
@@ -3967,17 +4071,14 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                            t2 = force_operand (gen_rtx_MINUS (compute_mode,
                                                               op0, t1),
                                                NULL_RTX);
-                           t3 = expand_shift
-                             (RSHIFT_EXPR, compute_mode, t2,
-                              build_int_cst (NULL_TREE, 1),
-                              NULL_RTX,1);
+                           t3 = expand_shift (RSHIFT_EXPR, compute_mode,
+                                              t2, 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),
-                              tquotient, 1);
+                              post_shift - 1, tquotient, 1);
                          }
                        else
                          {
@@ -3989,11 +4090,10 @@ 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),
-                              NULL_RTX, 1);
+                              pre_shift, NULL_RTX, 1);
                            extra_cost
-                             = (shift_cost[compute_mode][pre_shift]
-                                + shift_cost[compute_mode][post_shift]);
+                             = (shift_cost[speed][compute_mode][pre_shift]
+                                + shift_cost[speed][compute_mode][post_shift]);
                            t2 = expand_mult_highpart (compute_mode, t1, ml,
                                                       NULL_RTX, 1,
                                                       max_cost - extra_cost);
@@ -4001,8 +4101,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),
-                              tquotient, 1);
+                              post_shift, tquotient, 1);
                          }
                      }
                  }
@@ -4044,7 +4143,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                else if (d == -1)
                  quotient = expand_unop (compute_mode, neg_optab, op0,
                                          tquotient, 0);
-               else if (abs_d == (unsigned HOST_WIDE_INT) 1 << (size - 1))
+               else if (HOST_BITS_PER_WIDE_INT >= size
+                        && abs_d == (unsigned HOST_WIDE_INT) 1 << (size - 1))
                  {
                    /* This case is not handled correctly below.  */
                    quotient = emit_store_flag (tquotient, EQ, op0, op1,
@@ -4053,17 +4153,17 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                      goto fail1;
                  }
                else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
-                        && (rem_flag ? smod_pow2_cheap[compute_mode]
-                                     : sdiv_pow2_cheap[compute_mode])
+                        && (rem_flag ? smod_pow2_cheap[speed][compute_mode]
+                                     : sdiv_pow2_cheap[speed][compute_mode])
                         /* We assume that cheap metric is true if the
                            optab has an expander for this mode.  */
                         && ((optab_handler ((rem_flag ? smod_optab
                                              : sdiv_optab),
-                                             compute_mode)->insn_code
+                                            compute_mode)
                              != CODE_FOR_nothing)
-                            || (optab_handler(sdivmod_optab,
-                                              compute_mode)
-                                ->insn_code != CODE_FOR_nothing)))
+                            || (optab_handler (sdivmod_optab,
+                                               compute_mode)
+                                != CODE_FOR_nothing)))
                  ;
                else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
                  {
@@ -4074,10 +4174,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                          return gen_lowpart (mode, remainder);
                      }
 
-                   if (sdiv_pow2_cheap[compute_mode]
-                       && ((optab_handler (sdiv_optab, compute_mode)->insn_code
+                   if (sdiv_pow2_cheap[speed][compute_mode]
+                       && ((optab_handler (sdiv_optab, compute_mode)
                             != CODE_FOR_nothing)
-                           || (optab_handler (sdivmod_optab, compute_mode)->insn_code
+                           || (optab_handler (sdivmod_optab, compute_mode)
                                != CODE_FOR_nothing)))
                      quotient = expand_divmod (0, TRUNC_DIV_EXPR,
                                                compute_mode, op0,
@@ -4123,9 +4223,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                            || size - 1 >= BITS_PER_WORD)
                          goto fail1;
 
-                       extra_cost = (shift_cost[compute_mode][post_shift]
-                                     + shift_cost[compute_mode][size - 1]
-                                     + add_cost[compute_mode]);
+                       extra_cost = (shift_cost[speed][compute_mode][post_shift]
+                                     + shift_cost[speed][compute_mode][size - 1]
+                                     + add_cost[speed][compute_mode]);
                        t1 = expand_mult_highpart (compute_mode, op0, mlr,
                                                   NULL_RTX, 0,
                                                   max_cost - extra_cost);
@@ -4133,12 +4233,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                          goto fail1;
                        t2 = expand_shift
                          (RSHIFT_EXPR, compute_mode, t1,
-                          build_int_cst (NULL_TREE, post_shift),
-                          NULL_RTX, 0);
+                          post_shift, NULL_RTX, 0);
                        t3 = expand_shift
                          (RSHIFT_EXPR, compute_mode, op0,
-                          build_int_cst (NULL_TREE, size - 1),
-                          NULL_RTX, 0);
+                          size - 1, NULL_RTX, 0);
                        if (d < 0)
                          quotient
                            = force_operand (gen_rtx_MINUS (compute_mode,
@@ -4160,9 +4258,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
 
                        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]);
+                       extra_cost = (shift_cost[speed][compute_mode][post_shift]
+                                     + shift_cost[speed][compute_mode][size - 1]
+                                     + 2 * add_cost[speed][compute_mode]);
                        t1 = expand_mult_highpart (compute_mode, op0, mlr,
                                                   NULL_RTX, 0,
                                                   max_cost - extra_cost);
@@ -4173,12 +4271,10 @@ 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),
-                          NULL_RTX, 0);
+                          post_shift, NULL_RTX, 0);
                        t4 = expand_shift
                          (RSHIFT_EXPR, compute_mode, op0,
-                          build_int_cst (NULL_TREE, size - 1),
-                          NULL_RTX, 0);
+                          size - 1, NULL_RTX, 0);
                        if (d < 0)
                          quotient
                            = force_operand (gen_rtx_MINUS (compute_mode,
@@ -4235,8 +4331,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),
-                      tquotient, 0);
+                      pre_shift, tquotient, 0);
                  }
                else
                  {
@@ -4251,13 +4346,12 @@ 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, size - 1),
-                          NULL_RTX, 0);
+                          size - 1, NULL_RTX, 0);
                        t2 = expand_binop (compute_mode, xor_optab, op0, t1,
                                           NULL_RTX, 0, OPTAB_WIDEN);
-                       extra_cost = (shift_cost[compute_mode][post_shift]
-                                     + shift_cost[compute_mode][size - 1]
-                                     + 2 * add_cost[compute_mode]);
+                       extra_cost = (shift_cost[speed][compute_mode][post_shift]
+                                     + shift_cost[speed][compute_mode][size - 1]
+                                     + 2 * add_cost[speed][compute_mode]);
                        t3 = expand_mult_highpart (compute_mode, t2, ml,
                                                   NULL_RTX, 1,
                                                   max_cost - extra_cost);
@@ -4265,8 +4359,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),
-                              NULL_RTX, 1);
+                              post_shift, NULL_RTX, 1);
                            quotient = expand_binop (compute_mode, xor_optab,
                                                     t4, t1, tquotient, 0,
                                                     OPTAB_WIDEN);
@@ -4283,8 +4376,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),
-                  NULL_RTX, 0);
+                  size - 1, NULL_RTX, 0);
                t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
                                    NULL_RTX);
                t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
@@ -4398,8 +4490,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)),
-                                  tquotient, 1);
+                                  floor_log2 (d), tquotient, 1);
                t2 = expand_binop (compute_mode, and_optab, op0,
                                   GEN_INT (d - 1),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -4496,8 +4587,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)),
-                                  tquotient, 0);
+                                  floor_log2 (d), tquotient, 0);
                t2 = expand_binop (compute_mode, and_optab, op0,
                                   GEN_INT (d - 1),
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -4618,8 +4708,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),
-                              NULL_RTX, unsignedp);
+                              pre_shift, NULL_RTX, unsignedp);
            quotient = expand_mult (compute_mode, t1,
                                    gen_int_mode (ml, compute_mode),
                                    NULL_RTX, 1);
@@ -4652,9 +4741,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
                                          remainder, 1, OPTAB_LIB_WIDEN);
              }
            tem = plus_constant (op1, -1);
-           tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
-                               build_int_cst (NULL_TREE, 1),
-                               NULL_RTX, 1);
+           tem = expand_shift (RSHIFT_EXPR, compute_mode, tem, 1, NULL_RTX, 1);
            do_cmp_and_jump (remainder, tem, LEU, compute_mode, label);
            expand_inc (quotient, const1_rtx);
            expand_dec (remainder, op1);
@@ -4679,14 +4766,12 @@ 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),
-                               NULL_RTX, 1);
+                               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),
-                                NULL_RTX, 0);
+                                size - 1, NULL_RTX, 0);
            tem = expand_binop (compute_mode, xor_optab, mask, const1_rtx,
                                NULL_RTX, 0, OPTAB_WIDEN);
            tem = expand_binop (compute_mode, sub_optab, tem, mask,
@@ -4725,7 +4810,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
            = sign_expand_binop (compute_mode, umod_optab, smod_optab,
                                 op0, op1, target,
                                 unsignedp,
-                                ((optab_handler (optab2, compute_mode)->insn_code
+                                ((optab_handler (optab2, compute_mode)
                                   != CODE_FOR_nothing)
                                  ? OPTAB_DIRECT : OPTAB_WIDEN));
          if (remainder == 0)
@@ -4753,7 +4838,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
        = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
                             op0, op1, rem_flag ? NULL_RTX : target,
                             unsignedp,
-                            ((optab_handler (optab2, compute_mode)->insn_code
+                            ((optab_handler (optab2, compute_mode)
                               != CODE_FOR_nothing)
                              ? OPTAB_DIRECT : OPTAB_WIDEN));
 
@@ -4794,7 +4879,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
          if (!remainder)
            {
              remainder = gen_reg_rtx (compute_mode);
-             if (!expand_twoval_binop_libfunc 
+             if (!expand_twoval_binop_libfunc
                  (unsignedp ? udivmod_optab : sdivmod_optab,
                   op0, op1,
                   NULL_RTX, remainder,
@@ -4837,12 +4922,12 @@ make_tree (tree type, rtx x)
                 && (GET_MODE_BITSIZE (TYPE_MODE (type))
                     < HOST_BITS_PER_WIDE_INT)))
          hi = -1;
-      
+
        t = build_int_cst_wide (type, INTVAL (x), hi);
-       
+
        return t;
       }
-      
+
     case CONST_DOUBLE:
       if (GET_MODE (x) == VOIDmode)
        t = build_int_cst_wide (type,
@@ -4937,12 +5022,13 @@ make_tree (tree type, rtx x)
       /* else fall through.  */
 
     default:
-      t = build_decl (VAR_DECL, NULL_TREE, type);
+      t = build_decl (RTL_LOCATION (x), VAR_DECL, NULL_TREE, type);
 
-      /* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being
-        ptr_mode.  So convert.  */
+      /* If TYPE is a POINTER_TYPE, we might need to convert X from
+        address mode to pointer mode.  */
       if (POINTER_TYPE_P (type))
-       x = convert_memory_address (TYPE_MODE (type), x);
+       x = convert_memory_address_addr_space
+             (TYPE_MODE (type), x, TYPE_ADDR_SPACE (TREE_TYPE (type)));
 
       /* Note that we do *not* use SET_DECL_RTL here, because we do not
         want set_decl_rtl to go adjusting REG_ATTRS for this temporary.  */
@@ -4973,15 +5059,45 @@ expand_and (enum machine_mode mode, rtx op0, rtx op1, rtx target)
     emit_move_insn (target, tem);
   return target;
 }
-\f
+
 /* Helper function for emit_store_flag.  */
 static rtx
-emit_store_flag_1 (rtx target, rtx subtarget, enum machine_mode mode,
-                  int normalizep)
+emit_cstore (rtx target, enum insn_code icode, enum rtx_code code,
+            enum machine_mode mode, enum machine_mode compare_mode,
+            int unsignedp, rtx x, rtx y, int normalizep,
+            enum machine_mode target_mode)
 {
-  rtx op0;
-  enum machine_mode target_mode = GET_MODE (target);
-  
+  struct expand_operand ops[4];
+  rtx op0, last, comparison, subtarget;
+  enum machine_mode result_mode = insn_data[(int) icode].operand[0].mode;
+
+  last = get_last_insn ();
+  x = prepare_operand (icode, x, 2, mode, compare_mode, unsignedp);
+  y = prepare_operand (icode, y, 3, mode, compare_mode, unsignedp);
+  if (!x || !y)
+    {
+      delete_insns_since (last);
+      return NULL_RTX;
+    }
+
+  if (target_mode == VOIDmode)
+    target_mode = result_mode;
+  if (!target)
+    target = gen_reg_rtx (target_mode);
+
+  comparison = gen_rtx_fmt_ee (code, result_mode, x, y);
+
+  create_output_operand (&ops[0], optimize ? NULL_RTX : target, result_mode);
+  create_fixed_operand (&ops[1], comparison);
+  create_fixed_operand (&ops[2], x);
+  create_fixed_operand (&ops[3], y);
+  if (!maybe_expand_insn (icode, 4, ops))
+    {
+      delete_insns_since (last);
+      return NULL_RTX;
+    }
+  subtarget = ops[0].value;
+
   /* If we are converting to a wider mode, first convert to
      TARGET_MODE, then normalize.  This produces better combining
      opportunities on machines that have a SIGN_EXTRACT when we are
@@ -4990,15 +5106,13 @@ emit_store_flag_1 (rtx target, rtx subtarget, enum machine_mode mode,
      If STORE_FLAG_VALUE does not have the sign bit set when
      interpreted in MODE, we can do this conversion as unsigned, which
      is usually more efficient.  */
-  if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (mode))
+  if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (result_mode))
     {
       convert_move (target, subtarget,
-                   (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-                   && 0 == (STORE_FLAG_VALUE
-                            & ((HOST_WIDE_INT) 1
-                               << (GET_MODE_BITSIZE (mode) -1))));
+                   val_signbit_known_clear_p (result_mode,
+                                              STORE_FLAG_VALUE));
       op0 = target;
-      mode = target_mode;
+      result_mode = target_mode;
     }
   else
     op0 = subtarget;
@@ -5015,28 +5129,26 @@ emit_store_flag_1 (rtx target, rtx subtarget, enum machine_mode mode,
   /* STORE_FLAG_VALUE might be the most negative number, so write
      the comparison this way to avoid a compiler-time warning.  */
   else if (- normalizep == STORE_FLAG_VALUE)
-    op0 = expand_unop (mode, neg_optab, op0, subtarget, 0);
+    op0 = expand_unop (result_mode, neg_optab, op0, subtarget, 0);
 
   /* 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 (mode) <= HOST_BITS_PER_WIDE_INT
-          && (STORE_FLAG_VALUE
-              & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))))
-    op0 = expand_shift (RSHIFT_EXPR, mode, op0,
-                       size_int (GET_MODE_BITSIZE (mode) - 1), subtarget,
+  else if (val_signbit_known_set_p (result_mode, STORE_FLAG_VALUE))
+    op0 = expand_shift (RSHIFT_EXPR, result_mode, op0,
+                       GET_MODE_BITSIZE (result_mode) - 1, subtarget,
                        normalizep == 1);
   else
     {
       gcc_assert (STORE_FLAG_VALUE & 1);
 
-      op0 = expand_and (mode, op0, const1_rtx, subtarget);
+      op0 = expand_and (result_mode, op0, const1_rtx, subtarget);
       if (normalizep == -1)
-       op0 = expand_unop (mode, neg_optab, op0, op0, 0);
+       op0 = expand_unop (result_mode, neg_optab, op0, op0, 0);
     }
 
   /* If we were converting to a smaller mode, do the conversion now.  */
-  if (target_mode != mode)
+  if (target_mode != result_mode)
     {
       convert_move (target, op0, 0);
       return target;
@@ -5045,35 +5157,26 @@ emit_store_flag_1 (rtx target, rtx subtarget, enum machine_mode mode,
     return op0;
 }
 
-/* Emit a store-flags instruction for comparison CODE on OP0 and OP1
-   and storing in TARGET.  Normally return TARGET.
-   Return 0 if that cannot be done.
-
-   MODE is the mode to use for OP0 and OP1 should they be CONST_INTs.  If
-   it is VOIDmode, they cannot both be CONST_INT.
 
-   UNSIGNEDP is for the case where we have to widen the operands
-   to perform the operation.  It says to use zero-extension.
+/* A subroutine of emit_store_flag only including "tricks" that do not
+   need a recursive call.  These are kept separate to avoid infinite
+   loops.  */
 
-   NORMALIZEP is 1 if we should convert the result to be either zero
-   or one.  Normalize is -1 if we should convert the result to be
-   either zero or -1.  If NORMALIZEP is zero, the result will be left
-   "raw" out of the scc insn.  */
-
-rtx
-emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
-                enum machine_mode mode, int unsignedp, int normalizep)
+static rtx
+emit_store_flag_1 (rtx target, enum rtx_code code, rtx op0, rtx op1,
+                  enum machine_mode mode, int unsignedp, int normalizep,
+                  enum machine_mode target_mode)
 {
   rtx subtarget;
   enum insn_code icode;
   enum machine_mode compare_mode;
-  enum machine_mode target_mode = GET_MODE (target);
+  enum mode_class mclass;
+  enum rtx_code scode;
   rtx tem;
-  rtx last = get_last_insn ();
-  rtx pattern, comparison;
 
   if (unsignedp)
     code = unsigned_condition (code);
+  scode = swap_condition (code);
 
   /* If one operand is constant, make it the second one.  Only do this
      if the other operand is not constant as well.  */
@@ -5132,20 +5235,20 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
       if ((code == EQ || code == NE)
          && (op1 == const0_rtx || op1 == constm1_rtx))
        {
-         rtx op00, op01, op0both;
+         rtx op00, op01;
 
          /* Do a logical OR or AND of the two words and compare the
             result.  */
          op00 = simplify_gen_subreg (word_mode, op0, mode, 0);
          op01 = simplify_gen_subreg (word_mode, op0, mode, UNITS_PER_WORD);
-         op0both = expand_binop (word_mode,
-                                 op1 == const0_rtx ? ior_optab : and_optab,
-                                 op00, op01, NULL_RTX, unsignedp,
-                                 OPTAB_DIRECT);
-
-         if (op0both != 0)
-           return emit_store_flag (target, code, op0both, op1, word_mode,
-                                   unsignedp, normalizep);
+         tem = expand_binop (word_mode,
+                             op1 == const0_rtx ? ior_optab : and_optab,
+                             op00, op01, NULL_RTX, unsignedp,
+                             OPTAB_DIRECT);
+
+         if (tem != 0)
+           tem = emit_store_flag (NULL_RTX, code, tem, op1, word_mode,
+                                  unsignedp, normalizep);
        }
       else if ((code == LT || code == GE) && op1 == const0_rtx)
        {
@@ -5155,8 +5258,24 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
          op0h = simplify_gen_subreg (word_mode, op0, mode,
                                      subreg_highpart_offset (word_mode,
                                                              mode));
-         return emit_store_flag (target, code, op0h, op1, word_mode,
-                                 unsignedp, normalizep);
+         tem = emit_store_flag (NULL_RTX, code, op0h, op1, word_mode,
+                                unsignedp, normalizep);
+       }
+      else
+       tem = NULL_RTX;
+
+      if (tem)
+       {
+         if (target_mode == VOIDmode || GET_MODE (tem) == target_mode)
+           return tem;
+         if (!target)
+           target = gen_reg_rtx (target_mode);
+
+         convert_move (target, tem,
+                       !val_signbit_known_set_p (word_mode,
+                                                 (normalizep ? normalizep
+                                                  : STORE_FLAG_VALUE)));
+         return target;
        }
     }
 
@@ -5165,17 +5284,17 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
   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_WIDE_INT
-             && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
-                 == ((unsigned HOST_WIDE_INT) 1
-                     << (GET_MODE_BITSIZE (mode) - 1))))))
+         || val_signbit_p (mode, STORE_FLAG_VALUE)))
     {
       subtarget = target;
 
+      if (!target)
+       target_mode = mode;
+
       /* 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))
+      else if (GET_MODE_SIZE (target_mode) > GET_MODE_SIZE (mode))
        {
          op0 = convert_modes (target_mode, mode, op0, 0);
          mode = target_mode;
@@ -5194,7 +5313,7 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
           a logical shift from the sign bit to the low-order bit; for
           a -1/0 value, we do an arithmetic shift.  */
        op0 = expand_shift (RSHIFT_EXPR, mode, op0,
-                           size_int (GET_MODE_BITSIZE (mode) - 1),
+                           GET_MODE_BITSIZE (mode) - 1,
                            subtarget, normalizep != -1);
 
       if (mode != target_mode)
@@ -5203,145 +5322,183 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
       return op0;
     }
 
-  icode = setcc_gen_code[(int) code];
-
-  if (icode != CODE_FOR_nothing)
+  mclass = GET_MODE_CLASS (mode);
+  for (compare_mode = mode; compare_mode != VOIDmode;
+       compare_mode = GET_MODE_WIDER_MODE (compare_mode))
     {
-      insn_operand_predicate_fn pred;
-
-      /* We think we may be able to do this with a scc insn.  Emit the
-        comparison and then the scc insn.  */
-
-      do_pending_stack_adjust ();
-      last = get_last_insn ();
-
-      comparison
-       = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX);
-      if (CONSTANT_P (comparison))
+     enum machine_mode optab_mode = mclass == MODE_CC ? CCmode : compare_mode;
+     icode = optab_handler (cstore_optab, optab_mode);
+     if (icode != CODE_FOR_nothing)
        {
-         switch (GET_CODE (comparison))
+         do_pending_stack_adjust ();
+         tem = emit_cstore (target, icode, code, mode, compare_mode,
+                            unsignedp, op0, op1, normalizep, target_mode);
+         if (tem)
+           return tem;
+
+         if (GET_MODE_CLASS (mode) == MODE_FLOAT)
            {
-           case CONST_INT:
-             if (comparison == const0_rtx)
-               return const0_rtx;
-             break;
-             
-#ifdef FLOAT_STORE_FLAG_VALUE
-           case CONST_DOUBLE:
-             if (comparison == CONST0_RTX (GET_MODE (comparison)))
-               return const0_rtx;
-             break;
-#endif
-           default:
-             gcc_unreachable ();
+             tem = emit_cstore (target, icode, scode, mode, compare_mode,
+                                unsignedp, op1, op0, normalizep, target_mode);
+             if (tem)
+               return tem;
            }
-         
-         if (normalizep == 1)
-           return const1_rtx;
-         if (normalizep == -1)
-           return constm1_rtx;
-         return const_true_rtx;
+         break;
        }
+    }
 
-      /* The code of COMPARISON may not match CODE if compare_from_rtx
-        decided to swap its operands and reverse the original code.
-
-        We know that compare_from_rtx returns either a CONST_INT or
-        a new comparison code, so it is safe to just extract the
-        code from COMPARISON.  */
-      code = GET_CODE (comparison);
-
-      /* Get a reference to the target in the proper mode for this insn.  */
-      compare_mode = insn_data[(int) icode].operand[0].mode;
-      subtarget = target;
-      pred = insn_data[(int) icode].operand[0].predicate;
-      if (optimize || ! (*pred) (subtarget, compare_mode))
-       subtarget = gen_reg_rtx (compare_mode);
+  return 0;
+}
 
-      pattern = GEN_FCN (icode) (subtarget);
-      if (pattern)
-       {
-         emit_insn (pattern);
-         return emit_store_flag_1 (target, subtarget, compare_mode,
-                                   normalizep);
-       }
-    }
-  else
-    {
-      /* We don't have an scc insn, so try a cstore insn.  */
+/* Emit a store-flags instruction for comparison CODE on OP0 and OP1
+   and storing in TARGET.  Normally return TARGET.
+   Return 0 if that cannot be done.
 
-      for (compare_mode = mode; compare_mode != VOIDmode;
-          compare_mode = GET_MODE_WIDER_MODE (compare_mode))
-       {
-         icode = optab_handler (cstore_optab, compare_mode)->insn_code;
-         if (icode != CODE_FOR_nothing)
-           break;
-       }
+   MODE is the mode to use for OP0 and OP1 should they be CONST_INTs.  If
+   it is VOIDmode, they cannot both be CONST_INT.
 
-      if (icode != CODE_FOR_nothing)
-       {
-         enum machine_mode result_mode
-           = insn_data[(int) icode].operand[0].mode;
-         rtx cstore_op0 = op0;
-         rtx cstore_op1 = op1;
+   UNSIGNEDP is for the case where we have to widen the operands
+   to perform the operation.  It says to use zero-extension.
 
-         do_pending_stack_adjust ();
-         last = get_last_insn ();
+   NORMALIZEP is 1 if we should convert the result to be either zero
+   or one.  Normalize is -1 if we should convert the result to be
+   either zero or -1.  If NORMALIZEP is zero, the result will be left
+   "raw" out of the scc insn.  */
 
-         if (compare_mode != mode)
-           {
-             cstore_op0 = convert_modes (compare_mode, mode, cstore_op0,
-                                         unsignedp);
-             cstore_op1 = convert_modes (compare_mode, mode, cstore_op1,
-                                         unsignedp);
-           }
-         
-         if (!insn_data[(int) icode].operand[2].predicate (cstore_op0,
-                                                           compare_mode))
-           cstore_op0 = copy_to_mode_reg (compare_mode, cstore_op0);
+rtx
+emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
+                enum machine_mode mode, int unsignedp, int normalizep)
+{
+  enum machine_mode target_mode = target ? GET_MODE (target) : VOIDmode;
+  enum rtx_code rcode;
+  rtx subtarget;
+  rtx tem, last, trueval;
 
-         if (!insn_data[(int) icode].operand[3].predicate (cstore_op1,
-                                                           compare_mode))
-           cstore_op1 = copy_to_mode_reg (compare_mode, cstore_op1);
+  tem = emit_store_flag_1 (target, code, op0, op1, mode, unsignedp, normalizep,
+                          target_mode);
+  if (tem)
+    return tem;
 
-         comparison = gen_rtx_fmt_ee (code, result_mode, cstore_op0,
-                                      cstore_op1);
-         subtarget = target;
+  /* If we reached here, we can't do this with a scc insn, however there
+     are some comparisons that can be done in other ways.  Don't do any
+     of these cases if branches are very cheap.  */
+  if (BRANCH_COST (optimize_insn_for_speed_p (), false) == 0)
+    return 0;
 
-         if (optimize || !(insn_data[(int) icode].operand[0].predicate
-                           (subtarget, result_mode)))
-           subtarget = gen_reg_rtx (result_mode);
+  /* See what we need to return.  We can only return a 1, -1, or the
+     sign bit.  */
 
-         pattern = GEN_FCN (icode) (subtarget, comparison, cstore_op0,
-                                    cstore_op1);
+  if (normalizep == 0)
+    {
+      if (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+       normalizep = STORE_FLAG_VALUE;
 
-         if (pattern)
-           {
-             emit_insn (pattern);
-             return emit_store_flag_1 (target, subtarget, result_mode,
-                                       normalizep);
-           }
-       }
+      else if (val_signbit_p (mode, STORE_FLAG_VALUE))
+       ;
+      else
+       return 0;
     }
 
-  delete_insns_since (last);
+  last = get_last_insn ();
 
   /* If optimizing, use different pseudo registers for each insn, instead
      of reusing the same pseudo.  This leads to better CSE, but slows
      down the compiler, since there are more pseudos */
   subtarget = (!optimize
               && (target_mode == mode)) ? target : NULL_RTX;
+  trueval = GEN_INT (normalizep ? normalizep : STORE_FLAG_VALUE);
 
-  /* If we reached here, we can't do this with a scc insn.  However, there
-     are some comparisons that can be done directly.  For example, if
-     this is an equality comparison of integers, we can try to exclusive-or
+  /* For floating-point comparisons, try the reverse comparison or try
+     changing the "orderedness" of the comparison.  */
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+    {
+      enum rtx_code first_code;
+      bool and_them;
+
+      rcode = reverse_condition_maybe_unordered (code);
+      if (can_compare_p (rcode, mode, ccp_store_flag)
+          && (code == ORDERED || code == UNORDERED
+             || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
+             || (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
+       {
+          int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
+                         || (STORE_FLAG_VALUE == -1 && normalizep == 1));
+
+         /* For the reverse comparison, use either an addition or a XOR.  */
+          if (want_add
+             && rtx_cost (GEN_INT (normalizep), PLUS,
+                          optimize_insn_for_speed_p ()) == 0)
+           {
+             tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
+                                      STORE_FLAG_VALUE, target_mode);
+             if (tem)
+                return expand_binop (target_mode, add_optab, tem,
+                                    GEN_INT (normalizep),
+                                    target, 0, OPTAB_WIDEN);
+           }
+          else if (!want_add
+                  && rtx_cost (trueval, XOR,
+                               optimize_insn_for_speed_p ()) == 0)
+           {
+             tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
+                                      normalizep, target_mode);
+             if (tem)
+                return expand_binop (target_mode, xor_optab, tem, trueval,
+                                    target, INTVAL (trueval) >= 0, OPTAB_WIDEN);
+           }
+       }
+
+      delete_insns_since (last);
+
+      /* Cannot split ORDERED and UNORDERED, only try the above trick.   */
+      if (code == ORDERED || code == UNORDERED)
+       return 0;
+
+      and_them = split_comparison (code, mode, &first_code, &code);
+
+      /* If there are no NaNs, the first comparison should always fall through.
+         Effectively change the comparison to the other one.  */
+      if (!HONOR_NANS (mode))
+       {
+          gcc_assert (first_code == (and_them ? ORDERED : UNORDERED));
+         return emit_store_flag_1 (target, code, op0, op1, mode, 0, normalizep,
+                                   target_mode);
+       }
+
+#ifdef HAVE_conditional_move
+      /* Try using a setcc instruction for ORDERED/UNORDERED, followed by a
+        conditional move.  */
+      tem = emit_store_flag_1 (subtarget, first_code, op0, op1, mode, 0,
+                              normalizep, target_mode);
+      if (tem == 0)
+       return 0;
+
+      if (and_them)
+        tem = emit_conditional_move (target, code, op0, op1, mode,
+                                    tem, const0_rtx, GET_MODE (tem), 0);
+      else
+        tem = emit_conditional_move (target, code, op0, op1, mode,
+                                    trueval, tem, GET_MODE (tem), 0);
+
+      if (tem == 0)
+        delete_insns_since (last);
+      return tem;
+#else
+      return 0;
+#endif
+    }
+
+  /* The remaining tricks only apply to integer comparisons.  */
+
+  if (GET_MODE_CLASS (mode) != MODE_INT)
+    return 0;
+
+  /* If this is an equality comparison of integers, we can try to exclusive-or
      (or subtract) the two operands and use a recursive call to try the
      comparison with zero.  Don't do any of these cases if branches are
      very cheap.  */
 
-  if (BRANCH_COST > 0
-      && GET_MODE_CLASS (mode) == MODE_INT && (code == EQ || code == NE)
-      && op1 != const0_rtx)
+  if ((code == EQ || code == NE) && op1 != const0_rtx)
     {
       tem = expand_binop (mode, xor_optab, op0, op1, subtarget, 1,
                          OPTAB_WIDEN);
@@ -5352,9 +5509,50 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
       if (tem != 0)
        tem = emit_store_flag (target, code, tem, const0_rtx,
                               mode, unsignedp, normalizep);
-      if (tem == 0)
-       delete_insns_since (last);
-      return tem;
+      if (tem != 0)
+       return tem;
+
+      delete_insns_since (last);
+    }
+
+  /* For integer comparisons, try the reverse comparison.  However, for
+     small X and if we'd have anyway to extend, implementing "X != 0"
+     as "-(int)X >> 31" is still cheaper than inverting "(int)X == 0".  */
+  rcode = reverse_condition (code);
+  if (can_compare_p (rcode, mode, ccp_store_flag)
+      && ! (optab_handler (cstore_optab, mode) == CODE_FOR_nothing
+           && code == NE
+           && GET_MODE_SIZE (mode) < UNITS_PER_WORD
+           && op1 == const0_rtx))
+    {
+      int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1)
+                     || (STORE_FLAG_VALUE == -1 && normalizep == 1));
+
+      /* Again, for the reverse comparison, use either an addition or a XOR.  */
+      if (want_add
+         && rtx_cost (GEN_INT (normalizep), PLUS,
+                      optimize_insn_for_speed_p ()) == 0)
+       {
+         tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
+                                  STORE_FLAG_VALUE, target_mode);
+         if (tem != 0)
+            tem = expand_binop (target_mode, add_optab, tem,
+                               GEN_INT (normalizep), target, 0, OPTAB_WIDEN);
+       }
+      else if (!want_add
+              && rtx_cost (trueval, XOR,
+                           optimize_insn_for_speed_p ()) == 0)
+       {
+         tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0,
+                                  normalizep, target_mode);
+         if (tem != 0)
+            tem = expand_binop (target_mode, xor_optab, tem, trueval, target,
+                               INTVAL (trueval) >= 0, OPTAB_WIDEN);
+       }
+
+      if (tem != 0)
+       return tem;
+      delete_insns_since (last);
     }
 
   /* Some other cases we can do are EQ, NE, LE, and GT comparisons with
@@ -5362,28 +5560,12 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
      do LE and GT if branches are expensive since they are expensive on
      2-operand machines.  */
 
-  if (BRANCH_COST == 0
-      || GET_MODE_CLASS (mode) != MODE_INT || op1 != const0_rtx
+  if (op1 != const0_rtx
       || (code != EQ && code != NE
-         && (BRANCH_COST <= 1 || (code != LE && code != GT))))
+         && (BRANCH_COST (optimize_insn_for_speed_p (),
+                          false) <= 1 || (code != LE && code != GT))))
     return 0;
 
-  /* See what we need to return.  We can only return a 1, -1, or the
-     sign bit.  */
-
-  if (normalizep == 0)
-    {
-      if (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
-       normalizep = STORE_FLAG_VALUE;
-
-      else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-              && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
-                  == (unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))
-       ;
-      else
-       return 0;
-    }
-
   /* Try to put the result of the comparison in the sign bit.  Assume we can't
      do the necessary operation below.  */
 
@@ -5414,7 +5596,7 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
        subtarget = 0;
 
       tem = expand_shift (RSHIFT_EXPR, mode, op0,
-                         size_int (GET_MODE_BITSIZE (mode) - 1),
+                         GET_MODE_BITSIZE (mode) - 1,
                          subtarget, 0);
       tem = expand_binop (mode, sub_optab, tem, op0, subtarget, 0,
                          OPTAB_WIDEN);
@@ -5437,9 +5619,9 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
         that is compensated by the subsequent overflow when subtracting
         one / negating.  */
 
-      if (optab_handler (abs_optab, mode)->insn_code != CODE_FOR_nothing)
+      if (optab_handler (abs_optab, mode) != CODE_FOR_nothing)
        tem = expand_unop (mode, abs_optab, op0, subtarget, 1);
-      else if (optab_handler (ffs_optab, mode)->insn_code != CODE_FOR_nothing)
+      else if (optab_handler (ffs_optab, mode) != CODE_FOR_nothing)
        tem = expand_unop (mode, ffs_optab, op0, subtarget, 1);
       else if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        {
@@ -5461,7 +5643,10 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
         that "or", which is an extra insn, so we only handle EQ if branches
         are expensive.  */
 
-      if (tem == 0 && (code == NE || BRANCH_COST > 1))
+      if (tem == 0
+         && (code == NE
+             || BRANCH_COST (optimize_insn_for_speed_p (),
+                             false) > 1))
        {
          if (rtx_equal_p (subtarget, op0))
            subtarget = 0;
@@ -5477,12 +5662,14 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
   if (tem && normalizep)
     tem = expand_shift (RSHIFT_EXPR, mode, tem,
-                       size_int (GET_MODE_BITSIZE (mode) - 1),
+                       GET_MODE_BITSIZE (mode) - 1,
                        subtarget, normalizep == 1);
 
   if (tem)
     {
-      if (GET_MODE (tem) != target_mode)
+      if (!target)
+        ;
+      else if (GET_MODE (tem) != target_mode)
        {
          convert_move (target, tem, 0);
          tem = target;
@@ -5506,27 +5693,68 @@ emit_store_flag_force (rtx target, enum rtx_code code, rtx op0, rtx op1,
                       enum machine_mode mode, int unsignedp, int normalizep)
 {
   rtx tem, label;
+  rtx trueval, falseval;
 
   /* First see if emit_store_flag can do the job.  */
   tem = emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep);
   if (tem != 0)
     return tem;
 
-  if (normalizep == 0)
-    normalizep = 1;
+  if (!target)
+    target = gen_reg_rtx (word_mode);
 
-  /* If this failed, we have to do this with set/compare/jump/set code.  */
+  /* If this failed, we have to do this with set/compare/jump/set code.
+     For foo != 0, if foo is in OP0, just replace it with 1 if nonzero.  */
+  trueval = normalizep ? GEN_INT (normalizep) : const1_rtx;
+  if (code == NE
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && REG_P (target)
+      && op0 == target
+      && op1 == const0_rtx)
+    {
+      label = gen_label_rtx ();
+      do_compare_rtx_and_jump (target, const0_rtx, EQ, unsignedp,
+                              mode, NULL_RTX, NULL_RTX, label, -1);
+      emit_move_insn (target, trueval);
+      emit_label (label);
+      return target;
+    }
 
   if (!REG_P (target)
       || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
     target = gen_reg_rtx (GET_MODE (target));
 
-  emit_move_insn (target, const1_rtx);
+  /* Jump in the right direction if the target cannot implement CODE
+     but can jump on its reverse condition.  */
+  falseval = const0_rtx;
+  if (! can_compare_p (code, mode, ccp_jump)
+      && (! FLOAT_MODE_P (mode)
+          || code == ORDERED || code == UNORDERED
+          || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ))
+          || (! HONOR_SNANS (mode) && (code == EQ || code == NE))))
+    {
+      enum rtx_code rcode;
+      if (FLOAT_MODE_P (mode))
+        rcode = reverse_condition_maybe_unordered (code);
+      else
+        rcode = reverse_condition (code);
+
+      /* Canonicalize to UNORDERED for the libcall.  */
+      if (can_compare_p (rcode, mode, ccp_jump)
+          || (code == ORDERED && ! can_compare_p (ORDERED, mode, ccp_jump)))
+       {
+         falseval = trueval;
+         trueval = const0_rtx;
+         code = rcode;
+       }
+    }
+
+  emit_move_insn (target, trueval);
   label = gen_label_rtx ();
   do_compare_rtx_and_jump (op0, op1, code, unsignedp, mode, NULL_RTX,
-                          NULL_RTX, label);
+                          NULL_RTX, label, -1);
 
-  emit_move_insn (target, const0_rtx);
+  emit_move_insn (target, falseval);
   emit_label (label);
 
   return target;
@@ -5542,5 +5770,5 @@ do_cmp_and_jump (rtx arg1, rtx arg2, enum rtx_code op, enum machine_mode mode,
 {
   int unsignedp = (op == LTU || op == LEU || op == GTU || op == GEU);
   do_compare_rtx_and_jump (arg1, arg2, op, unsignedp, mode,
-                          NULL_RTX, NULL_RTX, label);
+                          NULL_RTX, NULL_RTX, label, -1);
 }