]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/expr.c
Update copyright years.
[thirdparty/gcc.git] / gcc / expr.c
index ef29ec5c40aa88ef1c710c7327fad145e1451dd3..b97c217e86da73401a04f3c4fc531d83987e8d5d 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
-   Copyright (C) 1988-2018 Free Software Foundation, Inc.
+   Copyright (C) 1988-2020 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -73,9 +73,10 @@ along with GCC; see the file COPYING3.  If not see
 int cse_not_expected;
 
 static bool block_move_libcall_safe_for_call_parm (void);
-static bool emit_block_move_via_movmem (rtx, rtx, rtx, unsigned, unsigned, HOST_WIDE_INT,
-                                       unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
-                                       unsigned HOST_WIDE_INT);
+static bool emit_block_move_via_pattern (rtx, rtx, rtx, unsigned, unsigned, 
+                                        HOST_WIDE_INT, unsigned HOST_WIDE_INT,
+                                        unsigned HOST_WIDE_INT,
+                                        unsigned HOST_WIDE_INT, bool);
 static void emit_block_move_via_loop (rtx, rtx, rtx, unsigned);
 static void clear_by_pieces (rtx, unsigned HOST_WIDE_INT, unsigned int);
 static rtx_insn *compress_float_constant (rtx, rtx);
@@ -249,6 +250,31 @@ convert_move (rtx to, rtx from, int unsignedp)
 
   if (VECTOR_MODE_P (to_mode) || VECTOR_MODE_P (from_mode))
     {
+      if (GET_MODE_UNIT_PRECISION (to_mode)
+         > GET_MODE_UNIT_PRECISION (from_mode))
+       {
+         optab op = unsignedp ? zext_optab : sext_optab;
+         insn_code icode = convert_optab_handler (op, to_mode, from_mode);
+         if (icode != CODE_FOR_nothing)
+           {
+             emit_unop_insn (icode, to, from,
+                             unsignedp ? ZERO_EXTEND : SIGN_EXTEND);
+             return;
+           }
+       }
+
+      if (GET_MODE_UNIT_PRECISION (to_mode)
+         < GET_MODE_UNIT_PRECISION (from_mode))
+       {
+         insn_code icode = convert_optab_handler (trunc_optab,
+                                                  to_mode, from_mode);
+         if (icode != CODE_FOR_nothing)
+           {
+             emit_unop_insn (icode, to, from, TRUNCATE);
+             return;
+           }
+       }
+
       gcc_assert (known_eq (GET_MODE_BITSIZE (from_mode),
                            GET_MODE_BITSIZE (to_mode)));
 
@@ -559,7 +585,6 @@ convert_mode_scalar (rtx to, rtx from, int unsignedp)
        }
       else
        {
-         scalar_mode intermediate;
          rtx tmp;
          int shift_amount;
 
@@ -1146,7 +1171,7 @@ class move_by_pieces_d : public op_by_pieces_d
     : op_by_pieces_d (to, false, from, true, NULL, NULL, len, align)
   {
   }
-  rtx finish_endp (int);
+  rtx finish_retmode (memop_ret);
 };
 
 /* Return true if MODE can be used for a set of copies, given an
@@ -1182,15 +1207,14 @@ move_by_pieces_d::generate (rtx op0, rtx op1,
 }
 
 /* Perform the final adjustment at the end of a string to obtain the
-   correct return value for the block operation.  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.  */
+   correct return value for the block operation.
+   Return value is based on RETMODE argument.  */
 
 rtx
-move_by_pieces_d::finish_endp (int endp)
+move_by_pieces_d::finish_retmode (memop_ret retmode)
 {
   gcc_assert (!m_reverse);
-  if (endp == 2)
+  if (retmode == RETURN_END_MINUS_ONE)
     {
       m_to.maybe_postinc (-1);
       --m_offset;
@@ -1206,13 +1230,11 @@ move_by_pieces_d::finish_endp (int endp)
 
    ALIGN is maximum stack alignment we can assume.
 
-   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.  */
+   Return value is based on RETMODE argument.  */
 
 rtx
 move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
-               unsigned int align, int endp)
+               unsigned int align, memop_ret retmode)
 {
 #ifndef PUSH_ROUNDING
   if (to == NULL)
@@ -1223,8 +1245,8 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len,
 
   data.run ();
 
-  if (endp)
-    return data.finish_endp (endp);
+  if (retmode != RETURN_BEGIN)
+    return data.finish_retmode (retmode);
   else
     return to;
 }
@@ -1244,7 +1266,7 @@ class store_by_pieces_d : public op_by_pieces_d
     : op_by_pieces_d (to, false, NULL_RTX, true, cfn, cfn_data, len, align)
   {
   }
-  rtx finish_endp (int);
+  rtx finish_retmode (memop_ret);
 };
 
 /* Return true if MODE can be used for a set of stores, given an
@@ -1272,15 +1294,14 @@ store_by_pieces_d::generate (rtx op0, rtx op1, machine_mode)
 }
 
 /* Perform the final adjustment at the end of a string to obtain the
-   correct return value for the block operation.  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.  */
+   correct return value for the block operation.
+   Return value is based on RETMODE argument.  */
 
 rtx
-store_by_pieces_d::finish_endp (int endp)
+store_by_pieces_d::finish_retmode (memop_ret retmode)
 {
   gcc_assert (!m_reverse);
-  if (endp == 2)
+  if (retmode == RETURN_END_MINUS_ONE)
     {
       m_to.maybe_postinc (-1);
       --m_offset;
@@ -1370,18 +1391,17 @@ can_store_by_pieces (unsigned HOST_WIDE_INT len,
    pointer which will be passed as argument in every CONSTFUN call.
    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.  */
+   Return value is based on RETMODE argument.  */
 
 rtx
 store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
                 rtx (*constfun) (void *, HOST_WIDE_INT, scalar_int_mode),
-                void *constfundata, unsigned int align, bool memsetp, int endp)
+                void *constfundata, unsigned int align, bool memsetp,
+                memop_ret retmode)
 {
   if (len == 0)
     {
-      gcc_assert (endp != 2);
+      gcc_assert (retmode != RETURN_END_MINUS_ONE);
       return to;
     }
 
@@ -1393,8 +1413,8 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len,
   store_by_pieces_d data (to, constfun, constfundata, len, align);
   data.run ();
 
-  if (endp)
-    return data.finish_endp (endp);
+  if (retmode != RETURN_BEGIN)
+    return data.finish_retmode (retmode);
   else
     return to;
 }
@@ -1555,7 +1575,7 @@ compare_by_pieces (rtx arg0, rtx arg1, unsigned HOST_WIDE_INT len,
    ALIGN is the maximum alignment we can assume they have.
    METHOD describes what kind of copy this is, and what mechanisms may be used.
    MIN_SIZE is the minimal size of block to move
-   MAX_SIZE is the maximal size of block to move, if it can not be represented
+   MAX_SIZE is the maximal size of block to move, if it cannot be represented
    in unsigned HOST_WIDE_INT, than it is mask of all ones.
 
    Return the address of the new block, if memcpy is called and returns it,
@@ -1566,12 +1586,17 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
                       unsigned int expected_align, HOST_WIDE_INT expected_size,
                       unsigned HOST_WIDE_INT min_size,
                       unsigned HOST_WIDE_INT max_size,
-                      unsigned HOST_WIDE_INT probable_max_size)
+                      unsigned HOST_WIDE_INT probable_max_size,
+                      bool bail_out_libcall, bool *is_move_done,
+                      bool might_overlap)
 {
   int may_use_call;
   rtx retval = 0;
   unsigned int align;
 
+  if (is_move_done)
+    *is_move_done = true;
+
   gcc_assert (size);
   if (CONST_INT_P (size) && INTVAL (size) == 0)
     return 0;
@@ -1623,31 +1648,49 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method,
       set_mem_size (y, const_size);
     }
 
-  if (CONST_INT_P (size) && can_move_by_pieces (INTVAL (size), align))
-    move_by_pieces (x, y, INTVAL (size), align, 0);
-  else if (emit_block_move_via_movmem (x, y, size, align,
+  bool pieces_ok = CONST_INT_P (size)
+    && can_move_by_pieces (INTVAL (size), align);
+  bool pattern_ok = false;
+
+  if (!pieces_ok || might_overlap)
+    {
+      pattern_ok
+       = emit_block_move_via_pattern (x, y, size, align,
                                       expected_align, expected_size,
-                                      min_size, max_size, probable_max_size))
+                                      min_size, max_size, probable_max_size,
+                                      might_overlap);
+      if (!pattern_ok && might_overlap)
+       {
+         /* Do not try any of the other methods below as they are not safe
+            for overlapping moves.  */
+         *is_move_done = false;
+         return retval;
+       }
+    }
+
+  if (pattern_ok)
     ;
-  else if (may_use_call
+  else if (pieces_ok)
+    move_by_pieces (x, y, INTVAL (size), align, RETURN_BEGIN);
+  else if (may_use_call && !might_overlap
           && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x))
           && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y)))
     {
+      if (bail_out_libcall)
+       {
+         if (is_move_done)
+           *is_move_done = false;
+         return retval;
+       }
+
       if (may_use_call < 0)
        return pc_rtx;
 
-      /* Since x and y are passed to a libcall, mark the corresponding
-        tree EXPR as addressable.  */
-      tree y_expr = MEM_EXPR (y);
-      tree x_expr = MEM_EXPR (x);
-      if (y_expr)
-       mark_addressable (y_expr);
-      if (x_expr)
-       mark_addressable (x_expr);
       retval = emit_block_copy_via_libcall (x, y, size,
                                            method == BLOCK_OP_TAILCALL);
     }
-
+  else if (might_overlap)
+    *is_move_done = false;
   else
     emit_block_move_via_loop (x, y, size, align);
 
@@ -1676,9 +1719,7 @@ emit_block_move (rtx x, rtx y, rtx size, enum block_op_methods method)
 static bool
 block_move_libcall_safe_for_call_parm (void)
 {
-#if defined (REG_PARM_STACK_SPACE)
   tree fn;
-#endif
 
   /* If arguments are pushed on the stack, then they're safe.  */
   if (PUSH_ARGS)
@@ -1701,7 +1742,7 @@ block_move_libcall_safe_for_call_parm (void)
   {
     CUMULATIVE_ARGS args_so_far_v;
     cumulative_args_t args_so_far;
-    tree fn, arg;
+    tree arg;
 
     fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
     INIT_CUMULATIVE_ARGS (args_so_far_v, TREE_TYPE (fn), NULL_RTX, 0, 3);
@@ -1711,31 +1752,39 @@ block_move_libcall_safe_for_call_parm (void)
     for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
       {
        machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
-       rtx tmp = targetm.calls.function_arg (args_so_far, mode,
-                                             NULL_TREE, true);
+       function_arg_info arg_info (mode, /*named=*/true);
+       rtx tmp = targetm.calls.function_arg (args_so_far, arg_info);
        if (!tmp || !REG_P (tmp))
          return false;
-       if (targetm.calls.arg_partial_bytes (args_so_far, mode, NULL, 1))
+       if (targetm.calls.arg_partial_bytes (args_so_far, arg_info))
          return false;
-       targetm.calls.function_arg_advance (args_so_far, mode,
-                                           NULL_TREE, true);
+       targetm.calls.function_arg_advance (args_so_far, arg_info);
       }
   }
   return true;
 }
 
-/* A subroutine of emit_block_move.  Expand a movmem pattern;
-   return true if successful.  */
+/* A subroutine of emit_block_move.  Expand a cpymem or movmem pattern;
+   return true if successful.
+  
+   X is the destination of the copy or move.
+   Y is the source of the copy or move.
+   SIZE is the size of the block to be moved.
+
+   MIGHT_OVERLAP indicates this originated with expansion of a
+   builtin_memmove() and the source and destination blocks may
+   overlap.
+  */
 
 static bool
-emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
-                           unsigned int expected_align, HOST_WIDE_INT expected_size,
-                           unsigned HOST_WIDE_INT min_size,
-                           unsigned HOST_WIDE_INT max_size,
-                           unsigned HOST_WIDE_INT probable_max_size)
+emit_block_move_via_pattern (rtx x, rtx y, rtx size, unsigned int align,
+                            unsigned int expected_align,
+                            HOST_WIDE_INT expected_size,
+                            unsigned HOST_WIDE_INT min_size,
+                            unsigned HOST_WIDE_INT max_size,
+                            unsigned HOST_WIDE_INT probable_max_size,
+                            bool might_overlap)
 {
-  int save_volatile_ok = volatile_ok;
-
   if (expected_align < align)
     expected_align = align;
   if (expected_size != -1)
@@ -1747,7 +1796,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
     }
 
   /* Since this is a move insn, we don't care about volatility.  */
-  volatile_ok = 1;
+  temporary_volatile_ok v (true);
 
   /* Try the most limited insn first, because there's no point
      including more than one in the machine description unless
@@ -1757,7 +1806,11 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
   FOR_EACH_MODE_IN_CLASS (mode_iter, MODE_INT)
     {
       scalar_int_mode mode = mode_iter.require ();
-      enum insn_code code = direct_optab_handler (movmem_optab, mode);
+      enum insn_code code;
+      if (might_overlap)
+       code = direct_optab_handler (movmem_optab, mode);
+      else
+       code = direct_optab_handler (cpymem_optab, mode);
 
       if (code != CODE_FOR_nothing
          /* We don't need MODE to be narrower than BITS_PER_HOST_WIDE_INT
@@ -1771,7 +1824,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
              || max_size <= (GET_MODE_MASK (mode) >> 1)
              || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
        {
-         struct expand_operand ops[9];
+         class expand_operand ops[9];
          unsigned int nops;
 
          /* ??? When called via emit_block_move_for_call, it'd be
@@ -1794,7 +1847,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
          if (nops >= 8)
            {
              create_integer_operand (&ops[6], min_size);
-             /* If we can not represent the maximal size,
+             /* If we cannot represent the maximal size,
                 make parameter NULL.  */
              if ((HOST_WIDE_INT) max_size != -1)
                create_integer_operand (&ops[7], max_size);
@@ -1803,7 +1856,7 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
            }
          if (nops == 9)
            {
-             /* If we can not represent the maximal size,
+             /* If we cannot represent the maximal size,
                 make parameter NULL.  */
              if ((HOST_WIDE_INT) probable_max_size != -1)
                create_integer_operand (&ops[8], probable_max_size);
@@ -1811,14 +1864,10 @@ emit_block_move_via_movmem (rtx x, rtx y, rtx size, unsigned int align,
                create_fixed_operand (&ops[8], NULL);
            }
          if (maybe_expand_insn (code, nops, ops))
-           {
-             volatile_ok = save_volatile_ok;
-             return true;
-           }
+           return true;
        }
     }
 
-  volatile_ok = save_volatile_ok;
   return false;
 }
 
@@ -1889,6 +1938,15 @@ emit_block_op_via_libcall (enum built_in_function fncode, rtx dst, rtx src,
   tree call_expr, dst_tree, src_tree, size_tree;
   machine_mode size_mode;
 
+  /* Since dst and src are passed to a libcall, mark the corresponding
+     tree EXPR as addressable.  */
+  tree dst_expr = MEM_EXPR (dst);
+  tree src_expr = MEM_EXPR (src);
+  if (dst_expr)
+    mark_addressable (dst_expr);
+  if (src_expr)
+    mark_addressable (src_expr);
+
   dst_addr = copy_addr_to_reg (XEXP (dst, 0));
   dst_addr = convert_memory_address (ptr_mode, dst_addr);
   dst_tree = make_tree (ptr_type_node, dst_addr);
@@ -1925,7 +1983,7 @@ expand_cmpstrn_or_cmpmem (insn_code icode, rtx target, rtx arg1_rtx,
   if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
     target = NULL_RTX;
 
-  struct expand_operand ops[5];
+  class expand_operand ops[5];
   create_output_operand (&ops[0], target, insn_mode);
   create_fixed_operand (&ops[1], arg1_rtx);
   create_fixed_operand (&ops[2], arg2_rtx);
@@ -3130,7 +3188,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
              || max_size <= (GET_MODE_MASK (mode) >> 1)
              || GET_MODE_BITSIZE (mode) >= GET_MODE_BITSIZE (Pmode)))
        {
-         struct expand_operand ops[9];
+         class expand_operand ops[9];
          unsigned int nops;
 
          nops = insn_data[(int) code].n_generator_args;
@@ -3149,7 +3207,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
          if (nops >= 8)
            {
              create_integer_operand (&ops[6], min_size);
-             /* If we can not represent the maximal size,
+             /* If we cannot represent the maximal size,
                 make parameter NULL.  */
              if ((HOST_WIDE_INT) max_size != -1)
                create_integer_operand (&ops[7], max_size);
@@ -3158,7 +3216,7 @@ set_storage_via_setmem (rtx object, rtx size, rtx val, unsigned int align,
            }
          if (nops == 9)
            {
-             /* If we can not represent the maximal size,
+             /* If we cannot represent the maximal size,
                 make parameter NULL.  */
              if ((HOST_WIDE_INT) probable_max_size != -1)
                create_integer_operand (&ops[8], probable_max_size);
@@ -3538,11 +3596,13 @@ emit_move_complex (machine_mode mode, rtx x, rtx y)
       rtx_insn *ret;
 
       /* For memory to memory moves, optimal behavior can be had with the
-        existing block move logic.  */
+        existing block move logic.  But use normal expansion if optimizing
+        for size.  */
       if (MEM_P (x) && MEM_P (y))
        {
          emit_block_move (x, y, gen_int_mode (GET_MODE_SIZE (mode), Pmode),
-                          BLOCK_OP_NO_LIBCALL);
+                          (optimize_insn_for_speed_p()
+                           ? BLOCK_OP_NO_LIBCALL : BLOCK_OP_NORMAL));
          return get_last_insn ();
        }
 
@@ -4174,7 +4234,7 @@ emit_single_push_insn_1 (machine_mode mode, rtx x, tree type)
   icode = optab_handler (push_optab, mode);
   if (icode != CODE_FOR_nothing)
     {
-      struct expand_operand ops[1];
+      class expand_operand ops[1];
 
       create_input_operand (&ops[0], x, mode);
       if (maybe_expand_insn (icode, 1, ops))
@@ -4421,7 +4481,8 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
              && where_pad != stack_direction)
            anti_adjust_stack (gen_int_mode (extra, Pmode));
 
-         move_by_pieces (NULL, xinner, INTVAL (size) - used, align, 0);
+         move_by_pieces (NULL, xinner, INTVAL (size) - used, align,
+                         RETURN_BEGIN);
        }
       else
 #endif /* PUSH_ROUNDING  */
@@ -4445,16 +4506,16 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
          /* Get the address of the stack space.
             In this case, we do not deal with EXTRA separately.
             A single stack adjust will do.  */
-         poly_int64 offset;
+         poly_int64 const_args_so_far;
          if (! args_addr)
            {
              temp = push_block (size, extra, where_pad == PAD_DOWNWARD);
              extra = 0;
            }
-         else if (poly_int_rtx_p (args_so_far, &offset))
+         else if (poly_int_rtx_p (args_so_far, &const_args_so_far))
            temp = memory_address (BLKmode,
                                   plus_constant (Pmode, args_addr,
-                                                 skip + offset));
+                                                 skip + const_args_so_far));
          else
            temp = memory_address (BLKmode,
                                   plus_constant (Pmode,
@@ -4529,8 +4590,8 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
     {
       /* Scalar partly in registers.  This case is only supported
         for fixed-wdth modes.  */
-      int size = GET_MODE_SIZE (mode).to_constant ();
-      size /= UNITS_PER_WORD;
+      int num_words = GET_MODE_SIZE (mode).to_constant ();
+      num_words /= UNITS_PER_WORD;
       int i;
       int not_stack;
       /* # bytes of start of argument
@@ -4577,7 +4638,7 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
       /* Loop over all the words allocated on the stack for this arg.  */
       /* We can do it by words, because any scalar bigger than a word
         has a size a multiple of a word.  */
-      for (i = size - 1; i >= not_stack; i--)
+      for (i = num_words - 1; i >= not_stack; i--)
        if (i >= not_stack + offset)
          if (!emit_push_insn (operand_subword_force (x, i, mode),
                          word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
@@ -4941,37 +5002,46 @@ get_bit_range (poly_uint64_pod *bitstart, poly_uint64_pod *bitend, tree exp,
   *bitend = *bitstart + tree_to_poly_uint64 (DECL_SIZE (repr)) - 1;
 }
 
-/* Returns true if ADDR is an ADDR_EXPR of a DECL that does not reside
-   in memory and has non-BLKmode.  DECL_RTL must not be a MEM; if
-   DECL_RTL was not set yet, return NORTL.  */
+/* Returns true if BASE is a DECL that does not reside in memory and
+   has non-BLKmode.  DECL_RTL must not be a MEM; if
+   DECL_RTL was not set yet, return false.  */
 
 static inline bool
-addr_expr_of_non_mem_decl_p_1 (tree addr, bool nortl)
+non_mem_decl_p (tree base)
 {
-  if (TREE_CODE (addr) != ADDR_EXPR)
-    return false;
-
-  tree base = TREE_OPERAND (addr, 0);
-
   if (!DECL_P (base)
       || TREE_ADDRESSABLE (base)
       || DECL_MODE (base) == BLKmode)
     return false;
 
   if (!DECL_RTL_SET_P (base))
-    return nortl;
+    return false;
 
   return (!MEM_P (DECL_RTL (base)));
 }
 
-/* Returns true if the MEM_REF REF refers to an object that does not
+/* Returns true if REF refers to an object that does not
    reside in memory and has non-BLKmode.  */
 
 static inline bool
 mem_ref_refers_to_non_mem_p (tree ref)
 {
-  tree base = TREE_OPERAND (ref, 0);
-  return addr_expr_of_non_mem_decl_p_1 (base, false);
+  tree base;
+
+  if (TREE_CODE (ref) == MEM_REF
+      || TREE_CODE (ref) == TARGET_MEM_REF)
+    {
+      tree addr = TREE_OPERAND (ref, 0);
+
+      if (TREE_CODE (addr) != ADDR_EXPR)
+       return false;
+
+      base = TREE_OPERAND (addr, 0);
+    }
+  else
+    base = ref;
+
+  return non_mem_decl_p (base);
 }
 
 /* Expand an assignment that stores the value of FROM into TO.  If NONTEMPORAL
@@ -5000,7 +5070,8 @@ expand_assignment (tree to, tree from, bool nontemporal)
   /* Handle misaligned stores.  */
   mode = TYPE_MODE (TREE_TYPE (to));
   if ((TREE_CODE (to) == MEM_REF
-       || TREE_CODE (to) == TARGET_MEM_REF)
+       || TREE_CODE (to) == TARGET_MEM_REF
+       || DECL_P (to))
       && mode != BLKmode
       && !mem_ref_refers_to_non_mem_p (to)
       && ((align = get_object_alignment (to))
@@ -5019,7 +5090,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
 
       if (icode != CODE_FOR_nothing)
        {
-         struct expand_operand ops[2];
+         class expand_operand ops[2];
 
          create_fixed_operand (&ops[0], mem);
          create_input_operand (&ops[1], reg, mode);
@@ -5214,9 +5285,16 @@ expand_assignment (tree to, tree from, bool nontemporal)
                }
              else
                {
-                 rtx from_rtx
-                   = simplify_gen_subreg (to_mode, result,
-                                          TYPE_MODE (TREE_TYPE (from)), 0);
+                 machine_mode from_mode
+                   = GET_MODE (result) == VOIDmode
+                     ? TYPE_MODE (TREE_TYPE (from))
+                     : GET_MODE (result);
+                 rtx from_rtx;
+                 if (MEM_P (result))
+                   from_rtx = change_address (result, to_mode, NULL_RTX);
+                 else
+                   from_rtx
+                     = simplify_gen_subreg (to_mode, result, from_mode, 0);
                  if (from_rtx)
                    {
                      emit_move_insn (XEXP (to_rtx, 0),
@@ -5226,15 +5304,11 @@ expand_assignment (tree to, tree from, bool nontemporal)
                    }
                  else
                    {
-                     machine_mode to_mode
-                       = GET_MODE_INNER (GET_MODE (to_rtx));
+                     to_mode = GET_MODE_INNER (to_mode);
                      rtx from_real
-                       = simplify_gen_subreg (to_mode, result,
-                                              TYPE_MODE (TREE_TYPE (from)),
-                                              0);
+                       = simplify_gen_subreg (to_mode, result, from_mode, 0);
                      rtx from_imag
-                       = simplify_gen_subreg (to_mode, result,
-                                              TYPE_MODE (TREE_TYPE (from)),
+                       = simplify_gen_subreg (to_mode, result, from_mode,
                                               GET_MODE_SIZE (to_mode));
                      if (!from_real || !from_imag)
                        goto concat_store_slow;
@@ -5246,7 +5320,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
          else
            {
            concat_store_slow:;
-             rtx temp = assign_stack_temp (to_mode,
+             rtx temp = assign_stack_temp (GET_MODE (to_rtx),
                                            GET_MODE_SIZE (GET_MODE (to_rtx)));
              write_complex_part (temp, XEXP (to_rtx, 0), false);
              write_complex_part (temp, XEXP (to_rtx, 1), true);
@@ -5258,6 +5332,21 @@ expand_assignment (tree to, tree from, bool nontemporal)
              emit_move_insn (XEXP (to_rtx, 1), read_complex_part (temp, true));
            }
        }
+      /* For calls to functions returning variable length structures, if TO_RTX
+        is not a MEM, go through a MEM because we must not create temporaries
+        of the VLA type.  */
+      else if (!MEM_P (to_rtx)
+              && TREE_CODE (from) == CALL_EXPR
+              && COMPLETE_TYPE_P (TREE_TYPE (from))
+              && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) != INTEGER_CST)
+       {
+         rtx temp = assign_stack_temp (GET_MODE (to_rtx),
+                                       GET_MODE_SIZE (GET_MODE (to_rtx)));
+         result = store_field (temp, bitsize, bitpos, bitregion_start,
+                               bitregion_end, mode1, from, get_alias_set (to),
+                               nontemporal, reversep);
+         emit_move_insn (to_rtx, temp);
+       }
       else
        {
          if (MEM_P (to_rtx))
@@ -5429,7 +5518,7 @@ expand_assignment (tree to, tree from, bool nontemporal)
 bool
 emit_storent_insn (rtx to, rtx from)
 {
-  struct expand_operand ops[2];
+  class expand_operand ops[2];
   machine_mode mode = GET_MODE (to);
   enum insn_code code = optab_handler (storent_optab, mode);
 
@@ -5441,6 +5530,30 @@ emit_storent_insn (rtx to, rtx from)
   return maybe_expand_insn (code, 2, ops);
 }
 
+/* Helper function for store_expr storing of STRING_CST.  */
+
+static rtx
+string_cst_read_str (void *data, HOST_WIDE_INT offset, scalar_int_mode mode)
+{
+  tree str = (tree) data;
+
+  gcc_assert (offset >= 0);
+  if (offset >= TREE_STRING_LENGTH (str))
+    return const0_rtx;
+
+  if ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
+      > (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (str))
+    {
+      char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
+      size_t l = TREE_STRING_LENGTH (str) - offset;
+      memcpy (p, TREE_STRING_POINTER (str) + offset, l);
+      memset (p + l, '\0', GET_MODE_SIZE (mode) - l);
+      return c_readstr (p, mode, false);
+    }
+
+  return c_readstr (TREE_STRING_POINTER (str) + offset, mode, false);
+}
+
 /* Generate code for computing expression EXP,
    and storing the value into TARGET.
 
@@ -5460,7 +5573,7 @@ emit_storent_insn (rtx to, rtx from)
 
 rtx
 store_expr (tree exp, rtx target, int call_param_p,
-                       bool nontemporal, bool reverse)
+           bool nontemporal, bool reverse)
 {
   rtx temp;
   rtx alt_rtl = NULL_RTX;
@@ -5594,35 +5707,33 @@ store_expr (tree exp, rtx target, int call_param_p,
       if (TREE_STRING_LENGTH (str) <= 0)
        goto normal_expr;
 
-      str_copy_len = strlen (TREE_STRING_POINTER (str));
-      if (str_copy_len < TREE_STRING_LENGTH (str) - 1)
-       goto normal_expr;
+      if (can_store_by_pieces (exp_len, string_cst_read_str, (void *) str,
+                              MEM_ALIGN (target), false))
+       {
+         store_by_pieces (target, exp_len, string_cst_read_str, (void *) str,
+                          MEM_ALIGN (target), false, RETURN_BEGIN);
+         return NULL_RTX;
+       }
 
       str_copy_len = TREE_STRING_LENGTH (str);
-      if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0
-         && TREE_STRING_POINTER (str)[TREE_STRING_LENGTH (str) - 1] == '\0')
+      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,
-                               CONST_CAST (char *, TREE_STRING_POINTER (str)),
-                               MEM_ALIGN (target), false))
+      if (str_copy_len >= exp_len)
+       goto normal_expr;
+
+      if (!can_store_by_pieces (str_copy_len, string_cst_read_str,
+                               (void *) str, MEM_ALIGN (target), false))
        goto normal_expr;
 
-      dest_mem = target;
-
-      dest_mem = store_by_pieces (dest_mem,
-                                 str_copy_len, builtin_strncpy_read_str,
-                                 CONST_CAST (char *,
-                                             TREE_STRING_POINTER (str)),
-                                 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);
+      dest_mem = store_by_pieces (target, str_copy_len, string_cst_read_str,
+                                 (void *) str, MEM_ALIGN (target), false,
+                                 RETURN_END);
+      clear_storage (adjust_address_1 (dest_mem, BLKmode, 0, 1, 1, 0,
+                                      exp_len - str_copy_len),
+                    GEN_INT (exp_len - str_copy_len), BLOCK_OP_NORMAL);
       return NULL_RTX;
     }
   else
@@ -5706,7 +5817,8 @@ store_expr (tree exp, rtx target, int call_param_p,
                copy_blkmode_from_reg (target, temp, TREE_TYPE (exp));
              else
                store_bit_field (target,
-                                INTVAL (expr_size (exp)) * BITS_PER_UNIT,
+                                rtx_to_poly_int64 (expr_size (exp))
+                                * BITS_PER_UNIT,
                                 0, 0, 0, GET_MODE (temp), temp, reverse);
            }
          else
@@ -5948,10 +6060,11 @@ count_type_elements (const_tree type, bool for_ctor_p)
 
 static bool
 categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
+                           HOST_WIDE_INT *p_unique_nz_elts,
                            HOST_WIDE_INT *p_init_elts, bool *p_complete)
 {
   unsigned HOST_WIDE_INT idx;
-  HOST_WIDE_INT nz_elts, init_elts, num_fields;
+  HOST_WIDE_INT nz_elts, unique_nz_elts, init_elts, num_fields;
   tree value, purpose, elt_type;
 
   /* Whether CTOR is a valid constant initializer, in accordance with what
@@ -5961,6 +6074,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
   bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
 
   nz_elts = 0;
+  unique_nz_elts = 0;
   init_elts = 0;
   num_fields = 0;
   elt_type = NULL_TREE;
@@ -5985,12 +6099,13 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
        {
        case CONSTRUCTOR:
          {
-           HOST_WIDE_INT nz = 0, ic = 0;
+           HOST_WIDE_INT nz = 0, unz = 0, ic = 0;
 
-           bool const_elt_p = categorize_ctor_elements_1 (value, &nz, &ic,
-                                                          p_complete);
+           bool const_elt_p = categorize_ctor_elements_1 (value, &nz, &unz,
+                                                          &ic, p_complete);
 
            nz_elts += mult * nz;
+           unique_nz_elts += unz;
            init_elts += mult * ic;
 
            if (const_from_elts_p && const_p)
@@ -6002,21 +6117,31 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
        case REAL_CST:
        case FIXED_CST:
          if (!initializer_zerop (value))
-           nz_elts += mult;
+           {
+             nz_elts += mult;
+             unique_nz_elts++;
+           }
          init_elts += mult;
          break;
 
        case STRING_CST:
          nz_elts += mult * TREE_STRING_LENGTH (value);
+         unique_nz_elts += TREE_STRING_LENGTH (value);
          init_elts += mult * TREE_STRING_LENGTH (value);
          break;
 
        case COMPLEX_CST:
          if (!initializer_zerop (TREE_REALPART (value)))
-           nz_elts += mult;
+           {
+             nz_elts += mult;
+             unique_nz_elts++;
+           }
          if (!initializer_zerop (TREE_IMAGPART (value)))
-           nz_elts += mult;
-         init_elts += mult;
+           {
+             nz_elts += mult;
+             unique_nz_elts++;
+           }
+         init_elts += 2 * mult;
          break;
 
        case VECTOR_CST:
@@ -6028,7 +6153,10 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
              {
                tree v = VECTOR_CST_ELT (value, i);
                if (!initializer_zerop (v))
-                 nz_elts += mult;
+                 {
+                   nz_elts += mult;
+                   unique_nz_elts++;
+                 }
                init_elts += mult;
              }
          }
@@ -6038,6 +6166,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
          {
            HOST_WIDE_INT tc = count_type_elements (elt_type, false);
            nz_elts += mult * tc;
+           unique_nz_elts += tc;
            init_elts += mult * tc;
 
            if (const_from_elts_p && const_p)
@@ -6057,6 +6186,7 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
     *p_complete = false;
 
   *p_nz_elts += nz_elts;
+  *p_unique_nz_elts += unique_nz_elts;
   *p_init_elts += init_elts;
 
   return const_p;
@@ -6065,6 +6195,11 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
 /* Examine CTOR to discover:
    * how many scalar fields are set to nonzero values,
      and place it in *P_NZ_ELTS;
+   * the same, but counting RANGE_EXPRs as multiplier of 1 instead of
+     high - low + 1 (this can be useful for callers to determine ctors
+     that could be cheaply initialized with - perhaps nested - loops
+     compared to copied from huge read-only data),
+     and place it in *P_UNIQUE_NZ_ELTS;
    * how many scalar fields in total are in CTOR,
      and place it in *P_ELT_COUNT.
    * whether the constructor is complete -- in the sense that every
@@ -6076,13 +6211,16 @@ categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
 
 bool
 categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
+                         HOST_WIDE_INT *p_unique_nz_elts,
                          HOST_WIDE_INT *p_init_elts, bool *p_complete)
 {
   *p_nz_elts = 0;
+  *p_unique_nz_elts = 0;
   *p_init_elts = 0;
   *p_complete = true;
 
-  return categorize_ctor_elements_1 (ctor, p_nz_elts, p_init_elts, p_complete);
+  return categorize_ctor_elements_1 (ctor, p_nz_elts, p_unique_nz_elts,
+                                    p_init_elts, p_complete);
 }
 
 /* TYPE is initialized by a constructor with NUM_ELTS elements, the last
@@ -6113,17 +6251,18 @@ complete_ctor_at_level_p (const_tree type, HOST_WIDE_INT num_elts,
   return count_type_elements (type, true) == num_elts;
 }
 
-/* Return 1 if EXP contains mostly (3/4)  zeros.  */
+/* Return 1 if EXP contains mostly (3/4) zeros.  */
 
 static int
 mostly_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
     {
-      HOST_WIDE_INT nz_elts, init_elts;
+      HOST_WIDE_INT nz_elts, unz_elts, init_elts;
       bool complete_p;
 
-      categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
+      categorize_ctor_elements (exp, &nz_elts, &unz_elts, &init_elts,
+                               &complete_p);
       return !complete_p || nz_elts < init_elts / 4;
     }
 
@@ -6137,10 +6276,11 @@ all_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
     {
-      HOST_WIDE_INT nz_elts, init_elts;
+      HOST_WIDE_INT nz_elts, unz_elts, init_elts;
       bool complete_p;
 
-      categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
+      categorize_ctor_elements (exp, &nz_elts, &unz_elts, &init_elts,
+                               &complete_p);
       return nz_elts == 0;
     }
 
@@ -6345,7 +6485,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
                && exp_size >= 0
                && bitpos + BITS_PER_WORD <= exp_size * BITS_PER_UNIT)
              {
-               tree type = TREE_TYPE (value);
+               type = TREE_TYPE (value);
 
                if (TYPE_PRECISION (type) < BITS_PER_WORD)
                  {
@@ -6422,7 +6562,6 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
        else
          {
            unsigned HOST_WIDE_INT idx;
-           tree index, value;
            HOST_WIDE_INT count = 0, zero_count = 0;
            need_to_clear = ! const_bounds_p;
 
@@ -6682,7 +6821,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
                != CODE_FOR_nothing)
            && (elt = uniform_vector_p (exp)))
          {
-           struct expand_operand ops[2];
+           class expand_operand ops[2];
            create_output_operand (&ops[0], target, mode);
            create_input_operand (&ops[1], expand_normal (elt), eltmode);
            expand_insn (icode, 2, ops);
@@ -6697,6 +6836,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
            && n_elts.is_constant (&const_n_elts))
          {
            machine_mode emode = eltmode;
+           bool vector_typed_elts_p = false;
 
            if (CONSTRUCTOR_NELTS (exp)
                && (TREE_CODE (TREE_TYPE (CONSTRUCTOR_ELT (exp, 0)->value))
@@ -6707,20 +6847,21 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
                                      * TYPE_VECTOR_SUBPARTS (etype),
                                      n_elts));
                emode = TYPE_MODE (etype);
+               vector_typed_elts_p = true;
              }
            icode = convert_optab_handler (vec_init_optab, mode, emode);
            if (icode != CODE_FOR_nothing)
              {
-               unsigned int i, n = const_n_elts;
+               unsigned int n = const_n_elts;
 
-               if (emode != eltmode)
+               if (vector_typed_elts_p)
                  {
                    n = CONSTRUCTOR_NELTS (exp);
                    vec_vec_init_p = true;
                  }
                vector = rtvec_alloc (n);
-               for (i = 0; i < n; i++)
-                 RTVEC_ELT (vector, i) = CONST0_RTX (emode);
+               for (unsigned int k = 0; k < n; k++)
+                 RTVEC_ELT (vector, k) = CONST0_RTX (emode);
              }
          }
 
@@ -7041,7 +7182,7 @@ store_field (rtx target, poly_int64 bitsize, poly_int64 bitpos,
         word size, we need to load the value (see again store_bit_field).  */
       if (GET_MODE (temp) == BLKmode && known_le (bitsize, BITS_PER_WORD))
        {
-         scalar_int_mode temp_mode = smallest_int_mode_for_size (bitsize);
+         temp_mode = smallest_int_mode_for_size (bitsize);
          temp = extract_bit_field (temp, bitsize, 0, 1, NULL_RTX, temp_mode,
                                    temp_mode, false, NULL);
        }
@@ -7150,12 +7291,13 @@ get_inner_reference (tree exp, poly_int64_pod *pbitsize,
       *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
-         && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))
-         && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp))))
-        mode = TYPE_MODE (TREE_TYPE (exp));
+      /* For vector element types with the correct size of access or for
+         vector typed accesses use the mode of the access type.  */
+      if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == VECTOR_TYPE
+          && TREE_TYPE (exp) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0)))
+          && tree_int_cst_equal (size_tree, TYPE_SIZE (TREE_TYPE (exp))))
+         || VECTOR_TYPE_P (TREE_TYPE (exp)))
+       mode = TYPE_MODE (TREE_TYPE (exp));
     }
   else
     {
@@ -8094,12 +8236,12 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
   if ((TREE_STATIC (exp)
        && ((mode == BLKmode
            && ! (target != 0 && safe_from_p (target, exp, 1)))
-                 || TREE_ADDRESSABLE (exp)
-                 || (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))
-                     && (! can_move_by_pieces
-                                    (tree_to_uhwi (TYPE_SIZE_UNIT (type)),
-                                     TYPE_ALIGN (type)))
-                     && ! mostly_zeros_p (exp))))
+          || TREE_ADDRESSABLE (exp)
+          || (tree_fits_uhwi_p (TYPE_SIZE_UNIT (type))
+              && (! can_move_by_pieces
+                  (tree_to_uhwi (TYPE_SIZE_UNIT (type)),
+                   TYPE_ALIGN (type)))
+              && ! mostly_zeros_p (exp))))
       || ((modifier == EXPAND_INITIALIZER || modifier == EXPAND_CONST_ADDRESS)
          && TREE_CONSTANT (exp)))
     {
@@ -8181,6 +8323,8 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
    DECL_RTL of the VAR_DECL.  *ALT_RTL is also set if EXP is a
    COMPOUND_EXPR whose second argument is such a VAR_DECL, and so on
    recursively.
+   If the result can be stored at TARGET, and ALT_RTL is non-NULL,
+   then *ALT_RTL is set to TARGET (before legitimziation).
 
    If INNER_REFERENCE_P is true, we are expanding an inner reference.
    In this case, we don't adjust a returned MEM rtx that wouldn't be
@@ -8261,7 +8405,7 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED,
   if (TREE_CODE (treeop0) == SSA_NAME
       && (srcstmt = get_def_for_expr_class (treeop0, tcc_comparison)))
     {
-      tree type = TREE_TYPE (gimple_assign_rhs1 (srcstmt));
+      type = TREE_TYPE (gimple_assign_rhs1 (srcstmt));
       enum tree_code cmpcode = gimple_assign_rhs_code (srcstmt);
       op00 = expand_normal (gimple_assign_rhs1 (srcstmt));
       op01 = expand_normal (gimple_assign_rhs2 (srcstmt));
@@ -8271,7 +8415,7 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED,
     }
   else if (COMPARISON_CLASS_P (treeop0))
     {
-      tree type = TREE_TYPE (TREE_OPERAND (treeop0, 0));
+      type = TREE_TYPE (TREE_OPERAND (treeop0, 0));
       enum tree_code cmpcode = TREE_CODE (treeop0);
       op00 = expand_normal (TREE_OPERAND (treeop0, 0));
       op01 = expand_normal (TREE_OPERAND (treeop0, 1));
@@ -8318,6 +8462,40 @@ expand_cond_expr_using_cmove (tree treeop0 ATTRIBUTE_UNUSED,
   return NULL_RTX;
 }
 
+/* A helper function for expand_expr_real_2 to be used with a
+   misaligned mem_ref TEMP.  Assume an unsigned type if UNSIGNEDP
+   is nonzero, with alignment ALIGN in bits.
+   Store the value at TARGET if possible (if TARGET is nonzero).
+   Regardless of TARGET, we return the rtx for where the value is placed.
+   If the result can be stored at TARGET, and ALT_RTL is non-NULL,
+   then *ALT_RTL is set to TARGET (before legitimziation).  */
+
+static rtx
+expand_misaligned_mem_ref (rtx temp, machine_mode mode, int unsignedp,
+                          unsigned int align, rtx target, rtx *alt_rtl)
+{
+  enum insn_code icode;
+
+  if ((icode = optab_handler (movmisalign_optab, mode))
+      != CODE_FOR_nothing)
+    {
+      class expand_operand ops[2];
+
+      /* We've already validated the memory, and we're creating a
+        new pseudo destination.  The predicates really can't fail,
+        nor can the generator.  */
+      create_output_operand (&ops[0], NULL_RTX, mode);
+      create_fixed_operand (&ops[1], temp);
+      expand_insn (icode, 2, ops);
+      temp = ops[0].value;
+    }
+  else if (targetm.slow_unaligned_access (mode, align))
+    temp = extract_bit_field (temp, GET_MODE_BITSIZE (mode),
+                             0, unsignedp, target,
+                             mode, mode, false, alt_rtl);
+  return temp;
+}
+
 rtx
 expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
                    enum expand_modifier modifier)
@@ -8750,8 +8928,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
                 != INTEGER_CST check.  Handle it.  */
              if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
                {
-                 op0 = convert_modes (innermode, mode, op0, true);
-                 op1 = convert_modes (innermode, mode, op1, false);
+                 op0 = convert_modes (mode, innermode, op0, true);
+                 op1 = convert_modes (mode, innermode, op1, false);
                  return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1,
                                                        target, unsignedp));
                }
@@ -8773,7 +8951,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
          if (TREE_CODE (treeop0) != INTEGER_CST)
            {
              if (find_widening_optab_handler (this_optab, mode, innermode)
-                   != CODE_FOR_nothing)
+                 != CODE_FOR_nothing)
                {
                  expand_operands (treeop0, treeop1, NULL_RTX, &op0, &op1,
                                   EXPAND_NORMAL);
@@ -8782,9 +8960,9 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
                  if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
                    {
                     widen_mult_const:
-                     op0 = convert_modes (innermode, mode, op0, zextend_p);
+                     op0 = convert_modes (mode, innermode, op0, zextend_p);
                      op1
-                       = convert_modes (innermode, mode, op1,
+                       = convert_modes (mode, innermode, op1,
                                         TYPE_UNSIGNED (TREE_TYPE (treeop1)));
                      return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1,
                                                            target,
@@ -8795,18 +8973,13 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
                  return REDUCE_BIT_FIELD (temp);
                }
              if (find_widening_optab_handler (other_optab, mode, innermode)
-                   != CODE_FOR_nothing
+                 != CODE_FOR_nothing
                  && innermode == word_mode)
                {
                  rtx htem, hipart;
                  op0 = expand_normal (treeop0);
-                 if (TREE_CODE (treeop1) == INTEGER_CST)
-                   op1 = convert_modes (word_mode, mode,
-                                        expand_normal (treeop1),
-                                        TYPE_UNSIGNED (TREE_TYPE (treeop1)));
-                 else
-                   op1 = expand_normal (treeop1);
-                 /* op0 and op1 might still be constant, despite the above
+                 op1 = expand_normal (treeop1);
+                 /* op0 and op1 might be constants, despite the above
                     != INTEGER_CST check.  Handle it.  */
                  if (GET_MODE (op0) == VOIDmode && GET_MODE (op1) == VOIDmode)
                    goto widen_mult_const;
@@ -9468,12 +9641,34 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
       gcc_assert (target);
       return target;
 
-    case VEC_PACK_TRUNC_EXPR:
     case VEC_PACK_SAT_EXPR:
     case VEC_PACK_FIX_TRUNC_EXPR:
       mode = TYPE_MODE (TREE_TYPE (treeop0));
       goto binop;
 
+    case VEC_PACK_TRUNC_EXPR:
+      if (VECTOR_BOOLEAN_TYPE_P (type)
+         && VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (treeop0))
+         && mode == TYPE_MODE (TREE_TYPE (treeop0))
+         && SCALAR_INT_MODE_P (mode))
+       {
+         class expand_operand eops[4];
+         machine_mode imode = TYPE_MODE (TREE_TYPE (treeop0));
+         expand_operands (treeop0, treeop1,
+                          subtarget, &op0, &op1, EXPAND_NORMAL);
+         this_optab = vec_pack_sbool_trunc_optab;
+         enum insn_code icode = optab_handler (this_optab, imode);
+         create_output_operand (&eops[0], target, mode);
+         create_convert_operand_from (&eops[1], op0, imode, false);
+         create_convert_operand_from (&eops[2], op1, imode, false);
+         temp = GEN_INT (TYPE_VECTOR_SUBPARTS (type).to_constant ());
+         create_input_operand (&eops[3], temp, imode);
+         expand_insn (icode, 4, eops);
+         return eops[0].value;
+       }
+      mode = TYPE_MODE (TREE_TYPE (treeop0));
+      goto binop;
+
     case VEC_PACK_FLOAT_EXPR:
       mode = TYPE_MODE (TREE_TYPE (treeop0));
       expand_operands (treeop0, treeop1,
@@ -9511,7 +9706,6 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
        tree oprnd0 = treeop0;
        tree oprnd1 = treeop1;
        tree oprnd2 = treeop2;
-       rtx op2;
 
        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
        op2 = expand_normal (oprnd2);
@@ -9525,7 +9719,6 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
        tree oprnd0 = treeop0;
        tree oprnd1 = treeop1;
        tree oprnd2 = treeop2;
-       rtx op2;
 
        expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
        op2 = expand_normal (oprnd2);
@@ -9539,7 +9732,6 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
         tree oprnd0 = treeop0;
         tree oprnd1 = treeop1;
         tree oprnd2 = treeop2;
-        rtx op2;
 
         this_optab = optab_for_tree_code (code, type, optab_default);
         expand_operands (oprnd0, oprnd1, NULL_RTX, &op0, &op1, EXPAND_NORMAL);
@@ -9629,8 +9821,8 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
          bitsize = TYPE_PRECISION (TREE_TYPE (treeop1));
        else
          bitsize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (treeop1)));
-       rtx op0 = expand_normal (treeop0);
-       rtx op1 = expand_normal (treeop1);
+       op0 = expand_normal (treeop0);
+       op1 = expand_normal (treeop1);
        rtx dst = gen_reg_rtx (mode);
        emit_move_insn (dst, op0);
        store_bit_field (dst, bitsize, bitpos, 0, 0,
@@ -9829,7 +10021,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
        {
          rtx r;
          location_t saved_loc = curr_insn_location ();
-         location_t loc = gimple_location (g);
+         loc = gimple_location (g);
          if (loc != UNKNOWN_LOCATION)
            set_curr_insn_location (loc);
          ops.code = gimple_assign_rhs_code (g);
@@ -9962,6 +10154,23 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
        {
          if (exp && MEM_P (temp) && REG_P (XEXP (temp, 0)))
            mark_reg_pointer (XEXP (temp, 0), DECL_ALIGN (exp));
+       }
+      else if (MEM_P (decl_rtl))
+       temp = decl_rtl;
+
+      if (temp != 0)
+       {
+         if (MEM_P (temp)
+             && modifier != EXPAND_WRITE
+             && modifier != EXPAND_MEMORY
+             && modifier != EXPAND_INITIALIZER
+             && modifier != EXPAND_CONST_ADDRESS
+             && modifier != EXPAND_SUM
+             && !inner_reference_p
+             && mode != BLKmode
+             && MEM_ALIGN (temp) < GET_MODE_ALIGNMENT (mode))
+           temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
+                                             MEM_ALIGN (temp), NULL_RTX, NULL);
 
          return temp;
        }
@@ -10011,9 +10220,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
           GET_MODE_PRECISION (TYPE_MODE (type)), we need to extend from
           the former to the latter according to the signedness of the
           type.  */
-       scalar_int_mode mode = SCALAR_INT_TYPE_MODE (type);
+       scalar_int_mode int_mode = SCALAR_INT_TYPE_MODE (type);
        temp = immed_wide_int_const
-         (wi::to_wide (exp, GET_MODE_PRECISION (mode)), mode);
+         (wi::to_wide (exp, GET_MODE_PRECISION (int_mode)), int_mode);
        return temp;
       }
 
@@ -10088,9 +10297,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
       /* Handle evaluating a complex constant in a CONCAT target.  */
       if (original_target && GET_CODE (original_target) == CONCAT)
        {
-         machine_mode mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
          rtx rtarg, itarg;
 
+         mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (exp)));
          rtarg = XEXP (original_target, 0);
          itarg = XEXP (original_target, 1);
 
@@ -10177,7 +10386,6 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
       {
        addr_space_t as
          = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
-       enum insn_code icode;
        unsigned int align;
 
        op0 = addr_for_mem_ref (exp, as, true);
@@ -10189,22 +10397,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
        if (modifier != EXPAND_WRITE
            && modifier != EXPAND_MEMORY
            && mode != BLKmode
-           && align < GET_MODE_ALIGNMENT (mode)
-           /* If the target does not have special handling for unaligned
-              loads of mode then it can use regular moves for them.  */
-           && ((icode = optab_handler (movmisalign_optab, mode))
-               != CODE_FOR_nothing))
-         {
-           struct expand_operand ops[2];
-
-           /* We've already validated the memory, and we're creating a
-              new pseudo destination.  The predicates really can't fail,
-              nor can the generator.  */
-           create_output_operand (&ops[0], NULL_RTX, mode);
-           create_fixed_operand (&ops[1], temp);
-           expand_insn (icode, 2, ops);
-           temp = ops[0].value;
-         }
+           && align < GET_MODE_ALIGNMENT (mode))
+         temp = expand_misaligned_mem_ref (temp, mode, unsignedp,
+                                           align, NULL_RTX, NULL);
        return temp;
       }
 
@@ -10216,7 +10411,6 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
        machine_mode address_mode;
        tree base = TREE_OPERAND (exp, 0);
        gimple *def_stmt;
-       enum insn_code icode;
        unsigned align;
        /* Handle expansion of non-aliased memory with non-BLKmode.  That
           might end up in a register.  */
@@ -10246,7 +10440,6 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
            return expand_expr (exp, target, tmode, modifier);
          }
        address_mode = targetm.addr_space.address_mode (as);
-       base = TREE_OPERAND (exp, 0);
        if ((def_stmt = get_def_for_expr (base, BIT_AND_EXPR)))
          {
            tree mask = gimple_assign_rhs2 (def_stmt);
@@ -10273,27 +10466,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
            && !inner_reference_p
            && mode != BLKmode
            && align < GET_MODE_ALIGNMENT (mode))
-         {
-           if ((icode = optab_handler (movmisalign_optab, mode))
-               != CODE_FOR_nothing)
-             {
-               struct expand_operand ops[2];
-
-               /* We've already validated the memory, and we're creating a
-                  new pseudo destination.  The predicates really can't fail,
-                  nor can the generator.  */
-               create_output_operand (&ops[0], NULL_RTX, mode);
-               create_fixed_operand (&ops[1], temp);
-               expand_insn (icode, 2, ops);
-               temp = ops[0].value;
-             }
-           else if (targetm.slow_unaligned_access (mode, align))
-             temp = extract_bit_field (temp, GET_MODE_BITSIZE (mode),
-                                       0, TYPE_UNSIGNED (TREE_TYPE (exp)),
-                                       (modifier == EXPAND_STACK_PARM
-                                        ? NULL_RTX : target),
-                                       mode, mode, false, alt_rtl);
-         }
+         temp = expand_misaligned_mem_ref (temp, mode, unsignedp, align,
+                                           modifier == EXPAND_STACK_PARM
+                                           ? NULL_RTX : target, alt_rtl);
        if (reverse
            && modifier != EXPAND_MEMORY
            && modifier != EXPAND_WRITE)
@@ -10428,14 +10603,14 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
                if (tree_fits_uhwi_p (index1)
                    && compare_tree_int (index1, TREE_STRING_LENGTH (init)) < 0)
                  {
-                   tree type = TREE_TYPE (TREE_TYPE (init));
-                   scalar_int_mode mode;
+                   tree char_type = TREE_TYPE (TREE_TYPE (init));
+                   scalar_int_mode char_mode;
 
-                   if (is_int_mode (TYPE_MODE (type), &mode)
-                       && GET_MODE_SIZE (mode) == 1)
+                   if (is_int_mode (TYPE_MODE (char_type), &char_mode)
+                       && GET_MODE_SIZE (char_mode) == 1)
                      return gen_int_mode (TREE_STRING_POINTER (init)
                                           [TREE_INT_CST_LOW (index1)],
-                                          mode);
+                                          char_mode);
                  }
              }
          }
@@ -10589,8 +10764,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
                        rtx op = read_complex_part (op0, i != 0);
                        if (GET_CODE (op) == SUBREG)
                          op = force_reg (GET_MODE (op), op);
-                       rtx temp = gen_lowpart_common (GET_MODE_INNER (mode1),
-                                                      op);
+                       temp = gen_lowpart_common (GET_MODE_INNER (mode1), op);
                        if (temp)
                          op = temp;
                        else
@@ -10705,6 +10879,14 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
            MEM_VOLATILE_P (op0) = 1;
          }
 
+       if (MEM_P (op0) && TREE_CODE (tem) == FUNCTION_DECL)
+         {
+           if (op0 == orig_op0)
+             op0 = copy_rtx (op0);
+
+           set_mem_align (op0, BITS_PER_UNIT);
+         }
+
        /* In cases where an aligned union has an unaligned object
           as a field, we might be extracting a BLKmode value from
           an integer-mode (e.g., SImode) object.  Handle this case
@@ -10796,12 +10978,12 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
            if (MEM_P (op0) && REG_P (XEXP (op0, 0)))
              mark_reg_pointer (XEXP (op0, 0), MEM_ALIGN (op0));
 
-           /* If the result has a record type and the extraction is done in
+           /* If the result has aggregate type and the extraction is done in
               an integral mode, then the field may be not aligned on a byte
               boundary; in this case, if it has reverse storage order, it
               needs to be extracted as a scalar field with reverse storage
               order and put back into memory order afterwards.  */
-           if (TREE_CODE (type) == RECORD_TYPE
+           if (AGGREGATE_TYPE_P (type)
                && GET_MODE_CLASS (ext_mode) == MODE_INT)
              reversep = TYPE_REVERSE_STORAGE_ORDER (type);
 
@@ -10811,13 +10993,13 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
                                      ? NULL_RTX : target),
                                     ext_mode, ext_mode, reversep, alt_rtl);
 
-           /* If the result has a record type and the mode of OP0 is an
+           /* If the result has aggregate type and the mode of OP0 is an
               integral mode then, if BITSIZE is narrower than this mode
               and this is for big-endian data, we must put the field
               into the high-order bits.  And we must also put it back
               into memory order if it has been previously reversed.  */
            scalar_int_mode op0_mode;
-           if (TREE_CODE (type) == RECORD_TYPE
+           if (AGGREGATE_TYPE_P (type)
                && is_int_mode (GET_MODE (op0), &op0_mode))
              {
                HOST_WIDE_INT size = GET_MODE_BITSIZE (op0_mode);
@@ -10866,9 +11048,10 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
          op0 = copy_rtx (op0);
 
        /* Don't set memory attributes if the base expression is
-          SSA_NAME that got expanded as a MEM.  In that case, we should
-          just honor its original memory attributes.  */
-       if (TREE_CODE (tem) != SSA_NAME || !MEM_P (orig_op0))
+          SSA_NAME that got expanded as a MEM or a CONSTANT.  In that case,
+          we should just honor its original memory attributes.  */
+       if (!(TREE_CODE (tem) == SSA_NAME
+             && (MEM_P (orig_op0) || CONSTANT_P (orig_op0))))
          set_mem_attributes (op0, exp, 0);
 
        if (REG_P (XEXP (op0, 0)))
@@ -10959,11 +11142,10 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
        machine_mode mode1;
        poly_int64 bitsize, bitpos, bytepos;
        tree offset;
-       int unsignedp, reversep, volatilep = 0;
+       int reversep, volatilep = 0;
        tree tem
          = get_inner_reference (treeop0, &bitsize, &bitpos, &offset, &mode1,
                                 &unsignedp, &reversep, &volatilep);
-       rtx orig_op0;
 
        /* ??? We should work harder and deal with non-zero offsets.  */
        if (!offset
@@ -10973,7 +11155,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
            && known_eq (wi::to_poly_offset (TYPE_SIZE (type)), bitsize))
          {
            /* See the normal_inner_ref case for the rationale.  */
-           orig_op0
+           rtx orig_op0
              = expand_expr_real (tem,
                                  (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
                                   && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
@@ -11195,6 +11377,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
     case CATCH_EXPR:
     case EH_FILTER_EXPR:
     case TRY_FINALLY_EXPR:
+    case EH_ELSE_EXPR:
       /* Lowered by tree-eh.c.  */
       gcc_unreachable ();
 
@@ -11311,6 +11494,15 @@ is_aligning_offset (const_tree offset, const_tree exp)
 tree
 string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 {
+  tree dummy = NULL_TREE;;
+  if (!mem_size)
+    mem_size = &dummy;
+
+  /* Store the type of the original expression before conversions
+     via NOP_EXPR or POINTER_PLUS_EXPR to other types have been
+     removed.  */
+  tree argtype = TREE_TYPE (arg);
+
   tree array;
   STRIP_NOPS (arg);
 
@@ -11373,7 +11565,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
              && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == ARRAY_TYPE
              && !(decl && !*decl)
              && !(decl && tree_fits_uhwi_p (DECL_SIZE_UNIT (*decl))
-                  && mem_size && tree_fits_uhwi_p (*mem_size)
+                  && tree_fits_uhwi_p (*mem_size)
                   && tree_int_cst_equal (*mem_size, DECL_SIZE_UNIT (*decl))))
            return NULL_TREE;
 
@@ -11405,7 +11597,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
              && TREE_CODE (TREE_TYPE (TREE_TYPE (rhs1))) == ARRAY_TYPE
              && !(decl && !*decl)
              && !(decl && tree_fits_uhwi_p (DECL_SIZE_UNIT (*decl))
-                  && mem_size && tree_fits_uhwi_p (*mem_size)
+                  && tree_fits_uhwi_p (*mem_size)
                   && tree_int_cst_equal (*mem_size, DECL_SIZE_UNIT (*decl))))
            return NULL_TREE;
 
@@ -11439,8 +11631,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
   if (TREE_CODE (array) == STRING_CST)
     {
       *ptr_offset = fold_convert (sizetype, offset);
-      if (mem_size)
-       *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
+      *mem_size = TYPE_SIZE_UNIT (TREE_TYPE (array));
       if (decl)
        *decl = NULL_TREE;
       gcc_checking_assert (tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (array)))
@@ -11470,7 +11661,7 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 
       base_off = wioff.to_uhwi ();
       unsigned HOST_WIDE_INT fieldoff = 0;
-      init = fold_ctor_reference (NULL_TREE, init, base_off, 0, array,
+      init = fold_ctor_reference (TREE_TYPE (arg), init, base_off, 0, array,
                                  &fieldoff);
       HOST_WIDE_INT cstoff;
       if (!base_off.is_constant (&cstoff))
@@ -11489,17 +11680,11 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
 
   *ptr_offset = offset;
 
-  tree eltype = TREE_TYPE (init);
-  tree initsize = TYPE_SIZE_UNIT (eltype);
-  if (mem_size)
-    *mem_size = initsize;
-
-  if (decl)
-    *decl = array;
+  tree inittype = TREE_TYPE (init);
 
   if (TREE_CODE (init) == INTEGER_CST
       && (TREE_CODE (TREE_TYPE (array)) == INTEGER_TYPE
-         || TYPE_MAIN_VARIANT (eltype) == char_type_node))
+         || TYPE_MAIN_VARIANT (inittype) == char_type_node))
     {
       /* For a reference to (address of) a single constant character,
         store the native representation of the character in CHARBUF.
@@ -11511,17 +11696,49 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl)
       int len = native_encode_expr (init, charbuf, sizeof charbuf, 0);
       if (len > 0)
        {
-         /* Construct a string literal with elements of ELTYPE and
+         /* Construct a string literal with elements of INITTYPE and
             the representation above.  Then strip
             the ADDR_EXPR (ARRAY_REF (...)) around the STRING_CST.  */
-         init = build_string_literal (len, (char *)charbuf, eltype);
+         init = build_string_literal (len, (char *)charbuf, inittype);
          init = TREE_OPERAND (TREE_OPERAND (init, 0), 0);
        }
     }
 
+  tree initsize = TYPE_SIZE_UNIT (inittype);
+
+  if (TREE_CODE (init) == CONSTRUCTOR && initializer_zerop (init))
+    {
+      /* Fold an empty/zero constructor for an implicitly initialized
+        object or subobject into the empty string.  */
+
+      /* Determine the character type from that of the original
+        expression.  */
+      tree chartype = argtype;
+      if (POINTER_TYPE_P (chartype))
+       chartype = TREE_TYPE (chartype);
+      while (TREE_CODE (chartype) == ARRAY_TYPE)
+       chartype = TREE_TYPE (chartype);
+      /* Convert a char array to an empty STRING_CST having an array
+        of the expected type.  */
+      if (!initsize)
+         initsize = integer_zero_node;
+
+      unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize);
+      init = build_string_literal (size ? 1 : 0, "", chartype, size);
+      init = TREE_OPERAND (init, 0);
+      init = TREE_OPERAND (init, 0);
+
+      *ptr_offset = integer_zero_node;
+    }
+
+  if (decl)
+    *decl = array;
+
   if (TREE_CODE (init) != STRING_CST)
     return NULL_TREE;
 
+  *mem_size = initsize;
+
   gcc_checking_assert (tree_to_shwi (initsize) >= TREE_STRING_LENGTH (init));
 
   return init;
@@ -11939,11 +12156,12 @@ do_store_flag (sepops ops, rtx target, machine_mode mode)
       && TREE_CODE (arg0) == SSA_NAME
       && TREE_CODE (arg1) == INTEGER_CST)
     {
-      enum tree_code code = maybe_optimize_mod_cmp (ops->code, &arg0, &arg1);
-      if (code != ops->code)
+      enum tree_code new_code = maybe_optimize_mod_cmp (ops->code,
+                                                       &arg0, &arg1);
+      if (new_code != ops->code)
        {
          struct separate_ops nops = *ops;
-         nops.code = ops->code = code;
+         nops.code = ops->code = new_code;
          nops.op0 = arg0;
          nops.op1 = arg1;
          nops.type = TREE_TYPE (arg0);
@@ -12046,7 +12264,7 @@ do_store_flag (sepops ops, rtx target, machine_mode mode)
          && integer_pow2p (gimple_assign_rhs2 (srcstmt)))
        {
          enum tree_code tcode = code == NE ? NE_EXPR : EQ_EXPR;
-         tree type = lang_hooks.types.type_for_mode (mode, unsignedp);
+         type = lang_hooks.types.type_for_mode (mode, unsignedp);
          tree temp = fold_build2_loc (loc, BIT_AND_EXPR, TREE_TYPE (arg1),
                                       gimple_assign_rhs1 (srcstmt),
                                       gimple_assign_rhs2 (srcstmt));
@@ -12082,7 +12300,7 @@ try_casesi (tree index_type, tree index_expr, tree minval, tree range,
            rtx table_label, rtx default_label, rtx fallback_label,
             profile_probability default_probability)
 {
-  struct expand_operand ops[5];
+  class expand_operand ops[5];
   scalar_int_mode index_mode = SImode;
   rtx op1, op2, index;
 
@@ -12363,7 +12581,8 @@ build_personality_function (const char *lang)
 
   name = ACONCAT (("__", lang, "_personality", unwind_and_version, NULL));
 
-  type = build_function_type_list (integer_type_node, integer_type_node,
+  type = build_function_type_list (unsigned_type_node,
+                                  integer_type_node, integer_type_node,
                                   long_long_unsigned_type_node,
                                   ptr_type_node, ptr_type_node, NULL_TREE);
   decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,