> 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)