gcc.dg/tree-ssa/ssa-dom-cse-2.c: xfail scan for mmix.
[gcc.git] / gcc / gimple-ssa-store-merging.c
index 8371323ef4a3f5dc126a93b9b76c1d4ec6224eab..8c195584eed84d8664630fad85e42aab72db93e6 100644 (file)
@@ -61,7 +61,7 @@
    record the surrounding bit region, i.e. bits that could be stored in
    a read-modify-write operation when storing the bit-field.  Record store
    chains to different bases in a hash_map (m_stores) and make sure to
-   terminate such chains when appropriate (for example when when the stored
+   terminate such chains when appropriate (for example when the stored
    values get used subsequently).
    These stores can be a result of structure element initializers, array stores
    etc.  A store_immediate_info object is recorded for every such store.
@@ -315,7 +315,8 @@ verify_symbolic_number_p (struct symbolic_number *n, gimple *stmt)
 
   lhs_type = gimple_expr_type (stmt);
 
-  if (TREE_CODE (lhs_type) != INTEGER_TYPE)
+  if (TREE_CODE (lhs_type) != INTEGER_TYPE
+      && TREE_CODE (lhs_type) != ENUMERAL_TYPE)
     return false;
 
   if (TYPE_PRECISION (lhs_type) != TYPE_PRECISION (n->type))
@@ -597,6 +598,10 @@ find_bswap_or_nop_1 (gimple *stmt, struct symbolic_number *n, int limit)
   if (TREE_CODE (rhs1) == BIT_FIELD_REF
       && TREE_CODE (TREE_OPERAND (rhs1, 0)) == SSA_NAME)
     {
+      if (!tree_fits_uhwi_p (TREE_OPERAND (rhs1, 1))
+         || !tree_fits_uhwi_p (TREE_OPERAND (rhs1, 2)))
+       return NULL;
+
       unsigned HOST_WIDE_INT bitsize = tree_to_uhwi (TREE_OPERAND (rhs1, 1));
       unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (TREE_OPERAND (rhs1, 2));
       if (bitpos % BITS_PER_UNIT == 0
@@ -1361,9 +1366,9 @@ public:
   unsigned HOST_WIDE_INT bitregion_end;
   gimple *stmt;
   unsigned int order;
-  /* INTEGER_CST for constant stores, MEM_REF for memory copy,
-     BIT_*_EXPR for logical bitwise operation, BIT_INSERT_EXPR
-     for bit insertion.
+  /* INTEGER_CST for constant store, STRING_CST for string store,
+     MEM_REF for memory copy, BIT_*_EXPR for logical bitwise operation,
+     BIT_INSERT_EXPR for bit insertion.
      LROTATE_EXPR if it can be only bswap optimized and
      ops are not really meaningful.
      NOP_EXPR if bswap optimization detected identity, ops
@@ -1439,6 +1444,7 @@ public:
   unsigned int first_order;
   unsigned int last_order;
   bool bit_insertion;
+  bool string_concatenation;
   bool only_constants;
   unsigned int first_nonmergeable_order;
   int lp_nr;
@@ -1475,66 +1481,6 @@ dump_char_array (FILE *fd, unsigned char *ptr, unsigned int len)
   fprintf (fd, "\n");
 }
 
-/* Shift left the bytes in PTR of SZ elements by AMNT bits, carrying over the
-   bits between adjacent elements.  AMNT should be within
-   [0, BITS_PER_UNIT).
-   Example, AMNT = 2:
-   00011111|11100000 << 2 = 01111111|10000000
-   PTR[1]  | PTR[0]         PTR[1]  | PTR[0].  */
-
-static void
-shift_bytes_in_array (unsigned char *ptr, unsigned int sz, unsigned int amnt)
-{
-  if (amnt == 0)
-    return;
-
-  unsigned char carry_over = 0U;
-  unsigned char carry_mask = (~0U) << (unsigned char) (BITS_PER_UNIT - amnt);
-  unsigned char clear_mask = (~0U) << amnt;
-
-  for (unsigned int i = 0; i < sz; i++)
-    {
-      unsigned prev_carry_over = carry_over;
-      carry_over = (ptr[i] & carry_mask) >> (BITS_PER_UNIT - amnt);
-
-      ptr[i] <<= amnt;
-      if (i != 0)
-       {
-         ptr[i] &= clear_mask;
-         ptr[i] |= prev_carry_over;
-       }
-    }
-}
-
-/* Like shift_bytes_in_array but for big-endian.
-   Shift right the bytes in PTR of SZ elements by AMNT bits, carrying over the
-   bits between adjacent elements.  AMNT should be within
-   [0, BITS_PER_UNIT).
-   Example, AMNT = 2:
-   00011111|11100000 >> 2 = 00000111|11111000
-   PTR[0]  | PTR[1]         PTR[0]  | PTR[1].  */
-
-static void
-shift_bytes_in_array_right (unsigned char *ptr, unsigned int sz,
-                           unsigned int amnt)
-{
-  if (amnt == 0)
-    return;
-
-  unsigned char carry_over = 0U;
-  unsigned char carry_mask = ~(~0U << amnt);
-
-  for (unsigned int i = 0; i < sz; i++)
-    {
-      unsigned prev_carry_over = carry_over;
-      carry_over = ptr[i] & carry_mask;
-
-      carry_over <<= (unsigned char) BITS_PER_UNIT - amnt;
-      ptr[i] >>= amnt;
-      ptr[i] |= prev_carry_over;
-    }
-}
-
 /* Clear out LEN bits starting from bit START in the byte array
    PTR.  This clears the bits to the *right* from START.
    START must be within [0, BITS_PER_UNIT) and counts starting from
@@ -1709,7 +1655,10 @@ encode_tree_to_bitpos (tree expr, unsigned char *ptr, int bitlen, int bitpos,
     {
       fixed_size_mode mode
        = as_a <fixed_size_mode> (TYPE_MODE (TREE_TYPE (expr)));
-      byte_size = GET_MODE_SIZE (mode);
+      byte_size
+       = mode == BLKmode
+       ? tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (expr)))
+       : GET_MODE_SIZE (mode);
     }
   /* Allocate an extra byte so that we have space to shift into.  */
   byte_size++;
@@ -1793,7 +1742,7 @@ encode_tree_to_bitpos (tree expr, unsigned char *ptr, int bitlen, int bitpos,
   /* Create the shifted version of EXPR.  */
   if (!BYTES_BIG_ENDIAN)
     {
-      shift_bytes_in_array (tmpbuf, byte_size, shift_amnt);
+      shift_bytes_in_array_left (tmpbuf, byte_size, shift_amnt);
       if (shift_amnt == 0)
        byte_size--;
     }
@@ -1866,7 +1815,8 @@ merged_store_group::merged_store_group (store_immediate_info *info)
      width has been finalized.  */
   val = NULL;
   mask = NULL;
-  bit_insertion = false;
+  bit_insertion = info->rhs_code == BIT_INSERT_EXPR;
+  string_concatenation = info->rhs_code == STRING_CST;
   only_constants = info->rhs_code == INTEGER_CST;
   first_nonmergeable_order = ~0U;
   lp_nr = info->lp_nr;
@@ -1919,27 +1869,41 @@ merged_store_group::can_be_merged_into (store_immediate_info *info)
   if (info->rhs_code == stores[0]->rhs_code)
     return true;
 
-  /* BIT_INSERT_EXPR is compatible with INTEGER_CST.  */
+  /* BIT_INSERT_EXPR is compatible with INTEGER_CST if no STRING_CST.  */
   if (info->rhs_code == BIT_INSERT_EXPR && stores[0]->rhs_code == INTEGER_CST)
-    return true;
+    return !string_concatenation;
 
   if (stores[0]->rhs_code == BIT_INSERT_EXPR && info->rhs_code == INTEGER_CST)
-    return true;
+    return !string_concatenation;
 
-  /* We can turn MEM_REF into BIT_INSERT_EXPR for bit-field stores.  */
+  /* We can turn MEM_REF into BIT_INSERT_EXPR for bit-field stores, but do it
+     only for small regions since this can generate a lot of instructions.  */
   if (info->rhs_code == MEM_REF
       && (stores[0]->rhs_code == INTEGER_CST
          || stores[0]->rhs_code == BIT_INSERT_EXPR)
       && info->bitregion_start == stores[0]->bitregion_start
-      && info->bitregion_end == stores[0]->bitregion_end)
-    return true;
+      && info->bitregion_end == stores[0]->bitregion_end
+      && info->bitregion_end - info->bitregion_start <= MAX_FIXED_MODE_SIZE)
+    return !string_concatenation;
 
   if (stores[0]->rhs_code == MEM_REF
       && (info->rhs_code == INTEGER_CST
          || info->rhs_code == BIT_INSERT_EXPR)
       && info->bitregion_start == stores[0]->bitregion_start
-      && info->bitregion_end == stores[0]->bitregion_end)
-    return true;
+      && info->bitregion_end == stores[0]->bitregion_end
+      && info->bitregion_end - info->bitregion_start <= MAX_FIXED_MODE_SIZE)
+    return !string_concatenation;
+
+  /* STRING_CST is compatible with INTEGER_CST if no BIT_INSERT_EXPR.  */
+  if (info->rhs_code == STRING_CST
+      && stores[0]->rhs_code == INTEGER_CST
+      && stores[0]->bitsize == CHAR_BIT)
+    return !bit_insertion;
+
+  if (stores[0]->rhs_code == STRING_CST
+      && info->rhs_code == INTEGER_CST
+      && info->bitsize == CHAR_BIT)
+    return !bit_insertion;
 
   return false;
 }
@@ -1988,6 +1952,21 @@ merged_store_group::do_merge (store_immediate_info *info)
       first_order = info->order;
       first_stmt = stmt;
     }
+
+  /* We need to use extraction if there is any bit-field.  */
+  if (info->rhs_code == BIT_INSERT_EXPR)
+    {
+      bit_insertion = true;
+      gcc_assert (!string_concatenation);
+    }
+
+  /* We need to use concatenation if there is any string.  */
+  if (info->rhs_code == STRING_CST)
+    {
+      string_concatenation = true;
+      gcc_assert (!bit_insertion);
+    }
+
   if (info->rhs_code != INTEGER_CST)
     only_constants = false;
 }
@@ -2028,6 +2007,9 @@ merged_store_group::merge_overlapping (store_immediate_info *info)
 bool
 merged_store_group::apply_stores ()
 {
+  store_immediate_info *info;
+  unsigned int i;
+
   /* Make sure we have more than one store in the group, otherwise we cannot
      merge anything.  */
   if (bitregion_start % BITS_PER_UNIT != 0
@@ -2035,16 +2017,23 @@ merged_store_group::apply_stores ()
       || stores.length () == 1)
     return false;
 
-  stores.qsort (sort_by_order);
-  store_immediate_info *info;
-  unsigned int i;
+  buf_size = (bitregion_end - bitregion_start) / BITS_PER_UNIT;
+
+  /* Really do string concatenation for large strings only.  */
+  if (buf_size <= MOVE_MAX)
+    string_concatenation = false;
+
   /* Create a power-of-2-sized buffer for native_encode_expr.  */
-  buf_size = 1 << ceil_log2 ((bitregion_end - bitregion_start) / BITS_PER_UNIT);
+  if (!string_concatenation)
+    buf_size = 1 << ceil_log2 (buf_size);
+
   val = XNEWVEC (unsigned char, 2 * buf_size);
   mask = val + buf_size;
   memset (val, 0, buf_size);
   memset (mask, ~0U, buf_size);
 
+  stores.qsort (sort_by_order);
+
   FOR_EACH_VEC_ELT (stores, i, info)
     {
       unsigned int pos_in_buffer = info->bitpos - bitregion_start;
@@ -2056,14 +2045,9 @@ merged_store_group::apply_stores ()
       else
        cst = NULL_TREE;
       bool ret = true;
-      if (cst)
-       {
-         if (info->rhs_code == BIT_INSERT_EXPR)
-           bit_insertion = true;
-         else
-           ret = encode_tree_to_bitpos (cst, val, info->bitsize,
-                                        pos_in_buffer, buf_size);
-       }
+      if (cst && info->rhs_code != BIT_INSERT_EXPR)
+       ret = encode_tree_to_bitpos (cst, val, info->bitsize, pos_in_buffer,
+                                    buf_size);
       unsigned char *m = mask + (pos_in_buffer / BITS_PER_UNIT);
       if (BYTES_BIG_ENDIAN)
        clear_bit_region_be (m, (BITS_PER_UNIT - 1
@@ -2085,6 +2069,8 @@ merged_store_group::apply_stores ()
              dump_char_array (dump_file, mask, buf_size);
              if (bit_insertion)
                fputs ("  bit insertion is required\n", dump_file);
+             if (string_concatenation)
+               fputs ("  string concatenation is required\n", dump_file);
            }
          else
            fprintf (dump_file, "Failed to merge stores\n");
@@ -2430,8 +2416,9 @@ gather_bswap_load_refs (vec<tree> *refs, tree val)
 /* Check if there are any stores in M_STORE_INFO after index I
    (where M_STORE_INFO must be sorted by sort_by_bitpos) that overlap
    a potential group ending with END that have their order
-   smaller than LAST_ORDER.  RHS_CODE is the kind of store in the
-   group.  Return true if there are no such stores.
+   smaller than LAST_ORDER.  ALL_INTEGER_CST_P is true if
+   all the stores already merged and the one under consideration
+   have rhs_code of INTEGER_CST.  Return true if there are no such stores.
    Consider:
      MEM[(long long int *)p_28] = 0;
      MEM[(long long int *)p_28 + 8B] = 0;
@@ -2454,13 +2441,13 @@ gather_bswap_load_refs (vec<tree> *refs, tree val)
    the MEM[(long long int *)p_28 + 8B] = 0; would now be before it,
    so we need to refuse merging MEM[(long long int *)p_28 + 8B] = 0;
    into the group.  That way it will be its own store group and will
-   not be touched.  If RHS_CODE is INTEGER_CST and there are overlapping
+   not be touched.  If ALL_INTEGER_CST_P and there are overlapping
    INTEGER_CST stores, those are mergeable using merge_overlapping,
    so don't return false for those.  */
 
 static bool
 check_no_overlap (vec<store_immediate_info *> m_store_info, unsigned int i,
-                 enum tree_code rhs_code, unsigned int last_order,
+                 bool all_integer_cst_p, unsigned int last_order,
                  unsigned HOST_WIDE_INT end)
 {
   unsigned int len = m_store_info.length ();
@@ -2470,7 +2457,7 @@ check_no_overlap (vec<store_immediate_info *> m_store_info, unsigned int i,
       if (info->bitpos >= end)
        break;
       if (info->order < last_order
-         && (rhs_code != INTEGER_CST || info->rhs_code != INTEGER_CST))
+         && (!all_integer_cst_p || info->rhs_code != INTEGER_CST))
        return false;
     }
   return true;
@@ -2493,6 +2480,7 @@ imm_store_chain_info::try_coalesce_bswap (merged_store_group *merged_store,
   for (unsigned int i = first + 1; i < len; ++i)
     {
       if (m_store_info[i]->bitpos != m_store_info[first]->bitpos + width
+         || m_store_info[i]->lp_nr != merged_store->lp_nr
          || m_store_info[i]->ins_stmt == NULL)
        return false;
       width += m_store_info[i]->bitsize;
@@ -2623,7 +2611,7 @@ imm_store_chain_info::try_coalesce_bswap (merged_store_group *merged_store,
   if (n.base_addr == NULL_TREE && !is_gimple_val (n.src))
     return false;
 
-  if (!check_no_overlap (m_store_info, last, LROTATE_EXPR, last_order, end))
+  if (!check_no_overlap (m_store_info, last, false, last_order, end))
     return false;
 
   /* Don't handle memory copy this way if normal non-bswap processing
@@ -2740,6 +2728,7 @@ imm_store_chain_info::coalesce_immediate_stores ()
       if (info->bitpos == merged_store->start + merged_store->width
          && merged_store->stores.length () == 1
          && merged_store->stores[0]->ins_stmt != NULL
+         && info->lp_nr == merged_store->lp_nr
          && info->ins_stmt != NULL)
        {
          unsigned int try_size;
@@ -2773,7 +2762,14 @@ imm_store_chain_info::coalesce_immediate_stores ()
               |---store 2---|
         Overlapping stores.  */
       else if (IN_RANGE (info->bitpos, merged_store->start,
-                        merged_store->start + merged_store->width - 1))
+                        merged_store->start + merged_store->width - 1)
+              /* |---store 1---||---store 2---|
+                 Handle also the consecutive INTEGER_CST stores case here,
+                 as we have here the code to deal with overlaps.  */
+              || (info->bitregion_start <= merged_store->bitregion_end
+                  && info->rhs_code == INTEGER_CST
+                  && merged_store->only_constants
+                  && merged_store->can_be_merged_into (info)))
        {
          /* Only allow overlapping stores of constants.  */
          if (info->rhs_code == INTEGER_CST
@@ -2785,8 +2781,7 @@ imm_store_chain_info::coalesce_immediate_stores ()
              unsigned HOST_WIDE_INT end
                = MAX (merged_store->start + merged_store->width,
                       info->bitpos + info->bitsize);
-             if (check_no_overlap (m_store_info, i, INTEGER_CST,
-                                   last_order, end))
+             if (check_no_overlap (m_store_info, i, true, last_order, end))
                {
                  /* check_no_overlap call above made sure there are no
                     overlapping stores with non-INTEGER_CST rhs_code
@@ -2826,7 +2821,8 @@ imm_store_chain_info::coalesce_immediate_stores ()
                            break;
                          if (info2->order < try_order)
                            {
-                             if (info2->rhs_code != INTEGER_CST)
+                             if (info2->rhs_code != INTEGER_CST
+                                 || info2->lp_nr != merged_store->lp_nr)
                                {
                                  /* Normally check_no_overlap makes sure this
                                     doesn't happen, but if end grows below,
@@ -2844,6 +2840,7 @@ imm_store_chain_info::coalesce_immediate_stores ()
                                              info2->bitpos + info2->bitsize);
                            }
                          else if (info2->rhs_code == INTEGER_CST
+                                  && info2->lp_nr == merged_store->lp_nr
                                   && !last_iter)
                            {
                              max_order = MAX (max_order, info2->order + 1);
@@ -2939,7 +2936,7 @@ imm_store_chain_info::coalesce_immediate_stores ()
              std::swap (info->ops[0], info->ops[1]);
              info->ops_swapped_p = true;
            }
-         if (check_no_overlap (m_store_info, i, info->rhs_code,
+         if (check_no_overlap (m_store_info, i, false,
                                MAX (merged_store->last_order, info->order),
                                MAX (merged_store->start + merged_store->width,
                                     info->bitpos + info->bitsize)))
@@ -2961,6 +2958,7 @@ imm_store_chain_info::coalesce_immediate_stores ()
                      infoj->ops[0].val = gimple_assign_rhs1 (infoj->stmt);
                      infoj->ops[0].base_addr = NULL_TREE;
                    }
+                 merged_store->bit_insertion = true;
                }
              if ((infof->ops[0].base_addr
                   ? compatible_load_p (merged_store, info, base_addr, 0)
@@ -3188,6 +3186,7 @@ count_multiple_uses (store_immediate_info *info)
   switch (info->rhs_code)
     {
     case INTEGER_CST:
+    case STRING_CST:
       return 0;
     case BIT_AND_EXPR:
     case BIT_IOR_EXPR:
@@ -3283,13 +3282,14 @@ split_group (merged_store_group *group, bool allow_unaligned_store,
 
   gcc_assert ((size % BITS_PER_UNIT == 0) && (pos % BITS_PER_UNIT == 0));
 
+  /* For bswap framework using sets of stores, all the checking has been done
+     earlier in try_coalesce_bswap and the result always needs to be emitted
+     as a single store.  Likewise for string concatenation,  */
   if (group->stores[0]->rhs_code == LROTATE_EXPR
-      || group->stores[0]->rhs_code == NOP_EXPR)
+      || group->stores[0]->rhs_code == NOP_EXPR
+      || group->string_concatenation)
     {
       gcc_assert (!bzero_first);
-      /* For bswap framework using sets of stores, all the checking
-        has been done earlier in try_coalesce_bswap and needs to be
-        emitted as a single store.  */
       if (total_orig)
        {
          /* Avoid the old/new stmt count heuristics.  It should be
@@ -3703,16 +3703,12 @@ invert_op (split_store *split_store, int idx, tree int_type, tree &mask)
 bool
 imm_store_chain_info::output_merged_store (merged_store_group *group)
 {
-  split_store *split_store;
-  unsigned int i;
-  unsigned HOST_WIDE_INT start_byte_pos
+  const unsigned HOST_WIDE_INT start_byte_pos
     = group->bitregion_start / BITS_PER_UNIT;
-
   unsigned int orig_num_stmts = group->stores.length ();
   if (orig_num_stmts < 2)
     return false;
 
-  auto_vec<class split_store *, 32> split_stores;
   bool allow_unaligned_store
     = !STRICT_ALIGNMENT && param_store_merging_allow_unaligned;
   bool allow_unaligned_load = allow_unaligned_store;
@@ -3721,6 +3717,7 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
   unsigned int num_clobber_stmts = 0;
   if (group->stores[0]->rhs_code == INTEGER_CST)
     {
+      unsigned int i;
       FOR_EACH_VEC_ELT (group->stores, i, store)
        if (gimple_clobber_p (store->stmt))
          num_clobber_stmts++;
@@ -3770,7 +3767,10 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
       if ((pass_min & 2) == 0)
        bzero_first = false;
     }
-  unsigned total_orig, total_new;
+
+  auto_vec<class split_store *, 32> split_stores;
+  split_store *split_store;
+  unsigned total_orig, total_new, i;
   split_group (group, allow_unaligned_store, allow_unaligned_load, bzero_first,
               &split_stores, &total_orig, &total_new);
 
@@ -3985,12 +3985,14 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
 
   FOR_EACH_VEC_ELT (split_stores, i, split_store)
     {
-      unsigned HOST_WIDE_INT try_size = split_store->size;
-      unsigned HOST_WIDE_INT try_pos = split_store->bytepos;
-      unsigned HOST_WIDE_INT try_bitpos = try_pos * BITS_PER_UNIT;
-      unsigned HOST_WIDE_INT align = split_store->align;
+      const unsigned HOST_WIDE_INT try_size = split_store->size;
+      const unsigned HOST_WIDE_INT try_pos = split_store->bytepos;
+      const unsigned HOST_WIDE_INT try_bitpos = try_pos * BITS_PER_UNIT;
+      const unsigned HOST_WIDE_INT try_align = split_store->align;
+      const unsigned HOST_WIDE_INT try_offset = try_pos - start_byte_pos;
       tree dest, src;
       location_t loc;
+
       if (split_store->orig)
        {
          /* If there is just a single non-clobber constituent store
@@ -4017,12 +4019,20 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
            orig_stmts.safe_push (info->stmt);
          tree offset_type
            = get_alias_type_for_stmts (orig_stmts, false, &clique, &base);
+         tree dest_type;
          loc = get_location_for_stmts (orig_stmts);
          orig_stmts.truncate (0);
 
-         tree int_type = build_nonstandard_integer_type (try_size, UNSIGNED);
-         int_type = build_aligned_type (int_type, align);
-         dest = fold_build2 (MEM_REF, int_type, addr,
+         if (group->string_concatenation)
+           dest_type
+             = build_array_type_nelts (char_type_node,
+                                       try_size / BITS_PER_UNIT);
+         else
+           {
+             dest_type = build_nonstandard_integer_type (try_size, UNSIGNED);
+             dest_type = build_aligned_type (dest_type, try_align);
+           }
+         dest = fold_build2 (MEM_REF, dest_type, addr,
                              build_int_cst (offset_type, try_pos));
          if (TREE_CODE (dest) == MEM_REF)
            {
@@ -4031,12 +4041,11 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
            }
 
          tree mask;
-         if (bswap_res)
+         if (bswap_res || group->string_concatenation)
            mask = integer_zero_node;
          else
-           mask = native_interpret_expr (int_type,
-                                         group->mask + try_pos
-                                         - start_byte_pos,
+           mask = native_interpret_expr (dest_type,
+                                         group->mask + try_offset,
                                          group->buf_size);
 
          tree ops[2];
@@ -4047,6 +4056,12 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
              store_operand_info &op = split_store->orig_stores[0]->ops[j];
              if (bswap_res)
                ops[j] = bswap_res;
+             else if (group->string_concatenation)
+               {
+                 ops[j] = build_string (try_size / BITS_PER_UNIT,
+                                        (const char *) group->val + try_offset);
+                 TREE_TYPE (ops[j]) = dest_type;
+               }
              else if (op.base_addr)
                {
                  FOR_EACH_VEC_ELT (split_store->orig_stores, k, info)
@@ -4088,8 +4103,7 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
                       warnings in that case.  */
                    TREE_NO_WARNING (ops[j]) = 1;
 
-                 stmt = gimple_build_assign (make_ssa_name (int_type),
-                                             ops[j]);
+                 stmt = gimple_build_assign (make_ssa_name (dest_type), ops[j]);
                  gimple_set_location (stmt, load_loc);
                  if (gsi_bb (load_gsi[j]))
                    {
@@ -4104,10 +4118,10 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
                  ops[j] = gimple_assign_lhs (stmt);
                  tree xor_mask;
                  enum tree_code inv_op
-                   = invert_op (split_store, j, int_type, xor_mask);
+                   = invert_op (split_store, j, dest_type, xor_mask);
                  if (inv_op != NOP_EXPR)
                    {
-                     stmt = gimple_build_assign (make_ssa_name (int_type),
+                     stmt = gimple_build_assign (make_ssa_name (dest_type),
                                                  inv_op, ops[j], xor_mask);
                      gimple_set_location (stmt, load_loc);
                      ops[j] = gimple_assign_lhs (stmt);
@@ -4120,9 +4134,8 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
                    }
                }
              else
-               ops[j] = native_interpret_expr (int_type,
-                                               group->val + try_pos
-                                               - start_byte_pos,
+               ops[j] = native_interpret_expr (dest_type,
+                                               group->val + try_offset,
                                                group->buf_size);
            }
 
@@ -4141,7 +4154,7 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
              orig_stmts.truncate (0);
 
              stmt
-               = gimple_build_assign (make_ssa_name (int_type),
+               = gimple_build_assign (make_ssa_name (dest_type),
                                       split_store->orig_stores[0]->rhs_code,
                                       ops[0], ops[1]);
              gimple_set_location (stmt, bit_loc);
@@ -4160,10 +4173,10 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
              src = gimple_assign_lhs (stmt);
              tree xor_mask;
              enum tree_code inv_op;
-             inv_op = invert_op (split_store, 2, int_type, xor_mask);
+             inv_op = invert_op (split_store, 2, dest_type, xor_mask);
              if (inv_op != NOP_EXPR)
                {
-                 stmt = gimple_build_assign (make_ssa_name (int_type),
+                 stmt = gimple_build_assign (make_ssa_name (dest_type),
                                              inv_op, src, xor_mask);
                  gimple_set_location (stmt, bit_loc);
                  if (load_addr[1] == NULL_TREE && gsi_bb (load_gsi[0]))
@@ -4183,17 +4196,17 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
                  gimple_seq_add_stmt_without_update (&seq, stmt);
                  src = gimple_assign_lhs (stmt);
                }
-             if (!useless_type_conversion_p (int_type, TREE_TYPE (src)))
+             if (!useless_type_conversion_p (dest_type, TREE_TYPE (src)))
                {
-                 stmt = gimple_build_assign (make_ssa_name (int_type),
+                 stmt = gimple_build_assign (make_ssa_name (dest_type),
                                              NOP_EXPR, src);
                  gimple_seq_add_stmt_without_update (&seq, stmt);
                  src = gimple_assign_lhs (stmt);
                }
-             inv_op = invert_op (split_store, 2, int_type, xor_mask);
+             inv_op = invert_op (split_store, 2, dest_type, xor_mask);
              if (inv_op != NOP_EXPR)
                {
-                 stmt = gimple_build_assign (make_ssa_name (int_type),
+                 stmt = gimple_build_assign (make_ssa_name (dest_type),
                                              inv_op, src, xor_mask);
                  gimple_set_location (stmt, loc);
                  gimple_seq_add_stmt_without_update (&seq, stmt);
@@ -4220,6 +4233,15 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
                  const HOST_WIDE_INT end_gap
                    = (try_bitpos + try_size) - (info->bitpos + info->bitsize);
                  tree tem = info->ops[0].val;
+                 if (!INTEGRAL_TYPE_P (TREE_TYPE (tem)))
+                   {
+                     const unsigned HOST_WIDE_INT size
+                       = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (tem)));
+                     tree integer_type
+                       = build_nonstandard_integer_type (size, UNSIGNED);
+                     tem = gimple_build (&seq, loc, VIEW_CONVERT_EXPR,
+                                         integer_type, tem);
+                   }
                  if (TYPE_PRECISION (TREE_TYPE (tem)) <= info->bitsize)
                    {
                      tree bitfield_type
@@ -4242,18 +4264,18 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
                    tem = gimple_build (&seq, loc,
                                        RSHIFT_EXPR, TREE_TYPE (tem), tem,
                                        build_int_cst (NULL_TREE, -shift));
-                 tem = gimple_convert (&seq, loc, int_type, tem);
+                 tem = gimple_convert (&seq, loc, dest_type, tem);
                  if (shift > 0)
                    tem = gimple_build (&seq, loc,
-                                       LSHIFT_EXPR, int_type, tem,
+                                       LSHIFT_EXPR, dest_type, tem,
                                        build_int_cst (NULL_TREE, shift));
                  src = gimple_build (&seq, loc,
-                                     BIT_IOR_EXPR, int_type, tem, src);
+                                     BIT_IOR_EXPR, dest_type, tem, src);
                }
 
          if (!integer_zerop (mask))
            {
-             tree tem = make_ssa_name (int_type);
+             tree tem = make_ssa_name (dest_type);
              tree load_src = unshare_expr (dest);
              /* The load might load some or all bits uninitialized,
                 avoid -W*uninitialized warnings in that case.
@@ -4269,28 +4291,28 @@ imm_store_chain_info::output_merged_store (merged_store_group *group)
 
              /* FIXME: If there is a single chunk of zero bits in mask,
                 perhaps use BIT_INSERT_EXPR instead?  */
-             stmt = gimple_build_assign (make_ssa_name (int_type),
+             stmt = gimple_build_assign (make_ssa_name (dest_type),
                                          BIT_AND_EXPR, tem, mask);
              gimple_set_location (stmt, loc);
              gimple_seq_add_stmt_without_update (&seq, stmt);
              tem = gimple_assign_lhs (stmt);
 
              if (TREE_CODE (src) == INTEGER_CST)
-               src = wide_int_to_tree (int_type,
+               src = wide_int_to_tree (dest_type,
                                        wi::bit_and_not (wi::to_wide (src),
                                                         wi::to_wide (mask)));
              else
                {
                  tree nmask
-                   = wide_int_to_tree (int_type,
+                   = wide_int_to_tree (dest_type,
                                        wi::bit_not (wi::to_wide (mask)));
-                 stmt = gimple_build_assign (make_ssa_name (int_type),
+                 stmt = gimple_build_assign (make_ssa_name (dest_type),
                                              BIT_AND_EXPR, src, nmask);
                  gimple_set_location (stmt, loc);
                  gimple_seq_add_stmt_without_update (&seq, stmt);
                  src = gimple_assign_lhs (stmt);
                }
-             stmt = gimple_build_assign (make_ssa_name (int_type),
+             stmt = gimple_build_assign (make_ssa_name (dest_type),
                                          BIT_IOR_EXPR, tem, src);
              gimple_set_location (stmt, loc);
              gimple_seq_add_stmt_without_update (&seq, stmt);
@@ -4487,6 +4509,7 @@ lhs_valid_for_store_merging_p (tree lhs)
     case BIT_FIELD_REF:
     case COMPONENT_REF:
     case MEM_REF:
+    case VIEW_CONVERT_EXPR:
       return true;
     default:
       return false;
@@ -4716,8 +4739,8 @@ pass_store_merging::process_store (gimple *stmt)
 {
   tree lhs = gimple_assign_lhs (stmt);
   tree rhs = gimple_assign_rhs1 (stmt);
-  poly_uint64 bitsize, bitpos;
-  poly_uint64 bitregion_start, bitregion_end;
+  poly_uint64 bitsize, bitpos = 0;
+  poly_uint64 bitregion_start = 0, bitregion_end = 0;
   tree base_addr
     = mem_valid_for_store_merging (lhs, &bitsize, &bitpos,
                                   &bitregion_start, &bitregion_end);
@@ -4737,14 +4760,17 @@ pass_store_merging::process_store (gimple *stmt)
   store_operand_info ops[2];
   if (invalid)
     ;
+  else if (TREE_CODE (rhs) == STRING_CST)
+    {
+      rhs_code = STRING_CST;
+      ops[0].val = rhs;
+    }
   else if (rhs_valid_for_store_merging_p (rhs))
     {
       rhs_code = INTEGER_CST;
       ops[0].val = rhs;
     }
-  else if (TREE_CODE (rhs) != SSA_NAME)
-    invalid = true;
-  else
+  else if (TREE_CODE (rhs) == SSA_NAME)
     {
       gimple *def_stmt = SSA_NAME_DEF_STMT (rhs), *def_stmt1, *def_stmt2;
       if (!is_gimple_assign (def_stmt))
@@ -4836,7 +4862,7 @@ pass_store_merging::process_store (gimple *stmt)
          && bitsize.is_constant (&const_bitsize)
          && ((const_bitsize % BITS_PER_UNIT) != 0
              || !multiple_p (bitpos, BITS_PER_UNIT))
-         && const_bitsize <= 64)
+         && const_bitsize <= MAX_FIXED_MODE_SIZE)
        {
          /* Bypass a conversion to the bit-field type.  */
          if (!bit_not_p
@@ -4856,6 +4882,8 @@ pass_store_merging::process_store (gimple *stmt)
          invalid = false;
        }
     }
+  else
+    invalid = true;
 
   unsigned HOST_WIDE_INT const_bitsize, const_bitpos;
   unsigned HOST_WIDE_INT const_bitregion_start, const_bitregion_end;
@@ -5092,11 +5120,11 @@ verify_array_eq (unsigned char *x, unsigned char *y, unsigned int n)
     }
 }
 
-/* Test shift_bytes_in_array and that it carries bits across between
+/* Test shift_bytes_in_array_left and that it carries bits across between
    bytes correctly.  */
 
 static void
-verify_shift_bytes_in_array (void)
+verify_shift_bytes_in_array_left (void)
 {
    /* byte 1   | byte 0
       00011111 | 11100000.  */
@@ -5105,13 +5133,13 @@ verify_shift_bytes_in_array (void)
   memcpy (in, orig, sizeof orig);
 
   unsigned char expected[2] = { 0x80, 0x7f };
-  shift_bytes_in_array (in, sizeof (in), 2);
+  shift_bytes_in_array_left (in, sizeof (in), 2);
   verify_array_eq (in, expected, sizeof (in));
 
   memcpy (in, orig, sizeof orig);
   memcpy (expected, orig, sizeof orig);
   /* Check that shifting by zero doesn't change anything.  */
-  shift_bytes_in_array (in, sizeof (in), 0);
+  shift_bytes_in_array_left (in, sizeof (in), 0);
   verify_array_eq (in, expected, sizeof (in));
 
 }
@@ -5196,7 +5224,7 @@ verify_clear_bit_region_be (void)
 void
 store_merging_c_tests (void)
 {
-  verify_shift_bytes_in_array ();
+  verify_shift_bytes_in_array_left ();
   verify_shift_bytes_in_array_right ();
   verify_clear_bit_region ();
   verify_clear_bit_region_be ();