This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Make SRA produce less useless statements
- From: Richard Guenther <rguenther at suse dot de>
- To: Martin Jambor <mjambor at suse dot cz>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 6 Oct 2010 17:39:09 +0200 (CEST)
- Subject: Re: [PATCH] Make SRA produce less useless statements
- References: <20101006152810.GA24623@virgil.arch.suse.de>
On Wed, 6 Oct 2010, Martin Jambor wrote:
> Hi,
>
> SRA currently creates a useless s1$i replacement for:
>
> struct S
> {
> int i;
> int j;
> char c[32]; /* this disables total scalarization in foo2 */
> };
>
> extern struct S bar(void);
>
> int foo1 (int b)
> {
> struct S s1;
>
> s1 = bar ();
> return s1.i;
> }
>
> The reason why we do our heristics this way is to make sure we
> scalarize away s2 in:
>
> extern struct S *g;
>
> int foo2 (void)
> {
> struct S s2;
>
> s2 = *g;
> return s2.i;
> }
>
> But we can do both if we differentiate between assignment and
> non-assignment parent access writes exactly like we already do for
> reads. This patch avoids SRA in the first example while making sure
> it still happens in the second one.
>
> Bootstrapped and tested on x86_64-linux. OK for trunk?
Ok.
Thanks,
Richard.
> Thanks,
>
> Martin
>
>
> 2010-10-06 Martin Jambor <mjambor@suse.cz>
>
> * tree-sra.c (struct access): New field grp_assignment_write.
> (dump_access): Dump grp_assignment_write.
> (build_accesses_from_assign): Set grp_assignment_write.
> (sort_and_splice_var_accesses): Aggregate grp_assignment_write.
> (mark_read_status): Renamed to mark_rw_status, individual values
> renamed too.
> (analyze_access_subtree): Changed type of mark_write to
> mark_read_status. Fixed propagating of mark_read and
> mark_write. Changed benefit estimate. Updated comment.
>
> * testsuite/gcc.dg/tree-ssa/sra-11.c: New test.
>
> Index: mine/gcc/testsuite/gcc.dg/tree-ssa/sra-11.c
> ===================================================================
> *** /dev/null
> --- mine/gcc/testsuite/gcc.dg/tree-ssa/sra-11.c
> ***************
> *** 0 ****
> --- 1,33 ----
> + /* { dg-do compile } */
> + /* { dg-options "-O1 -fdump-tree-esra-details" } */
> +
> + struct S
> + {
> + int i;
> + int j;
> + char c[32]; /* this disables total scalarization */
> + };
> +
> + extern struct S bar(void);
> +
> + int foo1 (int b)
> + {
> + struct S s1;
> +
> + s1 = bar ();
> + return s1.i;
> + }
> +
> + extern struct S *g;
> +
> + int foo2 (void)
> + {
> + struct S s2;
> +
> + s2 = *g;
> + return s2.i;
> + }
> +
> + /* { dg-final { scan-tree-dump-times "Created a replacement for s1" 0 "esra"} } */
> + /* { dg-final { scan-tree-dump-times "Created a replacement for s2" 1 "esra"} } */
> + /* { dg-final { cleanup-tree-dump "esra" } } */
> Index: mine/gcc/tree-sra.c
> ===================================================================
> *** mine.orig/gcc/tree-sra.c
> --- mine/gcc/tree-sra.c
> *************** struct access
> *** 189,194 ****
> --- 189,198 ----
> statement? This flag is propagated down the access tree. */
> unsigned grp_assignment_read : 1;
>
> + /* Does this group contain a write access that comes from an assignment
> + statement? This flag is propagated down the access tree. */
> + unsigned grp_assignment_write : 1;
> +
> /* Other passes of the analysis use this bit to make function
> analyze_access_subtree create scalar replacements for this group if
> possible. */
> *************** dump_access (FILE *f, struct access *acc
> *** 364,378 ****
> if (grp)
> fprintf (f, ", grp_write = %d, total_scalarization = %d, "
> "grp_read = %d, grp_hint = %d, grp_assignment_read = %d,"
> ! "grp_covered = %d, grp_unscalarizable_region = %d, "
> ! "grp_unscalarized_data = %d, grp_partial_lhs = %d, "
> ! "grp_to_be_replaced = %d, grp_maybe_modified = %d, "
> "grp_not_necessarilly_dereferenced = %d\n",
> access->grp_write, access->total_scalarization,
> access->grp_read, access->grp_hint, access->grp_assignment_read,
> ! access->grp_covered, access->grp_unscalarizable_region,
> ! access->grp_unscalarized_data, access->grp_partial_lhs,
> ! access->grp_to_be_replaced, access->grp_maybe_modified,
> access->grp_not_necessarilly_dereferenced);
> else
> fprintf (f, ", write = %d, total_scalarization = %d, "
> --- 368,384 ----
> if (grp)
> fprintf (f, ", grp_write = %d, total_scalarization = %d, "
> "grp_read = %d, grp_hint = %d, grp_assignment_read = %d,"
> ! "grp_assignment_write = %d, grp_covered = %d, "
> ! "grp_unscalarizable_region = %d, grp_unscalarized_data = %d, "
> ! "grp_partial_lhs = %d, grp_to_be_replaced = %d, "
> ! "grp_maybe_modified = %d, "
> "grp_not_necessarilly_dereferenced = %d\n",
> access->grp_write, access->total_scalarization,
> access->grp_read, access->grp_hint, access->grp_assignment_read,
> ! access->grp_assignment_write, access->grp_covered,
> ! access->grp_unscalarizable_region, access->grp_unscalarized_data,
> ! access->grp_partial_lhs, access->grp_to_be_replaced,
> ! access->grp_maybe_modified,
> access->grp_not_necessarilly_dereferenced);
> else
> fprintf (f, ", write = %d, total_scalarization = %d, "
> *************** build_accesses_from_assign (gimple stmt)
> *** 1019,1024 ****
> --- 1025,1033 ----
> racc = build_access_from_expr_1 (rhs, stmt, false);
> lacc = build_access_from_expr_1 (lhs, stmt, true);
>
> + if (lacc)
> + lacc->grp_assignment_write = 1;
> +
> if (racc)
> {
> racc->grp_assignment_read = 1;
> *************** sort_and_splice_var_accesses (tree var)
> *** 1581,1586 ****
> --- 1590,1596 ----
> bool grp_write = access->write;
> bool grp_read = !access->write;
> bool grp_assignment_read = access->grp_assignment_read;
> + bool grp_assignment_write = access->grp_assignment_write;
> bool multiple_reads = false;
> bool total_scalarization = access->total_scalarization;
> bool grp_partial_lhs = access->grp_partial_lhs;
> *************** sort_and_splice_var_accesses (tree var)
> *** 1615,1620 ****
> --- 1625,1631 ----
> grp_read = true;
> }
> grp_assignment_read |= ac2->grp_assignment_read;
> + grp_assignment_write |= ac2->grp_assignment_write;
> grp_partial_lhs |= ac2->grp_partial_lhs;
> unscalarizable_region |= ac2->grp_unscalarizable_region;
> total_scalarization |= ac2->total_scalarization;
> *************** sort_and_splice_var_accesses (tree var)
> *** 1634,1639 ****
> --- 1645,1651 ----
> access->grp_write = grp_write;
> access->grp_read = grp_read;
> access->grp_assignment_read = grp_assignment_read;
> + access->grp_assignment_write = grp_assignment_write;
> access->grp_hint = multiple_reads || total_scalarization;
> access->grp_partial_lhs = grp_partial_lhs;
> access->grp_unscalarizable_region = unscalarizable_region;
> *************** expr_with_var_bounded_array_refs_p (tree
> *** 1822,1838 ****
> return false;
> }
>
> ! enum mark_read_status { SRA_MR_NOT_READ, SRA_MR_READ, SRA_MR_ASSIGN_READ};
>
> /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when
> both seeming beneficial and when ALLOW_REPLACEMENTS allows it. Also set all
> sorts of access flags appropriately along the way, notably always set
> grp_read and grp_assign_read according to MARK_READ and grp_write when
> ! MARK_WRITE is true. */
>
> static bool
> analyze_access_subtree (struct access *root, bool allow_replacements,
> ! enum mark_read_status mark_read, bool mark_write)
> {
> struct access *child;
> HOST_WIDE_INT limit = root->offset + root->size;
> --- 1834,1883 ----
> return false;
> }
>
> ! enum mark_rw_status { SRA_MRRW_NOTHING, SRA_MRRW_DIRECT, SRA_MRRW_ASSIGN};
>
> /* Analyze the subtree of accesses rooted in ROOT, scheduling replacements when
> both seeming beneficial and when ALLOW_REPLACEMENTS allows it. Also set all
> sorts of access flags appropriately along the way, notably always set
> grp_read and grp_assign_read according to MARK_READ and grp_write when
> ! MARK_WRITE is true.
> !
> ! Creating a replacement for a scalar access is considered beneficial if its
> ! grp_hint is set (this means we are either attempting total scalarization or
> ! there is more than one direct read access) or according to the following
> ! table:
> !
> ! Access written to individually (once or more times)
> ! |
> ! | Parent written to in an assignment statement
> ! | |
> ! | | Access read individually _once_
> ! | | |
> ! | | | Parent read in an assignment statement
> ! | | | |
> ! | | | | Scalarize Comment
> ! -----------------------------------------------------------------------------
> ! 0 0 0 0 No access for the scalar
> ! 0 0 0 1 No access for the scalar
> ! 0 0 1 0 No Single read - won't help
> ! 0 0 1 1 No The same case
> ! 0 1 0 0 No access for the scalar
> ! 0 1 0 1 No access for the scalar
> ! 0 1 1 0 Yes s = *g; return s.i;
> ! 0 1 1 1 Yes The same case as above
> ! 1 0 0 0 No Won't help
> ! 1 0 0 1 Yes s.i = 1; *g = s;
> ! 1 0 1 0 Yes s.i = 5; g = s.i;
> ! 1 0 1 1 Yes The same case as above
> ! 1 1 0 0 No Won't help.
> ! 1 1 0 1 Yes s.i = 1; *g = s;
> ! 1 1 1 0 Yes s = *g; return s.i;
> ! 1 1 1 1 Yes Any of the above yeses */
>
> static bool
> analyze_access_subtree (struct access *root, bool allow_replacements,
> ! enum mark_rw_status mark_read,
> ! enum mark_rw_status mark_write)
> {
> struct access *child;
> HOST_WIDE_INT limit = root->offset + root->size;
> *************** analyze_access_subtree (struct access *r
> *** 1840,1862 ****
> bool scalar = is_gimple_reg_type (root->type);
> bool hole = false, sth_created = false;
> bool direct_read = root->grp_read;
>
> ! if (mark_read == SRA_MR_ASSIGN_READ)
> {
> root->grp_read = 1;
> root->grp_assignment_read = 1;
> }
> ! if (mark_read == SRA_MR_READ)
> root->grp_read = 1;
> - else if (root->grp_assignment_read)
> - mark_read = SRA_MR_ASSIGN_READ;
> else if (root->grp_read)
> ! mark_read = SRA_MR_READ;
>
> ! if (mark_write)
> ! root->grp_write = true;
> else if (root->grp_write)
> ! mark_write = true;
>
> if (root->grp_unscalarizable_region)
> allow_replacements = false;
> --- 1885,1915 ----
> bool scalar = is_gimple_reg_type (root->type);
> bool hole = false, sth_created = false;
> bool direct_read = root->grp_read;
> + bool direct_write = root->grp_write;
>
> ! if (root->grp_assignment_read)
> ! mark_read = SRA_MRRW_ASSIGN;
> ! else if (mark_read == SRA_MRRW_ASSIGN)
> {
> root->grp_read = 1;
> root->grp_assignment_read = 1;
> }
> ! else if (mark_read == SRA_MRRW_DIRECT)
> root->grp_read = 1;
> else if (root->grp_read)
> ! mark_read = SRA_MRRW_DIRECT;
>
> ! if (root->grp_assignment_write)
> ! mark_write = SRA_MRRW_ASSIGN;
> ! else if (mark_write == SRA_MRRW_ASSIGN)
> ! {
> ! root->grp_write = 1;
> ! root->grp_assignment_write = 1;
> ! }
> ! else if (mark_write == SRA_MRRW_DIRECT)
> ! root->grp_write = 1;
> else if (root->grp_write)
> ! mark_write = SRA_MRRW_DIRECT;
>
> if (root->grp_unscalarizable_region)
> allow_replacements = false;
> *************** analyze_access_subtree (struct access *r
> *** 1881,1887 ****
>
> if (allow_replacements && scalar && !root->first_child
> && (root->grp_hint
> ! || (root->grp_write && (direct_read || root->grp_assignment_read))))
> {
> if (dump_file && (dump_flags & TDF_DETAILS))
> {
> --- 1934,1941 ----
>
> if (allow_replacements && scalar && !root->first_child
> && (root->grp_hint
> ! || ((direct_write || root->grp_assignment_write)
> ! && (direct_read || root->grp_assignment_read))))
> {
> if (dump_file && (dump_flags & TDF_DETAILS))
> {
> *************** analyze_access_trees (struct access *acc
> *** 1920,1926 ****
>
> while (access)
> {
> ! if (analyze_access_subtree (access, true, SRA_MR_NOT_READ, false))
> ret = true;
> access = access->next_grp;
> }
> --- 1974,1981 ----
>
> while (access)
> {
> ! if (analyze_access_subtree (access, true,
> ! SRA_MRRW_NOTHING, SRA_MRRW_NOTHING))
> ret = true;
> access = access->next_grp;
> }
>
>
--
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746 - GF: Markus Rex