]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/expr.c
Update copyright years.
[thirdparty/gcc.git] / gcc / expr.c
index 9ff5e5f2d76b36ed65c51601a0fa800d0600b92a..b97c217e86da73401a04f3c4fc531d83987e8d5d 100644 (file)
@@ -1,5 +1,5 @@
 /* Convert tree expression to rtl instructions, for GNU compiler.
-   Copyright (C) 1988-2019 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;
 
@@ -1561,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;
@@ -1618,23 +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, RETURN_BEGIN);
-  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;
 
       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);
 
@@ -1663,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)
@@ -1688,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);
@@ -1698,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)
@@ -1734,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
@@ -1744,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
@@ -1758,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
@@ -1798,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;
 }
 
@@ -1921,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);
@@ -3126,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;
@@ -3534,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 ();
        }
 
@@ -4170,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))
@@ -4442,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,
@@ -4526,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
@@ -4574,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,
@@ -4938,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
@@ -4997,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))
@@ -5016,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);
@@ -5211,13 +5285,16 @@ expand_assignment (tree to, tree from, bool nontemporal)
                }
              else
                {
+                 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,
-                                            TYPE_MODE (TREE_TYPE (from)), 0);
+                     = simplify_gen_subreg (to_mode, result, from_mode, 0);
                  if (from_rtx)
                    {
                      emit_move_insn (XEXP (to_rtx, 0),
@@ -5227,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;
@@ -5247,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);
@@ -5445,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);
 
@@ -5658,7 +5731,8 @@ store_expr (tree exp, rtx target, int call_param_p,
       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 (dest_mem, BLKmode, 0),
+      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;
     }
@@ -5743,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
@@ -6410,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)
                  {
@@ -6487,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;
 
@@ -6747,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);
@@ -6762,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))
@@ -6772,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);
              }
          }
 
@@ -7106,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);
        }
@@ -7215,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
     {
@@ -8246,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
@@ -8326,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));
@@ -8336,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));
@@ -8383,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)
@@ -8870,9 +8983,6 @@ 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)
                    goto widen_mult_const;
-                 if (TREE_CODE (treeop1) == INTEGER_CST)
-                   op1 = convert_modes (mode, word_mode, op1,
-                                        TYPE_UNSIGNED (TREE_TYPE (treeop1)));
                  temp = expand_binop (mode, other_optab, op0, op1, target,
                                       unsignedp, OPTAB_LIB_WIDEN);
                  hipart = gen_highpart (word_mode, temp);
@@ -9542,7 +9652,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
          && mode == TYPE_MODE (TREE_TYPE (treeop0))
          && SCALAR_INT_MODE_P (mode))
        {
-         struct expand_operand eops[4];
+         class expand_operand eops[4];
          machine_mode imode = TYPE_MODE (TREE_TYPE (treeop0));
          expand_operands (treeop0, treeop1,
                           subtarget, &op0, &op1, EXPAND_NORMAL);
@@ -9596,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);
@@ -9610,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);
@@ -9624,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);
@@ -9714,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,
@@ -9914,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);
@@ -10047,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;
        }
@@ -10096,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;
       }
 
@@ -10173,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);
 
@@ -10262,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);
@@ -10274,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;
       }
 
@@ -10301,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.  */
@@ -10331,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);
@@ -10358,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)
@@ -10513,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);
                  }
              }
          }
@@ -10674,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
@@ -10790,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
@@ -10881,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);
 
@@ -10896,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);
@@ -10951,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)))
@@ -11044,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
@@ -11058,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)))
@@ -11280,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 ();
 
@@ -11396,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);
 
@@ -11458,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;
 
@@ -11490,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;
 
@@ -11524,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)))
@@ -11555,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))
@@ -11574,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.
@@ -11596,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;
@@ -12024,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);
@@ -12131,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));
@@ -12167,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;
 
@@ -12448,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,