Hi, this is a followup to Richi's https://gcc.gnu.org/ml/gcc-patches/2017-11/msg02396.html to fix PR 83141. The basic idea is simple, be just as conservative about type changing MEM_REFs as we are about actual VCEs.
I have checked how that would affect compilation of SPEC 2006 and (non LTO) Mozilla Firefox and am happy to report that the difference was tiny. However, I had to make the test less strict, otherwise testcase gcc.dg/guality/pr54970.c kept failing because it contains folded memcpy and expects us to track values accross: int a[] = { 1, 2, 3 }; /* ... */ __builtin_memcpy (&a, (int [3]) { 4, 5, 6 }, sizeof (a)); /* { dg-final { gdb-test 31 "a\[0\]" "4" } } */ /* { dg-final { gdb-test 31 "a\[1\]" "5" } } */ /* { dg-final { gdb-test 31 "a\[2\]" "6" } } */ SRA is able to load replacement of a[0] directly from the temporary array which is apparently necessary to generate proper debug info. I have therefore allowed the current transformation to go forward if the source does not contain any padding or if it is a read-only declaration. I would especially appreciate a review of the type_contains_padding_p predicate as I am not sure it caches all cases. The added call to contains_vce_or_bfcref_p in build_accesses_from_assign is not strictly necessary, it is there to avoid attempting total scalarization in vain. This is also tested by the dump scan in the added testcase. A very similar patch has passed bootstrap and testing on x86_64, this exact one is undergoing both now. OK for trunk if it passes too? Thanks, Martin 2017-12-04 Martin Jambor <mjam...@suse.cz> PR tree-optimization/83141 * tree-sra.c (type_contains_padding_p): New function. (contains_vce_or_bfcref_p): Move up in the file, also test for MEM_REFs implicitely changing types with padding. Remove inline keyword. (build_accesses_from_assign): Check contains_vce_or_bfcref_p before setting bit in should_scalarize_away_bitmap. testsuite/ * gcc.dg/tree-ssa/pr83141.c: New test. --- gcc/testsuite/gcc.dg/tree-ssa/pr83141.c | 31 +++++++++ gcc/tree-sra.c | 116 ++++++++++++++++++++++++++------ 2 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr83141.c diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr83141.c b/gcc/testsuite/gcc.dg/tree-ssa/pr83141.c new file mode 100644 index 00000000000..86caf66025b --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr83141.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-options "-O -fdump-tree-esra-details" } */ + +volatile short vs; +volatile long vl; + +struct A { short s; long i; long j; }; +struct A a, b; +void foo () +{ + struct A c; + __builtin_memcpy (&c, &b, sizeof (struct A)); + __builtin_memcpy (&a, &c, sizeof (struct A)); + + vs = c.s; + vl = c.i; + vl = c.j; +} +int main() +{ + __builtin_memset (&b, 0, sizeof (struct A)); + b.s = 1; + __builtin_memcpy ((char *)&b+2, &b, 2); + foo (); + __builtin_memcpy (&a, (char *)&a+2, 2); + if (a.s != 1) + __builtin_abort (); + return 0; +} + +/* { dg-final { scan-tree-dump-not "Will attempt to totally scalarize" "esra" } } */ diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 866cff0edb0..0a9622e77f8 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -1141,6 +1141,101 @@ contains_view_convert_expr_p (const_tree ref) return false; } +/* Return false if we can determine that TYPE has no padding, otherwise return + true. */ + +static bool +type_contains_padding_p (tree type) +{ + if (is_gimple_reg_type (type)) + return false; + + if (!tree_fits_uhwi_p (TYPE_SIZE (type))) + return true; + + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + { + unsigned HOST_WIDE_INT pos = 0; + for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld)) + if (TREE_CODE (fld) == FIELD_DECL) + { + tree ft = TREE_TYPE (fld); + + if (DECL_BIT_FIELD (fld) + || DECL_PADDING_P (fld) + || !tree_fits_uhwi_p (TYPE_SIZE (ft))) + return true; + + tree t = bit_position (fld); + if (!tree_fits_uhwi_p (t)) + return true; + unsigned HOST_WIDE_INT bp = tree_to_uhwi (t); + if (pos != bp) + return true; + + pos += tree_to_uhwi (TYPE_SIZE (ft)); + if (type_contains_padding_p (ft)) + return true; + } + + if (pos != tree_to_uhwi (TYPE_SIZE (type))) + return true; + + return false; + } + + case ARRAY_TYPE: + return type_contains_padding_p (TYPE_SIZE (type)); + + default: + return true; + } + gcc_unreachable (); +} + +/* Return true if REF contains a MEM_REF that performs type conversion from a + type with padding or any VIEW_CONVERT_EXPR or a COMPONENT_REF with a + bit-field field declaration. */ + +static bool +contains_vce_or_bfcref_p (const_tree ref) +{ + while (true) + { + if (TREE_CODE (ref) == MEM_REF) + { + tree op0 = TREE_OPERAND (ref, 0); + if (TREE_CODE (op0) == ADDR_EXPR) + { + tree mem = TREE_OPERAND (op0, 0); + if ((TYPE_MAIN_VARIANT (TREE_TYPE (ref)) + != TYPE_MAIN_VARIANT (TREE_TYPE (mem))) + && !((DECL_P (mem) && TREE_READONLY (mem)) + || type_contains_padding_p (TREE_TYPE (mem)))) + return true; + + ref = mem; + continue; + } + else + return false; + } + + if (!handled_component_p (ref)) + return false; + + if (TREE_CODE (ref) == VIEW_CONVERT_EXPR + || (TREE_CODE (ref) == COMPONENT_REF + && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))) + return true; + ref = TREE_OPERAND (ref, 0); + } + + return false; +} + /* Search the given tree for a declaration by skipping handled components and exclude it from the candidates. */ @@ -1338,7 +1433,8 @@ build_accesses_from_assign (gimple *stmt) { racc->grp_assignment_read = 1; if (should_scalarize_away_bitmap && !gimple_has_volatile_ops (stmt) - && !is_gimple_reg_type (racc->type)) + && !is_gimple_reg_type (racc->type) + && !contains_vce_or_bfcref_p (rhs)) bitmap_set_bit (should_scalarize_away_bitmap, DECL_UID (racc->base)); if (storage_order_barrier_p (lhs)) racc->grp_unscalarizable_region = 1; @@ -3416,24 +3512,6 @@ get_repl_default_def_ssa_name (struct access *racc) return get_or_create_ssa_default_def (cfun, racc->replacement_decl); } -/* Return true if REF has an VIEW_CONVERT_EXPR or a COMPONENT_REF with a - bit-field field declaration somewhere in it. */ - -static inline bool -contains_vce_or_bfcref_p (const_tree ref) -{ - while (handled_component_p (ref)) - { - if (TREE_CODE (ref) == VIEW_CONVERT_EXPR - || (TREE_CODE (ref) == COMPONENT_REF - && DECL_BIT_FIELD (TREE_OPERAND (ref, 1)))) - return true; - ref = TREE_OPERAND (ref, 0); - } - - return false; -} - /* Examine both sides of the assignment statement pointed to by STMT, replace them with a scalare replacement if there is one and generate copying of replacements if scalarized aggregates have been used in the assignment. GSI -- 2.15.1