This moves the code used in optimize_agr_copyprop_1 (r16-3887-g597b50abb0d) to handle this same case into its new function and use it inside optimize_agr_copyprop_arg. This allows to remove more copies that show up only in arguments.
Bootstrapped and tested on x86_64-linux-gnu. gcc/ChangeLog: * tree-ssa-forwprop.cc (optimize_agr_copyprop_1): Split out the case where `operand_equal_p (dest, src2)` is false into ... (new_src_based_on_copy): This. New function. (optimize_agr_copyprop_arg): Use new_src_based_on_copy instead of operand_equal_p to find the new src. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c: New test. Signed-off-by: Andrew Pinski <andrew.pin...@oss.qualcomm.com> --- .../tree-ssa/copy-prop-aggregate-arg-2.c | 33 +++++ gcc/tree-ssa-forwprop.cc | 135 ++++++++++-------- 2 files changed, 106 insertions(+), 62 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c new file mode 100644 index 00000000000..11f0768c111 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-arg-2.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fdump-tree-optimized" } */ + + +struct s1 +{ + int t[1024]; +}; + +struct s2 { + struct s1 t; +}; + +struct s3 +{ + struct s2 t; +}; + +void g(struct s3); + +void f(struct s1 s) +{ + struct s2 removeme; + removeme.t = s; + struct s3 removeme2; + removeme2.t = removeme; + g(removeme2); +} + + +/* { dg-final { scan-tree-dump-times "after previous" 2 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-not "removeme " "optimized" } } */ +/* { dg-final { scan-tree-dump-not "removeme2 " "optimized" } } */ diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc index 1eacff01587..f58a7b8c591 100644 --- a/gcc/tree-ssa-forwprop.cc +++ b/gcc/tree-ssa-forwprop.cc @@ -1458,6 +1458,72 @@ split_core_and_offset_size (tree expr, return core; } +/* Returns a new src based on the + copy `DEST = SRC` and for the old SRC2. + Returns null if SRC2 is not related to DEST. */ + +static tree +new_src_based_on_copy (tree src2, tree dest, tree src) +{ + /* If the second src is not exactly the same as dest, + try to handle it seperately; see it is address/size equivalent. + Handles `a` and `a.b` and `MEM<char[N]>(&a)` which all have + the same size and offsets as address/size equivalent. + This allows copying over a memcpy and also one for copying + where one field is the same size as the whole struct. */ + if (operand_equal_p (dest, src2)) + return src; + /* A VCE can't be used with imag/real or BFR so reject them early. */ + if (TREE_CODE (src) == IMAGPART_EXPR + || TREE_CODE (src) == REALPART_EXPR + || TREE_CODE (src) == BIT_FIELD_REF) + return NULL_TREE; + tree core1, core2; + poly_int64 bytepos1, bytepos2; + poly_int64 bytesize1, bytesize2; + tree toffset1, toffset2; + int reversep1 = 0; + int reversep2 = 0; + poly_int64 diff = 0; + core1 = split_core_and_offset_size (dest, &bytesize1, &bytepos1, + &toffset1, &reversep1); + core2 = split_core_and_offset_size (src2, &bytesize2, &bytepos2, + &toffset2, &reversep2); + if (!core1 || !core2) + return NULL_TREE; + if (reversep1 != reversep2) + return NULL_TREE; + /* The sizes of the 2 accesses need to be the same. */ + if (!known_eq (bytesize1, bytesize2)) + return NULL_TREE; + if (!operand_equal_p (core1, core2, 0)) + return NULL_TREE; + + if (toffset1 && toffset2) + { + tree type = TREE_TYPE (toffset1); + if (type != TREE_TYPE (toffset2)) + toffset2 = fold_convert (type, toffset2); + + tree tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2); + if (!cst_and_fits_in_hwi (tdiff)) + return NULL_TREE; + + diff = int_cst_value (tdiff); + } + else if (toffset1 || toffset2) + { + /* If only one of the offsets is non-constant, the difference cannot + be a constant. */ + return NULL_TREE; + } + diff += bytepos1 - bytepos2; + /* The offset between the 2 need to be 0. */ + if (!known_eq (diff, 0)) + return NULL_TREE; + return fold_build1 (VIEW_CONVERT_EXPR,TREE_TYPE (src2), src); +} + /* Helper function for optimize_agr_copyprop. For aggregate copies in USE_STMT, see if DEST is on the lhs of USE_STMT and replace it with SRC. */ @@ -1474,66 +1540,9 @@ optimize_agr_copyprop_1 (gimple *stmt, gimple *use_stmt, /* If the new store is `src2 = src2;` skip over it. */ if (operand_equal_p (src2, dest2, 0)) return false; - /* If the second src is not exactly the same as dest, - try to handle it seperately; see it is address/size equivalent. - Handles `a` and `a.b` and `MEM<char[N]>(&a)` which all have - the same size and offsets as address/size equivalent. - This allows copying over a memcpy and also one for copying - where one field is the same size as the whole struct. */ - if (!operand_equal_p (dest, src2, 0)) - { - /* A VCE can't be used with imag/real or BFR so reject them early. */ - if (TREE_CODE (src) == IMAGPART_EXPR - || TREE_CODE (src) == REALPART_EXPR - || TREE_CODE (src) == BIT_FIELD_REF) - return false; - tree core1, core2; - poly_int64 bytepos1, bytepos2; - poly_int64 bytesize1, bytesize2; - tree toffset1, toffset2; - int reversep1 = 0; - int reversep2 = 0; - poly_int64 diff = 0; - core1 = split_core_and_offset_size (dest, &bytesize1, &bytepos1, - &toffset1, &reversep1); - core2 = split_core_and_offset_size (src2, &bytesize2, &bytepos2, - &toffset2, &reversep2); - if (!core1 || !core2) - return false; - if (reversep1 != reversep2) - return false; - /* The sizes of the 2 accesses need to be the same. */ - if (!known_eq (bytesize1, bytesize2)) - return false; - if (!operand_equal_p (core1, core2, 0)) - return false; - - if (toffset1 && toffset2) - { - tree type = TREE_TYPE (toffset1); - if (type != TREE_TYPE (toffset2)) - toffset2 = fold_convert (type, toffset2); - - tree tdiff = fold_build2 (MINUS_EXPR, type, toffset1, toffset2); - if (!cst_and_fits_in_hwi (tdiff)) - return false; - - diff = int_cst_value (tdiff); - } - else if (toffset1 || toffset2) - { - /* If only one of the offsets is non-constant, the difference cannot - be a constant. */ - return false; - } - diff += bytepos1 - bytepos2; - /* The offset between the 2 need to be 0. */ - if (!known_eq (diff, 0)) - return false; - src = fold_build1_loc (gimple_location (use_stmt), - VIEW_CONVERT_EXPR, - TREE_TYPE (src2), src); - } + src = new_src_based_on_copy (src2, dest, src); + if (!src) + return false; /* For 2 memory refences and using a temporary to do the copy, don't remove the temporary as the 2 memory references might overlap. Note t does not need to be decl as it could be field. @@ -1634,8 +1643,10 @@ optimize_agr_copyprop_arg (gimple *defstmt, gcall *call, || is_gimple_min_invariant (*argptr) || TYPE_VOLATILE (TREE_TYPE (*argptr))) continue; - if (!operand_equal_p (*argptr, dest, 0)) + tree newsrc = new_src_based_on_copy (*argptr, dest, src); + if (!newsrc) continue; + if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Simplified\n "); @@ -1643,7 +1654,7 @@ optimize_agr_copyprop_arg (gimple *defstmt, gcall *call, fprintf (dump_file, "after previous\n "); print_gimple_stmt (dump_file, defstmt, 0, dump_flags); } - *argptr = unshare_expr (src); + *argptr = unshare_expr (newsrc); changed = true; if (dump_file && (dump_flags & TDF_DETAILS)) { -- 2.43.0