mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-13 21:01:29 +08:00
Make SRA re-construct orginal memory accesses when easy
2019-06-06 Martin Jambor <mjambor@suse.cz> * tree-sra.c (struct access): New field grp_same_access_path. (dump_access): Dump it. (build_reconstructed_reference): New function. (build_ref_for_model): Use it if possible. (path_comparable_for_same_access): New function. (same_access_path_p): Likewise. (sort_and_splice_var_accesses): Set the new flag. (analyze_access_subtree): Likewise. (propagate_subaccesses_across_link): Propagate zero value of the new flag down the access tree. testsuite/ * gcc.dg/tree-ssa/alias-access-path-1.c: Remove -fno-tree-sra option. * gcc.dg/tree-ssa/ssa-dse-26.c: Disable FRE. * testsuite/gnat.dg/opt39.adb: Adjust scan dump. From-SVN: r272012
This commit is contained in:
parent
beb0086f59
commit
3b47da42de
@ -1,3 +1,16 @@
|
||||
2019-06-06 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* tree-sra.c (struct access): New field grp_same_access_path.
|
||||
(dump_access): Dump it.
|
||||
(build_reconstructed_reference): New function.
|
||||
(build_ref_for_model): Use it if possible.
|
||||
(path_comparable_for_same_access): New function.
|
||||
(same_access_path_p): Likewise.
|
||||
(sort_and_splice_var_accesses): Set the new flag.
|
||||
(analyze_access_subtree): Likewise.
|
||||
(propagate_subaccesses_across_link): Propagate zero value of the new
|
||||
flag down the access tree.
|
||||
|
||||
2019-06-06 Andrew Stubbs <ams@codesourcery.com>
|
||||
|
||||
* config.gcc (amdgcn-*-*): Allow --with-arch=gfx906.
|
||||
|
@ -1,3 +1,9 @@
|
||||
2019-06-06 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* gcc.dg/tree-ssa/alias-access-path-1.c: Remove -fno-tree-sra option.
|
||||
* gcc.dg/tree-ssa/ssa-dse-26.c: Disable FRE.
|
||||
* gnat.dg/opt39.adb: Adjust scan dump.
|
||||
|
||||
2019-06-06 Jozef Lawrynowicz <jozef.l@mittosystems.com>
|
||||
|
||||
* gcc.target/msp430/size-optimized-shifts.c: New test.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-fre3 -fno-tree-sra" } */
|
||||
/* { dg-options "-O2 -fdump-tree-fre3" } */
|
||||
struct foo
|
||||
{
|
||||
int val;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-dse1-details -fno-short-enums" } */
|
||||
/* { dg-options "-O2 -fdump-tree-dse1-details -fno-short-enums -fno-tree-fre" } */
|
||||
/* { dg-skip-if "temporary variable for constraint_expr is never used" { msp430-*-* } } */
|
||||
|
||||
enum constraint_expr_type
|
||||
|
@ -27,4 +27,5 @@ begin
|
||||
end if;
|
||||
end;
|
||||
|
||||
-- { dg-final { scan-tree-dump-times "MEM" 1 "optimized" } }
|
||||
-- { dg-final { scan-tree-dump-not "MEM" "optimized" } }
|
||||
-- { dg-final { scan-tree-dump-not "tmp" "optimized" } }
|
||||
|
135
gcc/tree-sra.c
135
gcc/tree-sra.c
@ -106,6 +106,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "ipa-utils.h"
|
||||
#include "builtins.h"
|
||||
|
||||
|
||||
/* Enumeration of all aggregate reductions we can do. */
|
||||
enum sra_mode { SRA_MODE_EARLY_IPA, /* early call regularization */
|
||||
SRA_MODE_EARLY_INTRA, /* early intraprocedural SRA */
|
||||
@ -242,6 +243,10 @@ struct access
|
||||
access tree. */
|
||||
unsigned grp_unscalarized_data : 1;
|
||||
|
||||
/* Set if all accesses in the group consist of the same chain of
|
||||
COMPONENT_REFs and ARRAY_REFs. */
|
||||
unsigned grp_same_access_path : 1;
|
||||
|
||||
/* Does this access and/or group contain a write access through a
|
||||
BIT_FIELD_REF? */
|
||||
unsigned grp_partial_lhs : 1;
|
||||
@ -443,16 +448,18 @@ dump_access (FILE *f, struct access *access, bool grp)
|
||||
"grp_scalar_write = %d, grp_total_scalarization = %d, "
|
||||
"grp_hint = %d, grp_covered = %d, "
|
||||
"grp_unscalarizable_region = %d, grp_unscalarized_data = %d, "
|
||||
"grp_partial_lhs = %d, grp_to_be_replaced = %d, "
|
||||
"grp_to_be_debug_replaced = %d, grp_maybe_modified = %d, "
|
||||
"grp_same_access_path = %d, grp_partial_lhs = %d, "
|
||||
"grp_to_be_replaced = %d, grp_to_be_debug_replaced = %d, "
|
||||
"grp_maybe_modified = %d, "
|
||||
"grp_not_necessarilly_dereferenced = %d\n",
|
||||
access->grp_read, access->grp_write, access->grp_assignment_read,
|
||||
access->grp_assignment_write, access->grp_scalar_read,
|
||||
access->grp_scalar_write, access->grp_total_scalarization,
|
||||
access->grp_hint, access->grp_covered,
|
||||
access->grp_unscalarizable_region, access->grp_unscalarized_data,
|
||||
access->grp_partial_lhs, access->grp_to_be_replaced,
|
||||
access->grp_to_be_debug_replaced, access->grp_maybe_modified,
|
||||
access->grp_same_access_path, access->grp_partial_lhs,
|
||||
access->grp_to_be_replaced, access->grp_to_be_debug_replaced,
|
||||
access->grp_maybe_modified,
|
||||
access->grp_not_necessarilly_dereferenced);
|
||||
else
|
||||
fprintf (f, ", write = %d, grp_total_scalarization = %d, "
|
||||
@ -1795,6 +1802,30 @@ build_ref_for_offset (location_t loc, tree base, poly_int64 offset,
|
||||
return mem_ref;
|
||||
}
|
||||
|
||||
/* Construct and return a memory reference that is equal to a portion of
|
||||
MODEL->expr but is based on BASE. If this cannot be done, return NULL. */
|
||||
|
||||
static tree
|
||||
build_reconstructed_reference (location_t, tree base, struct access *model)
|
||||
{
|
||||
tree expr = model->expr, prev_expr = NULL;
|
||||
while (!types_compatible_p (TREE_TYPE (expr), TREE_TYPE (base)))
|
||||
{
|
||||
if (!handled_component_p (expr))
|
||||
return NULL;
|
||||
prev_expr = expr;
|
||||
expr = TREE_OPERAND (expr, 0);
|
||||
}
|
||||
|
||||
if (get_object_alignment (base) < get_object_alignment (expr))
|
||||
return NULL;
|
||||
|
||||
TREE_OPERAND (prev_expr, 0) = base;
|
||||
tree ref = unshare_expr (model->expr);
|
||||
TREE_OPERAND (prev_expr, 0) = expr;
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* Construct a memory reference to a part of an aggregate BASE at the given
|
||||
OFFSET and of the same type as MODEL. In case this is a reference to a
|
||||
bit-field, the function will replicate the last component_ref of model's
|
||||
@ -1822,9 +1853,19 @@ build_ref_for_model (location_t loc, tree base, HOST_WIDE_INT offset,
|
||||
NULL_TREE);
|
||||
}
|
||||
else
|
||||
return
|
||||
build_ref_for_offset (loc, base, offset, model->reverse, model->type,
|
||||
gsi, insert_after);
|
||||
{
|
||||
tree res;
|
||||
if (model->grp_same_access_path
|
||||
&& !TREE_THIS_VOLATILE (base)
|
||||
&& offset <= model->offset
|
||||
/* build_reconstructed_reference can still fail if we have already
|
||||
massaged BASE because of another type incompatibility. */
|
||||
&& (res = build_reconstructed_reference (loc, base, model)))
|
||||
return res;
|
||||
else
|
||||
return build_ref_for_offset (loc, base, offset, model->reverse,
|
||||
model->type, gsi, insert_after);
|
||||
}
|
||||
}
|
||||
|
||||
/* Attempt to build a memory reference that we could but into a gimple
|
||||
@ -2076,6 +2117,69 @@ find_var_candidates (void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return true if EXP is a reference chain of COMPONENT_REFs and AREAY_REFs
|
||||
ending either with a DECL or a MEM_REF with zero offset. */
|
||||
|
||||
static bool
|
||||
path_comparable_for_same_access (tree expr)
|
||||
{
|
||||
while (handled_component_p (expr))
|
||||
{
|
||||
if (TREE_CODE (expr) == ARRAY_REF)
|
||||
{
|
||||
/* SSA name indices can occur here too when the array is of sie one.
|
||||
But we cannot just re-use array_refs with SSA names elsewhere in
|
||||
the function, so disallow non-constant indices. TODO: Remove this
|
||||
limitation after teaching build_reconstructed_reference to replace
|
||||
the index with the index type lower bound. */
|
||||
if (TREE_CODE (TREE_OPERAND (expr, 1)) != INTEGER_CST)
|
||||
return false;
|
||||
}
|
||||
expr = TREE_OPERAND (expr, 0);
|
||||
}
|
||||
|
||||
if (TREE_CODE (expr) == MEM_REF)
|
||||
{
|
||||
if (!zerop (TREE_OPERAND (expr, 1)))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
gcc_assert (DECL_P (expr));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Assuming that EXP1 consists of only COMPONENT_REFs and ARRAY_REFs, return
|
||||
true if the chain of these handled components are exactly the same as EXP2
|
||||
and the expression under them is the same DECL or an equivalent MEM_REF.
|
||||
The reference picked by compare_access_positions must go to EXP1. */
|
||||
|
||||
static bool
|
||||
same_access_path_p (tree exp1, tree exp2)
|
||||
{
|
||||
if (TREE_CODE (exp1) != TREE_CODE (exp2))
|
||||
{
|
||||
/* Special case single-field structures loaded sometimes as the field
|
||||
and sometimes as the structure. If the field is of a scalar type,
|
||||
compare_access_positions will put it into exp1.
|
||||
|
||||
TODO: The gimple register type condition can be removed if teach
|
||||
compare_access_positions to put inner types first. */
|
||||
if (is_gimple_reg_type (TREE_TYPE (exp1))
|
||||
&& TREE_CODE (exp1) == COMPONENT_REF
|
||||
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (exp1, 0)))
|
||||
== TYPE_MAIN_VARIANT (TREE_TYPE (exp2))))
|
||||
exp1 = TREE_OPERAND (exp1, 0);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!operand_equal_p (exp1, exp2, OEP_ADDRESS_OF))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Sort all accesses for the given variable, check for partial overlaps and
|
||||
return NULL if there are any. If there are none, pick a representative for
|
||||
each combination of offset and size and create a linked list out of them.
|
||||
@ -2116,6 +2220,7 @@ sort_and_splice_var_accesses (tree var)
|
||||
bool grp_partial_lhs = access->grp_partial_lhs;
|
||||
bool first_scalar = is_gimple_reg_type (access->type);
|
||||
bool unscalarizable_region = access->grp_unscalarizable_region;
|
||||
bool grp_same_access_path = true;
|
||||
bool bf_non_full_precision
|
||||
= (INTEGRAL_TYPE_P (access->type)
|
||||
&& TYPE_PRECISION (access->type) != access->size
|
||||
@ -2134,6 +2239,8 @@ sort_and_splice_var_accesses (tree var)
|
||||
gcc_assert (access->offset >= low
|
||||
&& access->offset + access->size <= high);
|
||||
|
||||
grp_same_access_path = path_comparable_for_same_access (access->expr);
|
||||
|
||||
j = i + 1;
|
||||
while (j < access_count)
|
||||
{
|
||||
@ -2184,6 +2291,11 @@ sort_and_splice_var_accesses (tree var)
|
||||
}
|
||||
unscalarizable_region = true;
|
||||
}
|
||||
|
||||
if (grp_same_access_path
|
||||
&& !same_access_path_p (access->expr, ac2->expr))
|
||||
grp_same_access_path = false;
|
||||
|
||||
ac2->group_representative = access;
|
||||
j++;
|
||||
}
|
||||
@ -2202,6 +2314,7 @@ sort_and_splice_var_accesses (tree var)
|
||||
access->grp_total_scalarization = total_scalarization;
|
||||
access->grp_partial_lhs = grp_partial_lhs;
|
||||
access->grp_unscalarizable_region = unscalarizable_region;
|
||||
access->grp_same_access_path = grp_same_access_path;
|
||||
|
||||
*prev_acc_ptr = access;
|
||||
prev_acc_ptr = &access->next_grp;
|
||||
@ -2471,6 +2584,8 @@ analyze_access_subtree (struct access *root, struct access *parent,
|
||||
root->grp_assignment_write = 1;
|
||||
if (parent->grp_total_scalarization)
|
||||
root->grp_total_scalarization = 1;
|
||||
if (!parent->grp_same_access_path)
|
||||
root->grp_same_access_path = 0;
|
||||
}
|
||||
|
||||
if (root->grp_unscalarizable_region)
|
||||
@ -2721,13 +2836,17 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
|
||||
lacc->type = racc->type;
|
||||
if (build_user_friendly_ref_for_offset (&t, TREE_TYPE (t),
|
||||
lacc->offset, racc->type))
|
||||
lacc->expr = t;
|
||||
{
|
||||
lacc->expr = t;
|
||||
lacc->grp_same_access_path = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lacc->expr = build_ref_for_model (EXPR_LOCATION (lacc->base),
|
||||
lacc->base, lacc->offset,
|
||||
racc, NULL, false);
|
||||
lacc->grp_no_warning = true;
|
||||
lacc->grp_same_access_path = false;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
Loading…
x
Reference in New Issue
Block a user