OSDN Git Service

2008-04-19 Paul Thomas <pault@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / expr.c
index 9286ffa..7f38643 100644 (file)
@@ -7,7 +7,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -16,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -53,6 +52,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tree-flow.h"
 #include "target.h"
 #include "timevar.h"
+#include "df.h"
+#include "diagnostic.h"
 
 /* Decide whether a function's arguments should be processed
    from first to last or from last to first.
@@ -139,14 +140,14 @@ static rtx compress_float_constant (rtx, rtx);
 static rtx get_subtarget (rtx);
 static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
                                     HOST_WIDE_INT, enum machine_mode,
-                                    tree, tree, int, int);
+                                    tree, tree, int, alias_set_type);
 static void store_constructor (tree, rtx, int, HOST_WIDE_INT);
 static rtx store_field (rtx, HOST_WIDE_INT, HOST_WIDE_INT, enum machine_mode,
-                       tree, tree, int);
+                       tree, tree, alias_set_type, bool);
 
-static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (tree, tree);
+static unsigned HOST_WIDE_INT highest_pow2_factor_for_target (const_tree, const_tree);
 
-static int is_aligning_offset (tree, tree);
+static int is_aligning_offset (const_tree, const_tree);
 static void expand_operands (tree, tree, rtx, rtx*, rtx*,
                             enum expand_modifier);
 static rtx reduce_to_bit_field_precision (rtx, rtx, tree);
@@ -186,8 +187,15 @@ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
 #endif
 
 /* This macro is used to determine whether store_by_pieces should be
-   called to "memset" storage with byte values other than zero, or
-   to "memcpy" storage when the source is a constant string.  */
+   called to "memset" storage with byte values other than zero.  */
+#ifndef SET_BY_PIECES_P
+#define SET_BY_PIECES_P(SIZE, ALIGN) \
+  (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
+   < (unsigned int) SET_RATIO)
+#endif
+
+/* This macro is used to determine whether store_by_pieces should be
+   called to "memcpy" storage when the source is a constant string.  */
 #ifndef STORE_BY_PIECES_P
 #define STORE_BY_PIECES_P(SIZE, ALIGN) \
   (move_by_pieces_ninsns (SIZE, ALIGN, STORE_MAX_PIECES + 1) \
@@ -236,11 +244,12 @@ enum insn_code sync_lock_release[NUM_MACHINE_MODES];
 #define SLOW_UNALIGNED_ACCESS(MODE, ALIGN) STRICT_ALIGNMENT
 #endif
 \f
-/* This is run once per compilation to set up which modes can be used
-   directly in memory and to initialize the block move optab.  */
+/* This is run to set up which modes can be used
+   directly in memory and to initialize the block move optab.  It is run
+   at the beginning of compilation and when the target is reinitialized.  */
 
 void
-init_expr_once (void)
+init_expr_target (void)
 {
   rtx insn, pat;
   enum machine_mode mode;
@@ -283,7 +292,7 @@ init_expr_once (void)
            if (! HARD_REGNO_MODE_OK (regno, mode))
              continue;
 
-           REGNO (reg) = regno;
+           SET_REGNO (reg, regno);
 
            SET_SRC (pat) = mem;
            SET_DEST (pat) = reg;
@@ -335,11 +344,12 @@ init_expr_once (void)
 void
 init_expr (void)
 {
-  cfun->expr = ggc_alloc_cleared (sizeof (struct expr_status));
+  memset (&crtl->expr, 0, sizeof (crtl->expr));
 }
 \f
 /* Copy data from FROM to TO, where the machine modes are not the same.
-   Both modes may be integer, or both may be floating.
+   Both modes may be integer, or both may be floating, or both may be
+   fixed-point.
    UNSIGNEDP should be nonzero if FROM is an unsigned type.
    This causes zero-extension instead of sign-extension.  */
 
@@ -359,6 +369,8 @@ convert_move (rtx to, rtx from, int unsignedp)
 
 
   gcc_assert (to_real == from_real);
+  gcc_assert (to_mode != BLKmode);
+  gcc_assert (from_mode != BLKmode);
 
   /* If the source and destination are already the same, then there's
      nothing to do.  */
@@ -413,7 +425,7 @@ convert_move (rtx to, rtx from, int unsignedp)
                   != GET_MODE_PRECISION (to_mode))
                  || (DECIMAL_FLOAT_MODE_P (from_mode)
                      != DECIMAL_FLOAT_MODE_P (to_mode)));
-      
+
       if (GET_MODE_PRECISION (from_mode) == GET_MODE_PRECISION (to_mode))
        /* Conversion between decimal float and binary float, same size.  */
        tab = DECIMAL_FLOAT_MODE_P (from_mode) ? trunc_optab : sext_optab;
@@ -424,7 +436,7 @@ convert_move (rtx to, rtx from, int unsignedp)
 
       /* Try converting directly if the insn is supported.  */
 
-      code = tab->handlers[to_mode][from_mode].insn_code;
+      code = convert_optab_handler (tab, to_mode, from_mode)->insn_code;
       if (code != CODE_FOR_nothing)
        {
          emit_unop_insn (code, to, from,
@@ -433,7 +445,7 @@ convert_move (rtx to, rtx from, int unsignedp)
        }
 
       /* Otherwise use a libcall.  */
-      libcall = tab->handlers[to_mode][from_mode].libfunc;
+      libcall = convert_optab_libfunc (tab, to_mode, from_mode);
 
       /* Is this conversion implemented yet?  */
       gcc_assert (libcall);
@@ -458,12 +470,12 @@ convert_move (rtx to, rtx from, int unsignedp)
       enum machine_mode full_mode
        = smallest_mode_for_size (GET_MODE_BITSIZE (to_mode), MODE_INT);
 
-      gcc_assert (trunc_optab->handlers[to_mode][full_mode].insn_code
+      gcc_assert (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code
                  != CODE_FOR_nothing);
 
       if (full_mode != from_mode)
        from = convert_to_mode (full_mode, from, unsignedp);
-      emit_unop_insn (trunc_optab->handlers[to_mode][full_mode].insn_code,
+      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, full_mode)->insn_code,
                      to, from, UNKNOWN);
       return;
     }
@@ -473,18 +485,18 @@ convert_move (rtx to, rtx from, int unsignedp)
       enum machine_mode full_mode
        = smallest_mode_for_size (GET_MODE_BITSIZE (from_mode), MODE_INT);
 
-      gcc_assert (sext_optab->handlers[full_mode][from_mode].insn_code
+      gcc_assert (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code
                  != CODE_FOR_nothing);
 
       if (to_mode == full_mode)
        {
-         emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+         emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
                          to, from, UNKNOWN);
          return;
        }
 
       new_from = gen_reg_rtx (full_mode);
-      emit_unop_insn (sext_optab->handlers[full_mode][from_mode].insn_code,
+      emit_unop_insn (convert_optab_handler (sext_optab, full_mode, from_mode)->insn_code,
                      new_from, from, UNKNOWN);
 
       /* else proceed to integer conversions below.  */
@@ -492,6 +504,22 @@ convert_move (rtx to, rtx from, int unsignedp)
       from = new_from;
     }
 
+   /* Make sure both are fixed-point modes or both are not.  */
+   gcc_assert (ALL_SCALAR_FIXED_POINT_MODE_P (from_mode) ==
+              ALL_SCALAR_FIXED_POINT_MODE_P (to_mode));
+   if (ALL_SCALAR_FIXED_POINT_MODE_P (from_mode))
+    {
+      /* If we widen from_mode to to_mode and they are in the same class,
+        we won't saturate the result.
+        Otherwise, always saturate the result to play safe.  */
+      if (GET_MODE_CLASS (from_mode) == GET_MODE_CLASS (to_mode)
+         && GET_MODE_SIZE (from_mode) < GET_MODE_SIZE (to_mode))
+       expand_fixed_convert (to, from, 0, 0);
+      else
+       expand_fixed_convert (to, from, 0, 1);
+      return;
+    }
+
   /* Now both modes are integers.  */
 
   /* Handle expanding beyond a word.  */
@@ -524,15 +552,15 @@ convert_move (rtx to, rtx from, int unsignedp)
               && ((code = can_extend_p (to_mode, word_mode, unsignedp))
                   != CODE_FOR_nothing))
        {
+         rtx word_to = gen_reg_rtx (word_mode);
          if (REG_P (to))
            {
              if (reg_overlap_mentioned_p (to, from))
                from = force_reg (from_mode, from);
              emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
            }
-         convert_move (gen_lowpart (word_mode, to), from, unsignedp);
-         emit_unop_insn (code, to,
-                         gen_lowpart (word_mode, to), equiv_code);
+         convert_move (word_to, from, unsignedp);
+         emit_unop_insn (code, to, word_to, equiv_code);
          return;
        }
 
@@ -688,9 +716,9 @@ convert_move (rtx to, rtx from, int unsignedp)
     }
 
   /* Support special truncate insns for certain modes.  */
-  if (trunc_optab->handlers[to_mode][from_mode].insn_code != CODE_FOR_nothing)
+  if (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code != CODE_FOR_nothing)
     {
-      emit_unop_insn (trunc_optab->handlers[to_mode][from_mode].insn_code,
+      emit_unop_insn (convert_optab_handler (trunc_optab, to_mode, from_mode)->insn_code,
                      to, from, UNKNOWN);
       return;
     }
@@ -982,7 +1010,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
       if (mode == VOIDmode)
        break;
 
-      icode = mov_optab->handlers[(int) mode].insn_code;
+      icode = optab_handler (mov_optab, mode)->insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        move_by_pieces_1 (GEN_FCN (icode), mode, &data);
 
@@ -1062,7 +1090,7 @@ move_by_pieces_ninsns (unsigned HOST_WIDE_INT l, unsigned int align,
       if (mode == VOIDmode)
        break;
 
-      icode = mov_optab->handlers[(int) mode].insn_code;
+      icode = optab_handler (mov_optab, mode)->insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        n_insns += l / GET_MODE_SIZE (mode), l %= GET_MODE_SIZE (mode);
 
@@ -1749,8 +1777,25 @@ emit_group_load_1 (rtx *tmps, rtx dst, rtx orig_src, tree type, int ssize)
       else if (CONSTANT_P (src) && GET_MODE (dst) != BLKmode
                && XVECLEN (dst, 0) > 1)
         tmps[i] = simplify_gen_subreg (mode, src, GET_MODE(dst), bytepos);
-      else if (CONSTANT_P (src)
-              || (REG_P (src) && GET_MODE (src) == mode))
+      else if (CONSTANT_P (src))
+       {
+         HOST_WIDE_INT len = (HOST_WIDE_INT) bytelen;
+
+         if (len == ssize)
+           tmps[i] = src;
+         else
+           {
+             rtx first, second;
+
+             gcc_assert (2 * len == ssize);
+             split_double (src, &first, &second);
+             if (i)
+               tmps[i] = second;
+             else
+               tmps[i] = first;
+           }
+       }
+      else if (REG_P (src) && GET_MODE (src) == mode)
        tmps[i] = src;
       else
        tmps[i] = extract_bit_field (src, bytelen * BITS_PER_UNIT,
@@ -2071,6 +2116,7 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
   rtx src = NULL, dst = NULL;
   unsigned HOST_WIDE_INT bitsize = MIN (TYPE_ALIGN (type), BITS_PER_WORD);
   unsigned HOST_WIDE_INT bitpos, xbitpos, padding_correction = 0;
+  enum machine_mode copy_mode;
 
   if (tgtblk == 0)
     {
@@ -2104,11 +2150,23 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
     padding_correction
       = (BITS_PER_WORD - ((bytes % UNITS_PER_WORD) * BITS_PER_UNIT));
 
-  /* Copy the structure BITSIZE bites at a time.
+  /* Copy the structure BITSIZE bits at a time.  If the target lives in
+     memory, take care of not reading/writing past its end by selecting
+     a copy mode suited to BITSIZE.  This should always be possible given
+     how it is computed.
 
      We could probably emit more efficient code for machines which do not use
      strict alignment, but it doesn't seem worth the effort at the current
      time.  */
+
+  copy_mode = word_mode;
+  if (MEM_P (tgtblk))
+    {
+      enum machine_mode mem_mode = mode_for_size (bitsize, MODE_INT, 1);
+      if (mem_mode != BLKmode)
+       copy_mode = mem_mode;
+    }
+
   for (bitpos = 0, xbitpos = padding_correction;
        bitpos < bytes * BITS_PER_UNIT;
        bitpos += bitsize, xbitpos += bitsize)
@@ -2127,11 +2185,11 @@ copy_blkmode_from_reg (rtx tgtblk, rtx srcreg, tree type)
        dst = operand_subword (tgtblk, bitpos / BITS_PER_WORD, 1, BLKmode);
 
       /* Use xbitpos for the source extraction (right justified) and
-        xbitpos for the destination store (left justified).  */
-      store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, word_mode,
+        bitpos for the destination store (left justified).  */
+      store_bit_field (dst, bitsize, bitpos % BITS_PER_WORD, copy_mode,
                       extract_bit_field (src, bitsize,
                                          xbitpos % BITS_PER_WORD, 1,
-                                         NULL_RTX, word_mode, word_mode));
+                                         NULL_RTX, copy_mode, copy_mode));
     }
 
   return tgtblk;
@@ -2144,7 +2202,7 @@ void
 use_reg (rtx *call_fusage, rtx reg)
 {
   gcc_assert (REG_P (reg) && REGNO (reg) < FIRST_PSEUDO_REGISTER);
-  
+
   *call_fusage
     = gen_rtx_EXPR_LIST (VOIDmode,
                         gen_rtx_USE (VOIDmode, reg), *call_fusage);
@@ -2189,13 +2247,14 @@ use_group_regs (rtx *call_fusage, rtx regs)
 /* Determine whether the LEN bytes generated by CONSTFUN can be
    stored to memory using several move instructions.  CONSTFUNDATA is
    a pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.  Return nonzero if a
-   call to store_by_pieces should succeed.  */
+   ALIGN is maximum alignment we can assume.  MEMSETP is true if this is
+   a memset operation and false if it's a copy of a constant string.
+   Return nonzero if a call to store_by_pieces should succeed.  */
 
 int
 can_store_by_pieces (unsigned HOST_WIDE_INT len,
                     rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
-                    void *constfundata, unsigned int align)
+                    void *constfundata, unsigned int align, bool memsetp)
 {
   unsigned HOST_WIDE_INT l;
   unsigned int max_size;
@@ -2208,7 +2267,9 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
   if (len == 0)
     return 1;
 
-  if (! STORE_BY_PIECES_P (len, align))
+  if (! (memsetp 
+        ? SET_BY_PIECES_P (len, align)
+        : STORE_BY_PIECES_P (len, align)))
     return 0;
 
   tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1);
@@ -2248,7 +2309,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
          if (mode == VOIDmode)
            break;
 
-         icode = mov_optab->handlers[(int) mode].insn_code;
+         icode = optab_handler (mov_optab, mode)->insn_code;
          if (icode != CODE_FOR_nothing
              && align >= GET_MODE_ALIGNMENT (mode))
            {
@@ -2283,7 +2344,8 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
 /* Generate several move instructions to store LEN bytes generated by
    CONSTFUN to block TO.  (A MEM rtx with BLKmode).  CONSTFUNDATA is a
    pointer which will be passed as argument in every CONSTFUN call.
-   ALIGN is maximum alignment we can assume.
+   ALIGN is maximum alignment we can assume.  MEMSETP is true if this is
+   a memset operation and false if it's a copy of a constant string.
    If ENDP is 0 return to, if ENDP is 1 return memory at the end ala
    mempcpy, and if ENDP is 2 return memory the end minus one byte ala
    stpcpy.  */
@@ -2291,7 +2353,7 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
 rtx
 store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
                 rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode),
-                void *constfundata, unsigned int align, int endp)
+                void *constfundata, unsigned int align, bool memsetp, int endp)
 {
   struct store_by_pieces data;
 
@@ -2301,7 +2363,9 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
       return to;
     }
 
-  gcc_assert (STORE_BY_PIECES_P (len, align));
+  gcc_assert (memsetp
+             ? SET_BY_PIECES_P (len, align)
+             : STORE_BY_PIECES_P (len, align));
   data.constfun = constfun;
   data.constfundata = constfundata;
   data.len = len;
@@ -2452,7 +2516,7 @@ store_by_pieces_1 (struct store_by_pieces *data ATTRIBUTE_UNUSED,
       if (mode == VOIDmode)
        break;
 
-      icode = mov_optab->handlers[(int) mode].insn_code;
+      icode = optab_handler (mov_optab, mode)->insn_code;
       if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode))
        store_by_pieces_2 (GEN_FCN (icode), mode, data);
 
@@ -2701,7 +2765,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
          pred = insn_data[(int) code].operand[1].predicate;
          if (pred != 0 && ! (*pred) (opsize, mode))
            opsize = copy_to_mode_reg (mode, opsize);
-         
+
          opchar = val;
          char_mode = insn_data[(int) code].operand[2].mode;
          if (char_mode != VOIDmode)
@@ -2867,7 +2931,12 @@ emit_move_change_mode (enum machine_mode new_mode,
 {
   rtx ret;
 
-  if (MEM_P (x))
+  if (push_operand (x, GET_MODE (x)))
+    {
+      ret = gen_rtx_MEM (new_mode, XEXP (x, 0));
+      MEM_COPY_ATTRIBUTES (ret, x);
+    }
+  else if (MEM_P (x))
     {
       /* We don't have to worry about changing the address since the
         size in bytes is supposed to be the same.  */
@@ -2914,7 +2983,7 @@ emit_move_via_integer (enum machine_mode mode, rtx x, rtx y, bool force)
     return NULL_RTX;
 
   /* The target must support moves in this mode.  */
-  code = mov_optab->handlers[imode].insn_code;
+  code = optab_handler (mov_optab, imode)->insn_code;
   if (code == CODE_FOR_nothing)
     return NULL_RTX;
 
@@ -3064,7 +3133,7 @@ emit_move_complex (enum machine_mode mode, rtx x, rtx y)
 
   /* Move floating point as parts.  */
   if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-      && mov_optab->handlers[GET_MODE_INNER (mode)].insn_code != CODE_FOR_nothing)
+      && optab_handler (mov_optab, GET_MODE_INNER (mode))->insn_code != CODE_FOR_nothing)
     try_int = false;
   /* Not possible if the values are inherently not adjacent.  */
   else if (GET_CODE (x) == CONCAT || GET_CODE (y) == CONCAT)
@@ -3115,7 +3184,7 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
   /* Assume all MODE_CC modes are equivalent; if we have movcc, use it.  */
   if (mode != CCmode)
     {
-      enum insn_code code = mov_optab->handlers[CCmode].insn_code;
+      enum insn_code code = optab_handler (mov_optab, CCmode)->insn_code;
       if (code != CODE_FOR_nothing)
        {
          x = emit_move_change_mode (CCmode, mode, x, true);
@@ -3134,7 +3203,7 @@ emit_move_ccmode (enum machine_mode mode, rtx x, rtx y)
    undefined bits of a paradoxical subreg.  */
 
 static bool
-undefined_operand_subword_p (rtx op, int i)
+undefined_operand_subword_p (const_rtx op, int i)
 {
   enum machine_mode innermode, innermostmode;
   int offset;
@@ -3174,9 +3243,9 @@ emit_move_multi_word (enum machine_mode mode, rtx x, rtx y)
   rtx seq, inner;
   bool need_clobber;
   int i;
-      
+
   gcc_assert (GET_MODE_SIZE (mode) >= UNITS_PER_WORD);
-      
+
   /* If X is a push on the stack, do the push now and replace
      X with a reference to the stack pointer.  */
   if (push_operand (x, mode))
@@ -3255,7 +3324,7 @@ emit_move_insn_1 (rtx x, rtx y)
 
   gcc_assert ((unsigned int) mode < (unsigned int) MAX_MACHINE_MODE);
 
-  code = mov_optab->handlers[mode].insn_code;
+  code = optab_handler (mov_optab, mode)->insn_code;
   if (code != CODE_FOR_nothing)
     return emit_insn (GEN_FCN (code) (x, y));
 
@@ -3263,7 +3332,8 @@ emit_move_insn_1 (rtx x, rtx y)
   if (COMPLEX_MODE_P (mode))
     return emit_move_complex (mode, x, y);
 
-  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT)
+  if (GET_MODE_CLASS (mode) == MODE_DECIMAL_FLOAT
+      || ALL_FIXED_POINT_MODE_P (mode))
     {
       rtx result = emit_move_via_integer (mode, x, y, true);
 
@@ -3334,16 +3404,12 @@ emit_move_insn (rtx x, rtx y)
   /* If X or Y are memory references, verify that their addresses are valid
      for the machine.  */
   if (MEM_P (x)
-      && ((! memory_address_p (GET_MODE (x), XEXP (x, 0))
-          && ! push_operand (x, GET_MODE (x)))
-         || (flag_force_addr
-             && CONSTANT_ADDRESS_P (XEXP (x, 0)))))
+      && (! memory_address_p (GET_MODE (x), XEXP (x, 0))
+         && ! push_operand (x, GET_MODE (x))))
     x = validize_mem (x);
 
   if (MEM_P (y)
-      && (! memory_address_p (GET_MODE (y), XEXP (y, 0))
-         || (flag_force_addr
-             && CONSTANT_ADDRESS_P (XEXP (y, 0)))))
+      && ! memory_address_p (GET_MODE (y), XEXP (y, 0)))
     y = validize_mem (y);
 
   gcc_assert (mode != BLKmode);
@@ -3507,7 +3573,7 @@ emit_single_push_insn (enum machine_mode mode, rtx x, tree type)
   stack_pointer_delta += PUSH_ROUNDING (GET_MODE_SIZE (mode));
   /* If there is push pattern, use it.  Otherwise try old way of throwing
      MEM representing push operation to move expander.  */
-  icode = push_optab->handlers[(int) mode].insn_code;
+  icode = optab_handler (push_optab, mode)->insn_code;
   if (icode != CODE_FOR_nothing)
     {
       if (((pred = insn_data[(int) icode].operand[0].predicate)
@@ -4067,10 +4133,11 @@ optimize_bitfield_assignment_op (unsigned HOST_WIDE_INT bitsize,
 }
 
 
-/* Expand an assignment that stores the value of FROM into TO.  */
+/* Expand an assignment that stores the value of FROM into TO.  If NONTEMPORAL
+   is true, try generating a nontemporal store.  */
 
 void
-expand_assignment (tree to, tree from)
+expand_assignment (tree to, tree from, bool nontemporal)
 {
   rtx to_rtx = 0;
   rtx result;
@@ -4157,12 +4224,13 @@ expand_assignment (tree to, tree from)
          if (TREE_CODE (TREE_TYPE (from)) == COMPLEX_TYPE)
            {
              gcc_assert (bitpos == 0);
-             result = store_expr (from, to_rtx, false);
+             result = store_expr (from, to_rtx, false, nontemporal);
            }
          else
            {
              gcc_assert (bitpos == 0 || bitpos == GET_MODE_BITSIZE (mode1));
-             result = store_expr (from, XEXP (to_rtx, bitpos != 0), false);
+             result = store_expr (from, XEXP (to_rtx, bitpos != 0), false,
+                                  nontemporal);
            }
        }
       else
@@ -4188,7 +4256,8 @@ expand_assignment (tree to, tree from)
            result = NULL;
          else
            result = store_field (to_rtx, bitsize, bitpos, mode1, from,
-                                 TREE_TYPE (tem), get_alias_set (to));
+                                 TREE_TYPE (tem), get_alias_set (to),
+                                 nontemporal);
        }
 
       if (result)
@@ -4295,13 +4364,46 @@ expand_assignment (tree to, tree from)
   /* Compute FROM and store the value in the rtx we got.  */
 
   push_temp_slots ();
-  result = store_expr (from, to_rtx, 0);
+  result = store_expr (from, to_rtx, 0, nontemporal);
   preserve_temp_slots (result);
   free_temp_slots ();
   pop_temp_slots ();
   return;
 }
 
+/* Emits nontemporal store insn that moves FROM to TO.  Returns true if this
+   succeeded, false otherwise.  */
+
+static bool
+emit_storent_insn (rtx to, rtx from)
+{
+  enum machine_mode mode = GET_MODE (to), imode;
+  enum insn_code code = optab_handler (storent_optab, mode)->insn_code;
+  rtx pattern;
+
+  if (code == CODE_FOR_nothing)
+    return false;
+
+  imode = insn_data[code].operand[0].mode;
+  if (!insn_data[code].operand[0].predicate (to, imode))
+    return false;
+
+  imode = insn_data[code].operand[1].mode;
+  if (!insn_data[code].operand[1].predicate (from, imode))
+    {
+      from = copy_to_mode_reg (imode, from);
+      if (!insn_data[code].operand[1].predicate (from, imode))
+       return false;
+    }
+
+  pattern = GEN_FCN (code) (to, from);
+  if (pattern == NULL_RTX)
+    return false;
+
+  emit_insn (pattern);
+  return true;
+}
+
 /* Generate code for computing expression EXP,
    and storing the value into TARGET.
 
@@ -4313,10 +4415,12 @@ expand_assignment (tree to, tree from)
    be more thorough?
 
    If CALL_PARAM_P is nonzero, this is a store into a call param on the
-   stack, and block moves may need to be treated specially.  */
+   stack, and block moves may need to be treated specially.
+   If NONTEMPORAL is true, try using a nontemporal store instruction.  */
 
 rtx
-store_expr (tree exp, rtx target, int call_param_p)
+store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
 {
   rtx temp;
   rtx alt_rtl = NULL_RTX;
@@ -4337,7 +4441,8 @@ store_expr (tree exp, rtx target, int call_param_p)
         part.  */
       expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
                   call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL);
-      return store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
+      return store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
+                        nontemporal);
     }
   else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode)
     {
@@ -4351,11 +4456,13 @@ store_expr (tree exp, rtx target, int call_param_p)
       do_pending_stack_adjust ();
       NO_DEFER_POP;
       jumpifnot (TREE_OPERAND (exp, 0), lab1);
-      store_expr (TREE_OPERAND (exp, 1), target, call_param_p);
+      store_expr (TREE_OPERAND (exp, 1), target, call_param_p,
+                 nontemporal);
       emit_jump_insn (gen_jump (lab2));
       emit_barrier ();
       emit_label (lab1);
-      store_expr (TREE_OPERAND (exp, 2), target, call_param_p);
+      store_expr (TREE_OPERAND (exp, 2), target, call_param_p,
+                 nontemporal);
       emit_label (lab2);
       OK_DEFER_POP;
 
@@ -4377,9 +4484,8 @@ store_expr (tree exp, rtx target, int call_param_p)
         converting modes.  */
       if (INTEGRAL_TYPE_P (TREE_TYPE (exp))
          && TREE_TYPE (TREE_TYPE (exp)) == 0
-         && (!lang_hooks.reduce_bit_field_operations
-             || (GET_MODE_PRECISION (GET_MODE (target))
-                 == TYPE_PRECISION (TREE_TYPE (exp)))))
+         && GET_MODE_PRECISION (GET_MODE (target))
+            == TYPE_PRECISION (TREE_TYPE (exp)))
        {
          if (TYPE_UNSIGNED (TREE_TYPE (exp))
              != SUBREG_PROMOTED_UNSIGNED_P (target))
@@ -4387,7 +4493,7 @@ store_expr (tree exp, rtx target, int call_param_p)
              /* Some types, e.g. Fortran's logical*4, won't have a signed
                 version, so use the mode instead.  */
              tree ntype
-               = (get_signed_or_unsigned_type
+               = (signed_or_unsigned_type_for
                   (SUBREG_PROMOTED_UNSIGNED_P (target), TREE_TYPE (exp)));
              if (ntype == NULL)
                ntype = lang_hooks.types.type_for_mode
@@ -4424,9 +4530,57 @@ store_expr (tree exp, rtx target, int call_param_p)
 
       return NULL_RTX;
     }
+  else if (TREE_CODE (exp) == STRING_CST
+          && !nontemporal && !call_param_p
+          && TREE_STRING_LENGTH (exp) > 0
+          && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+    {
+      /* Optimize initialization of an array with a STRING_CST.  */
+      HOST_WIDE_INT exp_len, str_copy_len;
+      rtx dest_mem;
+
+      exp_len = int_expr_size (exp);
+      if (exp_len <= 0)
+       goto normal_expr;
+
+      str_copy_len = strlen (TREE_STRING_POINTER (exp));
+      if (str_copy_len < TREE_STRING_LENGTH (exp) - 1)
+       goto normal_expr;
+
+      str_copy_len = TREE_STRING_LENGTH (exp);
+      if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0)
+       {
+         str_copy_len += STORE_MAX_PIECES - 1;
+         str_copy_len &= ~(STORE_MAX_PIECES - 1);
+       }
+      str_copy_len = MIN (str_copy_len, exp_len);
+      if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str,
+                               (void *) TREE_STRING_POINTER (exp),
+                               MEM_ALIGN (target), false))
+       goto normal_expr;
+
+      dest_mem = target;
+
+      dest_mem = store_by_pieces (dest_mem,
+                                 str_copy_len, builtin_strncpy_read_str,
+                                 (void *) TREE_STRING_POINTER (exp),
+                                 MEM_ALIGN (target), false,
+                                 exp_len > str_copy_len ? 1 : 0);
+      if (exp_len > str_copy_len)
+       clear_storage (adjust_address (dest_mem, BLKmode, 0),
+                      GEN_INT (exp_len - str_copy_len),
+                      BLOCK_OP_NORMAL);
+      return NULL_RTX;
+    }
   else
     {
-      temp = expand_expr_real (exp, target, GET_MODE (target),
+      rtx tmp_target;
+
+  normal_expr:
+      /* If we want to use a nontemporal store, force the value to
+        register first.  */
+      tmp_target = nontemporal ? NULL_RTX : target;
+      temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
                               (call_param_p
                                ? EXPAND_STACK_PARM : EXPAND_NORMAL),
                               &alt_rtl);
@@ -4499,6 +4653,12 @@ store_expr (tree exp, rtx target, int call_param_p)
              temp = convert_to_mode (GET_MODE (target), temp, unsignedp);
              emit_move_insn (target, temp);
            }
+         else if (GET_MODE (target) == BLKmode
+                  || GET_MODE (temp) == BLKmode)
+           emit_block_move (target, temp, expr_size (exp),
+                            (call_param_p
+                             ? BLOCK_OP_CALL_PARM
+                             : BLOCK_OP_NORMAL));
          else
            convert_move (target, temp, unsignedp);
        }
@@ -4579,6 +4739,11 @@ store_expr (tree exp, rtx target, int call_param_p)
        emit_block_move (target, temp, expr_size (exp),
                         (call_param_p
                          ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL));
+      else if (nontemporal
+              && emit_storent_insn (target, temp))
+       /* If we managed to emit a nontemporal store, there is nothing else to
+          do.  */
+       ;
       else
        {
          temp = force_operand (temp, target);
@@ -4593,7 +4758,7 @@ store_expr (tree exp, rtx target, int call_param_p)
 /* Helper for categorize_ctor_elements.  Identical interface.  */
 
 static bool
-categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
+categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
                            HOST_WIDE_INT *p_elt_count,
                            bool *p_must_clear)
 {
@@ -4630,7 +4795,7 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
        case CONSTRUCTOR:
          {
            HOST_WIDE_INT nz = 0, ic = 0;
-           
+
            bool const_elt_p
              = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
 
@@ -4644,6 +4809,7 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
 
        case INTEGER_CST:
        case REAL_CST:
+       case FIXED_CST:
          if (!initializer_zerop (value))
            nz_elts += mult;
          elt_count += mult;
@@ -4707,7 +4873,7 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
             largest element.  Which would avoid comparing the size of the
             initialized element against any tail padding in the union.
             Doesn't seem worth the effort...  */
-         if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)), 
+         if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)),
                                TYPE_SIZE (init_sub_type)) == 1)
            {
              /* And now we have to find out if the element itself is fully
@@ -4739,7 +4905,7 @@ categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
    as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
 
 bool
-categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
+categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
                          HOST_WIDE_INT *p_elt_count,
                          bool *p_must_clear)
 {
@@ -4756,7 +4922,7 @@ categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
    array member at the end of the structure.  */
 
 HOST_WIDE_INT
-count_type_elements (tree type, bool allow_flexarr)
+count_type_elements (const_tree type, bool allow_flexarr)
 {
   const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
   switch (TREE_CODE (type))
@@ -4809,14 +4975,7 @@ count_type_elements (tree type, bool allow_flexarr)
 
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      {
-       /* Ho hum.  How in the world do we guess here?  Clearly it isn't
-          right to count the fields.  Guess based on the number of words.  */
-        HOST_WIDE_INT n = int_size_in_bytes (type);
-       if (n < 0)
-         return -1;
-       return n / UNITS_PER_WORD;
-      }
+      return -1;
 
     case COMPLEX_TYPE:
       return 2;
@@ -4826,6 +4985,7 @@ count_type_elements (tree type, bool allow_flexarr)
 
     case INTEGER_TYPE:
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
     case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
     case POINTER_TYPE:
@@ -4845,7 +5005,7 @@ count_type_elements (tree type, bool allow_flexarr)
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
 
 static int
-mostly_zeros_p (tree exp)
+mostly_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
 
@@ -4868,7 +5028,7 @@ mostly_zeros_p (tree exp)
 /* Return 1 if EXP contains all zeros.  */
 
 static int
-all_zeros_p (tree exp)
+all_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
 
@@ -4897,7 +5057,8 @@ all_zeros_p (tree exp)
 static void
 store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
                         HOST_WIDE_INT bitpos, enum machine_mode mode,
-                        tree exp, tree type, int cleared, int alias_set)
+                        tree exp, tree type, int cleared,
+                        alias_set_type alias_set)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR
       /* We can only call store_constructor recursively if the size and
@@ -4929,7 +5090,7 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize,
       store_constructor (exp, target, cleared, bitsize / BITS_PER_UNIT);
     }
   else
-    store_field (target, bitsize, bitpos, mode, exp, type, alias_set);
+    store_field (target, bitsize, bitpos, mode, exp, type, alias_set, false);
 }
 
 /* Store the value of constructor EXP into the rtx TARGET.
@@ -4998,7 +5159,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            cleared = 1;
          }
 
-       if (cleared)
+       if (REG_P (target) && !cleared)
          emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
        /* Store each element of the constructor into the
@@ -5010,24 +5171,24 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            HOST_WIDE_INT bitpos = 0;
            tree offset;
            rtx to_rtx = target;
-           
+
            /* Just ignore missing fields.  We cleared the whole
               structure, above, if any fields are missing.  */
            if (field == 0)
              continue;
-           
+
            if (cleared && initializer_zerop (value))
              continue;
-           
+
            if (host_integerp (DECL_SIZE (field), 1))
              bitsize = tree_low_cst (DECL_SIZE (field), 1);
            else
              bitsize = -1;
-           
+
            mode = DECL_MODE (field);
            if (DECL_BIT_FIELD (field))
              mode = VOIDmode;
-           
+
            offset = DECL_FIELD_OFFSET (field);
            if (host_integerp (offset, 0)
                && host_integerp (bit_position (field), 0))
@@ -5037,11 +5198,11 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
              }
            else
              bitpos = tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 0);
-           
+
            if (offset)
              {
                rtx offset_rtx;
-               
+
                offset
                  = SUBSTITUTE_PLACEHOLDER_IN_EXPR (offset,
                                                    make_tree (TREE_TYPE (exp),
@@ -5049,7 +5210,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
                offset_rtx = expand_normal (offset);
                gcc_assert (MEM_P (to_rtx));
-               
+
 #ifdef POINTERS_EXTEND_UNSIGNED
                if (GET_MODE (offset_rtx) != Pmode)
                  offset_rtx = convert_to_mode (Pmode, offset_rtx, 0);
@@ -5077,14 +5238,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
              {
                tree type = TREE_TYPE (value);
-               
+
                if (TYPE_PRECISION (type) < BITS_PER_WORD)
                  {
                    type = lang_hooks.types.type_for_size
                      (BITS_PER_WORD, TYPE_UNSIGNED (type));
                    value = fold_convert (type, value);
                  }
-               
+
                if (BYTES_BIG_ENDIAN)
                  value
                   = fold_build2 (LSHIFT_EXPR, type, value,
@@ -5101,7 +5262,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                to_rtx = copy_rtx (to_rtx);
                MEM_KEEP_ALIAS_SET_P (to_rtx) = 1;
              }
-           
+
            store_constructor_field (to_rtx, bitsize, bitpos, mode,
                                     value, type, cleared,
                                     get_alias_set (TREE_TYPE (field)));
@@ -5145,7 +5306,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            tree index, value;
            HOST_WIDE_INT count = 0, zero_count = 0;
            need_to_clear = ! const_bounds_p;
-           
+
            /* This loop is a more accurate version of the loop in
               mostly_zeros_p (it handles RANGE_EXPR in an index).  It
               is also needed to check for missing elements.  */
@@ -5155,30 +5316,30 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
                if (need_to_clear)
                  break;
-               
+
                if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
                  {
                    tree lo_index = TREE_OPERAND (index, 0);
                    tree hi_index = TREE_OPERAND (index, 1);
-                   
+
                    if (! host_integerp (lo_index, 1)
                        || ! host_integerp (hi_index, 1))
                      {
                        need_to_clear = 1;
                        break;
                      }
-                   
+
                    this_node_count = (tree_low_cst (hi_index, 1)
                                       - tree_low_cst (lo_index, 1) + 1);
                  }
                else
                  this_node_count = 1;
-               
+
                count += this_node_count;
                if (mostly_zeros_p (value))
                  zero_count += this_node_count;
              }
-           
+
            /* Clear the entire array first if there are any missing
               elements, or if the incidence of zero elements is >=
               75%.  */
@@ -5187,7 +5348,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    || 4 * zero_count >= 3 * count))
              need_to_clear = 1;
          }
-       
+
        if (need_to_clear && size > 0)
          {
            if (REG_P (target))
@@ -5211,10 +5372,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
            HOST_WIDE_INT bitpos;
            int unsignedp;
            rtx xtarget = target;
-           
+
            if (cleared && initializer_zerop (value))
              continue;
-           
+
            unsignedp = TYPE_UNSIGNED (elttype);
            mode = TYPE_MODE (elttype);
            if (mode == BLKmode)
@@ -5223,7 +5384,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                         : -1);
            else
              bitsize = GET_MODE_BITSIZE (mode);
-           
+
            if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
              {
                tree lo_index = TREE_OPERAND (index, 0);
@@ -5231,7 +5392,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                rtx index_r, pos_rtx;
                HOST_WIDE_INT lo, hi, count;
                tree position;
-               
+
                /* If the range is constant and "small", unroll the loop.  */
                if (const_bounds_p
                    && host_integerp (lo_index, 0)
@@ -5249,7 +5410,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    for (; lo <= hi; lo++)
                      {
                        bitpos = lo * tree_low_cst (TYPE_SIZE (elttype), 0);
-                       
+
                        if (MEM_P (target)
                            && !MEM_KEEP_ALIAS_SET_P (target)
                            && TREE_CODE (type) == ARRAY_TYPE
@@ -5258,7 +5419,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                            target = copy_rtx (target);
                            MEM_KEEP_ALIAS_SET_P (target) = 1;
                          }
-                       
+
                        store_constructor_field
                          (target, bitsize, bitpos, mode, value, type, cleared,
                           get_alias_set (elttype));
@@ -5269,18 +5430,18 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                    rtx loop_start = gen_label_rtx ();
                    rtx loop_end = gen_label_rtx ();
                    tree exit_cond;
-                   
+
                    expand_normal (hi_index);
                    unsignedp = TYPE_UNSIGNED (domain);
-                   
+
                    index = build_decl (VAR_DECL, NULL_TREE, domain);
-                   
+
                    index_r
                      = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
                                                   &unsignedp, 0));
                    SET_DECL_RTL (index, index_r);
-                   store_expr (lo_index, index_r, 0);
-                   
+                   store_expr (lo_index, index_r, 0, false);
+
                    /* Build the head of the loop.  */
                    do_pending_stack_adjust ();
                    emit_label (loop_start);
@@ -5297,7 +5458,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                        size_binop (MULT_EXPR, position,
                                    fold_convert (ssizetype,
                                                  TYPE_SIZE_UNIT (elttype)));
-                   
+
                    pos_rtx = expand_normal (position);
                    xtarget = offset_address (target, pos_rtx,
                                              highest_pow2_factor (position));
@@ -5306,21 +5467,22 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                      store_constructor (value, xtarget, cleared,
                                         bitsize / BITS_PER_UNIT);
                    else
-                     store_expr (value, xtarget, 0);
+                     store_expr (value, xtarget, 0, false);
 
                    /* Generate a conditional jump to exit the loop.  */
                    exit_cond = build2 (LT_EXPR, integer_type_node,
                                        index, hi_index);
                    jumpif (exit_cond, loop_end);
-                   
+
                    /* Update the loop counter, and jump to the head of
                       the loop.  */
                    expand_assignment (index,
                                       build2 (PLUS_EXPR, TREE_TYPE (index),
-                                              index, integer_one_node));
-                   
+                                              index, integer_one_node),
+                                      false);
+
                    emit_jump (loop_start);
-                   
+
                    /* Build the end of the loop.  */
                    emit_label (loop_end);
                  }
@@ -5329,17 +5491,17 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                     || ! host_integerp (TYPE_SIZE (elttype), 1))
              {
                tree position;
-               
+
                if (index == 0)
                  index = ssize_int (1);
-               
+
                if (minelt)
                  index = fold_convert (ssizetype,
                                        fold_build2 (MINUS_EXPR,
                                                     TREE_TYPE (index),
                                                     index,
                                                     TYPE_MIN_VALUE (domain)));
-               
+
                position =
                  size_binop (MULT_EXPR, index,
                              fold_convert (ssizetype,
@@ -5348,7 +5510,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                          expand_normal (position),
                                          highest_pow2_factor (position));
                xtarget = adjust_address (xtarget, mode, 0);
-               store_expr (value, xtarget, 0);
+               store_expr (value, xtarget, 0, false);
              }
            else
              {
@@ -5357,7 +5519,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                            * tree_low_cst (TYPE_SIZE (elttype), 1));
                else
                  bitpos = (i * tree_low_cst (TYPE_SIZE (elttype), 1));
-               
+
                if (MEM_P (target) && !MEM_KEEP_ALIAS_SET_P (target)
                    && TREE_CODE (type) == ARRAY_TYPE
                    && TYPE_NONALIASED_COMPONENT (type))
@@ -5386,25 +5548,25 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
        HOST_WIDE_INT bitpos;
        rtvec vector = NULL;
        unsigned n_elts;
-       
+
        gcc_assert (eltmode != BLKmode);
-       
+
        n_elts = TYPE_VECTOR_SUBPARTS (type);
        if (REG_P (target) && VECTOR_MODE_P (GET_MODE (target)))
          {
            enum machine_mode mode = GET_MODE (target);
-           
-           icode = (int) vec_init_optab->handlers[mode].insn_code;
+
+           icode = (int) optab_handler (vec_init_optab, mode)->insn_code;
            if (icode != CODE_FOR_nothing)
              {
                unsigned int i;
-               
+
                vector = rtvec_alloc (n_elts);
                for (i = 0; i < n_elts; i++)
                  RTVEC_ELT (vector, i) = CONST0_RTX (GET_MODE_INNER (mode));
              }
          }
-       
+
        /* If the constructor has fewer elements than the vector,
           clear the whole array first.  Similarly if this is static
           constructor of a non-BLKmode object.  */
@@ -5416,14 +5578,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          {
            unsigned HOST_WIDE_INT count = 0, zero_count = 0;
            tree value;
-           
+
            FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
              {
                int n_elts_here = tree_low_cst
                  (int_const_binop (TRUNC_DIV_EXPR,
                                    TYPE_SIZE (TREE_TYPE (value)),
                                    TYPE_SIZE (elttype), 0), 1);
-               
+
                count += n_elts_here;
                if (mostly_zeros_p (value))
                  zero_count += n_elts_here;
@@ -5433,7 +5595,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
               or if the incidence of zero elements is >= 75%.  */
            need_to_clear = (count < n_elts || 4 * zero_count >= 3 * count);
          }
-       
+
        if (need_to_clear && size > 0 && !vector)
          {
            if (REG_P (target))
@@ -5442,7 +5604,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
              clear_storage (target, GEN_INT (size), BLOCK_OP_NORMAL);
            cleared = 1;
          }
-       
+
        /* Inform later passes that the old value is dead.  */
        if (!cleared && !vector && REG_P (target))
          emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
@@ -5455,16 +5617,16 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
          {
            HOST_WIDE_INT eltpos;
            tree value = ce->value;
-           
+
            bitsize = tree_low_cst (TYPE_SIZE (TREE_TYPE (value)), 1);
            if (cleared && initializer_zerop (value))
              continue;
-           
+
            if (ce->index)
              eltpos = tree_low_cst (ce->index, 1);
            else
              eltpos = i;
-           
+
            if (vector)
              {
                /* Vector CONSTRUCTORs should only be built from smaller
@@ -5485,14 +5647,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
                                         cleared, get_alias_set (elttype));
              }
          }
-       
+
        if (vector)
          emit_insn (GEN_FCN (icode)
                     (target,
                      gen_rtx_PARALLEL (GET_MODE (target), vector)));
        break;
       }
-      
+
     default:
       gcc_unreachable ();
     }
@@ -5510,11 +5672,14 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size)
 
    ALIAS_SET is the alias set for the destination.  This value will
    (in general) be different from that for TARGET, since TARGET is a
-   reference to the containing structure.  */
+   reference to the containing structure.
+   
+   If NONTEMPORAL is true, try generating a nontemporal store.  */
 
 static rtx
 store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
-            enum machine_mode mode, tree exp, tree type, int alias_set)
+            enum machine_mode mode, tree exp, tree type,
+            alias_set_type alias_set, bool nontemporal)
 {
   HOST_WIDE_INT width_mask = 0;
 
@@ -5549,7 +5714,8 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (bitsize != (HOST_WIDE_INT) GET_MODE_BITSIZE (GET_MODE (target)))
        emit_move_insn (object, target);
 
-      store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set);
+      store_field (blk_object, bitsize, bitpos, mode, exp, type, alias_set,
+                  nontemporal);
 
       emit_move_insn (target, object);
 
@@ -5562,7 +5728,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       /* We're storing into a struct containing a single __complex.  */
 
       gcc_assert (!bitpos);
-      return store_expr (exp, target, 0);
+      return store_expr (exp, target, 0, nontemporal);
     }
 
   /* If the structure is in a register or if the component
@@ -5663,7 +5829,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
       if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0)
        set_mem_alias_set (to_rtx, alias_set);
 
-      return store_expr (exp, to_rtx, 0);
+      return store_expr (exp, to_rtx, 0, nontemporal);
     }
 }
 \f
@@ -5713,7 +5879,6 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   enum machine_mode mode = VOIDmode;
   tree offset = size_zero_node;
   tree bit_offset = bitsize_zero_node;
-  tree tem;
 
   /* First get the mode, signedness, and size.  We do this from just the
      outermost expression.  */
@@ -5728,8 +5893,9 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
   else if (TREE_CODE (exp) == BIT_FIELD_REF)
     {
       size_tree = TREE_OPERAND (exp, 1);
-      *punsignedp = BIT_FIELD_REF_UNSIGNED (exp);
-      
+      *punsignedp = (! INTEGRAL_TYPE_P (TREE_TYPE (exp))
+                    || TYPE_UNSIGNED (TREE_TYPE (exp)));
+
       /* For vector types, with the correct size of access, use the mode of
         inner type.  */
       if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE
@@ -5756,6 +5922,8 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
        *pbitsize = tree_low_cst (size_tree, 1);
     }
 
+  *pmode = mode;
+
   /* Compute cumulative bit-offset for nested component-refs and array-refs,
      and find the ultimate containing object.  */
   while (1)
@@ -5840,21 +6008,69 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
  done:
 
   /* If OFFSET is constant, see if we can return the whole thing as a
-     constant bit position.  Otherwise, split it up.  */
-  if (host_integerp (offset, 0)
-      && 0 != (tem = size_binop (MULT_EXPR,
-                                fold_convert (bitsizetype, offset),
-                                bitsize_unit_node))
-      && 0 != (tem = size_binop (PLUS_EXPR, tem, bit_offset))
-      && host_integerp (tem, 0))
-    *pbitpos = tree_low_cst (tem, 0), *poffset = 0;
-  else
-    *pbitpos = tree_low_cst (bit_offset, 0), *poffset = offset;
+     constant bit position.  Make sure to handle overflow during
+     this conversion.  */
+  if (host_integerp (offset, 0))
+    {
+      double_int tem = double_int_mul (tree_to_double_int (offset),
+                                      uhwi_to_double_int (BITS_PER_UNIT));
+      tem = double_int_add (tem, tree_to_double_int (bit_offset));
+      if (double_int_fits_in_shwi_p (tem))
+       {
+         *pbitpos = double_int_to_shwi (tem);
+         *poffset = NULL_TREE;
+         return exp;
+       }
+    }
+
+  /* Otherwise, split it up.  */
+  *pbitpos = tree_low_cst (bit_offset, 0);
+  *poffset = offset;
 
-  *pmode = mode;
   return exp;
 }
 
+/* Given an expression EXP that may be a COMPONENT_REF or an ARRAY_REF,
+   look for whether EXP or any nested component-refs within EXP is marked
+   as PACKED.  */
+
+bool
+contains_packed_reference (const_tree exp)
+{
+  bool packed_p = false;
+
+  while (1)
+    {
+      switch (TREE_CODE (exp))
+       {
+       case COMPONENT_REF:
+         {
+           tree field = TREE_OPERAND (exp, 1);
+           packed_p = DECL_PACKED (field) 
+                      || TYPE_PACKED (TREE_TYPE (field))
+                      || TYPE_PACKED (TREE_TYPE (exp));
+           if (packed_p)
+             goto done;
+         }
+         break;
+
+       case BIT_FIELD_REF:
+       case ARRAY_REF:
+       case ARRAY_RANGE_REF:
+       case REALPART_EXPR:
+       case IMAGPART_EXPR:
+       case VIEW_CONVERT_EXPR:
+         break;
+
+       default:
+         goto done;
+       }
+      exp = TREE_OPERAND (exp, 0);
+    }
+ done:
+  return packed_p;
+}
+
 /* Return a tree of sizetype representing the size, in bytes, of the element
    of EXP, an ARRAY_REF.  */
 
@@ -5951,7 +6167,7 @@ component_ref_field_offset (tree exp)
 /* Return 1 if T is an expression that get_inner_reference handles.  */
 
 int
-handled_component_p (tree t)
+handled_component_p (const_tree t)
 {
   switch (TREE_CODE (t))
     {
@@ -5989,12 +6205,13 @@ force_operand (rtx value, rtx target)
       && !REG_P (SUBREG_REG (value))
       && !MEM_P (SUBREG_REG (value)))
     {
-      value = simplify_gen_subreg (GET_MODE (value),
-                                  force_reg (GET_MODE (SUBREG_REG (value)),
-                                             force_operand (SUBREG_REG (value),
-                                                            NULL_RTX)),
-                                  GET_MODE (SUBREG_REG (value)),
-                                  SUBREG_BYTE (value));
+      value
+       = simplify_gen_subreg (GET_MODE (value),
+                              force_reg (GET_MODE (SUBREG_REG (value)),
+                                         force_operand (SUBREG_REG (value),
+                                                        NULL_RTX)),
+                              GET_MODE (SUBREG_REG (value)),
+                              SUBREG_BYTE (value));
       code = GET_CODE (value);
     }
 
@@ -6058,23 +6275,18 @@ force_operand (rtx value, rtx target)
                                  FLOAT_MODE_P (GET_MODE (value))
                                  ? RDIV_EXPR : TRUNC_DIV_EXPR,
                                  GET_MODE (value), op1, op2, target, 0);
-         break;
        case MOD:
          return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
                                target, 0);
-         break;
        case UDIV:
          return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
                                target, 1);
-         break;
        case UMOD:
          return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
                                target, 1);
-         break;
        case ASHIFTRT:
          return expand_simple_binop (GET_MODE (value), code, op1, op2,
                                      target, 0, OPTAB_LIB_WIDEN);
-         break;
        default:
          return expand_simple_binop (GET_MODE (value), code, op1, op2,
                                      target, 1, OPTAB_LIB_WIDEN);
@@ -6137,7 +6349,7 @@ force_operand (rtx value, rtx target)
    searches for optimization opportunities.  */
 
 int
-safe_from_p (rtx x, tree exp, int top_p)
+safe_from_p (const_rtx x, tree exp, int top_p)
 {
   rtx exp_rtl = 0;
   int i, nops;
@@ -6341,7 +6553,7 @@ safe_from_p (rtx x, tree exp, int top_p)
    This is used in updating alignment of MEMs in array references.  */
 
 unsigned HOST_WIDE_INT
-highest_pow2_factor (tree exp)
+highest_pow2_factor (const_tree exp)
 {
   unsigned HOST_WIDE_INT c0, c1;
 
@@ -6412,7 +6624,7 @@ highest_pow2_factor (tree exp)
    the structure gives the alignment.  */
 
 static unsigned HOST_WIDE_INT
-highest_pow2_factor_for_target (tree target, tree exp)
+highest_pow2_factor_for_target (const_tree target, const_tree exp)
 {
   unsigned HOST_WIDE_INT target_align, factor;
 
@@ -6437,39 +6649,6 @@ emutls_var_address (tree var)
   return fold_convert (build_pointer_type (TREE_TYPE (var)), call);
 }
 \f
-/* Expands variable VAR.  */
-
-void
-expand_var (tree var)
-{
-  if (DECL_EXTERNAL (var))
-    return;
-
-  if (TREE_STATIC (var))
-    /* If this is an inlined copy of a static local variable,
-       look up the original decl.  */
-    var = DECL_ORIGIN (var);
-
-  if (TREE_STATIC (var)
-      ? !TREE_ASM_WRITTEN (var)
-      : !DECL_RTL_SET_P (var))
-    {
-      if (TREE_CODE (var) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (var))
-       /* Should be ignored.  */;
-      else if (lang_hooks.expand_decl (var))
-       /* OK.  */;
-      else if (TREE_CODE (var) == VAR_DECL && !TREE_STATIC (var))
-       expand_decl (var);
-      else if (TREE_CODE (var) == VAR_DECL && TREE_STATIC (var))
-       rest_of_decl_compilation (var, 0, 0);
-      else
-       /* No expansion needed.  */
-       gcc_assert (TREE_CODE (var) == TYPE_DECL
-                   || TREE_CODE (var) == CONST_DECL
-                   || TREE_CODE (var) == FUNCTION_DECL
-                   || TREE_CODE (var) == LABEL_DECL);
-    }
-}
 
 /* Subroutine of expand_expr.  Expand the two operands of a binary
    expression EXP0 and EXP1 placing the results in OP0 and OP1.
@@ -6532,8 +6711,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
   /* ??? This should be considered a front-end bug.  We should not be
      generating ADDR_EXPR of something that isn't an LVALUE.  The only
      exception here is STRING_CST.  */
-  if (TREE_CODE (exp) == CONSTRUCTOR
-      || CONSTANT_CLASS_P (exp))
+  if (CONSTANT_CLASS_P (exp))
     return XEXP (expand_expr_constant (exp, 0, modifier), 0);
 
   /* Everything must be something allowed by is_gimple_addressable.  */
@@ -6580,9 +6758,12 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
     default:
       /* If the object is a DECL, then expand it for its rtl.  Don't bypass
         expand_expr, as that can have various side effects; LABEL_DECLs for
-        example, may not have their DECL_RTL set yet.  Assume language
-        specific tree nodes can be expanded in some interesting way.  */
+        example, may not have their DECL_RTL set yet.  Expand the rtl of
+        CONSTRUCTORs too, which should yield a memory reference for the
+        constructor's contents.  Assume language specific tree nodes can
+        be expanded in some interesting way.  */
       if (DECL_P (exp)
+         || TREE_CODE (exp) == CONSTRUCTOR
          || TREE_CODE (exp) >= LAST_AND_UNUSED_TREE_CODE)
        {
          result = expand_expr (exp, target, tmode,
@@ -6630,7 +6811,9 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode,
 
       if (modifier != EXPAND_NORMAL)
        result = force_operand (result, NULL);
-      tmp = expand_expr (offset, NULL_RTX, tmode, EXPAND_NORMAL);
+      tmp = expand_expr (offset, NULL_RTX, tmode, 
+                        modifier == EXPAND_INITIALIZER
+                         ? EXPAND_INITIALIZER : EXPAND_NORMAL);
 
       result = convert_memory_address (tmode, result);
       tmp = convert_memory_address (tmode, tmp);
@@ -6694,6 +6877,89 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
   return result;
 }
 
+/* Generate code for computing CONSTRUCTOR EXP.
+   An rtx for the computed value is returned.  If AVOID_TEMP_MEM
+   is TRUE, instead of creating a temporary variable in memory
+   NULL is returned and the caller needs to handle it differently.  */
+
+static rtx
+expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
+                   bool avoid_temp_mem)
+{
+  tree type = TREE_TYPE (exp);
+  enum machine_mode mode = TYPE_MODE (type);
+
+  /* Try to avoid creating a temporary at all.  This is possible
+     if all of the initializer is zero.
+     FIXME: try to handle all [0..255] initializers we can handle
+     with memset.  */
+  if (TREE_STATIC (exp)
+      && !TREE_ADDRESSABLE (exp)
+      && target != 0 && mode == BLKmode
+      && all_zeros_p (exp))
+    {
+      clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
+      return target;
+    }
+
+  /* All elts simple constants => refer to a constant in memory.  But
+     if this is a non-BLKmode mode, let it store a field at a time
+     since that should make a CONST_INT or CONST_DOUBLE when we
+     fold.  Likewise, if we have a target we can use, it is best to
+     store directly into the target unless the type is large enough
+     that memcpy will be used.  If we are making an initializer and
+     all operands are constant, put it in memory as well.
+
+     FIXME: Avoid trying to fill vector constructors piece-meal.
+     Output them with output_constant_def below unless we're sure
+     they're zeros.  This should go away when vector initializers
+     are treated like VECTOR_CST instead of arrays.  */
+  if ((TREE_STATIC (exp)
+       && ((mode == BLKmode
+           && ! (target != 0 && safe_from_p (target, exp, 1)))
+                 || TREE_ADDRESSABLE (exp)
+                 || (host_integerp (TYPE_SIZE_UNIT (type), 1)
+                     && (! MOVE_BY_PIECES_P
+                                    (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
+                                     TYPE_ALIGN (type)))
+                     && ! mostly_zeros_p (exp))))
+      || ((modifier == EXPAND_INITIALIZER || modifier == EXPAND_CONST_ADDRESS)
+         && TREE_CONSTANT (exp)))
+    {
+      rtx constructor;
+
+      if (avoid_temp_mem)
+       return NULL_RTX;
+
+      constructor = expand_expr_constant (exp, 1, modifier);
+
+      if (modifier != EXPAND_CONST_ADDRESS
+         && modifier != EXPAND_INITIALIZER
+         && modifier != EXPAND_SUM)
+       constructor = validize_mem (constructor);
+
+      return constructor;
+    }
+
+  /* Handle calls that pass values in multiple non-contiguous
+     locations.  The Irix 6 ABI has examples of this.  */
+  if (target == 0 || ! safe_from_p (target, exp, 1)
+      || GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM)
+    {
+      if (avoid_temp_mem)
+       return NULL_RTX;
+
+      target
+       = assign_temp (build_qualified_type (type, (TYPE_QUALS (type)
+                                                   | (TREE_READONLY (exp)
+                                                      * TYPE_QUAL_CONST))),
+                      0, TREE_ADDRESSABLE (exp), 1);
+    }
+
+  store_constructor (exp, target, 0, int_expr_size (exp));
+  return target;
+}
+
 
 /* expand_expr: generate code for computing expression EXP.
    An rtx for the computed value is returned.  The value is never null.
@@ -6755,6 +7021,7 @@ expand_expr_real (tree exp, rtx target, enum machine_mode tmode,
 
   /* Handle ERROR_MARK before anybody tries to access its type.  */
   if (TREE_CODE (exp) == ERROR_MARK
+      || TREE_CODE (exp) == PREDICT_EXPR
       || (!GIMPLE_TUPLE_P (exp) && TREE_CODE (TREE_TYPE (exp)) == ERROR_MARK))
     {
       ret = CONST0_RTX (tmode);
@@ -6833,8 +7100,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
   rtx subtarget, original_target;
   int ignore;
   tree context, subexp0, subexp1;
-  bool reduce_bit_field = false;
-#define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore              \
+  bool reduce_bit_field;
+#define REDUCE_BIT_FIELD(expr) (reduce_bit_field                         \
                                 ? reduce_to_bit_field_precision ((expr), \
                                                                  target, \
                                                                  type)   \
@@ -6852,27 +7119,20 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       mode = TYPE_MODE (type);
       unsignedp = TYPE_UNSIGNED (type);
     }
-  if (lang_hooks.reduce_bit_field_operations
-      && TREE_CODE (type) == INTEGER_TYPE
-      && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type))
-    {
-      /* An operation in what may be a bit-field type needs the
-        result to be reduced to the precision of the bit-field type,
-        which is narrower than that of the type's mode.  */
-      reduce_bit_field = true;
-      if (modifier == EXPAND_STACK_PARM)
-       target = 0;
-    }
 
-  /* Use subtarget as the target for operand 0 of a binary operation.  */
-  subtarget = get_subtarget (target);
-  original_target = target;
   ignore = (target == const0_rtx
            || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
                 || code == CONVERT_EXPR || code == COND_EXPR
                 || code == VIEW_CONVERT_EXPR)
                && TREE_CODE (type) == VOID_TYPE));
 
+  /* An operation in what may be a bit-field type needs the
+     result to be reduced to the precision of the bit-field type,
+     which is narrower than that of the type's mode.  */
+  reduce_bit_field = (!ignore
+                     && TREE_CODE (type) == INTEGER_TYPE
+                     && GET_MODE_PRECISION (mode) > TYPE_PRECISION (type));
+
   /* If we are going to ignore this result, we need only do something
      if there is a side-effect somewhere in the expression.  If there
      is, short-circuit the most common cases here.  Note that we must
@@ -6921,6 +7181,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       target = 0;
     }
 
+  if (reduce_bit_field && modifier == EXPAND_STACK_PARM)
+    target = 0;
+
+  /* Use subtarget as the target for operand 0 of a binary operation.  */
+  subtarget = get_subtarget (target);
+  original_target = target;
 
   switch (code)
     {
@@ -6998,9 +7264,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (MEM_P (decl_rtl) && REG_P (XEXP (decl_rtl, 0)))
        temp = validize_mem (decl_rtl);
 
-      /* If DECL_RTL is memory, we are in the normal case and either
-        the address is not valid or it is not a register and -fforce-addr
-        is specified, get the address into a register.  */
+      /* If DECL_RTL is memory, we are in the normal case and the
+        address is not valid, get the address into a register.  */
 
       else if (MEM_P (decl_rtl) && modifier != EXPAND_INITIALIZER)
        {
@@ -7009,8 +7274,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          decl_rtl = use_anchored_address (decl_rtl);
          if (modifier != EXPAND_CONST_ADDRESS
              && modifier != EXPAND_SUM
-             && (!memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0))
-                 || (flag_force_addr && !REG_P (XEXP (decl_rtl, 0)))))
+             && !memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0)))
            temp = replace_equiv_address (decl_rtl,
                                          copy_rtx (XEXP (decl_rtl, 0)));
        }
@@ -7033,7 +7297,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          && GET_MODE (decl_rtl) != DECL_MODE (exp))
        {
          enum machine_mode pmode;
-         
+
          /* Get the signedness used for this variable.  Ensure we get the
             same mode we got when the variable was declared.  */
          pmode = promote_mode (type, DECL_MODE (exp), &unsignedp,
@@ -7053,22 +7317,17 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       temp = immed_double_const (TREE_INT_CST_LOW (exp),
                                 TREE_INT_CST_HIGH (exp), mode);
 
-      /* ??? If overflow is set, fold will have done an incomplete job,
-        which can result in (plus xx (const_int 0)), which can get
-        simplified by validate_replace_rtx during virtual register
-        instantiation, which can result in unrecognizable insns.
-        Avoid this by forcing all overflows into registers.  */
-      if (TREE_OVERFLOW (exp)
-         && modifier != EXPAND_INITIALIZER)
-       temp = force_reg (mode, temp);
-
       return temp;
 
     case VECTOR_CST:
       {
        tree tmp = NULL_TREE;
        if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
-           || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_FRACT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_UFRACT
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_ACCUM
+           || GET_MODE_CLASS (mode) == MODE_VECTOR_UACCUM)
          return const_vector_from_tree (exp);
        if (GET_MODE_CLASS (mode) == MODE_INT)
          {
@@ -7100,6 +7359,10 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (exp),
                                           TYPE_MODE (TREE_TYPE (exp)));
 
+    case FIXED_CST:
+      return CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (exp),
+                                          TYPE_MODE (TREE_TYPE (exp)));
+
     case COMPLEX_CST:
       /* Handle evaluating a complex constant in a CONCAT target.  */
       if (original_target && GET_CODE (original_target) == CONCAT)
@@ -7133,8 +7396,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       if (modifier != EXPAND_CONST_ADDRESS
          && modifier != EXPAND_INITIALIZER
          && modifier != EXPAND_SUM
-         && (! memory_address_p (mode, XEXP (temp, 0))
-             || flag_force_addr))
+         && ! memory_address_p (mode, XEXP (temp, 0)))
        return replace_equiv_address (temp,
                                      copy_rtx (XEXP (temp, 0)));
       return temp;
@@ -7187,71 +7449,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          return const0_rtx;
        }
 
-      /* Try to avoid creating a temporary at all.  This is possible
-        if all of the initializer is zero.
-        FIXME: try to handle all [0..255] initializers we can handle
-        with memset.  */
-      else if (TREE_STATIC (exp)
-              && !TREE_ADDRESSABLE (exp)
-              && target != 0 && mode == BLKmode
-              && all_zeros_p (exp))
-       {
-         clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
-         return target;
-       }
-
-      /* All elts simple constants => refer to a constant in memory.  But
-        if this is a non-BLKmode mode, let it store a field at a time
-        since that should make a CONST_INT or CONST_DOUBLE when we
-        fold.  Likewise, if we have a target we can use, it is best to
-        store directly into the target unless the type is large enough
-        that memcpy will be used.  If we are making an initializer and
-        all operands are constant, put it in memory as well.
-
-       FIXME: Avoid trying to fill vector constructors piece-meal.
-       Output them with output_constant_def below unless we're sure
-       they're zeros.  This should go away when vector initializers
-       are treated like VECTOR_CST instead of arrays.
-      */
-      else if ((TREE_STATIC (exp)
-               && ((mode == BLKmode
-                    && ! (target != 0 && safe_from_p (target, exp, 1)))
-                   || TREE_ADDRESSABLE (exp)
-                   || (host_integerp (TYPE_SIZE_UNIT (type), 1)
-                       && (! MOVE_BY_PIECES_P
-                           (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
-                            TYPE_ALIGN (type)))
-                       && ! mostly_zeros_p (exp))))
-              || ((modifier == EXPAND_INITIALIZER
-                   || modifier == EXPAND_CONST_ADDRESS)
-                  && TREE_CONSTANT (exp)))
-       {
-         rtx constructor = expand_expr_constant (exp, 1, modifier);
-
-         if (modifier != EXPAND_CONST_ADDRESS
-             && modifier != EXPAND_INITIALIZER
-             && modifier != EXPAND_SUM)
-           constructor = validize_mem (constructor);
-
-         return constructor;
-       }
-      else
-       {
-         /* Handle calls that pass values in multiple non-contiguous
-            locations.  The Irix 6 ABI has examples of this.  */
-         if (target == 0 || ! safe_from_p (target, exp, 1)
-             || GET_CODE (target) == PARALLEL
-             || modifier == EXPAND_STACK_PARM)
-           target
-             = assign_temp (build_qualified_type (type,
-                                                  (TYPE_QUALS (type)
-                                                   | (TREE_READONLY (exp)
-                                                      * TYPE_QUAL_CONST))),
-                            0, TREE_ADDRESSABLE (exp), 1);
-
-         store_constructor (exp, target, 0, int_expr_size (exp));
-         return target;
-       }
+      return expand_constructor (exp, target, modifier, false);
 
     case MISALIGNED_INDIRECT_REF:
     case ALIGN_INDIRECT_REF:
@@ -7296,7 +7494,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                        || modifier == EXPAND_STACK_PARM);
 
            /* The vectorizer should have already checked the mode.  */
-           icode = movmisalign_optab->handlers[mode].insn_code;
+           icode = optab_handler (movmisalign_optab, mode)->insn_code;
            gcc_assert (icode != CODE_FOR_nothing);
 
            /* We've already validated the memory, and we're creating a
@@ -7393,10 +7591,25 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                                              field, value)
                      if (tree_int_cst_equal (field, index))
                        {
-                         if (!TREE_SIDE_EFFECTS (value))
-                           return expand_expr (fold (value), target, tmode,
-                                               modifier);
-                         break;
+                         if (TREE_SIDE_EFFECTS (value))
+                           break;
+
+                         if (TREE_CODE (value) == CONSTRUCTOR)
+                           {
+                             /* If VALUE is a CONSTRUCTOR, this
+                                optimization is only useful if
+                                this doesn't store the CONSTRUCTOR
+                                into memory.  If it does, it is more
+                                efficient to just load the data from
+                                the array directly.  */
+                             rtx ret = expand_constructor (value, target,
+                                                           modifier, true);
+                             if (ret == NULL_RTX)
+                               break;
+                           }
+
+                         return expand_expr (fold (value), target, tmode,
+                                             modifier);
                        }
                  }
                else if(TREE_CODE (init) == STRING_CST)
@@ -7404,19 +7617,19 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                    tree index1 = index;
                    tree low_bound = array_ref_low_bound (exp);
                    index1 = fold_convert (sizetype, TREE_OPERAND (exp, 1));
-                   
+
                    /* Optimize the special-case of a zero lower bound.
-                   
+
                       We convert the low_bound to sizetype to avoid some problems
                       with constant folding.  (E.g. suppose the lower bound is 1,
                       and its mode is QI.  Without the conversion,l (ARRAY
                       +(INDEX-(unsigned char)1)) becomes ((ARRAY+(-(unsigned char)1))
                       +INDEX), which becomes (ARRAY+255+INDEX).  Opps!)  */
-                   
+
                    if (! integer_zerop (low_bound))
                      index1 = size_diffop (index1, fold_convert (sizetype,
                                                                  low_bound));
-                 
+
                    if (0 > compare_tree_int (index1,
                                              TREE_STRING_LENGTH (init)))
                      {
@@ -7772,23 +7985,39 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
 
     case CALL_EXPR:
-      /* Check for a built-in function.  */
-      if (TREE_CODE (CALL_EXPR_FN (exp)) == ADDR_EXPR
-         && (TREE_CODE (TREE_OPERAND (CALL_EXPR_FN (exp), 0))
-             == FUNCTION_DECL)
-         && DECL_BUILT_IN (TREE_OPERAND (CALL_EXPR_FN (exp), 0)))
-       {
-         if (DECL_BUILT_IN_CLASS (TREE_OPERAND (CALL_EXPR_FN (exp), 0))
-             == BUILT_IN_FRONTEND)
-           return lang_hooks.expand_expr (exp, original_target,
-                                          tmode, modifier,
-                                          alt_rtl);
-         else
-           return expand_builtin (exp, target, subtarget, tmode, ignore);
-       }
-
+      /* All valid uses of __builtin_va_arg_pack () are removed during
+        inlining.  */
+      if (CALL_EXPR_VA_ARG_PACK (exp))
+       error ("%Kinvalid use of %<__builtin_va_arg_pack ()%>", exp);
+      {
+       tree fndecl = get_callee_fndecl (exp), attr;
+
+       if (fndecl
+           && (attr = lookup_attribute ("error",
+                                        DECL_ATTRIBUTES (fndecl))) != NULL)
+         error ("%Kcall to %qs declared with attribute error: %s",
+                exp, lang_hooks.decl_printable_name (fndecl, 1),
+                TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+       if (fndecl
+           && (attr = lookup_attribute ("warning",
+                                        DECL_ATTRIBUTES (fndecl))) != NULL)
+         warning (0, "%Kcall to %qs declared with attribute warning: %s",
+                  exp, lang_hooks.decl_printable_name (fndecl, 1),
+                  TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
+
+       /* Check for a built-in function.  */
+       if (fndecl && DECL_BUILT_IN (fndecl))
+         {
+           if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_FRONTEND)
+             return lang_hooks.expand_expr (exp, original_target,
+                                            tmode, modifier, alt_rtl);
+           else
+             return expand_builtin (exp, target, subtarget, tmode, ignore);
+         }
+      }
       return expand_call (exp, target, ignore);
 
+    case PAREN_EXPR:
     case NON_LVALUE_EXPR:
     case NOP_EXPR:
     case CONVERT_EXPR:
@@ -7823,12 +8052,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            /* Store data into beginning of memory target.  */
            store_expr (TREE_OPERAND (exp, 0),
                        adjust_address (target, TYPE_MODE (valtype), 0),
-                       modifier == EXPAND_STACK_PARM);
+                       modifier == EXPAND_STACK_PARM,
+                       false);
 
          else
            {
              gcc_assert (REG_P (target));
-             
+
              /* Store this field into a union of the proper type.  */
              store_field (target,
                           MIN ((int_size_in_bytes (TREE_TYPE
@@ -7836,7 +8066,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                                 * BITS_PER_UNIT),
                                (HOST_WIDE_INT) GET_MODE_BITSIZE (mode)),
                           0, TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
-                          type, 0);
+                          type, 0, false);
            }
 
          /* Return the entire union.  */
@@ -7914,9 +8144,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         other.  */
       else if (SCALAR_INT_MODE_P (GET_MODE (op0))
               && SCALAR_INT_MODE_P (TYPE_MODE (type)))
-       op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0, 
+       op0 = convert_modes (TYPE_MODE (type), GET_MODE (op0), op0,
                             TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
-      /* As a last resort, spill op0 to memory, and reload it in a 
+      /* As a last resort, spill op0 to memory, and reload it in a
         different mode.  */
       else if (!MEM_P (op0))
        {
@@ -7977,20 +8207,28 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
       return op0;
 
+    case POINTER_PLUS_EXPR: 
+      /* Even though the sizetype mode and the pointer's mode can be different
+         expand is able to handle this correctly and get the correct result out 
+         of the PLUS_EXPR code.  */
     case PLUS_EXPR:
+
       /* Check if this is a case for multiplication and addition.  */
-      if (TREE_CODE (type) == INTEGER_TYPE
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == FIXED_POINT_TYPE)
          && TREE_CODE (TREE_OPERAND (exp, 0)) == MULT_EXPR)
        {
          tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1;
+         enum tree_code code0, code1, this_code;
 
          subexp0 = TREE_OPERAND (exp, 0);
          subsubexp0 = TREE_OPERAND (subexp0, 0);
          subsubexp1 = TREE_OPERAND (subexp0, 1);
          code0 = TREE_CODE (subsubexp0);
          code1 = TREE_CODE (subsubexp1);
-         if (code0 == NOP_EXPR && code1 == NOP_EXPR
+         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
+                                                      : FIXED_CONVERT_EXPR;
+         if (code0 == this_code && code1 == this_code
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
                  < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
@@ -8001,9 +8239,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
              enum machine_mode innermode = TYPE_MODE (op0type);
              bool zextend_p = TYPE_UNSIGNED (op0type);
-             this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab;
+             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
+             if (sat_p == 0)
+               this_optab = zextend_p ? umadd_widen_optab : smadd_widen_optab;
+             else
+               this_optab = zextend_p ? usmadd_widen_optab
+                                      : ssmadd_widen_optab;
              if (mode == GET_MODE_2XWIDER_MODE (innermode)
-                 && (this_optab->handlers[(int) mode].insn_code
+                 && (optab_handler (this_optab, mode)->insn_code
                      != CODE_FOR_nothing))
                {
                  expand_operands (TREE_OPERAND (subsubexp0, 0),
@@ -8134,18 +8377,21 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case MINUS_EXPR:
       /* Check if this is a case for multiplication and subtraction.  */
-      if (TREE_CODE (type) == INTEGER_TYPE
+      if ((TREE_CODE (type) == INTEGER_TYPE
+          || TREE_CODE (type) == FIXED_POINT_TYPE)
          && TREE_CODE (TREE_OPERAND (exp, 1)) == MULT_EXPR)
        {
          tree subsubexp0, subsubexp1;
-         enum tree_code code0, code1;
+         enum tree_code code0, code1, this_code;
 
          subexp1 = TREE_OPERAND (exp, 1);
          subsubexp0 = TREE_OPERAND (subexp1, 0);
          subsubexp1 = TREE_OPERAND (subexp1, 1);
          code0 = TREE_CODE (subsubexp0);
          code1 = TREE_CODE (subsubexp1);
-         if (code0 == NOP_EXPR && code1 == NOP_EXPR
+         this_code = TREE_CODE (type) == INTEGER_TYPE ? NOP_EXPR
+                                                      : FIXED_CONVERT_EXPR;
+         if (code0 == this_code && code1 == this_code
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
                  < TYPE_PRECISION (TREE_TYPE (subsubexp0)))
              && (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (subsubexp0, 0)))
@@ -8156,9 +8402,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
              tree op0type = TREE_TYPE (TREE_OPERAND (subsubexp0, 0));
              enum machine_mode innermode = TYPE_MODE (op0type);
              bool zextend_p = TYPE_UNSIGNED (op0type);
-             this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
+             bool sat_p = TYPE_SATURATING (TREE_TYPE (subsubexp0));
+             if (sat_p == 0)
+               this_optab = zextend_p ? umsub_widen_optab : smsub_widen_optab;
+             else
+               this_optab = zextend_p ? usmsub_widen_optab
+                                      : ssmsub_widen_optab;
              if (mode == GET_MODE_2XWIDER_MODE (innermode)
-                 && (this_optab->handlers[(int) mode].insn_code
+                 && (optab_handler (this_optab, mode)->insn_code
                      != CODE_FOR_nothing))
                {
                  expand_operands (TREE_OPERAND (subsubexp0, 0),
@@ -8215,6 +8466,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       goto binop2;
 
     case MULT_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_mult" doesn't support sat/no-sat fixed-point
+         multiplications.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       /* If first operand is constant, swap them.
         Thus the following special case checks need only
         check the second operand.  */
@@ -8273,7 +8530,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
          this_optab = usmul_widen_optab;
          if (mode == GET_MODE_WIDER_MODE (innermode))
            {
-             if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+             if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
                {
                  if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (subexp0, 0))))
                    expand_operands (TREE_OPERAND (subexp0, 0),
@@ -8323,7 +8580,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
          if (mode == GET_MODE_2XWIDER_MODE (innermode))
            {
-             if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+             if (optab_handler (this_optab, mode)->insn_code != CODE_FOR_nothing)
                {
                  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
                    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
@@ -8335,7 +8592,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                                     NULL_RTX, &op0, &op1, EXPAND_NORMAL);
                  goto binop3;
                }
-             else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+             else if (optab_handler (other_optab, mode)->insn_code != CODE_FOR_nothing
                       && innermode == word_mode)
                {
                  rtx htem, hipart;
@@ -8367,6 +8624,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case CEIL_DIV_EXPR:
     case ROUND_DIV_EXPR:
     case EXACT_DIV_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_divmod" doesn't support sat/no-sat fixed-point
+         divisions.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       /* Possible optimization: compute the dividend with EXPAND_SUM
@@ -8389,6 +8652,19 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                       subtarget, &op0, &op1, 0);
       return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
 
+    case FIXED_CONVERT_EXPR:
+      op0 = expand_normal (TREE_OPERAND (exp, 0));
+      if (target == 0 || modifier == EXPAND_STACK_PARM)
+       target = gen_reg_rtx (mode);
+
+      if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == INTEGER_TYPE
+          && TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
+          || (TREE_CODE (type) == INTEGER_TYPE && TYPE_UNSIGNED (type)))
+       expand_fixed_convert (target, op0, 1, TYPE_SATURATING (type));
+      else
+       expand_fixed_convert (target, op0, 0, TYPE_SATURATING (type));
+      return target;
+
     case FIX_TRUNC_EXPR:
       op0 = expand_normal (TREE_OPERAND (exp, 0));
       if (target == 0 || modifier == EXPAND_STACK_PARM)
@@ -8590,18 +8866,33 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
     case BIT_XOR_EXPR:
       goto binop;
 
-    case LSHIFT_EXPR:
-    case RSHIFT_EXPR:
     case LROTATE_EXPR:
     case RROTATE_EXPR:
+      /* The expansion code only handles expansion of mode precision
+        rotates.  */
+      gcc_assert (GET_MODE_PRECISION (TYPE_MODE (type))
+                 == TYPE_PRECISION (type));
+
+      /* Falltrough.  */
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+      /* If this is a fixed-point operation, then we cannot use the code
+        below because "expand_shift" doesn't support sat/no-sat fixed-point
+         shifts.   */
+      if (ALL_FIXED_POINT_MODE_P (mode))
+       goto binop;
+
       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
        subtarget = 0;
       if (modifier == EXPAND_STACK_PARM)
        target = 0;
       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget,
                         VOIDmode, EXPAND_NORMAL);
-      return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
+      temp = expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
                           unsignedp);
+      if (code == LSHIFT_EXPR)
+       temp = REDUCE_BIT_FIELD (temp);
+      return temp;
 
       /* Could determine the answer when only additive constants differ.  Also,
         the addition of one can be handled by changing the condition.  */
@@ -8752,13 +9043,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        op1 = gen_label_rtx ();
        jumpifnot (TREE_OPERAND (exp, 0), op0);
        store_expr (TREE_OPERAND (exp, 1), temp,
-                 modifier == EXPAND_STACK_PARM);
+                 modifier == EXPAND_STACK_PARM,
+                 false);
 
        emit_jump_insn (gen_jump (op1));
        emit_barrier ();
        emit_label (op0);
        store_expr (TREE_OPERAND (exp, 2), temp,
-                 modifier == EXPAND_STACK_PARM);
+                 modifier == EXPAND_STACK_PARM,
+                 false);
 
        emit_label (op1);
        OK_DEFER_POP;
@@ -8773,7 +9066,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        tree lhs = TREE_OPERAND (exp, 0);
        tree rhs = TREE_OPERAND (exp, 1);
        gcc_assert (ignore);
-       expand_assignment (lhs, rhs);
+       expand_assignment (lhs, rhs, false);
        return const0_rtx;
       }
 
@@ -8805,13 +9098,14 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
            do_jump (TREE_OPERAND (rhs, 1),
                     value ? label : 0,
                     value ? 0 : label);
-           expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value));
+           expand_assignment (lhs, build_int_cst (TREE_TYPE (rhs), value),
+                              MOVE_NONTEMPORAL (exp));
            do_pending_stack_adjust ();
            emit_label (label);
            return const0_rtx;
          }
 
-       expand_assignment (lhs, rhs);
+       expand_assignment (lhs, rhs, MOVE_NONTEMPORAL (exp));
        return const0_rtx;
       }
 
@@ -8878,11 +9172,18 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       /* Lowered by gimplify.c.  */
       gcc_unreachable ();
 
+    case CHANGE_DYNAMIC_TYPE_EXPR:
+      /* This is ignored at the RTL level.  The tree level set
+        DECL_POINTER_ALIAS_SET of any variable to be 0, which is
+        overkill for the RTL layer but is all that we can
+        represent.  */
+      return const0_rtx;
+
     case EXC_PTR_EXPR:
-      return get_exception_pointer (cfun);
+      return get_exception_pointer ();
 
     case FILTER_EXPR:
-      return get_exception_filter (cfun);
+      return get_exception_filter ();
 
     case FDESC_EXPR:
       /* Function descriptors are not valid except for as
@@ -8909,7 +9210,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
     case REALIGN_LOAD_EXPR:
       {
-        tree oprnd0 = TREE_OPERAND (exp, 0); 
+        tree oprnd0 = TREE_OPERAND (exp, 0);
         tree oprnd1 = TREE_OPERAND (exp, 1);
         tree oprnd2 = TREE_OPERAND (exp, 2);
         rtx op2;
@@ -8917,7 +9218,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
         this_optab = optab_for_tree_code (code, type);
         expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
         op2 = expand_normal (oprnd2);
-        temp = expand_ternary_op (mode, this_optab, op0, op1, op2, 
+        temp = expand_ternary_op (mode, this_optab, op0, op1, op2,
                                  target, unsignedp);
         gcc_assert (temp);
         return temp;
@@ -8932,7 +9233,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 
        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
        op2 = expand_normal (oprnd2);
-       target = expand_widen_pattern_expr (exp, op0, op1, op2, 
+       target = expand_widen_pattern_expr (exp, op0, op1, op2,
                                            target, unsignedp);
        return target;
       }
@@ -8941,7 +9242,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
       {
         tree oprnd0 = TREE_OPERAND (exp, 0);
         tree oprnd1 = TREE_OPERAND (exp, 1);
-                                                                               
+
         expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, 0);
         target = expand_widen_pattern_expr (exp, op0, NULL_RTX, op1,
                                             target, unsignedp);
@@ -9037,6 +9338,13 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
        goto binop;
       }
 
+    case OMP_ATOMIC_LOAD:
+    case OMP_ATOMIC_STORE:
+      /* OMP expansion is not run when there were errors, so these codes
+                 can get here.  */
+      gcc_assert (errorcount != 0);
+      return NULL_RTX;
+
     default:
       return lang_hooks.expand_expr (exp, original_target, tmode,
                                     modifier, alt_rtl);
@@ -9100,7 +9408,7 @@ reduce_to_bit_field_precision (rtx exp, rtx target, tree type)
    aligned more than BIGGEST_ALIGNMENT.  */
 
 static int
-is_aligning_offset (tree offset, tree exp)
+is_aligning_offset (const_tree offset, const_tree exp)
 {
   /* Strip off any conversions.  */
   while (TREE_CODE (offset) == NON_LVALUE_EXPR
@@ -9179,14 +9487,14 @@ string_constant (tree arg, tree *ptr_offset)
              if (TREE_CODE (offset) != INTEGER_CST)
                return 0;
              /* Adjust offset by the lower bound.  */
-             offset = size_diffop (fold_convert (sizetype, offset), 
+             offset = size_diffop (fold_convert (sizetype, offset),
                                    fold_convert (sizetype, lower_bound));
            }
        }
       else
        return 0;
     }
-  else if (TREE_CODE (arg) == PLUS_EXPR)
+  else if (TREE_CODE (arg) == PLUS_EXPR || TREE_CODE (arg) == POINTER_PLUS_EXPR)
     {
       tree arg0 = TREE_OPERAND (arg, 0);
       tree arg1 = TREE_OPERAND (arg, 1);
@@ -9400,7 +9708,8 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
     }
 
   /* Put a constant second.  */
-  if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST)
+  if (TREE_CODE (arg0) == REAL_CST || TREE_CODE (arg0) == INTEGER_CST
+      || TREE_CODE (arg0) == FIXED_CST)
     {
       tem = arg0; arg0 = arg1; arg1 = tem;
       code = swap_condition (code);
@@ -9434,11 +9743,11 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
   if (icode == CODE_FOR_nothing)
     {
       enum machine_mode wmode;
-      
+
       for (wmode = operand_mode;
           icode == CODE_FOR_nothing && wmode != VOIDmode;
           wmode = GET_MODE_WIDER_MODE (wmode))
-       icode = cstore_optab->handlers[(int) wmode].insn_code;
+       icode = optab_handler (cstore_optab, wmode)->insn_code;
     }
 
   if (icode == CODE_FOR_nothing
@@ -9451,9 +9760,9 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
        ;
       else if (! only_cheap && (code == NE || code == EQ)
               && TREE_CODE (type) != REAL_TYPE
-              && ((abs_optab->handlers[(int) operand_mode].insn_code
+              && ((optab_handler (abs_optab, operand_mode)->insn_code
                    != CODE_FOR_nothing)
-                  || (ffs_optab->handlers[(int) operand_mode].insn_code
+                  || (optab_handler (ffs_optab, operand_mode)->insn_code
                       != CODE_FOR_nothing)))
        ;
       else
@@ -9489,7 +9798,7 @@ do_store_flag (tree exp, rtx target, enum machine_mode mode, int only_cheap)
   label = gen_label_rtx ();
   do_compare_rtx_and_jump (op0, op1, code, unsignedp, operand_mode, NULL_RTX,
                           NULL_RTX, label);
-  
+
   emit_move_insn (target, invert ? const1_rtx : const0_rtx);
   emit_label (label);
 
@@ -9521,7 +9830,8 @@ case_values_threshold (void)
    0 otherwise (i.e. if there is no casesi instruction).  */
 int
 try_casesi (tree index_type, tree index_expr, tree minval, tree range,
-           rtx table_label ATTRIBUTE_UNUSED, rtx default_label)
+           rtx table_label ATTRIBUTE_UNUSED, rtx default_label,
+           rtx fallback_label ATTRIBUTE_UNUSED)
 {
   enum machine_mode index_mode = SImode;
   int index_bits = GET_MODE_BITSIZE (index_mode);
@@ -9542,8 +9852,9 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
                           index_expr, minval);
       minval = integer_zero_node;
       index = expand_normal (index_expr);
-      emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
-                              omode, 1, default_label);
+      if (default_label)
+        emit_cmp_and_jump_insns (rangertx, index, LTU, NULL_RTX,
+                                omode, 1, default_label);
       /* Now we can safely truncate.  */
       index = convert_to_mode (index_mode, index, 0);
     }
@@ -9584,7 +9895,8 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
     op2 = copy_to_mode_reg (op_mode, op2);
 
   emit_jump_insn (gen_casesi (index, op1, op2,
-                             table_label, default_label));
+                             table_label, !default_label
+                                          ? fallback_label : default_label));
   return 1;
 }
 
@@ -9611,8 +9923,8 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
 {
   rtx temp, vector;
 
-  if (INTVAL (range) > cfun->max_jumptable_ents)
-    cfun->max_jumptable_ents = INTVAL (range);
+  if (INTVAL (range) > cfun->cfg->max_jumptable_ents)
+    cfun->cfg->max_jumptable_ents = INTVAL (range);
 
   /* Do an unsigned comparison (in the proper mode) between the index
      expression and the value which represents the length of the range.
@@ -9622,8 +9934,9 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
      or equal to the minimum value of the range and less than or equal to
      the maximum value of the range.  */
 
-  emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
-                          default_label);
+  if (default_label)
+    emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
+                            default_label);
 
   /* If index is in range, it must fit in Pmode.
      Convert to Pmode so we can index with it.  */
@@ -9638,10 +9951,6 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
     index = copy_to_mode_reg (Pmode, index);
 #endif
 
-  /* If flag_force_addr were to affect this address
-     it could interfere with the tricky assumptions made
-     about addresses that contain label-refs,
-     which may be valid only very near the tablejump itself.  */
   /* ??? The only correct use of CASE_VECTOR_MODE is the one inside the
      GET_MODE_SIZE, because this indicates how large insns are.  The other
      uses should all be Pmode, because they are addresses.  This code
@@ -9655,7 +9964,7 @@ do_tablejump (rtx index, enum machine_mode mode, rtx range, rtx table_label,
     index = PIC_CASE_VECTOR_ADDRESS (index);
   else
 #endif
-    index = memory_address_noforce (CASE_VECTOR_MODE, index);
+    index = memory_address (CASE_VECTOR_MODE, index);
   temp = gen_reg_rtx (CASE_VECTOR_MODE);
   vector = gen_const_mem (CASE_VECTOR_MODE, index);
   convert_move (temp, vector, 0);
@@ -9704,7 +10013,11 @@ vector_mode_valid_p (enum machine_mode mode)
 
   /* Doh!  What's going on?  */
   if (class != MODE_VECTOR_INT
-      && class != MODE_VECTOR_FLOAT)
+      && class != MODE_VECTOR_FLOAT
+      && class != MODE_VECTOR_FRACT
+      && class != MODE_VECTOR_UFRACT
+      && class != MODE_VECTOR_ACCUM
+      && class != MODE_VECTOR_UACCUM)
     return 0;
 
   /* Hardware support.  Woo hoo!  */
@@ -9748,6 +10061,9 @@ const_vector_from_tree (tree exp)
       if (TREE_CODE (elt) == REAL_CST)
        RTVEC_ELT (v, i) = CONST_DOUBLE_FROM_REAL_VALUE (TREE_REAL_CST (elt),
                                                         inner);
+      else if (TREE_CODE (elt) == FIXED_CST)
+       RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
+                                                        inner);
       else
        RTVEC_ELT (v, i) = immed_double_const (TREE_INT_CST_LOW (elt),
                                               TREE_INT_CST_HIGH (elt),