In gcc/ada/ 2005-03-12 Daniel Berlin <dberlin@dberlin.org>

In gcc/ada/
2005-03-12  Daniel Berlin <dberlin@dberlin.org>

	* misc.c (gnat_post_options): Turn off structural
	aliasing for now.
In gcc/
2005-03-12  Daniel Berlin  <dberlin@dberlin.org>

	* tree-flow-inline.h (ref_contains_array_ref): New function.
	(lookup_subvars_for_var): Ditto.
	(get_subvars_for_var): Ditto.
	(var_can_have_subvars): Ditto.

	* tree-flow.h (mem_tag_kind): Add STRUCT_FIELD.
	(struct subvar): New type.

	* tree-dfa.c (okay_component_ref_for_subvars): New function.

	* tree-optimize.c (init_tree_optimization_passes): Call
	pass_create_structure_vars.

	* tree-ssa-alias.c: Include vec.h.
	(init_alias_info): Don't auto-clear call clobbered on struct-field
	tags.
	(compute_flow_insensitive_aliasing): Handle subvars.
	(group_aliases): Handle STRUCT_FIELD aliases.
	(setup_pointers_and_addressables): Ditto.
	Don't mark variables non-addressable if they still have
	addressable subvars.
	Also mark subvars addressable when the real variable is marked
	addressable.
	(add_pointed_to_var): Try to prune the pointed-to set by only
	pointing to subvars when possible.
	Otherwise, make sure we set addresses_needed and pt_vars to
	properly include subvars.
	(bitpos_of_field): New function.
	(push_fields_onto_fieldstack): Ditto.
	(get_or_create_used_part_for): Ditto.
	(create_overlap_variables_for): Ditto.
	(find_used_portions): Ditto.
	(create_structure_vars): Ditto.
	(pass_create_structure_vars): New structure.

	* tree-ssa-operands.c (finalize_ssa_v_must_defs): Remove assert.
	(get_expr_operands): Handle subvars.  Also try to turn
	COMPONENT_REF accesses into must-defs now that we can accurately
	portray it.
	(note_addressable): Try to only mark as addressable those subvars
	we know a COMPONENT_REF touches.
	(overlap_subvar): New function.

	* tree-vect-analyze.c (vect_object_analysis): Add new parameter.
	Handle subvar storing.
	(vect_address_analysis): Update caller of vect_object_analysis.

	* tree-vect-transform.c (vect_create_data_ref_ptr): Copy subvars.

	* tree-vectorizer.h (struct _stmt_vec_info): Add subvars member.
	(STMT_VINFO_SUBVARS): New macro.

	* common.opts: add flag_tree_salias.

	* opts.c (decode_options): flag_tree_salias defaults to on.

	* doc/invoke.texi: Document fdump-tree-svars and -ftree-salias.

	* doc/tree-ssa.texi: Document structural alias analysis.

From-SVN: r96362
This commit is contained in:
Daniel Berlin 2005-03-13 00:46:07 +00:00 committed by Daniel Berlin
parent 23845f0220
commit c75ab02281
20 changed files with 1026 additions and 72 deletions

View File

@ -1,3 +1,65 @@
2005-03-12 Daniel Berlin <dberlin@dberlin.org>
* tree-flow-inline.h (ref_contains_array_ref): New function.
(lookup_subvars_for_var): Ditto.
(get_subvars_for_var): Ditto.
(var_can_have_subvars): Ditto.
* tree-flow.h (mem_tag_kind): Add STRUCT_FIELD.
(struct subvar): New type.
* tree-dfa.c (okay_component_ref_for_subvars): New function.
* tree-optimize.c (init_tree_optimization_passes): Call
pass_create_structure_vars.
* tree-ssa-alias.c: Include vec.h.
(init_alias_info): Don't auto-clear call clobbered on struct-field
tags.
(compute_flow_insensitive_aliasing): Handle subvars.
(group_aliases): Handle STRUCT_FIELD aliases.
(setup_pointers_and_addressables): Ditto.
Don't mark variables non-addressable if they still have
addressable subvars.
Also mark subvars addressable when the real variable is marked
addressable.
(add_pointed_to_var): Try to prune the pointed-to set by only
pointing to subvars when possible.
Otherwise, make sure we set addresses_needed and pt_vars to
properly include subvars.
(bitpos_of_field): New function.
(push_fields_onto_fieldstack): Ditto.
(get_or_create_used_part_for): Ditto.
(create_overlap_variables_for): Ditto.
(find_used_portions): Ditto.
(create_structure_vars): Ditto.
(pass_create_structure_vars): New structure.
* tree-ssa-operands.c (finalize_ssa_v_must_defs): Remove assert.
(get_expr_operands): Handle subvars. Also try to turn
COMPONENT_REF accesses into must-defs now that we can accurately
portray it.
(note_addressable): Try to only mark as addressable those subvars
we know a COMPONENT_REF touches.
(overlap_subvar): New function.
* tree-vect-analyze.c (vect_object_analysis): Add new parameter.
Handle subvar storing.
(vect_address_analysis): Update caller of vect_object_analysis.
* tree-vect-transform.c (vect_create_data_ref_ptr): Copy subvars.
* tree-vectorizer.h (struct _stmt_vec_info): Add subvars member.
(STMT_VINFO_SUBVARS): New macro.
* common.opts: add flag_tree_salias.
* opts.c (decode_options): flag_tree_salias defaults to on.
* doc/invoke.texi: Document fdump-tree-svars and -ftree-salias.
* doc/tree-ssa.texi: Document structural alias analysis.
2005-03-12 Steven Bosscher <stevenb@suse.de>
* tree-cfg.c (make_goto_expr_edges): Don't use error_mark_node.

View File

@ -1,3 +1,8 @@
2005-03-12 Daniel Berlin <dberlin@dberlin.org>
* misc.c (gnat_post_options): Turn off structural
aliasing for now.
2005-03-08 Laurent Guerby <laurent@guerby.net>
* system-linux-sparc.ads: Fix typo in previous commit.

View File

@ -352,6 +352,8 @@ gnat_post_options (const char **pfilename ATTRIBUTE_UNUSED)
flag_no_inline = 1;
if (flag_inline_functions)
flag_inline_trees = 2;
flag_tree_salias = 0;
return false;
}

View File

@ -872,6 +872,10 @@ ftree-pre
Common Report Var(flag_tree_pre)
Enable SSA-PRE optimization on trees
ftree-salias
Common Report Var(flag_tree_salias)
Perform structural alias analysis
ftree-sink
Common Report Var(flag_tree_sink)
Enable SSA code sinking on trees

View File

@ -266,6 +266,7 @@ Objective-C and Objective-C++ Dialects}.
-fdump-tree-nrv -fdump-tree-vect @gol
-fdump-tree-sink @gol
-fdump-tree-sra@r{[}-@var{n}@r{]} @gol
-fdump-tree-salias @gol
-fdump-tree-fre@r{[}-@var{n}@r{]} @gol
-ftree-vectorizer-verbose=@var{n} @gol
-feliminate-dwarf2-dups -feliminate-unused-debug-types @gol
@ -322,6 +323,7 @@ Objective-C and Objective-C++ Dialects}.
-ftree-loop-linear -ftree-loop-im -ftree-loop-ivcanon -fivopts @gol
-ftree-dominator-opts -ftree-dse -ftree-copyrename -ftree-sink @gol
-ftree-ch -ftree-sra -ftree-ter -ftree-lrs -ftree-fre -ftree-vectorize @gol
-ftree-salias @gol
--param @var{name}=@var{value}
-O -O0 -O1 -O2 -O3 -Os}
@ -3819,6 +3821,11 @@ appending @file{.ch} to the source file name.
Dump SSA related information to a file. The file name is made by appending
@file{.ssa} to the source file name.
@item salias
@opindex fdump-tree-salias
Dump structure aliasing variable information to a file. This file name
is made by appending @file{.salias} to the source file name.
@item alias
@opindex fdump-tree-alias
Dump aliasing information for each function. The file name is made by
@ -4695,6 +4702,10 @@ that are computed on all paths leading to the redundant computation.
This analysis faster than PRE, though it exposes fewer redundancies.
This flag is enabled by default at @option{-O} and higher.
@item -ftree-salias
Perform structural alias analysis on trees. This flag
is enabled by default at @option{-O} and higher.
@item -ftree-sink
Perform forward store motion on trees. This flag is
enabled by default at @option{-O} and higher.

View File

@ -1208,9 +1208,46 @@ hooks to execute custom code at various points during traversal:
@cindex flow-sensitive alias analysis
@cindex flow-insensitive alias analysis
Alias analysis proceeds in 3 main phases:
Alias analysis proceeds in 4 main phases:
@enumerate
@item Structural alias analysis.
This phase walks the types for structure variables, and determines which
of the fields can overlap using offset and size of each field. For each
field, a ``subvariable'' called a ``Structure field tag'' (SFT)@ is
created, which represents that field as a separate variable. All
accesses that could possibly overlap with a given field will have
virtual operands for the SFT of that field.
@smallexample
struct foo
@{
int a;
int b;
@}
struct foo temp;
int bar (void)
@{
int tmp1, tmp2, tmp3;
SFT.0_2 = V_MUST_DEF <SFT.0_1>
temp.a = 5;
SFT.1_4 = V_MUST_DEF <SFT.1_3>
temp.b = 6;
VUSE <SFT.1_4>
tmp1_5 = temp.b;
VUSE <SFT.0_2>
tmp2_6 = temp.a;
tmp3_7 = tmp1_5 + tmp2_6;
return tmp3_7;
@}
@end smallexample
If you copy the type tag for a variable for some reason, you probably
also want to copy the subvariables for that variable.
@item Points-to and escape analysis.
This phase walks the use-def chains in the SSA web looking for

View File

@ -502,6 +502,7 @@ decode_options (unsigned int argc, const char **argv)
flag_tree_copyrename = 1;
flag_tree_fre = 1;
flag_tree_sink = 1;
flag_tree_salias = 1;
if (!optimize_size)
{

View File

@ -0,0 +1,15 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-lim-details" } */
int x; int y;
struct { int x; int y; } global;
int foo() {
int i;
for ( i=0; i<10; i++)
y += x*x;
for ( i=0; i<10; i++)
global.y += global.x*global.x;
}
/* { dg-final { scan-tree-dump-times "Executing store motion of global.y" 1 "lim" } } */
/* XXX: We should also check for the load motion of global.x, but there is no easy way to do this. */

View File

@ -0,0 +1,45 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized -fno-tree-sra" } */
/* Even without SRA being enabled, we should be able to eliminate every structure store and load here. */
extern void foo (const int);
int main(void)
{
struct a
{
int e;
int f;
int g;
} a;
struct a b;
int x, c;
a.e = 50;
a.f = 9;
a.g = a.e * a.f;
foo (a.f);
foo (a.g);
x = a.f;
c = a.e;
foo (x);
foo (c);
a.e = 5;
a.f = 40;
a.g = 90;
foo (a.e);
foo (a.f);
foo (a.g);
c = a.f;
foo (c);
b.e = 9;
a.e = b.e + 1 * c;
a.f = 30;
foo (a.e);
foo (a.f);
x = a.e * a.f;
foo (x);
}
/* { dg-final { scan-tree-dump-times "a.e" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "a.f" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "a.g" 0 "optimized" } } */
/* { dg-final { scan-tree-dump-times "b.e" 0 "optimized" } } */

View File

@ -0,0 +1,16 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-optimized" } */
struct foo
{
int a;
int b;
} temp;
/* We should be able to optimize this to return 11. */
int main(void)
{
temp.a = 5;
temp.b = 6;
return temp.a + temp.b;
}
/* { dg-final { scan-tree-dump-times "return 11" 1 "optimized" } } */

View File

@ -1053,3 +1053,46 @@ mark_call_clobbered_vars_to_rename (void)
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
}
}
/* If REF is a COMPONENT_REF for a structure that can have sub-variables, and
we know where REF is accessing, return the variable in REF that has the
sub-variables. If the return value is not NULL, POFFSET will be the
offset, in bits, of REF inside the return value, and PSIZE will be the
size, in bits, of REF inside the return value. */
tree
okay_component_ref_for_subvars (tree ref, HOST_WIDE_INT *poffset,
HOST_WIDE_INT *psize)
{
tree result = NULL;
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
tree offset;
enum machine_mode mode;
int unsignedp;
int volatilep;
gcc_assert (!SSA_VAR_P (ref));
*poffset = 0;
*psize = (unsigned int) -1;
if (ref_contains_array_ref (ref))
return result;
ref = get_inner_reference (ref, &bitsize, &bitpos, &offset, &mode,
&unsignedp, &volatilep, false);
if (TREE_CODE (ref) == INDIRECT_REF)
return result;
else if (offset == NULL && bitsize != -1 && SSA_VAR_P (ref))
{
*poffset = bitpos;
*psize = bitsize;
if (get_subvars_for_var (ref) != NULL)
return ref;
}
else if (SSA_VAR_P (ref))
{
if (get_subvars_for_var (ref) != NULL)
return ref;
}
return NULL_TREE;
}

View File

@ -878,4 +878,60 @@ op_iter_init_mustdef (ssa_op_iter *ptr, tree stmt, use_operand_p *kill,
op_iter_init (ptr, stmt, SSA_OP_VMUSTDEFKILL);
op_iter_next_mustdef (kill, def, ptr);
}
/* Return true if REF, a COMPONENT_REF, has an ARRAY_REF somewhere in it. */
static inline bool
ref_contains_array_ref (tree ref)
{
while (handled_component_p (ref))
{
if (TREE_CODE (ref) == ARRAY_REF)
return true;
ref = TREE_OPERAND (ref, 0);
}
return false;
}
/* Given a variable VAR, lookup and return a pointer to the list of
subvariables for it. */
static inline subvar_t *
lookup_subvars_for_var (tree var)
{
var_ann_t ann = var_ann (var);
gcc_assert (ann);
return &ann->subvars;
}
/* Given a variable VAR, return a linked list of subvariables for VAR, or
NULL, if there are no subvariables. */
static inline subvar_t
get_subvars_for_var (tree var)
{
subvar_t subvars;
gcc_assert (SSA_VAR_P (var));
if (TREE_CODE (var) == SSA_NAME)
subvars = *(lookup_subvars_for_var (SSA_NAME_VAR (var)));
else
subvars = *(lookup_subvars_for_var (var));
return subvars;
}
/* Return true if V is a tree that we can have subvars for.
Normally, this is any aggregate type, however, due to implementation
limitations ATM, we exclude array types as well. */
static inline bool
var_can_have_subvars (tree v)
{
return (AGGREGATE_TYPE_P (TREE_TYPE (v)) &&
TREE_CODE (TREE_TYPE (v)) != ARRAY_TYPE);
}
#endif /* _TREE_FLOW_INLINE_H */

View File

@ -138,7 +138,26 @@ enum mem_tag_kind {
TYPE_TAG,
/* This variable is a name memory tag (NMT). */
NAME_TAG
NAME_TAG,
/* This variable represents a structure field. */
STRUCT_FIELD
};
struct subvar;
typedef struct subvar *subvar_t;
/* This structure represents a fake sub-variable for a structure field. */
struct subvar GTY(())
{
/* Fake variable name */
tree var;
/* Offset inside structure. */
HOST_WIDE_INT offset;
/* Size of field. */
HOST_WIDE_INT size;
/* Next subvar for this structure. */
subvar_t next;
};
struct var_ann_d GTY(())
@ -211,6 +230,8 @@ struct var_ann_d GTY(())
live at the same time and this can happen for each call to the
dominator optimizer. */
tree current_def;
subvar_t subvars;
};
@ -556,6 +577,9 @@ extern tree make_rename_temp (tree, const char *);
extern void record_vars (tree);
extern bool block_may_fallthru (tree block);
typedef tree tree_on_heap;
DEF_VEC_MALLOC_P (tree_on_heap);
/* In tree-ssa-alias.c */
extern void dump_may_aliases_for (FILE *, tree);
extern void debug_may_aliases_for (tree);
@ -567,13 +591,15 @@ extern void dump_points_to_info_for (FILE *, tree);
extern void debug_points_to_info_for (tree);
extern bool may_be_aliased (tree);
extern struct ptr_info_def *get_ptr_info (tree);
static inline subvar_t get_subvars_for_var (tree);
static inline bool ref_contains_array_ref (tree);
extern tree okay_component_ref_for_subvars (tree, HOST_WIDE_INT *,
HOST_WIDE_INT *);
static inline bool var_can_have_subvars (tree);
/* Call-back function for walk_use_def_chains(). At each reaching
definition, a function with this prototype is called. */
typedef bool (*walk_use_def_chains_fn) (tree, tree, void *);
typedef tree tree_on_heap;
DEF_VEC_MALLOC_P (tree_on_heap);
/* In tree-ssa.c */
extern void init_tree_ssa (void);

View File

@ -348,6 +348,7 @@ init_tree_optimization_passes (void)
p = &pass_all_optimizations.sub;
NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_create_structure_vars);
NEXT_PASS (pass_build_ssa);
NEXT_PASS (pass_may_alias);
NEXT_PASS (pass_rename_ssa_copies);

View File

@ -167,5 +167,6 @@ extern struct tree_opt_pass pass_rest_of_compilation;
extern struct tree_opt_pass pass_sink_code;
extern struct tree_opt_pass pass_fre;
extern struct tree_opt_pass pass_linear_transform;
extern struct tree_opt_pass pass_create_structure_vars;
#endif /* GCC_TREE_PASS_H */

View File

@ -42,6 +42,7 @@ Boston, MA 02111-1307, USA. */
#include "tree-pass.h"
#include "convert.h"
#include "params.h"
#include "vec.h"
/* 'true' after aliases have been computed (see compute_may_aliases). */
bool aliases_computed_p;
@ -524,8 +525,15 @@ init_alias_info (void)
variables, clear the call-clobbered flag. Variables that
are intrinsically call-clobbered (globals, local statics,
etc) will not be marked by the aliasing code, so we can't
remove them from CALL_CLOBBERED_VARS. */
if (ann->mem_tag_kind != NOT_A_TAG || !is_global_var (var))
remove them from CALL_CLOBBERED_VARS.
NB: STRUCT_FIELDS are still call clobbered if they are for
a global variable, so we *don't* clear their call clobberedness
just because they are tags, though we will clear it if they
aren't for global variables. */
if (ann->mem_tag_kind == NAME_TAG
|| ann->mem_tag_kind == TYPE_TAG
|| !is_global_var (var))
clear_call_clobbered (var);
}
@ -982,13 +990,28 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
if (may_alias_p (p_map->var, p_map->set, var, v_map->set))
{
subvar_t svars;
size_t num_tag_refs, num_var_refs;
num_tag_refs = VARRAY_UINT (ai->num_references, tag_ann->uid);
num_var_refs = VARRAY_UINT (ai->num_references, v_ann->uid);
/* Add VAR to TAG's may-aliases set. */
add_may_alias (tag, var);
/* If this is an aggregate, we may have subvariables for it
that need to be pointed to. */
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
add_may_alias (tag, sv->var);
}
else
{
add_may_alias (tag, var);
}
/* Update the total number of virtual operands due to
aliasing. Since we are adding one more alias to TAG's
@ -1040,7 +1063,7 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
sbitmap may_aliases2 = p_map2->may_aliases;
/* If the pointers may not point to each other, do nothing. */
if (!may_alias_p (p_map1->var, p_map1->set, p_map2->var, p_map2->set))
if (!may_alias_p (p_map1->var, p_map1->set, tag2, p_map2->set))
continue;
/* The two pointers may alias each other. If they already have
@ -1293,7 +1316,9 @@ group_aliases (struct alias_info *ai)
tree alias = VARRAY_TREE (aliases, j);
var_ann_t ann = var_ann (alias);
if (ann->mem_tag_kind == NOT_A_TAG && ann->may_aliases)
if ((ann->mem_tag_kind == NOT_A_TAG
|| ann->mem_tag_kind == STRUCT_FIELD)
&& ann->may_aliases)
{
tree new_alias;
@ -1378,13 +1403,19 @@ setup_pointers_and_addressables (struct alias_info *ai)
{
tree var = referenced_var (i);
var_ann_t v_ann = var_ann (var);
subvar_t svars;
/* Name memory tags already have flow-sensitive aliasing
information, so they need not be processed by
compute_flow_insensitive_aliasing. Similarly, type memory
tags are already accounted for when we process their
associated pointer. */
if (v_ann->mem_tag_kind != NOT_A_TAG)
associated pointer.
Structure fields, on the other hand, have to have some of this
information processed for them, but it's pointless to mark them
non-addressable (since they are fake variables anyway). */
if (v_ann->mem_tag_kind != NOT_A_TAG
&& v_ann->mem_tag_kind != STRUCT_FIELD)
continue;
/* Remove the ADDRESSABLE flag from every addressable variable whose
@ -1392,20 +1423,36 @@ setup_pointers_and_addressables (struct alias_info *ai)
of ADDR_EXPR constants into INDIRECT_REF expressions and the
removal of dead pointer assignments done by the early scalar
cleanup passes. */
if (TREE_ADDRESSABLE (var))
if (TREE_ADDRESSABLE (var) && v_ann->mem_tag_kind != STRUCT_FIELD)
{
if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid)
&& TREE_CODE (var) != RESULT_DECL
&& !is_global_var (var))
{
/* The address of VAR is not needed, remove the
addressable bit, so that it can be optimized as a
regular variable. */
mark_non_addressable (var);
bool okay_to_mark = true;
/* Since VAR is now a regular GIMPLE register, we will need
to rename VAR into SSA afterwards. */
bitmap_set_bit (vars_to_rename, v_ann->uid);
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
{
var_ann_t svann = var_ann (sv->var);
if (bitmap_bit_p (ai->addresses_needed, svann->uid))
okay_to_mark = false;
bitmap_set_bit (vars_to_rename, svann->uid);
}
}
/* The address of VAR is not needed, remove the
addressable bit, so that it can be optimized as a
regular variable. */
if (okay_to_mark)
mark_non_addressable (var);
}
else
{
@ -1414,6 +1461,14 @@ setup_pointers_and_addressables (struct alias_info *ai)
clobber memory. In those cases, we need to clobber
all call-clobbered variables and all addressables. */
bitmap_set_bit (addressable_vars, v_ann->uid);
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
bitmap_set_bit (addressable_vars, var_ann (sv->var)->uid);
}
}
}
@ -1422,7 +1477,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
if (may_be_aliased (var))
{
create_alias_map_for (var, ai);
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
}
/* Add pointer variables that have been dereferenced to the POINTERS
@ -1579,7 +1634,17 @@ maybe_create_global_var (struct alias_info *ai)
.GLOBAL_VAR has been created, make it an alias for all
call-clobbered variables. */
if (global_var && var != global_var)
add_may_alias (var, global_var);
{
subvar_t svars;
add_may_alias (var, global_var);
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
bitmap_set_bit (vars_to_rename, var_ann (sv->var)->uid);
}
}
bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
}
@ -1644,7 +1709,6 @@ may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
alias_stats.tbaa_resolved++;
return false;
}
alias_stats.alias_mayalias++;
return true;
}
@ -1894,23 +1958,73 @@ static void
add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
{
struct ptr_info_def *pi = get_ptr_info (ptr);
tree pt_var;
tree pt_var = NULL_TREE;
HOST_WIDE_INT offset, size;
tree addrop;
size_t uid;
tree ref;
subvar_t svars;
gcc_assert (TREE_CODE (value) == ADDR_EXPR);
pt_var = TREE_OPERAND (value, 0);
if (REFERENCE_CLASS_P (pt_var))
pt_var = get_base_address (pt_var);
addrop = TREE_OPERAND (value, 0);
if (REFERENCE_CLASS_P (addrop))
pt_var = get_base_address (addrop);
else
pt_var = addrop;
if (pt_var && SSA_VAR_P (pt_var))
/* If this is a component_ref, see if we can get a smaller number of
variables to take the address of. */
if (TREE_CODE (addrop) == COMPONENT_REF
&& (ref = okay_component_ref_for_subvars (addrop, &offset ,&size)))
{
subvar_t sv;
svars = get_subvars_for_var (ref);
uid = var_ann (pt_var)->uid;
bitmap_set_bit (ai->addresses_needed, uid);
if (pi->pt_vars == NULL)
pi->pt_vars = BITMAP_GGC_ALLOC ();
/* If the variable is a global, mark the pointer as pointing to
global memory (which will make its tag a global variable). */
if (is_global_var (pt_var))
pi->pt_global_mem = 1;
for (sv = svars; sv; sv = sv->next)
{
if (offset == sv->offset && size == sv->size)
bitmap_set_bit (pi->pt_vars, var_ann (sv->var)->uid);
else if (offset >= sv->offset && offset < (sv->offset + sv->size))
bitmap_set_bit (pi->pt_vars, var_ann (sv->var)->uid);
else if (offset < sv->offset
&& (offset + size > sv->offset))
bitmap_set_bit (pi->pt_vars, var_ann (sv->var)->uid);
}
}
else if (pt_var && SSA_VAR_P (pt_var))
{
uid = var_ann (pt_var)->uid;
bitmap_set_bit (ai->addresses_needed, uid);
if (pi->pt_vars == NULL)
pi->pt_vars = BITMAP_GGC_ALLOC ();
bitmap_set_bit (pi->pt_vars, uid);
/* If this is an aggregate, we may have subvariables for it that need
to be pointed to. */
if (var_can_have_subvars (pt_var)
&& (svars = get_subvars_for_var (pt_var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
{
uid = var_ann (sv->var)->uid;
bitmap_set_bit (ai->addresses_needed, uid);
bitmap_set_bit (pi->pt_vars, uid);
}
}
else
bitmap_set_bit (pi->pt_vars, uid);
/* If the variable is a global, mark the pointer as pointing to
global memory (which will make its tag a global variable). */
@ -2540,3 +2654,400 @@ may_be_aliased (tree var)
return true;
}
/* This structure is simply used during pushing fields onto the fieldstack
to track the offset of the field, since bitpos_of_field gives it relative
to its immediate containing type, and we want it relative to the ultimate
containing object. */
typedef struct fieldoff
{
tree field;
HOST_WIDE_INT offset;
} *fieldoff_t;
DEF_VEC_MALLOC_P(fieldoff_t);
/* Return the position, in bits, of FIELD_DECL from the beginning of its
structure.
Return -1 if the position is conditional or otherwise non-constant
integer. */
static HOST_WIDE_INT
bitpos_of_field (const tree fdecl)
{
if (TREE_CODE (DECL_FIELD_OFFSET (fdecl)) != INTEGER_CST
|| TREE_CODE (DECL_FIELD_BIT_OFFSET (fdecl)) != INTEGER_CST)
return -1;
return (tree_low_cst (DECL_FIELD_OFFSET (fdecl), 1) * 8)
+ tree_low_cst (DECL_FIELD_BIT_OFFSET (fdecl), 1);
}
/* Given a TYPE, and a vector of field offsets FIELDSTACK, push all the fields
of TYPE onto fieldstack, recording their offsets along the way.
OFFSET is used to keep track of the offset in this entire structure, rather
than just the immediately containing structure. */
static void
push_fields_onto_fieldstack (tree type, VEC(fieldoff_t) **fieldstack,
HOST_WIDE_INT offset)
{
fieldoff_t pair;
tree field = TYPE_FIELDS (type);
if (!field)
return;
if (var_can_have_subvars (field)
&& TREE_CODE (field) == FIELD_DECL)
{
size_t before = VEC_length (fieldoff_t, *fieldstack);
/* Empty structures may have actual size, like in C++. So see if we
actually end up pushing a field, and if not, if the size is non-zero,
push the field onto the stack */
push_fields_onto_fieldstack (TREE_TYPE (field), fieldstack, offset);
if (before == VEC_length (fieldoff_t, *fieldstack)
&& DECL_SIZE (field)
&& !integer_zerop (DECL_SIZE (field)))
{
pair = xmalloc (sizeof (struct fieldoff));
pair->field = field;
pair->offset = offset;
VEC_safe_push (fieldoff_t, *fieldstack, pair);
}
}
else if (TREE_CODE (field) == FIELD_DECL)
{
pair = xmalloc (sizeof (struct fieldoff));
pair->field = field;
pair->offset = offset + bitpos_of_field (field);
VEC_safe_push (fieldoff_t, *fieldstack, pair);
}
for (field = TREE_CHAIN (field); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) != FIELD_DECL)
continue;
if (var_can_have_subvars (field))
{
push_fields_onto_fieldstack (TREE_TYPE (field), fieldstack,
offset + bitpos_of_field (field));
}
else
{
pair = xmalloc (sizeof (struct fieldoff));
pair->field = field;
pair->offset = offset + bitpos_of_field (field);
VEC_safe_push (fieldoff_t, *fieldstack, pair);
}
}
}
/* This represents the used range of a variable. */
typedef struct used_part
{
HOST_WIDE_INT minused;
HOST_WIDE_INT maxused;
} *used_part_t;
/* An array of used_part structures, indexed by variable uid. */
static used_part_t *used_portions;
/* Given a variable uid, UID, get or create the entry in the used portions
table for the variable. */
static used_part_t
get_or_create_used_part_for (size_t uid)
{
used_part_t up;
if (used_portions[uid] == NULL)
{
up = xcalloc (1, sizeof (struct used_part));
up->minused = INT_MAX;
up->maxused = 0;
}
else
up = used_portions[uid];
return up;
}
/* Given an aggregate VAR, create the subvariables that represent its
fields. */
static void
create_overlap_variables_for (tree var)
{
VEC(fieldoff_t) *fieldstack = NULL;
used_part_t up;
size_t uid = var_ann (var)->uid;
if (used_portions[uid] == NULL)
return;
push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0);
if (VEC_length (fieldoff_t, fieldstack) != 0)
{
subvar_t *subvars;
fieldoff_t fo;
bool notokay = false;
int i;
/* Not all fields have DECL_SIZE set, and those that don't, we don't
know their size, and thus, can't handle.
The same is true of fields with DECL_SIZE that is not an integer
constant (such as variable sized fields).
Fields with offsets which are not constant will have an offset < 0
We *could* handle fields that are constant sized arrays, but
currently don't. Doing so would require some extra changes to
tree-ssa-operands.c. */
for (i = 0; VEC_iterate (fieldoff_t, fieldstack, i, fo); i++)
{
if (!DECL_SIZE (fo->field)
|| TREE_CODE (DECL_SIZE (fo->field)) != INTEGER_CST
|| TREE_CODE (TREE_TYPE (fo->field)) == ARRAY_TYPE
|| fo->offset < 0)
{
notokay = true;
break;
}
}
/* Cleanup after ourselves if we can't create overlap variables. */
if (notokay)
{
while (VEC_length (fieldoff_t, fieldstack) != 0)
{
fo = VEC_pop (fieldoff_t, fieldstack);
free (fo);
}
VEC_free (fieldoff_t, fieldstack);
return;
}
/* Otherwise, create the variables. */
subvars = lookup_subvars_for_var (var);
up = used_portions[uid];
while (VEC_length (fieldoff_t, fieldstack) != 0)
{
subvar_t sv = ggc_alloc (sizeof (struct subvar));
HOST_WIDE_INT fosize;
var_ann_t ann;
fo = VEC_pop (fieldoff_t, fieldstack);
fosize = TREE_INT_CST_LOW (DECL_SIZE (fo->field));
if ((fo->offset <= up->minused
&& fo->offset + fosize <= up->minused)
|| fo->offset >= up->maxused)
{
free (fo);
continue;
}
sv->offset = fo->offset;
sv->size = fosize;
sv->next = *subvars;
sv->var = create_tmp_var_raw (TREE_TYPE (fo->field), "SFT");
if (dump_file)
{
fprintf (dump_file, "structure field tag %s created for var %s",
get_name (sv->var), get_name (var));
fprintf (dump_file, " offset " HOST_WIDE_INT_PRINT_DEC,
sv->offset);
fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
sv->size);
fprintf (dump_file, "\n");
}
/* We need to copy the various flags from var to sv->var, so that
they are is_global_var iff the original variable was. */
DECL_EXTERNAL (sv->var) = DECL_EXTERNAL (var);
TREE_PUBLIC (sv->var) = TREE_PUBLIC (var);
TREE_STATIC (sv->var) = TREE_STATIC (var);
TREE_READONLY (sv->var) = TREE_READONLY (var);
/* Like other memory tags, these need to be marked addressable to
keep is_gimple_reg from thinking they are real. */
TREE_ADDRESSABLE (sv->var) = 1;
DECL_CONTEXT (sv->var) = DECL_CONTEXT (var);
ann = get_var_ann (sv->var);
ann->mem_tag_kind = STRUCT_FIELD;
ann->type_mem_tag = NULL;
add_referenced_tmp_var (sv->var);
*subvars = sv;
free (fo);
}
}
VEC_free (fieldoff_t, fieldstack);
}
/* Find the conservative answer to the question of what portions of what
structures are used by this statement. We assume that if we have a
component ref with a known size + offset, that we only need that part
of the structure. For unknown cases, or cases where we do something
to the whole structure, we assume we need to create fields for the
entire structure. */
static tree
find_used_portions (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
{
switch (TREE_CODE (*tp))
{
case COMPONENT_REF:
{
HOST_WIDE_INT bitsize;
HOST_WIDE_INT bitpos;
tree offset;
enum machine_mode mode;
int unsignedp;
int volatilep;
tree ref;
ref = get_inner_reference (*tp, &bitsize, &bitpos, &offset, &mode,
&unsignedp, &volatilep, false);
if (DECL_P (ref) && offset == NULL && bitsize != -1)
{
size_t uid = var_ann (ref)->uid;
used_part_t up;
up = get_or_create_used_part_for (uid);
if (bitpos <= up->minused)
up->minused = bitpos;
if ((bitpos + bitsize >= up->maxused))
up->maxused = bitpos + bitsize;
used_portions[uid] = up;
*walk_subtrees = 0;
return NULL_TREE;
}
else if (DECL_P (ref))
{
if (DECL_SIZE (ref)
&& var_can_have_subvars (ref)
&& TREE_CODE (DECL_SIZE (ref)) == INTEGER_CST)
{
used_part_t up;
size_t uid = var_ann (ref)->uid;
up = get_or_create_used_part_for (uid);
up->minused = 0;
up->maxused = TREE_INT_CST_LOW (DECL_SIZE (ref));
used_portions[uid] = up;
*walk_subtrees = 0;
return NULL_TREE;
}
}
}
break;
case VAR_DECL:
case PARM_DECL:
{
tree var = *tp;
if (DECL_SIZE (var)
&& var_can_have_subvars (var)
&& TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
{
used_part_t up;
size_t uid = var_ann (var)->uid;
up = get_or_create_used_part_for (uid);
up->minused = 0;
up->maxused = TREE_INT_CST_LOW (DECL_SIZE (var));
used_portions[uid] = up;
*walk_subtrees = 0;
return NULL_TREE;
}
}
break;
default:
break;
}
return NULL_TREE;
}
/* We are about to create some new referenced variables, and we need the
before size. */
static size_t old_referenced_vars;
/* Create structure field variables for structures used in this function. */
static void
create_structure_vars (void)
{
basic_block bb;
size_t i;
old_referenced_vars = num_referenced_vars;
used_portions = xcalloc (num_referenced_vars, sizeof (used_part_t));
FOR_EACH_BB (bb)
{
block_stmt_iterator bsi;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
{
walk_tree_without_duplicates (bsi_stmt_ptr (bsi),
find_used_portions,
NULL);
}
}
for (i = 0; i < old_referenced_vars; i++)
{
tree var = referenced_var (i);
/* The C++ FE creates vars without DECL_SIZE set, for some reason. */
if (var
&& DECL_SIZE (var)
&& var_can_have_subvars (var)
&& var_ann (var)->mem_tag_kind == NOT_A_TAG
&& TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
create_overlap_variables_for (var);
}
for (i = 0; i < old_referenced_vars; i++)
free (used_portions[i]);
free (used_portions);
}
static bool
gate_structure_vars (void)
{
return flag_tree_salias != 0;
}
struct tree_opt_pass pass_create_structure_vars =
{
"salias", /* name */
gate_structure_vars, /* gate */
create_structure_vars, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
0, /* tv_id */
PROP_cfg, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func, /* todo_flags_finish */
0 /* letter */
};

View File

@ -683,8 +683,12 @@ finalize_ssa_v_must_defs (v_must_def_optype *old_ops_p,
if (num == 0)
return NULL;
/* There should only be a single V_MUST_DEF per assignment. */
gcc_assert (TREE_CODE (stmt) != MODIFY_EXPR || num <= 1);
/* In the presence of subvars, there may be more than one V_MUST_DEF per
statement (one for each subvar). It is a bit expensive to verify that
all must-defs in a statement belong to subvars if there is more than one
MUST-def, so we don't do it. Suffice to say, if you reach here without
having subvars, and have num >1, you have hit a bug. */
old_ops = *old_ops_p;
@ -907,7 +911,6 @@ build_ssa_operands (tree stmt, stmt_ann_t ann, stmt_operands_p old_ops,
lhs = TREE_OPERAND (lhs, 0);
if (TREE_CODE (lhs) != ARRAY_REF && TREE_CODE (lhs) != ARRAY_RANGE_REF
&& TREE_CODE (lhs) != COMPONENT_REF
&& TREE_CODE (lhs) != BIT_FIELD_REF
&& TREE_CODE (lhs) != REALPART_EXPR
&& TREE_CODE (lhs) != IMAGPART_EXPR)
@ -1021,6 +1024,49 @@ get_stmt_operands (tree stmt)
}
/* Return true if OFFSET and SIZE define a range that overlaps with some
portion of the range of SV, a subvar. If there was an exact overlap,
*EXACT will be set to true upon return. */
static bool
overlap_subvar (HOST_WIDE_INT offset, HOST_WIDE_INT size,
subvar_t sv, bool *exact)
{
/* There are three possible cases of overlap.
1. We can have an exact overlap, like so:
|offset, offset + size |
|sv->offset, sv->offset + sv->size |
2. We can have offset starting after sv->offset, like so:
|offset, offset + size |
|sv->offset, sv->offset + sv->size |
3. We can have offset starting before sv->offset, like so:
|offset, offset + size |
|sv->offset, sv->offset + sv->size|
*/
if (exact)
*exact = false;
if (offset == sv->offset && size == sv->size)
{
if (exact)
*exact = true;
return true;
}
else if (offset >= sv->offset && offset < (sv->offset + sv->size))
{
return true;
}
else if (offset < sv->offset && (offset + size > sv->offset))
{
return true;
}
return false;
}
/* Recursively scan the expression pointed by EXPR_P in statement referred to
by INFO. FLAGS is one of the OPF_* constants modifying how to interpret the
operands found. */
@ -1068,11 +1114,25 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
case PARM_DECL:
case RESULT_DECL:
case CONST_DECL:
/* If we found a variable, add it to DEFS or USES depending
on the operand flags. */
add_stmt_operand (expr_p, s_ann, flags);
return;
{
subvar_t svars;
/* Add the subvars for a variable if it has subvars, to DEFS or USES.
Otherwise, add the variable itself.
Whether it goes to USES or DEFS depends on the operand flags. */
if (var_can_have_subvars (expr)
&& (svars = get_subvars_for_var (expr)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
add_stmt_operand (&sv->var, s_ann, flags);
}
else
{
add_stmt_operand (expr_p, s_ann, flags);
}
return;
}
case MISALIGNED_INDIRECT_REF:
get_expr_operands (stmt, &TREE_OPERAND (expr, 1), flags);
/* fall through */
@ -1104,30 +1164,39 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
case COMPONENT_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
/* Similarly to arrays, references to compound variables (complex
types and structures/unions) are globbed.
FIXME: This means that
a.x = 6;
a.y = 7;
foo (a.x, a.y);
will not be constant propagated because the two partial
definitions to 'a' will kill each other. Note that SRA may be
able to fix this problem if 'a' can be scalarized. */
/* If the LHS of the compound reference is not a regular variable,
recurse to keep looking for more operands in the subexpression. */
if (SSA_VAR_P (TREE_OPERAND (expr, 0)))
add_stmt_operand (expr_p, s_ann, flags);
else
get_expr_operands (stmt, &TREE_OPERAND (expr, 0), flags);
if (code == COMPONENT_REF)
get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none);
return;
{
tree ref;
HOST_WIDE_INT offset, size;
/* This component ref becomes an access to all of the subvariables
it can touch, if we can determine that, but *NOT* the real one.
If we can't determine which fields we could touch, the recursion
will eventually get to a variable and add *all* of its subvars, or
whatever is the minimum correct subset. */
ref = okay_component_ref_for_subvars (expr, &offset, &size);
if (ref)
{
subvar_t svars = get_subvars_for_var (ref);
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
{
bool exact;
if (overlap_subvar (offset, size, sv, &exact))
{
if (exact)
flags &= ~opf_kill_def;
add_stmt_operand (&sv->var, s_ann, flags);
}
}
}
else
get_expr_operands (stmt, &TREE_OPERAND (expr, 0),
flags & ~opf_kill_def);
if (code == COMPONENT_REF)
get_expr_operands (stmt, &TREE_OPERAND (expr, 2), opf_none);
return;
}
case WITH_SIZE_EXPR:
/* WITH_SIZE_EXPR is a pass-through reference to its first argument,
and an rvalue reference to its second argument. */
@ -1158,7 +1227,6 @@ get_expr_operands (tree stmt, tree *expr_p, int flags)
op = TREE_OPERAND (expr, 0);
if (TREE_CODE (op) == ARRAY_REF
|| TREE_CODE (op) == ARRAY_RANGE_REF
|| TREE_CODE (op) == COMPONENT_REF
|| TREE_CODE (op) == REALPART_EXPR
|| TREE_CODE (op) == IMAGPART_EXPR)
subflags = opf_is_def;
@ -1554,9 +1622,10 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
{
if (flags & opf_kill_def)
{
/* Only regular variables may get a V_MUST_DEF
operand. */
gcc_assert (v_ann->mem_tag_kind == NOT_A_TAG);
/* Only regular variables or struct fields may get a
V_MUST_DEF operand. */
gcc_assert (v_ann->mem_tag_kind == NOT_A_TAG
|| v_ann->mem_tag_kind == STRUCT_FIELD);
/* V_MUST_DEF for non-aliased, non-GIMPLE register
variable definitions. */
append_v_must_def (var);
@ -1615,26 +1684,60 @@ add_stmt_operand (tree *var_p, stmt_ann_t s_ann, int flags)
}
}
/* Record that VAR had its address taken in the statement with annotations
S_ANN. */
static void
note_addressable (tree var, stmt_ann_t s_ann)
{
tree ref;
subvar_t svars;
HOST_WIDE_INT offset;
HOST_WIDE_INT size;
if (!s_ann)
return;
/* If this is a COMPONENT_REF, and we know exactly what it touches, we only
take the address of the subvariables it will touch.
Otherwise, we take the address of all the subvariables, plus the real
ones. */
if (var && TREE_CODE (var) == COMPONENT_REF
&& (ref = okay_component_ref_for_subvars (var, &offset, &size)))
{
subvar_t sv;
svars = get_subvars_for_var (ref);
if (s_ann->addresses_taken == NULL)
s_ann->addresses_taken = BITMAP_GGC_ALLOC ();
for (sv = svars; sv; sv = sv->next)
{
if (overlap_subvar (offset, size, sv, NULL))
bitmap_set_bit (s_ann->addresses_taken, var_ann (sv->var)->uid);
}
return;
}
var = get_base_address (var);
if (var && SSA_VAR_P (var))
{
if (s_ann->addresses_taken == NULL)
s_ann->addresses_taken = BITMAP_GGC_ALLOC ();
s_ann->addresses_taken = BITMAP_GGC_ALLOC ();
bitmap_set_bit (s_ann->addresses_taken, var_ann (var)->uid);
if (var_can_have_subvars (var)
&& (svars = get_subvars_for_var (var)))
{
subvar_t sv;
for (sv = svars; sv; sv = sv->next)
bitmap_set_bit (s_ann->addresses_taken, var_ann (sv->var)->uid);
}
}
}
/* Add clobbering definitions for .GLOBAL_VAR or for each of the call
clobbered variables in the function. */

View File

@ -70,7 +70,7 @@ static bool vect_base_addr_differ_p (struct data_reference *,
struct data_reference *drb, bool *);
static tree vect_object_analysis (tree, tree, bool, tree,
struct data_reference **, tree *, tree *,
tree *, bool *, tree *);
tree *, bool *, tree *, subvar_t *);
static tree vect_address_analysis (tree, tree, bool, tree,
struct data_reference *, tree *, tree *,
tree *, bool *);
@ -1377,6 +1377,7 @@ vect_address_analysis (tree expr, tree stmt, bool is_read, tree vectype,
tree oprnd0, oprnd1, base_address, offset_expr, base_addr0, base_addr1;
tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
tree dummy;
subvar_t dummy2;
switch (TREE_CODE (expr))
{
@ -1426,9 +1427,10 @@ vect_address_analysis (tree expr, tree stmt, bool is_read, tree vectype,
return base_addr0 ? base_addr0 : base_addr1;
case ADDR_EXPR:
base_address = vect_object_analysis (TREE_OPERAND (expr, 0), stmt, is_read,
vectype, &dr, offset, misalign, step,
base_aligned, &dummy);
base_address = vect_object_analysis (TREE_OPERAND (expr, 0), stmt,
is_read, vectype, &dr, offset,
misalign, step, base_aligned,
&dummy, &dummy2);
return base_address;
case SSA_NAME:
@ -1507,6 +1509,7 @@ vect_address_analysis (tree expr, tree stmt, bool is_read, tree vectype,
STEP - evolution of the DR_REF in the loop
BASE_ALIGNED - indicates if BASE is aligned
MEMTAG - memory tag for aliasing purposes
SUBVAR - Sub-variables of the variable
If something unexpected is encountered (an unsupported form of data-ref),
then NULL_TREE is returned. */
@ -1515,7 +1518,8 @@ static tree
vect_object_analysis (tree memref, tree stmt, bool is_read,
tree vectype, struct data_reference **dr,
tree *offset, tree *misalign, tree *step,
bool *base_aligned, tree *memtag)
bool *base_aligned, tree *memtag,
subvar_t *subvars)
{
tree base = NULL_TREE, base_address = NULL_TREE;
tree object_offset = ssize_int (0), object_misalign = ssize_int (0);
@ -1611,6 +1615,8 @@ vect_object_analysis (tree memref, tree stmt, bool is_read,
us to object. */
DR_BASE_NAME ((*dr)) = memref;
if (SSA_VAR_P (memref) && var_can_have_subvars (memref))
*subvars = get_subvars_for_var (memref);
base_address = build_fold_addr_expr (memref);
*memtag = memref;
}
@ -1698,6 +1704,9 @@ vect_object_analysis (tree memref, tree stmt, bool is_read,
/* MEMREF cannot be analyzed. */
return NULL_TREE;
if (SSA_VAR_P (*memtag) && var_can_have_subvars (*memtag))
*subvars = get_subvars_for_var (*memtag);
/* Part 2: Combine the results of object and address analysis to calculate
INITIAL_OFFSET, STEP and misalignment info. */
*offset = size_binop (PLUS_EXPR, object_offset, address_offset);
@ -1780,6 +1789,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo)
tree scalar_type, vectype;
tree base, offset, misalign, step, tag;
bool base_aligned;
subvar_t subvars;
/* Assumption: there exists a data-ref in stmt, if and only if
it has vuses/vdefs. */
@ -1843,7 +1853,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo)
dr = NULL;
base = vect_object_analysis (memref, stmt, is_read, vectype, &dr,
&offset, &misalign, &step,
&base_aligned, &tag);
&base_aligned, &tag, &subvars);
if (!base)
{
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS,
@ -1860,6 +1870,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo)
STMT_VINFO_VECT_MISALIGNMENT (stmt_info) = misalign;
STMT_VINFO_VECT_BASE_ALIGNED_P (stmt_info) = base_aligned;
STMT_VINFO_MEMTAG (stmt_info) = tag;
STMT_VINFO_SUBVARS (stmt_info) = subvars;
STMT_VINFO_VECTYPE (stmt_info) = vectype;
VARRAY_PUSH_GENERIC_PTR (*datarefs, dr);
STMT_VINFO_DATA_REF (stmt_info) = dr;

View File

@ -353,12 +353,14 @@ vect_create_data_ref_ptr (tree stmt, block_stmt_iterator *bsi, tree offset,
tag = STMT_VINFO_MEMTAG (stmt_info);
gcc_assert (tag);
get_var_ann (vect_ptr)->type_mem_tag = tag;
get_var_ann (vect_ptr)->subvars = STMT_VINFO_SUBVARS (stmt_info);
/* Mark for renaming all aliased variables
(i.e, the may-aliases of the type-mem-tag). */
nvuses = NUM_VUSES (vuses);
nv_may_defs = NUM_V_MAY_DEFS (v_may_defs);
nv_must_defs = NUM_V_MUST_DEFS (v_must_defs);
for (i = 0; i < nvuses; i++)
{
tree use = VUSE_OP (vuses, i);

View File

@ -172,6 +172,7 @@ typedef struct _stmt_vec_info {
/* Aliasing information. */
tree memtag;
subvar_t subvars;
/** The following fields are used to store the information about
data-reference. {base_address + initial_offset} is the first location
@ -213,6 +214,7 @@ typedef struct _stmt_vec_info {
#define STMT_VINFO_VEC_STMT(S) (S)->vectorized_stmt
#define STMT_VINFO_DATA_REF(S) (S)->data_ref_info
#define STMT_VINFO_MEMTAG(S) (S)->memtag
#define STMT_VINFO_SUBVARS(S) (S)->subvars
#define STMT_VINFO_VECT_DR_BASE_ADDRESS(S)(S)->base_address
#define STMT_VINFO_VECT_INIT_OFFSET(S) (S)->initial_offset
#define STMT_VINFO_VECT_STEP(S) (S)->step