diff options
author | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2020-07-03 18:10:25 +0200 |
---|---|---|
committer | Eric Botcazou <ebotcazou@gcc.gnu.org> | 2020-07-03 18:31:04 +0200 |
commit | e362a897655e3b92949b65a2b53e00fb3ab8ded0 (patch) | |
tree | 4a6123efd03f9969c0a3124c6add9061e421a983 /gcc/gimple-fold.c | |
parent | b9a15a8325ba89b926e3c437b7961829a6b2fa2b (diff) | |
download | gcc-e362a897655e3b92949b65a2b53e00fb3ab8ded0.zip gcc-e362a897655e3b92949b65a2b53e00fb3ab8ded0.tar.gz gcc-e362a897655e3b92949b65a2b53e00fb3ab8ded0.tar.bz2 |
Extend store merging to STRING_CST
The GIMPLE store merging pass doesn't merge STRING_CSTs in the general
case, although they are accepted by native_encode_expr; the reason is
that the pass only works with integral modes, i.e. with chunks whose
size is a power of two.
There are two possible ways of extending it to handle STRING_CSTs:
1) lift the condition of integral modes and treat STRING_CSTs as
other _CST nodes but with arbitrary size; 2) implement a specific
and separate handling for STRING_CSTs.
The attached patch implements 2) for the following reasons: on the
one hand, even in Ada where character strings are first-class citizens,
cases where merging STRING_CSTs with other *_CST nodes would be possible
are quite rare in practice; on the other hand, string concatenations
happen more naturally and frequently thanks to the "&" operator, giving
rise to merging opportunities.
gcc/ChangeLog:
* gimple-fold.c (gimple_fold_builtin_memory_op): Fold calls that
were initially created for the assignment of a variable-sized
object and whose source is now a string constant.
* gimple-ssa-store-merging.c (struct merged_store_group): Document
STRING_CST for rhs_code field.
Add string_concatenation boolean field.
(merged_store_group::merged_store_group): Initialize it as well as
bit_insertion here.
(merged_store_group::do_merge): Set it upon seeing a STRING_CST.
Also set bit_insertion here upon seeing a BIT_INSERT_EXPR.
(merged_store_group::apply_stores): Clear it for small regions.
Do not create a power-of-2-sized buffer if it is still true.
And do not set bit_insertion here again.
(encode_tree_to_bitpos): Deal with BLKmode for the expression.
(merged_store_group::can_be_merged_into): Deal with STRING_CST.
(imm_store_chain_info::coalesce_immediate_stores): Set bit_insertion
to true after changing MEM_REF stores into BIT_INSERT_EXPR stores.
(count_multiple_uses): Return 0 for STRING_CST.
(split_group): Do not split the group for a string concatenation.
(imm_store_chain_info::output_merged_store): Constify and rename
some local variables. Build an array type as destination type
for a string concatenation, as well as a zero mask, and call
build_string to build the source.
(lhs_valid_for_store_merging_p): Return true for VIEW_CONVERT_EXPR.
(pass_store_merging::process_store): Accept STRING_CST on the RHS.
* gimple.h (gimple_call_alloca_for_var_p): New accessor function.
* gimplify.c (gimplify_modify_expr_to_memcpy): Set alloca_for_var.
* tree.h (CALL_ALLOCA_FOR_VAR_P): Document it for BUILT_IN_MEMCPY.
gcc/testsuite/ChangeLog:
* gnat.dg/opt87.adb: New test.
* gnat.dg/opt87_pkg.ads: New helper.
* gnat.dg/opt87_pkg.adb: Likewise.
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r-- | gcc/gimple-fold.c | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 4e3de95..72c5e43 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -700,7 +700,6 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, gimple *stmt = gsi_stmt (*gsi); tree lhs = gimple_call_lhs (stmt); tree len = gimple_call_arg (stmt, 2); - tree destvar, srcvar; location_t loc = gimple_location (stmt); /* If the LEN parameter is a constant zero or in range where @@ -741,7 +740,7 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, } else { - tree srctype, desttype; + tree srctype, desttype, destvar, srcvar, srcoff; unsigned int src_align, dest_align; tree off0; const char *tmp_str; @@ -991,7 +990,9 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, /* Choose between src and destination type for the access based on alignment, whether the access constitutes a register access and whether it may actually expose a declaration for SSA rewrite - or SRA decomposition. */ + or SRA decomposition. Also try to expose a string constant, we + might be able to concatenate several of them later into a single + string store. */ destvar = NULL_TREE; srcvar = NULL_TREE; if (TREE_CODE (dest) == ADDR_EXPR @@ -1008,7 +1009,16 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, && (is_gimple_reg_type (srctype) || dest_align >= TYPE_ALIGN (srctype))) srcvar = fold_build2 (MEM_REF, srctype, src, off0); - if (srcvar == NULL_TREE && destvar == NULL_TREE) + /* FIXME: Don't transform copies from strings with known original length. + As soon as strlenopt tests that rely on it for passing are adjusted, + this hack can be removed. */ + else if (gimple_call_alloca_for_var_p (stmt) + && (srcvar = string_constant (src, &srcoff, NULL, NULL)) + && integer_zerop (srcoff) + && tree_int_cst_equal (TYPE_SIZE_UNIT (TREE_TYPE (srcvar)), len) + && dest_align >= TYPE_ALIGN (TREE_TYPE (srcvar))) + srctype = TREE_TYPE (srcvar); + else return false; /* Now that we chose an access type express the other side in @@ -1071,19 +1081,29 @@ 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 (srcvar) == STRING_CST) + desttype = srctype; + + /* 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) |