> Hmm, that's a good question - so would your patch be replaceable by
> simply amending var_decl_component_p by
> 
>   (var_decl_component_p (TREE_OPERAND (src, 0))
> 
>    || TREE_CODE (TREE_OPERAND (src, 0)) == STRING_CST)
> 
> ?

The gimple_call_alloca_for_var_p (stmt) kludge is still needed though and the 
end of the transformation needs to be adjusted, so I'm not sure it's better.

-- 
Eric Botcazou
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 4e3de95d2d2..6d5670c8e06 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -840,6 +840,32 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
 	    }
 	}
 
+      /* If this was a variable-sized copy operation that has been turned
+	 into a fixed-size string store, typically after inlining, then do
+	 the fixed-size store explicitly.  We might be able to concatenate
+	 several of them later into a single string store.  */
+      if (tree_fits_uhwi_p (len)
+	  && gimple_call_alloca_for_var_p (stmt)
+	  && TREE_CODE (src) == ADDR_EXPR
+	  && TREE_CODE (TREE_OPERAND (src, 0)) == STRING_CST
+	  && tree_int_cst_equal
+	     (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (src, 0))), len)
+	  && BITS_PER_UNIT == 8)
+	{
+	  tree new_src = TREE_OPERAND (src, 0);
+	  tree new_dest
+	    = fold_build2 (MEM_REF, TREE_TYPE (new_src), dest, off0);
+	  gimple *new_stmt = gimple_build_assign (new_dest, new_src);
+	  gimple_move_vops (new_stmt, stmt);
+	  if (!lhs)
+	    {
+	      gsi_replace (gsi, new_stmt, false);
+	      return true;
+	    }
+	  gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
+	  goto done;
+	}
+
       if (code == BUILT_IN_MEMMOVE)
 	{
 	  /* Both DEST and SRC must be pointer types.
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 4e3de95d2d2..52c54ac14be 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1002,7 +1002,9 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
 	      || src_align >= TYPE_ALIGN (desttype)))
 	destvar = fold_build2 (MEM_REF, desttype, dest, off0);
       else if (TREE_CODE (src) == ADDR_EXPR
-	       && var_decl_component_p (TREE_OPERAND (src, 0))
+	       && (var_decl_component_p (TREE_OPERAND (src, 0))
+		   || (TREE_CODE (TREE_OPERAND (src, 0)) == STRING_CST
+		       && gimple_call_alloca_for_var_p (stmt)))
 	       && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len)
 	       && src_align >= TYPE_ALIGN (srctype)
 	       && (is_gimple_reg_type (srctype)
@@ -1071,19 +1073,34 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi,
 	  goto set_vop_and_replace;
 	}
 
-      /* We get an aggregate copy.  Use an unsigned char[] type to
-	 perform the copying to preserve padding and to avoid any issues
-	 with TREE_ADDRESSABLE types or float modes behavior on copying.  */
-      desttype = build_array_type_nelts (unsigned_char_type_node,
-					 tree_to_uhwi (len));
-      srctype = desttype;
-      if (src_align > TYPE_ALIGN (srctype))
-	srctype = build_aligned_type (srctype, src_align);
+      /* We get an aggregate copy.  If the source is a STRING_CST, then
+	 directly use its type to perform the copy.  */
+      if (TREE_CODE (src) == ADDR_EXPR
+	  && TREE_CODE (TREE_OPERAND (src, 0)) == STRING_CST
+	  && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
+	{
+	  desttype = srctype;
+	  srcvar = TREE_OPERAND (src, 0);
+	}
+
+      /* Or else, use an unsigned char[] type to perform the copy in order
+	 to preserve padding and to avoid any issues with TREE_ADDRESSABLE
+	 types or float modes behavior on copying.  */
+      else
+	{
+	  desttype = build_array_type_nelts (unsigned_char_type_node,
+					     tree_to_uhwi (len));
+	  srctype = desttype;
+	  if (src_align > TYPE_ALIGN (srctype))
+	    srctype = build_aligned_type (srctype, src_align);
+	  srcvar = fold_build2 (MEM_REF, srctype, src, off0);
+	}
+
       if (dest_align > TYPE_ALIGN (desttype))
 	desttype = build_aligned_type (desttype, dest_align);
-      new_stmt
-	= gimple_build_assign (fold_build2 (MEM_REF, desttype, dest, off0),
-			       fold_build2 (MEM_REF, srctype, src, off0));
+      destvar = fold_build2 (MEM_REF, desttype, dest, off0);
+      new_stmt = gimple_build_assign (destvar, srcvar);
+
 set_vop_and_replace:
       gimple_move_vops (new_stmt, stmt);
       if (!lhs)

Reply via email to