Commit 3cb960c7 by Zdenek Dvorak Committed by Zdenek Dvorak

tree-scalar-evolution.c (resolve_mixers): Exported.

	* tree-scalar-evolution.c (resolve_mixers): Exported.
	* tree-scalar-evolution.h (resolve_mixers): Declare.
	* tree-data-ref.c (object_analysis, ptr_decl_may_alias_p,
	ptr_ptr_may_alias_p, may_alias_p, record_ptr_differ_p,
	record_record_differ_p, record_array_differ_p, array_ptr_differ_p,
	base_object_differ_p, base_addr_differ_p, analyze_array_indexes,
	init_array_ref, init_pointer_ref, analyze_indirect_ref,
	strip_conversion, analyze_offset_expr, address_analysis,
	object_analysis, analyze_offset): Removed.
	(dr_analyze_innermost, dr_analyze_indices, dr_analyze_alias,
	split_constant_offset, canonicalize_base_object_address,
	object_address_invariant_in_loop_p, disjoint_objects_p,
	dr_may_alias_p, dr_address_invariant_p): New functions.
	(create_data_ref): Use dr_analyze_innermost, dr_analyze_indices
	and dr_analyze_alias.
	(initialize_data_dependence_relation): Use dr_may_alias_p
	and object_address_invariant_in_loop_p.
	(compute_self_dependence): Handle the case when DDR_ARE_DEPENDENT (ddr)
	is chrec_dont_know.
	(find_data_references_in_stmt): Restrict the analysis of data references
	to the given loop nest.
	(find_data_references_in_loop): Made static.  Pass loop nest to
	find_data_references_in_stmt.
	(compute_data_dependences_for_loop): Use DR_VOPS.
	(free_data_ref): Free DR_VOPS.
	* tree-data-ref.h (struct first_location_in_loop): Replaced by ...
	(struct innermost_loop_behavior): ... new.
	(struct base_object_info): Replaced by ...
	(struct indices): ... new.
	(struct dr_alias): New.
	(enum data_ref_type): Removed.
	(struct data_reference): Consist of struct innermost_loop_behavior,
	struct indices and struct dr_alias.
	(DR_SET_ACCESS_FNS, DR_FREE_ACCESS_FNS): Removed.
	(DR_MEMTAG): Renamed to ...
	(DR_SYMBOL_TAG): ... this.
	(find_data_references_in_loop): Declaration removed.
	* tree-vect-analyze.c (vect_compute_data_ref_alignment): Use DR_INIT
	instead of DR_OFFSET_MISALIGNMENT.  DR_ALIGNED_TO is never NULL.
	(vect_analyze_data_refs): Use DR_SYMBOL_TAG instead of DR_MEMTAG.
	* tree-vect-transform.c (vect_create_data_ref_ptr): Ditto.

	* gcc.dg/vect/no-section-anchors-vect-69.c: Fix outcome.
	* gcc.dg/tree-ssa/loop-30.c: New test.

From-SVN: r124655
parent de5e4138
2007-05-13 Zdenek Dvorak <dvorakz@suse.cz>
* tree-scalar-evolution.c (resolve_mixers): Exported.
* tree-scalar-evolution.h (resolve_mixers): Declare.
* tree-data-ref.c (object_analysis, ptr_decl_may_alias_p,
ptr_ptr_may_alias_p, may_alias_p, record_ptr_differ_p,
record_record_differ_p, record_array_differ_p, array_ptr_differ_p,
base_object_differ_p, base_addr_differ_p, analyze_array_indexes,
init_array_ref, init_pointer_ref, analyze_indirect_ref,
strip_conversion, analyze_offset_expr, address_analysis,
object_analysis, analyze_offset): Removed.
(dr_analyze_innermost, dr_analyze_indices, dr_analyze_alias,
split_constant_offset, canonicalize_base_object_address,
object_address_invariant_in_loop_p, disjoint_objects_p,
dr_may_alias_p, dr_address_invariant_p): New functions.
(create_data_ref): Use dr_analyze_innermost, dr_analyze_indices
and dr_analyze_alias.
(initialize_data_dependence_relation): Use dr_may_alias_p
and object_address_invariant_in_loop_p.
(compute_self_dependence): Handle the case when DDR_ARE_DEPENDENT (ddr)
is chrec_dont_know.
(find_data_references_in_stmt): Restrict the analysis of data references
to the given loop nest.
(find_data_references_in_loop): Made static. Pass loop nest to
find_data_references_in_stmt.
(compute_data_dependences_for_loop): Use DR_VOPS.
(free_data_ref): Free DR_VOPS.
* tree-data-ref.h (struct first_location_in_loop): Replaced by ...
(struct innermost_loop_behavior): ... new.
(struct base_object_info): Replaced by ...
(struct indices): ... new.
(struct dr_alias): New.
(enum data_ref_type): Removed.
(struct data_reference): Consist of struct innermost_loop_behavior,
struct indices and struct dr_alias.
(DR_SET_ACCESS_FNS, DR_FREE_ACCESS_FNS): Removed.
(DR_MEMTAG): Renamed to ...
(DR_SYMBOL_TAG): ... this.
(find_data_references_in_loop): Declaration removed.
* tree-vect-analyze.c (vect_compute_data_ref_alignment): Use DR_INIT
instead of DR_OFFSET_MISALIGNMENT. DR_ALIGNED_TO is never NULL.
(vect_analyze_data_refs): Use DR_SYMBOL_TAG instead of DR_MEMTAG.
* tree-vect-transform.c (vect_create_data_ref_ptr): Ditto.
2007-05-13 Revital Eres <eres@il.ibm.com> 2007-05-13 Revital Eres <eres@il.ibm.com>
* tree-ssa-dse.c (get_use_of_stmt_lhs): New function * tree-ssa-dse.c (get_use_of_stmt_lhs): New function
......
2007-05-13 Zdenek Dvorak <dvorakz@suse.cz>
* gcc.dg/vect/no-section-anchors-vect-69.c: Fix outcome.
* gcc.dg/tree-ssa/loop-30.c: New test.
2007-05-13 Richard Guenther <rguenther@suse.de> 2007-05-13 Richard Guenther <rguenther@suse.de>
* gcc.dg/tree-ssa/pr17141-1.c: Scan in forwprop2, xfail * gcc.dg/tree-ssa/pr17141-1.c: Scan in forwprop2, xfail
/* PR 25371 */
/* { dg-do compile } */
/* { dg-options "-O2 -ftree-vectorize" } */
void
slow_close(int n)
{
int i;
double *mm;
for (i=0;i<2*n;i++)
for (i=0;i<2*n;i++)
*(mm+i*2*n+i) = 0;
}
...@@ -50,7 +50,7 @@ int main1 () ...@@ -50,7 +50,7 @@ int main1 ()
abort (); abort ();
} }
/* 2. aligned on 8-bytes */ /* 2. aligned */
for (i = 3; i < N-1; i++) for (i = 3; i < N-1; i++)
{ {
tmp1[2].a.n[1][2][i] = 6; tmp1[2].a.n[1][2][i] = 6;
...@@ -63,7 +63,7 @@ int main1 () ...@@ -63,7 +63,7 @@ int main1 ()
abort (); abort ();
} }
/* 3. aligned on 16-bytes */ /* 3. aligned */
for (i = 0; i < N; i++) for (i = 0; i < N; i++)
{ {
for (j = 0; j < N; j++) for (j = 0; j < N; j++)
...@@ -113,8 +113,5 @@ int main (void) ...@@ -113,8 +113,5 @@ int main (void)
/* { dg-final { scan-tree-dump-times "vectorized 4 loops" 1 "vect" } } */ /* { dg-final { scan-tree-dump-times "vectorized 4 loops" 1 "vect" } } */
/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 0 "vect" } } */ /* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 0 "vect" } } */
/* Loops 1,2,4 are unaligned on targets that require 16-byte alignment. /* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 2 "vect" } } */
Loops 1,4 are unaligned on targets that require 8-byte alignment (ia64). */
/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 3 "vect" { xfail ia64-*-* } } } */
/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 2 "vect" { target ia64-*-* } } } */
/* { dg-final { cleanup-tree-dump "vect" } } */ /* { dg-final { cleanup-tree-dump "vect" } } */
...@@ -122,463 +122,9 @@ static struct datadep_stats ...@@ -122,463 +122,9 @@ static struct datadep_stats
int num_miv_unimplemented; int num_miv_unimplemented;
} dependence_stats; } dependence_stats;
static tree object_analysis (tree, tree, bool, struct data_reference **,
tree *, tree *, tree *, tree *, tree *,
struct ptr_info_def **, subvar_t *);
static bool subscript_dependence_tester_1 (struct data_dependence_relation *, static bool subscript_dependence_tester_1 (struct data_dependence_relation *,
struct data_reference *, struct data_reference *,
struct data_reference *); struct data_reference *);
/* Determine if PTR and DECL may alias, the result is put in ALIASED.
Return FALSE if there is no symbol memory tag for PTR. */
static bool
ptr_decl_may_alias_p (tree ptr, tree decl,
struct data_reference *ptr_dr,
bool *aliased)
{
tree tag = NULL_TREE;
struct ptr_info_def *pi = DR_PTR_INFO (ptr_dr);
gcc_assert (TREE_CODE (ptr) == SSA_NAME && DECL_P (decl));
if (pi)
tag = pi->name_mem_tag;
if (!tag)
tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
if (!tag)
tag = DR_MEMTAG (ptr_dr);
if (!tag)
return false;
*aliased = is_aliased_with (tag, decl);
return true;
}
/* Determine if two pointers may alias, the result is put in ALIASED.
Return FALSE if there is no symbol memory tag for one of the pointers. */
static bool
ptr_ptr_may_alias_p (tree ptr_a, tree ptr_b,
struct data_reference *dra,
struct data_reference *drb,
bool *aliased)
{
tree tag_a = NULL_TREE, tag_b = NULL_TREE;
struct ptr_info_def *pi_a = DR_PTR_INFO (dra);
struct ptr_info_def *pi_b = DR_PTR_INFO (drb);
bitmap bal1, bal2;
if (pi_a && pi_a->name_mem_tag && pi_b && pi_b->name_mem_tag)
{
tag_a = pi_a->name_mem_tag;
tag_b = pi_b->name_mem_tag;
}
else
{
tag_a = symbol_mem_tag (SSA_NAME_VAR (ptr_a));
if (!tag_a)
tag_a = DR_MEMTAG (dra);
if (!tag_a)
return false;
tag_b = symbol_mem_tag (SSA_NAME_VAR (ptr_b));
if (!tag_b)
tag_b = DR_MEMTAG (drb);
if (!tag_b)
return false;
}
bal1 = BITMAP_ALLOC (NULL);
bitmap_set_bit (bal1, DECL_UID (tag_a));
if (MTAG_P (tag_a) && MTAG_ALIASES (tag_a))
bitmap_ior_into (bal1, MTAG_ALIASES (tag_a));
bal2 = BITMAP_ALLOC (NULL);
bitmap_set_bit (bal2, DECL_UID (tag_b));
if (MTAG_P (tag_b) && MTAG_ALIASES (tag_b))
bitmap_ior_into (bal2, MTAG_ALIASES (tag_b));
*aliased = bitmap_intersect_p (bal1, bal2);
BITMAP_FREE (bal1);
BITMAP_FREE (bal2);
return true;
}
/* Determine if BASE_A and BASE_B may alias, the result is put in ALIASED.
Return FALSE if there is no symbol memory tag for one of the symbols. */
static bool
may_alias_p (tree base_a, tree base_b,
struct data_reference *dra,
struct data_reference *drb,
bool *aliased)
{
if (TREE_CODE (base_a) == ADDR_EXPR || TREE_CODE (base_b) == ADDR_EXPR)
{
if (TREE_CODE (base_a) == ADDR_EXPR && TREE_CODE (base_b) == ADDR_EXPR)
{
*aliased = (TREE_OPERAND (base_a, 0) == TREE_OPERAND (base_b, 0));
return true;
}
if (TREE_CODE (base_a) == ADDR_EXPR)
return ptr_decl_may_alias_p (base_b, TREE_OPERAND (base_a, 0), drb,
aliased);
else
return ptr_decl_may_alias_p (base_a, TREE_OPERAND (base_b, 0), dra,
aliased);
}
return ptr_ptr_may_alias_p (base_a, base_b, dra, drb, aliased);
}
/* Determine if a pointer (BASE_A) and a record/union access (BASE_B)
are not aliased. Return TRUE if they differ. */
static bool
record_ptr_differ_p (struct data_reference *dra,
struct data_reference *drb)
{
bool aliased;
tree base_a = DR_BASE_OBJECT (dra);
tree base_b = DR_BASE_OBJECT (drb);
if (TREE_CODE (base_b) != COMPONENT_REF)
return false;
/* Peel COMPONENT_REFs to get to the base. Do not peel INDIRECT_REFs.
For a.b.c.d[i] we will get a, and for a.b->c.d[i] we will get a.b.
Probably will be unnecessary with struct alias analysis. */
while (TREE_CODE (base_b) == COMPONENT_REF)
base_b = TREE_OPERAND (base_b, 0);
/* Compare a record/union access (b.c[i] or p->c[i]) and a pointer
((*q)[i]). */
if (TREE_CODE (base_a) == INDIRECT_REF
&& ((TREE_CODE (base_b) == VAR_DECL
&& (ptr_decl_may_alias_p (TREE_OPERAND (base_a, 0), base_b, dra,
&aliased)
&& !aliased))
|| (TREE_CODE (base_b) == INDIRECT_REF
&& (ptr_ptr_may_alias_p (TREE_OPERAND (base_a, 0),
TREE_OPERAND (base_b, 0), dra, drb,
&aliased)
&& !aliased))))
return true;
else
return false;
}
/* Determine if two record/union accesses are aliased. Return TRUE if they
differ. */
static bool
record_record_differ_p (struct data_reference *dra,
struct data_reference *drb)
{
bool aliased;
tree base_a = DR_BASE_OBJECT (dra);
tree base_b = DR_BASE_OBJECT (drb);
if (TREE_CODE (base_b) != COMPONENT_REF
|| TREE_CODE (base_a) != COMPONENT_REF)
return false;
/* Peel COMPONENT_REFs to get to the base. Do not peel INDIRECT_REFs.
For a.b.c.d[i] we will get a, and for a.b->c.d[i] we will get a.b.
Probably will be unnecessary with struct alias analysis. */
while (TREE_CODE (base_b) == COMPONENT_REF)
base_b = TREE_OPERAND (base_b, 0);
while (TREE_CODE (base_a) == COMPONENT_REF)
base_a = TREE_OPERAND (base_a, 0);
if (TREE_CODE (base_a) == INDIRECT_REF
&& TREE_CODE (base_b) == INDIRECT_REF
&& ptr_ptr_may_alias_p (TREE_OPERAND (base_a, 0),
TREE_OPERAND (base_b, 0),
dra, drb, &aliased)
&& !aliased)
return true;
else
return false;
}
/* Determine if an array access (BASE_A) and a record/union access (BASE_B)
are not aliased. Return TRUE if they differ. */
static bool
record_array_differ_p (struct data_reference *dra,
struct data_reference *drb)
{
bool aliased;
tree base_a = DR_BASE_OBJECT (dra);
tree base_b = DR_BASE_OBJECT (drb);
if (TREE_CODE (base_b) != COMPONENT_REF)
return false;
/* Peel COMPONENT_REFs to get to the base. Do not peel INDIRECT_REFs.
For a.b.c.d[i] we will get a, and for a.b->c.d[i] we will get a.b.
Probably will be unnecessary with struct alias analysis. */
while (TREE_CODE (base_b) == COMPONENT_REF)
base_b = TREE_OPERAND (base_b, 0);
/* Compare a record/union access (b.c[i] or p->c[i]) and an array access
(a[i]). In case of p->c[i] use alias analysis to verify that p is not
pointing to a. */
if (TREE_CODE (base_a) == VAR_DECL
&& (TREE_CODE (base_b) == VAR_DECL
|| (TREE_CODE (base_b) == INDIRECT_REF
&& (ptr_decl_may_alias_p (TREE_OPERAND (base_b, 0), base_a, drb,
&aliased)
&& !aliased))))
return true;
else
return false;
}
/* Determine if an array access (BASE_A) and a pointer (BASE_B)
are not aliased. Return TRUE if they differ. */
static bool
array_ptr_differ_p (tree base_a, tree base_b,
struct data_reference *drb)
{
bool aliased;
/* In case one of the bases is a pointer (a[i] and (*p)[i]), we check with the
help of alias analysis that p is not pointing to a. */
if (TREE_CODE (base_a) == VAR_DECL && TREE_CODE (base_b) == INDIRECT_REF
&& (ptr_decl_may_alias_p (TREE_OPERAND (base_b, 0), base_a, drb, &aliased)
&& !aliased))
return true;
else
return false;
}
/* This is the simplest data dependence test: determines whether the
data references A and B access the same array/region. Returns
false when the property is not computable at compile time.
Otherwise return true, and DIFFER_P will record the result. This
utility will not be necessary when alias_sets_conflict_p will be
less conservative. */
static bool
base_object_differ_p (struct data_reference *a,
struct data_reference *b,
bool *differ_p)
{
tree base_a = DR_BASE_OBJECT (a);
tree base_b = DR_BASE_OBJECT (b);
bool aliased;
if (!base_a || !base_b)
return false;
/* Determine if same base. Example: for the array accesses
a[i], b[i] or pointer accesses *a, *b, bases are a, b. */
if (base_a == base_b)
{
*differ_p = false;
return true;
}
/* For pointer based accesses, (*p)[i], (*q)[j], the bases are (*p)
and (*q) */
if (TREE_CODE (base_a) == INDIRECT_REF && TREE_CODE (base_b) == INDIRECT_REF
&& TREE_OPERAND (base_a, 0) == TREE_OPERAND (base_b, 0))
{
*differ_p = false;
return true;
}
/* Record/union based accesses - s.a[i], t.b[j]. bases are s.a,t.b. */
if (TREE_CODE (base_a) == COMPONENT_REF && TREE_CODE (base_b) == COMPONENT_REF
&& TREE_OPERAND (base_a, 0) == TREE_OPERAND (base_b, 0)
&& TREE_OPERAND (base_a, 1) == TREE_OPERAND (base_b, 1))
{
*differ_p = false;
return true;
}
/* Determine if different bases. */
/* At this point we know that base_a != base_b. However, pointer
accesses of the form x=(*p) and y=(*q), whose bases are p and q,
may still be pointing to the same base. In SSAed GIMPLE p and q will
be SSA_NAMES in this case. Therefore, here we check if they are
really two different declarations. */
if (TREE_CODE (base_a) == VAR_DECL && TREE_CODE (base_b) == VAR_DECL)
{
*differ_p = true;
return true;
}
/* In case one of the bases is a pointer (a[i] and (*p)[i]), we check with the
help of alias analysis that p is not pointing to a. */
if (array_ptr_differ_p (base_a, base_b, b)
|| array_ptr_differ_p (base_b, base_a, a))
{
*differ_p = true;
return true;
}
/* If the bases are pointers ((*q)[i] and (*p)[i]), we check with the
help of alias analysis they don't point to the same bases. */
if (TREE_CODE (base_a) == INDIRECT_REF && TREE_CODE (base_b) == INDIRECT_REF
&& (may_alias_p (TREE_OPERAND (base_a, 0), TREE_OPERAND (base_b, 0), a, b,
&aliased)
&& !aliased))
{
*differ_p = true;
return true;
}
/* Compare two record/union bases s.a and t.b: s != t or (a != b and
s and t are not unions). */
if (TREE_CODE (base_a) == COMPONENT_REF && TREE_CODE (base_b) == COMPONENT_REF
&& ((TREE_CODE (TREE_OPERAND (base_a, 0)) == VAR_DECL
&& TREE_CODE (TREE_OPERAND (base_b, 0)) == VAR_DECL
&& TREE_OPERAND (base_a, 0) != TREE_OPERAND (base_b, 0))
|| (TREE_CODE (TREE_TYPE (TREE_OPERAND (base_a, 0))) == RECORD_TYPE
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (base_b, 0))) == RECORD_TYPE
&& TREE_OPERAND (base_a, 1) != TREE_OPERAND (base_b, 1))))
{
*differ_p = true;
return true;
}
/* Compare a record/union access (b.c[i] or p->c[i]) and a pointer
((*q)[i]). */
if (record_ptr_differ_p (a, b) || record_ptr_differ_p (b, a))
{
*differ_p = true;
return true;
}
/* Compare a record/union access (b.c[i] or p->c[i]) and an array access
(a[i]). In case of p->c[i] use alias analysis to verify that p is not
pointing to a. */
if (record_array_differ_p (a, b) || record_array_differ_p (b, a))
{
*differ_p = true;
return true;
}
/* Compare two record/union accesses (b.c[i] or p->c[i]). */
if (record_record_differ_p (a, b))
{
*differ_p = true;
return true;
}
return false;
}
/* Function base_addr_differ_p.
This is the simplest data dependence test: determines whether the
data references DRA and DRB access the same array/region. Returns
false when the property is not computable at compile time.
Otherwise return true, and DIFFER_P will record the result.
The algorithm:
1. if (both DRA and DRB are represented as arrays)
compare DRA.BASE_OBJECT and DRB.BASE_OBJECT
2. else if (both DRA and DRB are represented as pointers)
try to prove that DRA.FIRST_LOCATION == DRB.FIRST_LOCATION
3. else if (DRA and DRB are represented differently or 2. fails)
only try to prove that the bases are surely different
*/
static bool
base_addr_differ_p (struct data_reference *dra,
struct data_reference *drb,
bool *differ_p)
{
tree addr_a = DR_BASE_ADDRESS (dra);
tree addr_b = DR_BASE_ADDRESS (drb);
tree type_a, type_b;
tree decl_a, decl_b;
bool aliased;
if (!addr_a || !addr_b)
return false;
type_a = TREE_TYPE (addr_a);
type_b = TREE_TYPE (addr_b);
gcc_assert (POINTER_TYPE_P (type_a) && POINTER_TYPE_P (type_b));
/* 1. if (both DRA and DRB are represented as arrays)
compare DRA.BASE_OBJECT and DRB.BASE_OBJECT. */
if (DR_TYPE (dra) == ARRAY_REF_TYPE && DR_TYPE (drb) == ARRAY_REF_TYPE)
return base_object_differ_p (dra, drb, differ_p);
/* 2. else if (both DRA and DRB are represented as pointers)
try to prove that DRA.FIRST_LOCATION == DRB.FIRST_LOCATION. */
/* If base addresses are the same, we check the offsets, since the access of
the data-ref is described by {base addr + offset} and its access function,
i.e., in order to decide whether the bases of data-refs are the same we
compare both base addresses and offsets. */
if (DR_TYPE (dra) == POINTER_REF_TYPE && DR_TYPE (drb) == POINTER_REF_TYPE
&& (addr_a == addr_b
|| (TREE_CODE (addr_a) == ADDR_EXPR && TREE_CODE (addr_b) == ADDR_EXPR
&& TREE_OPERAND (addr_a, 0) == TREE_OPERAND (addr_b, 0))))
{
/* Compare offsets. */
tree offset_a = DR_OFFSET (dra);
tree offset_b = DR_OFFSET (drb);
STRIP_NOPS (offset_a);
STRIP_NOPS (offset_b);
/* FORNOW: we only compare offsets that are MULT_EXPR, i.e., we don't handle
PLUS_EXPR. */
if (offset_a == offset_b
|| (TREE_CODE (offset_a) == MULT_EXPR
&& TREE_CODE (offset_b) == MULT_EXPR
&& TREE_OPERAND (offset_a, 0) == TREE_OPERAND (offset_b, 0)
&& TREE_OPERAND (offset_a, 1) == TREE_OPERAND (offset_b, 1)))
{
*differ_p = false;
return true;
}
}
/* 3. else if (DRA and DRB are represented differently or 2. fails)
only try to prove that the bases are surely different. */
/* Apply alias analysis. */
if (may_alias_p (addr_a, addr_b, dra, drb, &aliased) && !aliased)
{
*differ_p = true;
return true;
}
/* An instruction writing through a restricted pointer is "independent" of any
instruction reading or writing through a different restricted pointer,
in the same block/scope. */
else if (TYPE_RESTRICT (type_a)
&& TYPE_RESTRICT (type_b)
&& (!DR_IS_READ (drb) || !DR_IS_READ (dra))
&& TREE_CODE (DR_BASE_ADDRESS (dra)) == SSA_NAME
&& (decl_a = SSA_NAME_VAR (DR_BASE_ADDRESS (dra)))
&& TREE_CODE (decl_a) == PARM_DECL
&& TREE_CODE (DECL_CONTEXT (decl_a)) == FUNCTION_DECL
&& TREE_CODE (DR_BASE_ADDRESS (drb)) == SSA_NAME
&& (decl_b = SSA_NAME_VAR (DR_BASE_ADDRESS (drb)))
&& TREE_CODE (decl_b) == PARM_DECL
&& TREE_CODE (DECL_CONTEXT (decl_b)) == FUNCTION_DECL
&& DECL_CONTEXT (decl_a) == DECL_CONTEXT (decl_b))
{
*differ_p = true;
return true;
}
return false;
}
/* Returns true iff A divides B. */ /* Returns true iff A divides B. */
static inline bool static inline bool
...@@ -940,1125 +486,334 @@ dump_ddrs (FILE *file, VEC (ddr_p, heap) *ddrs) ...@@ -940,1125 +486,334 @@ dump_ddrs (FILE *file, VEC (ddr_p, heap) *ddrs)
fprintf (file, "\n\n"); fprintf (file, "\n\n");
} }
/* Expresses EXP as VAR + OFF, where off is a constant. The type of OFF
will be ssizetype. */
/* Given an ARRAY_REF node REF, records its access functions.
Example: given A[i][3], record in ACCESS_FNS the opnd1 function,
i.e. the constant "3", then recursively call the function on opnd0,
i.e. the ARRAY_REF "A[i]".
The function returns the base name: "A". */
static tree
analyze_array_indexes (struct loop *loop,
VEC(tree,heap) **access_fns,
tree ref, tree stmt)
{
tree opnd0, opnd1;
tree access_fn;
opnd0 = TREE_OPERAND (ref, 0);
opnd1 = TREE_OPERAND (ref, 1);
/* The detection of the evolution function for this data access is static void
postponed until the dependence test. This lazy strategy avoids split_constant_offset (tree exp, tree *var, tree *off)
the computation of access functions that are of no interest for
the optimizers. */
access_fn = instantiate_parameters
(loop, analyze_scalar_evolution (loop, opnd1));
VEC_safe_push (tree, heap, *access_fns, access_fn);
/* Recursively record other array access functions. */
if (TREE_CODE (opnd0) == ARRAY_REF)
return analyze_array_indexes (loop, access_fns, opnd0, stmt);
/* Return the base name of the data access. */
else
return opnd0;
}
/* For a data reference REF contained in the statement STMT, initialize
a DATA_REFERENCE structure, and return it. IS_READ flag has to be
set to true when REF is in the right hand side of an
assignment. */
static struct data_reference *
init_array_ref (tree stmt, tree ref, bool is_read)
{
struct loop *loop = loop_containing_stmt (stmt);
VEC(tree,heap) *acc_fns = VEC_alloc (tree, heap, 3);
struct data_reference *res = XNEW (struct data_reference);;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "(init_array_ref \n");
fprintf (dump_file, " (ref = ");
print_generic_stmt (dump_file, ref, 0);
fprintf (dump_file, ")\n");
}
DR_STMT (res) = stmt;
DR_REF (res) = ref;
DR_BASE_OBJECT (res) = analyze_array_indexes (loop, &acc_fns, ref, stmt);
DR_TYPE (res) = ARRAY_REF_TYPE;
DR_SET_ACCESS_FNS (res, acc_fns);
DR_IS_READ (res) = is_read;
DR_BASE_ADDRESS (res) = NULL_TREE;
DR_OFFSET (res) = NULL_TREE;
DR_INIT (res) = NULL_TREE;
DR_STEP (res) = NULL_TREE;
DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
DR_MEMTAG (res) = NULL_TREE;
DR_PTR_INFO (res) = NULL;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ")\n");
return res;
}
/* For a data reference REF contained in the statement STMT, initialize
a DATA_REFERENCE structure, and return it. */
static struct data_reference *
init_pointer_ref (tree stmt, tree ref, tree access_fn, bool is_read,
tree base_address, tree step, struct ptr_info_def *ptr_info)
{
struct data_reference *res = XNEW (struct data_reference);
VEC(tree,heap) *acc_fns = VEC_alloc (tree, heap, 3);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "(init_pointer_ref \n");
fprintf (dump_file, " (ref = ");
print_generic_stmt (dump_file, ref, 0);
fprintf (dump_file, ")\n");
}
DR_STMT (res) = stmt;
DR_REF (res) = ref;
DR_BASE_OBJECT (res) = NULL_TREE;
DR_TYPE (res) = POINTER_REF_TYPE;
DR_SET_ACCESS_FNS (res, acc_fns);
VEC_quick_push (tree, DR_ACCESS_FNS (res), access_fn);
DR_IS_READ (res) = is_read;
DR_BASE_ADDRESS (res) = base_address;
DR_OFFSET (res) = NULL_TREE;
DR_INIT (res) = NULL_TREE;
DR_STEP (res) = step;
DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
DR_MEMTAG (res) = NULL_TREE;
DR_PTR_INFO (res) = ptr_info;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, ")\n");
return res;
}
/* Analyze an indirect memory reference, REF, that comes from STMT.
IS_READ is true if this is an indirect load, and false if it is
an indirect store.
Return a new data reference structure representing the indirect_ref, or
NULL if we cannot describe the access function. */
static struct data_reference *
analyze_indirect_ref (tree stmt, tree ref, bool is_read)
{
struct loop *loop = loop_containing_stmt (stmt);
tree ptr_ref = TREE_OPERAND (ref, 0);
tree access_fn = analyze_scalar_evolution (loop, ptr_ref);
tree init = initial_condition_in_loop_num (access_fn, loop->num);
tree base_address = NULL_TREE, evolution, step = NULL_TREE;
struct ptr_info_def *ptr_info = NULL;
if (TREE_CODE (ptr_ref) == SSA_NAME)
ptr_info = SSA_NAME_PTR_INFO (ptr_ref);
STRIP_NOPS (init);
if (access_fn == chrec_dont_know || !init || init == chrec_dont_know)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nBad access function of ptr: ");
print_generic_expr (dump_file, ref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL;
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nAccess function of ptr: ");
print_generic_expr (dump_file, access_fn, TDF_SLIM);
fprintf (dump_file, "\n");
}
if (!expr_invariant_in_loop_p (loop, init))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\ninitial condition is not loop invariant.\n");
}
else
{
base_address = init;
evolution = evolution_part_in_loop_num (access_fn, loop->num);
if (evolution != chrec_dont_know)
{
if (!evolution)
step = ssize_int (0);
else
{
if (TREE_CODE (evolution) == INTEGER_CST)
step = fold_convert (ssizetype, evolution);
else
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nnon constant step for ptr access.\n");
}
}
else
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nunknown evolution of ptr.\n");
}
return init_pointer_ref (stmt, ref, access_fn, is_read, base_address,
step, ptr_info);
}
/* Function strip_conversions
Strip conversions that don't narrow the mode. */
static tree
strip_conversion (tree expr)
{
tree to, ti, oprnd0;
while (TREE_CODE (expr) == NOP_EXPR || TREE_CODE (expr) == CONVERT_EXPR)
{
to = TREE_TYPE (expr);
oprnd0 = TREE_OPERAND (expr, 0);
ti = TREE_TYPE (oprnd0);
if (!INTEGRAL_TYPE_P (to) || !INTEGRAL_TYPE_P (ti))
return NULL_TREE;
if (GET_MODE_SIZE (TYPE_MODE (to)) < GET_MODE_SIZE (TYPE_MODE (ti)))
return NULL_TREE;
expr = oprnd0;
}
return expr;
}
/* Function analyze_offset_expr
Given an offset expression EXPR received from get_inner_reference, analyze
it and create an expression for INITIAL_OFFSET by substituting the variables
of EXPR with initial_condition of the corresponding access_fn in the loop.
E.g.,
for i
for (j = 3; j < N; j++)
a[j].b[i][j] = 0;
For a[j].b[i][j], EXPR will be 'i * C_i + j * C_j + C'. 'i' cannot be
substituted, since its access_fn in the inner loop is i. 'j' will be
substituted with 3. An INITIAL_OFFSET will be 'i * C_i + C`', where
C` = 3 * C_j + C.
Compute MISALIGN (the misalignment of the data reference initial access from
its base). Misalignment can be calculated only if all the variables can be
substituted with constants, otherwise, we record maximum possible alignment
in ALIGNED_TO. In the above example, since 'i' cannot be substituted, MISALIGN
will be NULL_TREE, and the biggest divider of C_i (a power of 2) will be
recorded in ALIGNED_TO.
STEP is an evolution of the data reference in this loop in bytes.
In the above example, STEP is C_j.
Return FALSE, if the analysis fails, e.g., there is no access_fn for a
variable. In this case, all the outputs (INITIAL_OFFSET, MISALIGN, ALIGNED_TO
and STEP) are NULL_TREEs. Otherwise, return TRUE.
*/
static bool
analyze_offset_expr (tree expr,
struct loop *loop,
tree *initial_offset,
tree *misalign,
tree *aligned_to,
tree *step)
{ {
tree oprnd0; tree type = TREE_TYPE (exp), otype;
tree oprnd1; tree var0, var1;
tree left_offset = ssize_int (0); tree off0, off1;
tree right_offset = ssize_int (0);
tree left_misalign = ssize_int (0);
tree right_misalign = ssize_int (0);
tree left_step = ssize_int (0);
tree right_step = ssize_int (0);
enum tree_code code;
tree init, evolution;
tree left_aligned_to = NULL_TREE, right_aligned_to = NULL_TREE;
*step = NULL_TREE;
*misalign = NULL_TREE;
*aligned_to = NULL_TREE;
*initial_offset = NULL_TREE;
/* Strip conversions that don't narrow the mode. */
expr = strip_conversion (expr);
if (!expr)
return false;
/* Stop conditions:
1. Constant. */
if (TREE_CODE (expr) == INTEGER_CST)
{
*initial_offset = fold_convert (ssizetype, expr);
*misalign = fold_convert (ssizetype, expr);
*step = ssize_int (0);
return true;
}
/* 2. Variable. Try to substitute with initial_condition of the corresponding
access_fn in the current loop. */
if (SSA_VAR_P (expr))
{
tree access_fn = analyze_scalar_evolution (loop, expr);
if (access_fn == chrec_dont_know)
/* No access_fn. */
return false;
init = initial_condition_in_loop_num (access_fn, loop->num); *var = exp;
if (!expr_invariant_in_loop_p (loop, init)) STRIP_NOPS (exp);
/* Not enough information: may be not loop invariant. otype = TREE_TYPE (exp);
E.g., for a[b[i]], we get a[D], where D=b[i]. EXPR is D, its
initial_condition is D, but it depends on i - loop's induction
variable. */
return false;
evolution = evolution_part_in_loop_num (access_fn, loop->num);
if (evolution && TREE_CODE (evolution) != INTEGER_CST)
/* Evolution is not constant. */
return false;
if (TREE_CODE (init) == INTEGER_CST)
*misalign = fold_convert (ssizetype, init);
else
/* Not constant, misalignment cannot be calculated. */
*misalign = NULL_TREE;
*initial_offset = fold_convert (ssizetype, init);
*step = evolution ? fold_convert (ssizetype, evolution) : ssize_int (0);
return true;
}
/* Recursive computation. */ switch (TREE_CODE (exp))
if (!BINARY_CLASS_P (expr))
{ {
/* We expect to get binary expressions (PLUS/MINUS and MULT). */ case INTEGER_CST:
if (dump_file && (dump_flags & TDF_DETAILS)) *var = build_int_cst (type, 0);
{ *off = fold_convert (ssizetype, exp);
fprintf (dump_file, "\nNot binary expression "); return;
print_generic_expr (dump_file, expr, TDF_SLIM);
fprintf (dump_file, "\n");
}
return false;
}
oprnd0 = TREE_OPERAND (expr, 0);
oprnd1 = TREE_OPERAND (expr, 1);
if (!analyze_offset_expr (oprnd0, loop, &left_offset, &left_misalign, case PLUS_EXPR:
&left_aligned_to, &left_step) case MINUS_EXPR:
|| !analyze_offset_expr (oprnd1, loop, &right_offset, &right_misalign, split_constant_offset (TREE_OPERAND (exp, 0), &var0, &off0);
&right_aligned_to, &right_step)) split_constant_offset (TREE_OPERAND (exp, 1), &var1, &off1);
return false; *var = fold_convert (type, fold_build2 (TREE_CODE (exp), otype,
var0, var1));
*off = size_binop (TREE_CODE (exp), off0, off1);
return;
/* The type of the operation: plus, minus or mult. */
code = TREE_CODE (expr);
switch (code)
{
case MULT_EXPR: case MULT_EXPR:
if (TREE_CODE (right_offset) != INTEGER_CST) off1 = TREE_OPERAND (exp, 1);
/* RIGHT_OFFSET can be not constant. For example, for arrays of variable if (TREE_CODE (off1) != INTEGER_CST)
sized types. break;
FORNOW: We don't support such cases. */
return false; split_constant_offset (TREE_OPERAND (exp, 0), &var0, &off0);
*var = fold_convert (type, fold_build2 (MULT_EXPR, otype,
/* Strip conversions that don't narrow the mode. */ var0, off1));
left_offset = strip_conversion (left_offset); *off = size_binop (MULT_EXPR, off0, fold_convert (ssizetype, off1));
if (!left_offset) return;
return false;
/* Misalignment computation. */
if (SSA_VAR_P (left_offset))
{
/* If the left side contains variables that can't be substituted with
constants, the misalignment is unknown. However, if the right side
is a multiple of some alignment, we know that the expression is
aligned to it. Therefore, we record such maximum possible value.
*/
*misalign = NULL_TREE;
*aligned_to = ssize_int (highest_pow2_factor (right_offset));
}
else
{
/* The left operand was successfully substituted with constant. */
if (left_misalign)
{
/* In case of EXPR '(i * C1 + j) * C2', LEFT_MISALIGN is
NULL_TREE. */
*misalign = size_binop (code, left_misalign, right_misalign);
if (left_aligned_to && right_aligned_to)
*aligned_to = size_binop (MIN_EXPR, left_aligned_to,
right_aligned_to);
else
*aligned_to = left_aligned_to ?
left_aligned_to : right_aligned_to;
}
else
*misalign = NULL_TREE;
}
/* Step calculation. */ case ADDR_EXPR:
/* Multiply the step by the right operand. */ {
*step = size_binop (MULT_EXPR, left_step, right_offset); tree op, base, poffset;
break; HOST_WIDE_INT pbitsize, pbitpos;
enum machine_mode pmode;
case PLUS_EXPR: int punsignedp, pvolatilep;
case MINUS_EXPR:
/* Combine the recursive calculations for step and misalignment. */
*step = size_binop (code, left_step, right_step);
/* Unknown alignment. */ op = TREE_OPERAND (exp, 0);
if ((!left_misalign && !left_aligned_to) if (!handled_component_p (op))
|| (!right_misalign && !right_aligned_to))
{
*misalign = NULL_TREE;
*aligned_to = NULL_TREE;
break; break;
}
if (left_misalign && right_misalign) base = get_inner_reference (op, &pbitsize, &pbitpos, &poffset,
*misalign = size_binop (code, left_misalign, right_misalign); &pmode, &punsignedp, &pvolatilep, false);
else
*misalign = left_misalign ? left_misalign : right_misalign;
if (left_aligned_to && right_aligned_to) if (pbitpos % BITS_PER_UNIT != 0)
*aligned_to = size_binop (MIN_EXPR, left_aligned_to, right_aligned_to); break;
else base = build_fold_addr_expr (base);
*aligned_to = left_aligned_to ? left_aligned_to : right_aligned_to; off0 = ssize_int (pbitpos / BITS_PER_UNIT);
break; if (poffset)
{
split_constant_offset (poffset, &poffset, &off1);
off0 = size_binop (PLUS_EXPR, off0, off1);
base = fold_build2 (PLUS_EXPR, TREE_TYPE (base),
base,
fold_convert (TREE_TYPE (base), poffset));
}
*var = fold_convert (type, base);
*off = off0;
return;
}
default: default:
gcc_unreachable (); break;
} }
/* Compute offset. */ *off = ssize_int (0);
*initial_offset = fold_convert (ssizetype,
fold_build2 (code, TREE_TYPE (left_offset),
left_offset,
right_offset));
return true;
} }
/* Function address_analysis /* Returns the address ADDR of an object in a canonical shape (without nop
casts, and with type of pointer to the object). */
Return the BASE of the address expression EXPR.
Also compute the OFFSET from BASE, MISALIGN and STEP.
Input:
EXPR - the address expression that is being analyzed
STMT - the statement that contains EXPR or its original memory reference
IS_READ - TRUE if STMT reads from EXPR, FALSE if writes to EXPR
DR - data_reference struct for the original memory reference
Output:
BASE (returned value) - the base of the data reference EXPR.
INITIAL_OFFSET - initial offset of EXPR from BASE (an expression)
MISALIGN - offset of EXPR from BASE in bytes (a constant) or NULL_TREE if the
computation is impossible
ALIGNED_TO - maximum alignment of EXPR or NULL_TREE if MISALIGN can be
calculated (doesn't depend on variables)
STEP - evolution of EXPR in the loop
If something unexpected is encountered (an unsupported form of data-ref),
then NULL_TREE is returned.
*/
static tree static tree
address_analysis (tree expr, tree stmt, bool is_read, struct data_reference *dr, canonicalize_base_object_address (tree addr)
tree *offset, tree *misalign, tree *aligned_to, tree *step)
{ {
tree oprnd0, oprnd1, base_address, offset_expr, base_addr0, base_addr1; STRIP_NOPS (addr);
tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
tree dummy, address_aligned_to = NULL_TREE;
struct ptr_info_def *dummy1;
subvar_t dummy2;
switch (TREE_CODE (expr))
{
case PLUS_EXPR:
case MINUS_EXPR:
/* EXPR is of form {base +/- offset} (or {offset +/- base}). */
oprnd0 = TREE_OPERAND (expr, 0);
oprnd1 = TREE_OPERAND (expr, 1);
STRIP_NOPS (oprnd0); if (TREE_CODE (addr) != ADDR_EXPR)
STRIP_NOPS (oprnd1); return addr;
/* Recursively try to find the base of the address contained in EXPR.
For offset, the returned base will be NULL. */
base_addr0 = address_analysis (oprnd0, stmt, is_read, dr, &address_offset,
&address_misalign, &address_aligned_to,
step);
base_addr1 = address_analysis (oprnd1, stmt, is_read, dr, &address_offset,
&address_misalign, &address_aligned_to,
step);
/* We support cases where only one of the operands contains an
address. */
if ((base_addr0 && base_addr1) || (!base_addr0 && !base_addr1))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
"\neither more than one address or no addresses in expr ");
print_generic_expr (dump_file, expr, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
/* To revert STRIP_NOPS. */ return build_fold_addr_expr (TREE_OPERAND (addr, 0));
oprnd0 = TREE_OPERAND (expr, 0);
oprnd1 = TREE_OPERAND (expr, 1);
offset_expr = base_addr0 ?
fold_convert (ssizetype, oprnd1) : fold_convert (ssizetype, oprnd0);
/* EXPR is of form {base +/- offset} (or {offset +/- base}). If offset is
a number, we can add it to the misalignment value calculated for base,
otherwise, misalignment is NULL. */
if (TREE_CODE (offset_expr) == INTEGER_CST && address_misalign)
{
*misalign = size_binop (TREE_CODE (expr), address_misalign,
offset_expr);
*aligned_to = address_aligned_to;
}
else
{
*misalign = NULL_TREE;
*aligned_to = NULL_TREE;
}
/* Combine offset (from EXPR {base + offset}) with the offset calculated
for base. */
*offset = size_binop (TREE_CODE (expr), address_offset, offset_expr);
return base_addr0 ? base_addr0 : base_addr1;
case ADDR_EXPR:
base_address = object_analysis (TREE_OPERAND (expr, 0), stmt, is_read,
&dr, offset, misalign, aligned_to, step,
&dummy, &dummy1, &dummy2);
return base_address;
case SSA_NAME:
if (!POINTER_TYPE_P (TREE_TYPE (expr)))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nnot pointer SSA_NAME ");
print_generic_expr (dump_file, expr, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
*aligned_to = ssize_int (TYPE_ALIGN_UNIT (TREE_TYPE (TREE_TYPE (expr))));
*misalign = ssize_int (0);
*offset = ssize_int (0);
*step = ssize_int (0);
return expr;
default:
return NULL_TREE;
}
} }
/* Analyzes the behavior of the memory reference DR in the innermost loop that
contains it. */
/* Function object_analysis static void
dr_analyze_innermost (struct data_reference *dr)
Create a data-reference structure DR for MEMREF.
Return the BASE of the data reference MEMREF if the analysis is possible.
Also compute the INITIAL_OFFSET from BASE, MISALIGN and STEP.
E.g., for EXPR a.b[i] + 4B, BASE is a, and OFFSET is the overall offset
'a.b[i] + 4B' from a (can be an expression), MISALIGN is an OFFSET
instantiated with initial_conditions of access_functions of variables,
and STEP is the evolution of the DR_REF in this loop.
Function get_inner_reference is used for the above in case of ARRAY_REF and
COMPONENT_REF.
The structure of the function is as follows:
Part 1:
Case 1. For handled_component_p refs
1.1 build data-reference structure for MEMREF
1.2 call get_inner_reference
1.2.1 analyze offset expr received from get_inner_reference
(fall through with BASE)
Case 2. For declarations
2.1 set MEMTAG
Case 3. For INDIRECT_REFs
3.1 build data-reference structure for MEMREF
3.2 analyze evolution and initial condition of MEMREF
3.3 set data-reference structure for MEMREF
3.4 call address_analysis to analyze INIT of the access function
3.5 extract memory tag
Part 2:
Combine the results of object and address analysis to calculate
INITIAL_OFFSET, STEP and misalignment info.
Input:
MEMREF - the memory reference that is being analyzed
STMT - the statement that contains MEMREF
IS_READ - TRUE if STMT reads from MEMREF, FALSE if writes to MEMREF
Output:
BASE_ADDRESS (returned value) - the base address of the data reference MEMREF
E.g, if MEMREF is a.b[k].c[i][j] the returned
base is &a.
DR - data_reference struct for MEMREF
INITIAL_OFFSET - initial offset of MEMREF from BASE (an expression)
MISALIGN - offset of MEMREF from BASE in bytes (a constant) modulo alignment of
ALIGNMENT or NULL_TREE if the computation is impossible
ALIGNED_TO - maximum alignment of EXPR or NULL_TREE if MISALIGN can be
calculated (doesn't depend on variables)
STEP - evolution of the DR_REF in the loop
MEMTAG - memory tag for aliasing purposes
PTR_INFO - NULL or points-to aliasing info from a pointer SSA_NAME
SUBVARS - Sub-variables of the variable
If the analysis of MEMREF evolution in the loop fails, NULL_TREE is returned,
but DR can be created anyway.
*/
static tree
object_analysis (tree memref, tree stmt, bool is_read,
struct data_reference **dr, tree *offset, tree *misalign,
tree *aligned_to, tree *step, tree *memtag,
struct ptr_info_def **ptr_info, subvar_t *subvars)
{ {
tree base = NULL_TREE, base_address = NULL_TREE; tree stmt = DR_STMT (dr);
tree object_offset = ssize_int (0), object_misalign = ssize_int (0); struct loop *loop = loop_containing_stmt (stmt);
tree object_step = ssize_int (0), address_step = ssize_int (0); tree ref = DR_REF (dr);
tree address_offset = ssize_int (0), address_misalign = ssize_int (0);
HOST_WIDE_INT pbitsize, pbitpos; HOST_WIDE_INT pbitsize, pbitpos;
tree poffset, bit_pos_in_bytes; tree base, poffset;
enum machine_mode pmode; enum machine_mode pmode;
int punsignedp, pvolatilep; int punsignedp, pvolatilep;
tree ptr_step = ssize_int (0), ptr_init = NULL_TREE; affine_iv base_iv, offset_iv;
struct loop *loop = loop_containing_stmt (stmt); tree init, dinit, step;
struct data_reference *ptr_dr = NULL;
tree object_aligned_to = NULL_TREE, address_aligned_to = NULL_TREE; if (dump_file && (dump_flags & TDF_DETAILS))
tree comp_ref = NULL_TREE; fprintf (dump_file, "analyze_innermost: ");
*ptr_info = NULL; base = get_inner_reference (ref, &pbitsize, &pbitpos, &poffset,
&pmode, &punsignedp, &pvolatilep, false);
gcc_assert (base != NULL_TREE);
/* Part 1: */ if (pbitpos % BITS_PER_UNIT != 0)
/* Case 1. handled_component_p refs. */
if (handled_component_p (memref))
{ {
/* 1.1 build data-reference structure for MEMREF. */ if (dump_file && (dump_flags & TDF_DETAILS))
if (!(*dr)) fprintf (dump_file, "failed: bit offset alignment.\n");
{ return;
if (TREE_CODE (memref) == ARRAY_REF) }
*dr = init_array_ref (stmt, memref, is_read);
else if (TREE_CODE (memref) == COMPONENT_REF)
comp_ref = memref;
else
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\ndata-ref of unsupported type ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
}
/* 1.2 call get_inner_reference. */ base = build_fold_addr_expr (base);
/* Find the base and the offset from it. */ if (!simple_iv (loop, stmt, base, &base_iv, false))
base = get_inner_reference (memref, &pbitsize, &pbitpos, &poffset, {
&pmode, &punsignedp, &pvolatilep, false); if (dump_file && (dump_flags & TDF_DETAILS))
if (!base) fprintf (dump_file, "failed: evolution of base is not affine.\n");
{ return;
if (dump_file && (dump_flags & TDF_DETAILS)) }
{ if (!poffset)
fprintf (dump_file, "\nfailed to get inner ref for "); {
print_generic_expr (dump_file, memref, TDF_SLIM); offset_iv.base = ssize_int (0);
fprintf (dump_file, "\n"); offset_iv.step = ssize_int (0);
} }
return NULL_TREE; else if (!simple_iv (loop, stmt, poffset, &offset_iv, false))
} {
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "failed: evolution of offset is not affine.\n");
return;
}
/* 1.2.1 analyze offset expr received from get_inner_reference. */ init = ssize_int (pbitpos / BITS_PER_UNIT);
if (poffset split_constant_offset (base_iv.base, &base_iv.base, &dinit);
&& !analyze_offset_expr (poffset, loop, &object_offset, init = size_binop (PLUS_EXPR, init, dinit);
&object_misalign, &object_aligned_to, split_constant_offset (offset_iv.base, &offset_iv.base, &dinit);
&object_step)) init = size_binop (PLUS_EXPR, init, dinit);
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nfailed to compute offset or step for ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
/* Add bit position to OFFSET and MISALIGN. */ step = size_binop (PLUS_EXPR,
fold_convert (ssizetype, base_iv.step),
fold_convert (ssizetype, offset_iv.step));
bit_pos_in_bytes = ssize_int (pbitpos/BITS_PER_UNIT); DR_BASE_ADDRESS (dr) = canonicalize_base_object_address (base_iv.base);
/* Check that there is no remainder in bits. */
if (pbitpos%BITS_PER_UNIT)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\nbit offset alignment.\n");
return NULL_TREE;
}
object_offset = size_binop (PLUS_EXPR, bit_pos_in_bytes, object_offset);
if (object_misalign)
object_misalign = size_binop (PLUS_EXPR, object_misalign,
bit_pos_in_bytes);
memref = base; /* To continue analysis of BASE. */
/* fall through */
}
/* Part 1: Case 2. Declarations. */
if (DECL_P (memref))
{
/* We expect to get a decl only if we already have a DR, or with
COMPONENT_REFs of type 'a[i].b'. */
if (!(*dr))
{
if (comp_ref && TREE_CODE (TREE_OPERAND (comp_ref, 0)) == ARRAY_REF)
{
*dr = init_array_ref (stmt, TREE_OPERAND (comp_ref, 0), is_read);
if (DR_NUM_DIMENSIONS (*dr) != 1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\n multidimensional component ref ");
print_generic_expr (dump_file, comp_ref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
}
else
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nunhandled decl ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
}
/* TODO: if during the analysis of INDIRECT_REF we get to an object, put DR_OFFSET (dr) = fold_convert (ssizetype, offset_iv.base);
the object in BASE_OBJECT field if we can prove that this is O.K., DR_INIT (dr) = init;
i.e., the data-ref access is bounded by the bounds of the BASE_OBJECT. DR_STEP (dr) = step;
(e.g., if the object is an array base 'a', where 'a[N]', we must prove
that every access with 'p' (the original INDIRECT_REF based on '&a')
in the loop is within the array boundaries - from a[0] to a[N-1]).
Otherwise, our alias analysis can be incorrect.
Even if an access function based on BASE_OBJECT can't be build, update
BASE_OBJECT field to enable us to prove that two data-refs are
different (without access function, distance analysis is impossible).
*/
if (SSA_VAR_P (memref) && var_can_have_subvars (memref))
*subvars = get_subvars_for_var (memref);
base_address = build_fold_addr_expr (memref);
/* 2.1 set MEMTAG. */
*memtag = memref;
}
/* Part 1: Case 3. INDIRECT_REFs. */ DR_ALIGNED_TO (dr) = size_int (highest_pow2_factor (offset_iv.base));
else if (TREE_CODE (memref) == INDIRECT_REF)
{
tree ptr_ref = TREE_OPERAND (memref, 0);
if (TREE_CODE (ptr_ref) == SSA_NAME)
*ptr_info = SSA_NAME_PTR_INFO (ptr_ref);
/* 3.1 build data-reference structure for MEMREF. */ if (dump_file && (dump_flags & TDF_DETAILS))
ptr_dr = analyze_indirect_ref (stmt, memref, is_read); fprintf (dump_file, "success.\n");
if (!ptr_dr) }
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nfailed to create dr for ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
/* 3.2 analyze evolution and initial condition of MEMREF. */ /* Determines the base object and the list of indices of memory reference
ptr_step = DR_STEP (ptr_dr); DR, analysed in loop nest NEST. */
ptr_init = DR_BASE_ADDRESS (ptr_dr);
if (!ptr_init || !ptr_step || !POINTER_TYPE_P (TREE_TYPE (ptr_init)))
{
*dr = (*dr) ? *dr : ptr_dr;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nbad pointer access ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
if (integer_zerop (ptr_step) && !(*dr)) static void
{ dr_analyze_indices (struct data_reference *dr, struct loop *nest)
if (dump_file && (dump_flags & TDF_DETAILS)) {
fprintf (dump_file, "\nptr is loop invariant.\n"); tree stmt = DR_STMT (dr);
*dr = ptr_dr; struct loop *loop = loop_containing_stmt (stmt);
return NULL_TREE; VEC (tree, heap) *access_fns = NULL;
tree ref = unshare_expr (DR_REF (dr)), aref = ref, op;
/* If there exists DR for MEMREF, we are analyzing the base of tree base, off, access_fn;
handled component (PTR_INIT), which not necessary has evolution in
the loop. */
}
object_step = size_binop (PLUS_EXPR, object_step, ptr_step);
/* 3.3 set data-reference structure for MEMREF. */
if (!*dr)
*dr = ptr_dr;
/* 3.4 call address_analysis to analyze INIT of the access
function. */
base_address = address_analysis (ptr_init, stmt, is_read, *dr,
&address_offset, &address_misalign,
&address_aligned_to, &address_step);
if (!base_address)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nfailed to analyze address ");
print_generic_expr (dump_file, ptr_init, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL_TREE;
}
/* 3.5 extract memory tag. */ while (handled_component_p (aref))
switch (TREE_CODE (base_address))
{
case SSA_NAME:
*memtag = symbol_mem_tag (SSA_NAME_VAR (base_address));
if (!(*memtag) && TREE_CODE (TREE_OPERAND (memref, 0)) == SSA_NAME)
*memtag = symbol_mem_tag (SSA_NAME_VAR (TREE_OPERAND (memref, 0)));
break;
case ADDR_EXPR:
*memtag = TREE_OPERAND (base_address, 0);
break;
default:
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nno memtag for ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
*memtag = NULL_TREE;
break;
}
}
if (!base_address)
{ {
/* MEMREF cannot be analyzed. */ if (TREE_CODE (aref) == ARRAY_REF)
if (dump_file && (dump_flags & TDF_DETAILS))
{ {
fprintf (dump_file, "\ndata-ref of unsupported type "); op = TREE_OPERAND (aref, 1);
print_generic_expr (dump_file, memref, TDF_SLIM); access_fn = analyze_scalar_evolution (loop, op);
fprintf (dump_file, "\n"); access_fn = resolve_mixers (nest, access_fn);
VEC_safe_push (tree, heap, access_fns, access_fn);
TREE_OPERAND (aref, 1) = build_int_cst (TREE_TYPE (op), 0);
} }
return NULL_TREE;
aref = TREE_OPERAND (aref, 0);
} }
if (comp_ref) if (INDIRECT_REF_P (aref))
DR_REF (*dr) = comp_ref;
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);
if ((!object_misalign && !object_aligned_to)
|| (!address_misalign && !address_aligned_to))
{
*misalign = NULL_TREE;
*aligned_to = NULL_TREE;
}
else
{ {
if (object_misalign && address_misalign) op = TREE_OPERAND (aref, 0);
*misalign = size_binop (PLUS_EXPR, object_misalign, address_misalign); access_fn = analyze_scalar_evolution (loop, op);
else access_fn = resolve_mixers (nest, access_fn);
*misalign = object_misalign ? object_misalign : address_misalign; base = initial_condition (access_fn);
if (object_aligned_to && address_aligned_to) split_constant_offset (base, &base, &off);
*aligned_to = size_binop (MIN_EXPR, object_aligned_to, access_fn = chrec_replace_initial_condition (access_fn,
address_aligned_to); fold_convert (TREE_TYPE (base), off));
else
*aligned_to = object_aligned_to ? TREE_OPERAND (aref, 0) = base;
object_aligned_to : address_aligned_to; VEC_safe_push (tree, heap, access_fns, access_fn);
} }
*step = size_binop (PLUS_EXPR, object_step, address_step);
return base_address; DR_BASE_OBJECT (dr) = ref;
DR_ACCESS_FNS (dr) = access_fns;
} }
/* Function analyze_offset. /* Extracts the alias analysis information from the memory reference DR. */
Extract INVARIANT and CONSTANT parts from OFFSET.
*/ static void
static bool dr_analyze_alias (struct data_reference *dr)
analyze_offset (tree offset, tree *invariant, tree *constant)
{ {
tree op0, op1, constant_0, constant_1, invariant_0, invariant_1; tree stmt = DR_STMT (dr);
enum tree_code code = TREE_CODE (offset); tree ref = DR_REF (dr);
tree base = get_base_address (ref), addr, smt = NULL_TREE;
ssa_op_iter it;
tree op;
bitmap vops;
if (DECL_P (base))
smt = base;
else if (INDIRECT_REF_P (base))
{
addr = TREE_OPERAND (base, 0);
if (TREE_CODE (addr) == SSA_NAME)
{
smt = symbol_mem_tag (SSA_NAME_VAR (addr));
DR_PTR_INFO (dr) = SSA_NAME_PTR_INFO (addr);
}
}
*invariant = NULL_TREE; DR_SYMBOL_TAG (dr) = smt;
*constant = NULL_TREE; if (var_can_have_subvars (smt))
DR_SUBVARS (dr) = get_subvars_for_var (smt);
/* Not PLUS/MINUS expression - recursion stop condition. */ vops = BITMAP_ALLOC (NULL);
if (code != PLUS_EXPR && code != MINUS_EXPR) FOR_EACH_SSA_TREE_OPERAND (op, stmt, it, SSA_OP_VIRTUAL_USES)
{ {
if (TREE_CODE (offset) == INTEGER_CST) bitmap_set_bit (vops, DECL_UID (SSA_NAME_VAR (op)));
*constant = offset;
else
*invariant = offset;
return true;
} }
op0 = TREE_OPERAND (offset, 0); DR_VOPS (dr) = vops;
op1 = TREE_OPERAND (offset, 1); }
/* Recursive call with the operands. */ /* Returns true if the address of DR is invariant. */
if (!analyze_offset (op0, &invariant_0, &constant_0)
|| !analyze_offset (op1, &invariant_1, &constant_1))
return false;
/* Combine the results. Add negation to the subtrahend in case of static bool
subtraction. */ dr_address_invariant_p (struct data_reference *dr)
if (constant_0 && constant_1) {
return false; unsigned i;
*constant = constant_0 ? constant_0 : constant_1; tree idx;
if (code == MINUS_EXPR && constant_1)
*constant = fold_build1 (NEGATE_EXPR, TREE_TYPE (*constant), *constant); for (i = 0; VEC_iterate (tree, DR_ACCESS_FNS (dr), i, idx); i++)
if (tree_contains_chrecs (idx, NULL))
return false;
if (invariant_0 && invariant_1)
*invariant =
fold_build2 (code, TREE_TYPE (invariant_0), invariant_0, invariant_1);
else
{
*invariant = invariant_0 ? invariant_0 : invariant_1;
if (code == MINUS_EXPR && invariant_1)
*invariant =
fold_build1 (NEGATE_EXPR, TREE_TYPE (*invariant), *invariant);
}
return true; return true;
} }
/* Free the memory used by the data reference DR. */ /* Frees data reference DR. */
static void static void
free_data_ref (data_reference_p dr) free_data_ref (data_reference_p dr)
{ {
DR_FREE_ACCESS_FNS (dr); BITMAP_FREE (DR_VOPS (dr));
VEC_free (tree, heap, DR_ACCESS_FNS (dr));
free (dr); free (dr);
} }
/* Function create_data_ref. /* Analyzes memory reference MEMREF accessed in STMT. The reference
is read if IS_READ is true, write otherwise. Returns the
Create a data-reference structure for MEMREF. Set its DR_BASE_ADDRESS, data_reference description of MEMREF. NEST is the outermost loop of the
DR_OFFSET, DR_INIT, DR_STEP, DR_OFFSET_MISALIGNMENT, DR_ALIGNED_TO, loop nest in that the reference should be analysed. */
DR_MEMTAG, and DR_POINTSTO_INFO fields.
Input:
MEMREF - the memory reference that is being analyzed
STMT - the statement that contains MEMREF
IS_READ - TRUE if STMT reads from MEMREF, FALSE if writes to MEMREF
Output:
DR (returned value) - data_reference struct for MEMREF
*/
static struct data_reference * static struct data_reference *
create_data_ref (tree memref, tree stmt, bool is_read) create_data_ref (struct loop *nest, tree memref, tree stmt, bool is_read)
{ {
struct data_reference *dr = NULL; struct data_reference *dr;
tree base_address, offset, step, misalign, memtag;
struct loop *loop = loop_containing_stmt (stmt);
tree invariant = NULL_TREE, constant = NULL_TREE;
tree type_size, init_cond;
struct ptr_info_def *ptr_info;
subvar_t subvars = NULL;
tree aligned_to, type = NULL_TREE, orig_offset;
if (!memref)
return NULL;
base_address = object_analysis (memref, stmt, is_read, &dr, &offset,
&misalign, &aligned_to, &step, &memtag,
&ptr_info, &subvars);
if (!dr || !base_address)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\ncreate_data_ref: failed to create a dr for ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL;
}
DR_BASE_ADDRESS (dr) = base_address;
DR_OFFSET (dr) = offset;
DR_INIT (dr) = ssize_int (0);
DR_STEP (dr) = step;
DR_OFFSET_MISALIGNMENT (dr) = misalign;
DR_ALIGNED_TO (dr) = aligned_to;
DR_MEMTAG (dr) = memtag;
DR_PTR_INFO (dr) = ptr_info;
DR_SUBVARS (dr) = subvars;
type_size = fold_convert (ssizetype, TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr))));
/* Extract CONSTANT and INVARIANT from OFFSET. */
/* Remove cast from OFFSET and restore it for INVARIANT part. */
orig_offset = offset;
STRIP_NOPS (offset);
if (offset != orig_offset)
type = TREE_TYPE (orig_offset);
if (!analyze_offset (offset, &invariant, &constant))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\ncreate_data_ref: failed to analyze dr's");
fprintf (dump_file, " offset for ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n");
}
return NULL;
}
if (type && invariant)
invariant = fold_convert (type, invariant);
/* Put CONSTANT part of OFFSET in DR_INIT and INVARIANT in DR_OFFSET field if (dump_file && (dump_flags & TDF_DETAILS))
of DR. */
if (constant)
{ {
DR_INIT (dr) = fold_convert (ssizetype, constant); fprintf (dump_file, "Creating dr for ");
init_cond = fold_build2 (TRUNC_DIV_EXPR, TREE_TYPE (constant), print_generic_expr (dump_file, memref, TDF_SLIM);
constant, type_size); fprintf (dump_file, "\n");
} }
else
DR_INIT (dr) = init_cond = ssize_int (0);
if (invariant)
DR_OFFSET (dr) = invariant;
else
DR_OFFSET (dr) = ssize_int (0);
/* Change the access function for INIDIRECT_REFs, according to
DR_BASE_ADDRESS. Analyze OFFSET calculated in object_analysis. OFFSET is
an expression that can contain loop invariant expressions and constants.
We put the constant part in the initial condition of the access function
(for data dependence tests), and in DR_INIT of the data-ref. The loop
invariant part is put in DR_OFFSET.
The evolution part of the access function is STEP calculated in
object_analysis divided by the size of data type.
*/
if (!DR_BASE_OBJECT (dr)
|| (TREE_CODE (memref) == COMPONENT_REF && DR_NUM_DIMENSIONS (dr) == 1))
{
tree access_fn;
tree new_step;
/* Update access function. */
access_fn = DR_ACCESS_FN (dr, 0);
if (automatically_generated_chrec_p (access_fn))
{
free_data_ref (dr);
return NULL;
}
new_step = size_binop (TRUNC_DIV_EXPR, dr = XCNEW (struct data_reference);
fold_convert (ssizetype, step), type_size); DR_STMT (dr) = stmt;
DR_REF (dr) = memref;
init_cond = chrec_convert (chrec_type (access_fn), init_cond, stmt); DR_IS_READ (dr) = is_read;
new_step = chrec_convert (chrec_type (access_fn), new_step, stmt);
if (automatically_generated_chrec_p (init_cond)
|| automatically_generated_chrec_p (new_step))
{
free_data_ref (dr);
return NULL;
}
access_fn = chrec_replace_initial_condition (access_fn, init_cond);
access_fn = reset_evolution_in_loop (loop->num, access_fn, new_step);
VEC_replace (tree, DR_ACCESS_FNS (dr), 0, access_fn); dr_analyze_innermost (dr);
} dr_analyze_indices (dr, nest);
dr_analyze_alias (dr);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
struct ptr_info_def *pi = DR_PTR_INFO (dr); fprintf (dump_file, "\tbase_address: ");
fprintf (dump_file, "\nCreated dr for ");
print_generic_expr (dump_file, memref, TDF_SLIM);
fprintf (dump_file, "\n\tbase_address: ");
print_generic_expr (dump_file, DR_BASE_ADDRESS (dr), TDF_SLIM); print_generic_expr (dump_file, DR_BASE_ADDRESS (dr), TDF_SLIM);
fprintf (dump_file, "\n\toffset from base address: "); fprintf (dump_file, "\n\toffset from base address: ");
print_generic_expr (dump_file, DR_OFFSET (dr), TDF_SLIM); print_generic_expr (dump_file, DR_OFFSET (dr), TDF_SLIM);
fprintf (dump_file, "\n\tconstant offset from base address: "); fprintf (dump_file, "\n\tconstant offset from base address: ");
print_generic_expr (dump_file, DR_INIT (dr), TDF_SLIM); print_generic_expr (dump_file, DR_INIT (dr), TDF_SLIM);
fprintf (dump_file, "\n\tbase_object: ");
print_generic_expr (dump_file, DR_BASE_OBJECT (dr), TDF_SLIM);
fprintf (dump_file, "\n\tstep: "); fprintf (dump_file, "\n\tstep: ");
print_generic_expr (dump_file, DR_STEP (dr), TDF_SLIM); print_generic_expr (dump_file, DR_STEP (dr), TDF_SLIM);
fprintf (dump_file, "B\n\tmisalignment from base: "); fprintf (dump_file, "\n\taligned to: ");
print_generic_expr (dump_file, DR_OFFSET_MISALIGNMENT (dr), TDF_SLIM); print_generic_expr (dump_file, DR_ALIGNED_TO (dr), TDF_SLIM);
if (DR_OFFSET_MISALIGNMENT (dr)) fprintf (dump_file, "\n\tbase_object: ");
fprintf (dump_file, "B"); print_generic_expr (dump_file, DR_BASE_OBJECT (dr), TDF_SLIM);
if (DR_ALIGNED_TO (dr)) fprintf (dump_file, "\n\tsymbol tag: ");
{ print_generic_expr (dump_file, DR_SYMBOL_TAG (dr), TDF_SLIM);
fprintf (dump_file, "\n\taligned to: ");
print_generic_expr (dump_file, DR_ALIGNED_TO (dr), TDF_SLIM);
}
fprintf (dump_file, "\n\tmemtag: ");
print_generic_expr (dump_file, DR_MEMTAG (dr), TDF_SLIM);
fprintf (dump_file, "\n"); fprintf (dump_file, "\n");
if (pi && pi->name_mem_tag) }
{
fprintf (dump_file, "\n\tnametag: "); /* FIXME -- data dependence analysis does not work correctly for objects with
print_generic_expr (dump_file, pi->name_mem_tag, TDF_SLIM); invariant addresses. Let us fail here until the problem is fixed. */
fprintf (dump_file, "\n"); if (dr_address_invariant_p (dr))
} {
} free_data_ref (dr);
dr = NULL;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\tFAILED as dr address is invariant\n");
}
return dr; return dr;
} }
...@@ -2259,6 +1014,180 @@ conflict_fn_no_dependence (void) ...@@ -2259,6 +1014,180 @@ conflict_fn_no_dependence (void)
return fn; return fn;
} }
/* Returns true if the address of OBJ is invariant in LOOP. */
static bool
object_address_invariant_in_loop_p (struct loop *loop, tree obj)
{
while (handled_component_p (obj))
{
if (TREE_CODE (obj) == ARRAY_REF)
{
/* Index of the ARRAY_REF was zeroed in analyze_indices, thus we only
need to check the stride and the lower bound of the reference. */
if (chrec_contains_symbols_defined_in_loop (TREE_OPERAND (obj, 2),
loop->num)
|| chrec_contains_symbols_defined_in_loop (TREE_OPERAND (obj, 3),
loop->num))
return false;
}
else if (TREE_CODE (obj) == COMPONENT_REF)
{
if (chrec_contains_symbols_defined_in_loop (TREE_OPERAND (obj, 2),
loop->num))
return false;
}
obj = TREE_OPERAND (obj, 0);
}
if (!INDIRECT_REF_P (obj))
return true;
return !chrec_contains_symbols_defined_in_loop (TREE_OPERAND (obj, 0),
loop->num);
}
/* Returns true if A and B are accesses to different objects, or to different
fields of the same object. */
static bool
disjoint_objects_p (tree a, tree b)
{
tree base_a, base_b;
VEC (tree, heap) *comp_a = NULL, *comp_b = NULL;
bool ret;
base_a = get_base_address (a);
base_b = get_base_address (b);
if (DECL_P (base_a)
&& DECL_P (base_b)
&& base_a != base_b)
return true;
if (!operand_equal_p (base_a, base_b, 0))
return false;
/* Compare the component references of A and B. We must start from the inner
ones, so record them to the vector first. */
while (handled_component_p (a))
{
VEC_safe_push (tree, heap, comp_a, a);
a = TREE_OPERAND (a, 0);
}
while (handled_component_p (b))
{
VEC_safe_push (tree, heap, comp_b, b);
b = TREE_OPERAND (b, 0);
}
ret = false;
while (1)
{
if (VEC_length (tree, comp_a) == 0
|| VEC_length (tree, comp_b) == 0)
break;
a = VEC_pop (tree, comp_a);
b = VEC_pop (tree, comp_b);
/* Real and imaginary part of a variable do not alias. */
if ((TREE_CODE (a) == REALPART_EXPR
&& TREE_CODE (b) == IMAGPART_EXPR)
|| (TREE_CODE (a) == IMAGPART_EXPR
&& TREE_CODE (b) == REALPART_EXPR))
{
ret = true;
break;
}
if (TREE_CODE (a) != TREE_CODE (b))
break;
/* Nothing to do for ARRAY_REFs, as the indices of array_refs in
DR_BASE_OBJECT are always zero. */
if (TREE_CODE (a) == ARRAY_REF)
continue;
else if (TREE_CODE (a) == COMPONENT_REF)
{
if (operand_equal_p (TREE_OPERAND (a, 1), TREE_OPERAND (b, 1), 0))
continue;
/* Different fields of unions may overlap. */
base_a = TREE_OPERAND (a, 0);
if (TREE_CODE (TREE_TYPE (base_a)) == UNION_TYPE)
break;
/* Different fields of structures cannot. */
ret = true;
break;
}
else
break;
}
VEC_free (tree, heap, comp_a);
VEC_free (tree, heap, comp_b);
return ret;
}
/* Returns false if we can prove that data references A and B do not alias,
true otherwise. */
static bool
dr_may_alias_p (struct data_reference *a, struct data_reference *b)
{
tree addr_a = DR_BASE_ADDRESS (a);
tree addr_b = DR_BASE_ADDRESS (b);
tree type_a, type_b;
tree decl_a = NULL_TREE, decl_b = NULL_TREE;
/* If the sets of virtual operands are disjoint, the memory references do not
alias. */
if (!bitmap_intersect_p (DR_VOPS (a), DR_VOPS (b)))
return false;
/* If the accessed objects are disjoint, the memory references do not
alias. */
if (disjoint_objects_p (DR_BASE_OBJECT (a), DR_BASE_OBJECT (b)))
return false;
if (!addr_a || !addr_b)
return true;
/* If the references are based on different static objects, they cannot alias
(PTA should be able to disambiguate such accesses, but often it fails to,
since currently we cannot distinguish between pointer and offset in pointer
arithmetics). */
if (TREE_CODE (addr_a) == ADDR_EXPR
&& TREE_CODE (addr_b) == ADDR_EXPR)
return TREE_OPERAND (addr_a, 0) == TREE_OPERAND (addr_b, 0);
/* An instruction writing through a restricted pointer is "independent" of any
instruction reading or writing through a different restricted pointer,
in the same block/scope. */
type_a = TREE_TYPE (addr_a);
type_b = TREE_TYPE (addr_b);
gcc_assert (POINTER_TYPE_P (type_a) && POINTER_TYPE_P (type_b));
if (TREE_CODE (addr_a) == SSA_NAME)
decl_a = SSA_NAME_VAR (addr_a);
if (TREE_CODE (addr_b) == SSA_NAME)
decl_b = SSA_NAME_VAR (addr_b);
if (TYPE_RESTRICT (type_a) && TYPE_RESTRICT (type_b)
&& (!DR_IS_READ (a) || !DR_IS_READ (b))
&& decl_a && TREE_CODE (decl_a) == PARM_DECL
&& decl_b && TREE_CODE (decl_b) == PARM_DECL
&& TREE_CODE (DECL_CONTEXT (decl_a)) == FUNCTION_DECL
&& DECL_CONTEXT (decl_a) == DECL_CONTEXT (decl_b))
return false;
return true;
}
/* Initialize a data dependence relation between data accesses A and /* Initialize a data dependence relation between data accesses A and
B. NB_LOOPS is the number of loops surrounding the references: the B. NB_LOOPS is the number of loops surrounding the references: the
size of the classic distance/direction vectors. */ size of the classic distance/direction vectors. */
...@@ -2269,7 +1198,6 @@ initialize_data_dependence_relation (struct data_reference *a, ...@@ -2269,7 +1198,6 @@ initialize_data_dependence_relation (struct data_reference *a,
VEC (loop_p, heap) *loop_nest) VEC (loop_p, heap) *loop_nest)
{ {
struct data_dependence_relation *res; struct data_dependence_relation *res;
bool differ_p, known_dependence;
unsigned int i; unsigned int i;
res = XNEW (struct data_dependence_relation); res = XNEW (struct data_dependence_relation);
...@@ -2283,34 +1211,33 @@ initialize_data_dependence_relation (struct data_reference *a, ...@@ -2283,34 +1211,33 @@ initialize_data_dependence_relation (struct data_reference *a,
return res; return res;
} }
/* When A and B are arrays and their dimensions differ, we directly /* If the data references do not alias, then they are independent. */
initialize the relation to "there is no dependence": chrec_known. */ if (!dr_may_alias_p (a, b))
if (DR_BASE_OBJECT (a) && DR_BASE_OBJECT (b)
&& DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b))
{ {
DDR_ARE_DEPENDENT (res) = chrec_known; DDR_ARE_DEPENDENT (res) = chrec_known;
return res; return res;
} }
if (DR_BASE_ADDRESS (a) && DR_BASE_ADDRESS (b)) /* If the references do not access the same object, we do not know
known_dependence = base_addr_differ_p (a, b, &differ_p); whether they alias or not. */
else if (!operand_equal_p (DR_BASE_OBJECT (a), DR_BASE_OBJECT (b), 0))
known_dependence = base_object_differ_p (a, b, &differ_p);
if (!known_dependence)
{ {
/* Can't determine whether the data-refs access the same memory
region. */
DDR_ARE_DEPENDENT (res) = chrec_dont_know; DDR_ARE_DEPENDENT (res) = chrec_dont_know;
return res; return res;
} }
if (differ_p) /* If the base of the object is not invariant in the loop nest, we cannot
analyse it. TODO -- in fact, it would suffice to record that there may
be arbitrary depencences in the loops where the base object varies. */
if (!object_address_invariant_in_loop_p (VEC_index (loop_p, loop_nest, 0),
DR_BASE_OBJECT (a)))
{ {
DDR_ARE_DEPENDENT (res) = chrec_known; DDR_ARE_DEPENDENT (res) = chrec_dont_know;
return res; return res;
} }
gcc_assert (DR_NUM_DIMENSIONS (a) == DR_NUM_DIMENSIONS (b));
DDR_AFFINE_P (res) = true; DDR_AFFINE_P (res) = true;
DDR_ARE_DEPENDENT (res) = NULL_TREE; DDR_ARE_DEPENDENT (res) = NULL_TREE;
DDR_SUBSCRIPTS (res) = VEC_alloc (subscript_p, heap, DR_NUM_DIMENSIONS (a)); DDR_SUBSCRIPTS (res) = VEC_alloc (subscript_p, heap, DR_NUM_DIMENSIONS (a));
...@@ -4895,6 +3822,9 @@ compute_self_dependence (struct data_dependence_relation *ddr) ...@@ -4895,6 +3822,9 @@ compute_self_dependence (struct data_dependence_relation *ddr)
unsigned int i; unsigned int i;
struct subscript *subscript; struct subscript *subscript;
if (DDR_ARE_DEPENDENT (ddr) != NULL_TREE)
return;
for (i = 0; VEC_iterate (subscript_p, DDR_SUBSCRIPTS (ddr), i, subscript); for (i = 0; VEC_iterate (subscript_p, DDR_SUBSCRIPTS (ddr), i, subscript);
i++) i++)
{ {
...@@ -5013,10 +3943,11 @@ get_references_in_stmt (tree stmt, VEC (data_ref_loc, heap) **references) ...@@ -5013,10 +3943,11 @@ get_references_in_stmt (tree stmt, VEC (data_ref_loc, heap) **references)
} }
/* Stores the data references in STMT to DATAREFS. If there is an unanalyzable /* Stores the data references in STMT to DATAREFS. If there is an unanalyzable
reference, returns false, otherwise returns true. */ reference, returns false, otherwise returns true. NEST is the outermost
loop of the loop nest in that the references should be analysed. */
static bool static bool
find_data_references_in_stmt (tree stmt, find_data_references_in_stmt (struct loop *nest, tree stmt,
VEC (data_reference_p, heap) **datarefs) VEC (data_reference_p, heap) **datarefs)
{ {
unsigned i; unsigned i;
...@@ -5033,7 +3964,7 @@ find_data_references_in_stmt (tree stmt, ...@@ -5033,7 +3964,7 @@ find_data_references_in_stmt (tree stmt,
for (i = 0; VEC_iterate (data_ref_loc, references, i, ref); i++) for (i = 0; VEC_iterate (data_ref_loc, references, i, ref); i++)
{ {
dr = create_data_ref (*ref->pos, stmt, ref->is_read); dr = create_data_ref (nest, *ref->pos, stmt, ref->is_read);
if (dr) if (dr)
VEC_safe_push (data_reference_p, heap, *datarefs, dr); VEC_safe_push (data_reference_p, heap, *datarefs, dr);
else else
...@@ -5049,11 +3980,11 @@ find_data_references_in_stmt (tree stmt, ...@@ -5049,11 +3980,11 @@ find_data_references_in_stmt (tree stmt,
/* Search the data references in LOOP, and record the information into /* Search the data references in LOOP, and record the information into
DATAREFS. Returns chrec_dont_know when failing to analyze a DATAREFS. Returns chrec_dont_know when failing to analyze a
difficult case, returns NULL_TREE otherwise. difficult case, returns NULL_TREE otherwise.
TODO: This function should be made smarter so that it can handle address TODO: This function should be made smarter so that it can handle address
arithmetic as if they were array accesses, etc. */ arithmetic as if they were array accesses, etc. */
tree static tree
find_data_references_in_loop (struct loop *loop, find_data_references_in_loop (struct loop *loop,
VEC (data_reference_p, heap) **datarefs) VEC (data_reference_p, heap) **datarefs)
{ {
...@@ -5071,24 +4002,10 @@ find_data_references_in_loop (struct loop *loop, ...@@ -5071,24 +4002,10 @@ find_data_references_in_loop (struct loop *loop,
{ {
tree stmt = bsi_stmt (bsi); tree stmt = bsi_stmt (bsi);
if (!find_data_references_in_stmt (stmt, datarefs)) if (!find_data_references_in_stmt (loop, stmt, datarefs))
{ {
struct data_reference *res; struct data_reference *res;
res = XNEW (struct data_reference); res = XCNEW (struct data_reference);
DR_STMT (res) = NULL_TREE;
DR_REF (res) = NULL_TREE;
DR_BASE_OBJECT (res) = NULL;
DR_TYPE (res) = ARRAY_REF_TYPE;
DR_SET_ACCESS_FNS (res, NULL);
DR_BASE_OBJECT (res) = NULL;
DR_IS_READ (res) = false;
DR_BASE_ADDRESS (res) = NULL_TREE;
DR_OFFSET (res) = NULL_TREE;
DR_INIT (res) = NULL_TREE;
DR_STEP (res) = NULL_TREE;
DR_OFFSET_MISALIGNMENT (res) = NULL_TREE;
DR_MEMTAG (res) = NULL_TREE;
DR_PTR_INFO (res) = NULL;
VEC_safe_push (data_reference_p, heap, *datarefs, res); VEC_safe_push (data_reference_p, heap, *datarefs, res);
free (bbs); free (bbs);
...@@ -5155,7 +4072,6 @@ compute_data_dependences_for_loop (struct loop *loop, ...@@ -5155,7 +4072,6 @@ compute_data_dependences_for_loop (struct loop *loop,
VEC (data_reference_p, heap) **datarefs, VEC (data_reference_p, heap) **datarefs,
VEC (ddr_p, heap) **dependence_relations) VEC (ddr_p, heap) **dependence_relations)
{ {
struct loop *loop_nest = loop;
VEC (loop_p, heap) *vloops = VEC_alloc (loop_p, heap, 3); VEC (loop_p, heap) *vloops = VEC_alloc (loop_p, heap, 3);
memset (&dependence_stats, 0, sizeof (dependence_stats)); memset (&dependence_stats, 0, sizeof (dependence_stats));
...@@ -5163,8 +4079,8 @@ compute_data_dependences_for_loop (struct loop *loop, ...@@ -5163,8 +4079,8 @@ compute_data_dependences_for_loop (struct loop *loop,
/* If the loop nest is not well formed, or one of the data references /* If the loop nest is not well formed, or one of the data references
is not computable, give up without spending time to compute other is not computable, give up without spending time to compute other
dependences. */ dependences. */
if (!loop_nest if (!loop
|| !find_loop_nest (loop_nest, &vloops) || !find_loop_nest (loop, &vloops)
|| find_data_references_in_loop (loop, datarefs) == chrec_dont_know) || find_data_references_in_loop (loop, datarefs) == chrec_dont_know)
{ {
struct data_dependence_relation *ddr; struct data_dependence_relation *ddr;
...@@ -5287,12 +4203,8 @@ analyze_all_data_dependences (struct loop *loop) ...@@ -5287,12 +4203,8 @@ analyze_all_data_dependences (struct loop *loop)
{ {
struct data_reference *a = DDR_A (ddr); struct data_reference *a = DDR_A (ddr);
struct data_reference *b = DDR_B (ddr); struct data_reference *b = DDR_B (ddr);
bool differ_p;
if (!bitmap_intersect_p (DR_VOPS (a), DR_VOPS (b)))
if ((DR_BASE_OBJECT (a) && DR_BASE_OBJECT (b)
&& DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b))
|| (base_object_differ_p (a, b, &differ_p)
&& differ_p))
nb_basename_differ++; nb_basename_differ++;
else else
nb_bot_relations++; nb_bot_relations++;
......
...@@ -26,48 +26,73 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ...@@ -26,48 +26,73 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "omega.h" #include "omega.h"
/* /*
The first location accessed by data-ref in the loop is the address of data-ref's innermost_loop_behavior describes the evolution of the address of the memory
base (BASE_ADDRESS) plus the initial offset from the base. We divide the initial offset reference in the innermost enclosing loop. The address is expressed as
into two parts: loop invariant offset (OFFSET) and constant offset (INIT). BASE + STEP * # of iteration, and base is further decomposed as the base
STEP is the stride of data-ref in the loop in bytes. pointer (BASE_ADDRESS), loop invariant offset (OFFSET) and
constant offset (INIT). Examples, in loop nest
for (i = 0; i < 100; i++)
for (j = 3; j < 100; j++)
Example 1 Example 2 Example 1 Example 2
data-ref a[j].b[i][j] a + x + 16B (a is int*) data-ref a[j].b[i][j] *(p + x + 16B + 4B * j)
First location info: innermost_loop_behavior
base_address &a a base_address &a p
offset j_0*D_j + i_0*D_i x offset i * D_i x
init C_b + C_a 16 init 3 * D_j + offsetof (b) 28
step D_j 4 step D_j 4
access_fn NULL {16, +, 1}
Base object info:
base_object a NULL
access_fn <access_fns of indexes of b> NULL
*/ */
struct first_location_in_loop struct innermost_loop_behavior
{ {
tree base_address; tree base_address;
tree offset; tree offset;
tree init; tree init;
tree step; tree step;
/* Access function related to first location in the loop. */
VEC(tree,heap) *access_fns; /* Alignment information. ALIGNED_TO is set to the largest power of two
that divides OFFSET. */
tree aligned_to;
}; };
struct base_object_info /* Describes the evolutions of indices of the memory reference. The indices
are indices of the ARRAY_REFs and the operands of INDIRECT_REFs.
For ARRAY_REFs, BASE_OBJECT is the reference with zeroed indices
(note that this reference does not have to be valid, if zero does not
belong to the range of the array; hence it is not recommended to use
BASE_OBJECT in any code generation). For INDIRECT_REFs, the address is
set to the loop-invariant part of the address of the object, except for
the constant offset. For the examples above,
base_object: a[0].b[0][0] *(p + x + 4B * j_0)
indices: {j_0, +, 1}_2 {16, +, 4}_2
{i_0, +, 1}_1
{j_0, +, 1}_2
*/
struct indices
{ {
/* The object. */ /* The object. */
tree base_object; tree base_object;
/* A list of chrecs. Access functions related to BASE_OBJECT. */ /* A list of chrecs. Access functions of the indices. */
VEC(tree,heap) *access_fns; VEC(tree,heap) *access_fns;
}; };
enum data_ref_type { struct dr_alias
ARRAY_REF_TYPE, {
POINTER_REF_TYPE /* The alias information that should be used for new pointers to this
location. SYMBOL_TAG is either a DECL or a SYMBOL_MEMORY_TAG. */
tree symbol_tag;
subvar_t subvars;
struct ptr_info_def *ptr_info;
/* The set of virtual operands corresponding to this memory reference,
serving as a description of the alias information for the memory
reference. This could be eliminated if we had alias oracle. */
bitmap vops;
}; };
struct data_reference struct data_reference
...@@ -75,7 +100,7 @@ struct data_reference ...@@ -75,7 +100,7 @@ struct data_reference
/* A pointer to the statement that contains this DR. */ /* A pointer to the statement that contains this DR. */
tree stmt; tree stmt;
/* A pointer to the ARRAY_REF node. */ /* A pointer to the memory reference. */
tree ref; tree ref;
/* Auxiliary info specific to a pass. */ /* Auxiliary info specific to a pass. */
...@@ -84,58 +109,14 @@ struct data_reference ...@@ -84,58 +109,14 @@ struct data_reference
/* True when the data reference is in RHS of a stmt. */ /* True when the data reference is in RHS of a stmt. */
bool is_read; bool is_read;
/* First location accessed by the data-ref in the loop. */ /* Behavior of the memory reference in the innermost loop. */
struct first_location_in_loop first_location; struct innermost_loop_behavior innermost;
/* Base object related info. */ /* Decomposition to indices for alias analysis. */
struct base_object_info object_info; struct indices indices;
/* Aliasing information. This field represents the symbol that /* Alias information for the data reference. */
should be aliased by a pointer holding the address of this data struct dr_alias alias;
reference. If the original data reference was a pointer
dereference, then this field contains the memory tag that should
be used by the new vector-pointer. */
tree memtag;
struct ptr_info_def *ptr_info;
subvar_t subvars;
/* Alignment information.
MISALIGNMENT is the offset of the data-reference from its base in bytes.
ALIGNED_TO is the maximum data-ref's alignment.
Example 1,
for i
for (j = 3; j < N; j++)
a[j].b[i][j] = 0;
For a[j].b[i][j], the offset from base (calculated in get_inner_reference()
will be 'i * C_i + j * C_j + C'.
We try to substitute the variables of the offset expression
with initial_condition of the corresponding access_fn in the loop.
'i' cannot be substituted, since its access_fn in the inner loop is i. 'j'
will be substituted with 3.
Example 2
for (j = 3; j < N; j++)
a[j].b[5][j] = 0;
Here the offset expression (j * C_j + C) will not contain variables after
substitution of j=3 (3*C_j + C).
Misalignment can be calculated only if all the variables can be
substituted with constants, otherwise, we record maximum possible alignment
in ALIGNED_TO. In Example 1, since 'i' cannot be substituted,
MISALIGNMENT will be NULL_TREE, and the biggest divider of C_i (a power of
2) will be recorded in ALIGNED_TO.
In Example 2, MISALIGNMENT will be the value of 3*C_j + C in bytes, and
ALIGNED_TO will be NULL_TREE.
*/
tree misalignment;
tree aligned_to;
/* The type of the data-ref. */
enum data_ref_type type;
}; };
typedef struct data_reference *data_reference_p; typedef struct data_reference *data_reference_p;
...@@ -144,37 +125,20 @@ DEF_VEC_ALLOC_P (data_reference_p, heap); ...@@ -144,37 +125,20 @@ DEF_VEC_ALLOC_P (data_reference_p, heap);
#define DR_STMT(DR) (DR)->stmt #define DR_STMT(DR) (DR)->stmt
#define DR_REF(DR) (DR)->ref #define DR_REF(DR) (DR)->ref
#define DR_BASE_OBJECT(DR) (DR)->object_info.base_object #define DR_BASE_OBJECT(DR) (DR)->indices.base_object
#define DR_TYPE(DR) (DR)->type #define DR_ACCESS_FNS(DR) (DR)->indices.access_fns
#define DR_ACCESS_FNS(DR)\
(DR_TYPE(DR) == ARRAY_REF_TYPE ? \
(DR)->object_info.access_fns : (DR)->first_location.access_fns)
#define DR_ACCESS_FN(DR, I) VEC_index (tree, DR_ACCESS_FNS (DR), I) #define DR_ACCESS_FN(DR, I) VEC_index (tree, DR_ACCESS_FNS (DR), I)
#define DR_NUM_DIMENSIONS(DR) VEC_length (tree, DR_ACCESS_FNS (DR)) #define DR_NUM_DIMENSIONS(DR) VEC_length (tree, DR_ACCESS_FNS (DR))
#define DR_IS_READ(DR) (DR)->is_read #define DR_IS_READ(DR) (DR)->is_read
#define DR_BASE_ADDRESS(DR) (DR)->first_location.base_address #define DR_BASE_ADDRESS(DR) (DR)->innermost.base_address
#define DR_OFFSET(DR) (DR)->first_location.offset #define DR_OFFSET(DR) (DR)->innermost.offset
#define DR_INIT(DR) (DR)->first_location.init #define DR_INIT(DR) (DR)->innermost.init
#define DR_STEP(DR) (DR)->first_location.step #define DR_STEP(DR) (DR)->innermost.step
#define DR_MEMTAG(DR) (DR)->memtag #define DR_SYMBOL_TAG(DR) (DR)->alias.symbol_tag
#define DR_ALIGNED_TO(DR) (DR)->aligned_to #define DR_PTR_INFO(DR) (DR)->alias.ptr_info
#define DR_OFFSET_MISALIGNMENT(DR) (DR)->misalignment #define DR_SUBVARS(DR) (DR)->alias.subvars
#define DR_PTR_INFO(DR) (DR)->ptr_info #define DR_VOPS(DR) (DR)->alias.vops
#define DR_SUBVARS(DR) (DR)->subvars #define DR_ALIGNED_TO(DR) (DR)->innermost.aligned_to
#define DR_SET_ACCESS_FNS(DR, ACC_FNS) \
{ \
if (DR_TYPE(DR) == ARRAY_REF_TYPE) \
(DR)->object_info.access_fns = ACC_FNS; \
else \
(DR)->first_location.access_fns = ACC_FNS; \
}
#define DR_FREE_ACCESS_FNS(DR) \
{ \
if (DR_TYPE(DR) == ARRAY_REF_TYPE) \
VEC_free (tree, heap, (DR)->object_info.access_fns); \
else \
VEC_free (tree, heap, (DR)->first_location.access_fns); \
}
enum data_dependence_direction { enum data_dependence_direction {
dir_positive, dir_positive,
...@@ -335,8 +299,6 @@ DEF_VEC_O (data_ref_loc); ...@@ -335,8 +299,6 @@ DEF_VEC_O (data_ref_loc);
DEF_VEC_ALLOC_O (data_ref_loc, heap); DEF_VEC_ALLOC_O (data_ref_loc, heap);
bool get_references_in_stmt (tree, VEC (data_ref_loc, heap) **); bool get_references_in_stmt (tree, VEC (data_ref_loc, heap) **);
extern tree find_data_references_in_loop (struct loop *,
VEC (data_reference_p, heap) **);
extern void compute_data_dependences_for_loop (struct loop *, bool, extern void compute_data_dependences_for_loop (struct loop *, bool,
VEC (data_reference_p, heap) **, VEC (data_reference_p, heap) **,
VEC (ddr_p, heap) **); VEC (ddr_p, heap) **);
......
...@@ -254,7 +254,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ...@@ -254,7 +254,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#include "params.h" #include "params.h"
static tree analyze_scalar_evolution_1 (struct loop *, tree, tree); static tree analyze_scalar_evolution_1 (struct loop *, tree, tree);
static tree resolve_mixers (struct loop *, tree);
/* The cached information about a ssa name VAR, claiming that inside LOOP, /* The cached information about a ssa name VAR, claiming that inside LOOP,
the value of VAR can be expressed as CHREC. */ the value of VAR can be expressed as CHREC. */
...@@ -2408,7 +2407,7 @@ instantiate_parameters (struct loop *loop, ...@@ -2408,7 +2407,7 @@ instantiate_parameters (struct loop *loop,
care about causing overflows, as long as they do not affect value care about causing overflows, as long as they do not affect value
of an expression. */ of an expression. */
static tree tree
resolve_mixers (struct loop *loop, tree chrec) resolve_mixers (struct loop *loop, tree chrec)
{ {
htab_t cache = htab_create (10, hash_scev_info, eq_scev_info, del_scev_info); htab_t cache = htab_create (10, hash_scev_info, eq_scev_info, del_scev_info);
......
...@@ -31,6 +31,7 @@ extern void scev_reset (void); ...@@ -31,6 +31,7 @@ extern void scev_reset (void);
extern void scev_finalize (void); extern void scev_finalize (void);
extern tree analyze_scalar_evolution (struct loop *, tree); extern tree analyze_scalar_evolution (struct loop *, tree);
extern tree instantiate_parameters (struct loop *, tree); extern tree instantiate_parameters (struct loop *, tree);
extern tree resolve_mixers (struct loop *, tree);
extern void gather_stats_on_scev_database (void); extern void gather_stats_on_scev_database (void);
extern void scev_analysis (void); extern void scev_analysis (void);
unsigned int scev_const_prop (void); unsigned int scev_const_prop (void);
......
...@@ -1130,15 +1130,14 @@ vect_compute_data_ref_alignment (struct data_reference *dr) ...@@ -1130,15 +1130,14 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
/* Initialize misalignment to unknown. */ /* Initialize misalignment to unknown. */
DR_MISALIGNMENT (dr) = -1; DR_MISALIGNMENT (dr) = -1;
misalign = DR_OFFSET_MISALIGNMENT (dr); misalign = DR_INIT (dr);
aligned_to = DR_ALIGNED_TO (dr); aligned_to = DR_ALIGNED_TO (dr);
base_addr = DR_BASE_ADDRESS (dr); base_addr = DR_BASE_ADDRESS (dr);
base = build_fold_indirect_ref (base_addr); base = build_fold_indirect_ref (base_addr);
vectype = STMT_VINFO_VECTYPE (stmt_info); vectype = STMT_VINFO_VECTYPE (stmt_info);
alignment = ssize_int (TYPE_ALIGN (vectype)/BITS_PER_UNIT); alignment = ssize_int (TYPE_ALIGN (vectype)/BITS_PER_UNIT);
if ((aligned_to && tree_int_cst_compare (aligned_to, alignment) < 0) if (tree_int_cst_compare (aligned_to, alignment) < 0)
|| !misalign)
{ {
if (vect_print_dump_info (REPORT_DETAILS)) if (vect_print_dump_info (REPORT_DETAILS))
{ {
...@@ -2044,7 +2043,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo) ...@@ -2044,7 +2043,7 @@ vect_analyze_data_refs (loop_vec_info loop_vinfo)
} }
return false; return false;
} }
if (!DR_MEMTAG (dr)) if (!DR_SYMBOL_TAG (dr))
{ {
if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS)) if (vect_print_dump_info (REPORT_UNVECTORIZED_LOOPS))
{ {
......
...@@ -298,7 +298,7 @@ vect_create_data_ref_ptr (tree stmt, ...@@ -298,7 +298,7 @@ vect_create_data_ref_ptr (tree stmt,
/** (2) Add aliasing information to the new vector-pointer: /** (2) Add aliasing information to the new vector-pointer:
(The points-to info (DR_PTR_INFO) may be defined later.) **/ (The points-to info (DR_PTR_INFO) may be defined later.) **/
tag = DR_MEMTAG (dr); tag = DR_SYMBOL_TAG (dr);
gcc_assert (tag); gcc_assert (tag);
/* If tag is a variable (and NOT_A_TAG) than a new symbol memory /* If tag is a variable (and NOT_A_TAG) than a new symbol memory
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment