summaryrefslogtreecommitdiff
path: root/gcc/tree-data-ref.c
diff options
context:
space:
mode:
authorspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>2008-02-28 12:37:24 +0000
committerspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>2008-02-28 12:37:24 +0000
commit801c5610886591ce60ea92d2073a0f8cf2caea31 (patch)
tree9b84bf0f68098103bdd76fd0c6c2fa17afc3dd07 /gcc/tree-data-ref.c
parent9c467f1355d2f806a7ac06c22a18fd1d2e7e748f (diff)
downloadgcc-801c5610886591ce60ea92d2073a0f8cf2caea31.tar.gz
* doc/invoke.texi: Document -ftree-loop-distribution.
* tree-loop-distribution.c: New. * tree-pass.h (pass_loop_distribution): New. * graphds.h (struct graph): Add htab_t indices. * timevar.def (TV_TREE_LOOP_DISTRIBUTION): New. * tree-vectorizer.c (rename_variables_in_loop): Extern. (slpeel_tree_duplicate_loop_to_edge_cfg): Init PENDING_STMT to NULL. * tree-vectorizer.h (tree_duplicate_loop_on_edge): Declared. * tree-data-ref.c (debug_data_dependence_relations): New. (dump_data_dependence_relation): Also print data references. (free_data_ref): Extern. (same_access_functions): Moved... (find_vertex_for_stmt): Renamed rdg_vertex_for_stmt. (dump_rdg_vertex, debug_rdg_vertex, dump_rdg_component, debug_rdg_component, dump_rdg, debug_rdg, dot_rdg_1, dot_rdg, struct rdg_vertex_info, rdg_vertex_for_stmt): New. (create_rdg_edge_for_ddr, create_rdg_vertices): Cleaned up. (stmts_from_loop): Skip LABEL_EXPR. (hash_stmt_vertex_info, eq_stmt_vertex_info, hash_stmt_vertex_del): New. (build_rdg): Initialize rdg->indices htab. (free_rdg, stores_from_loop, ref_base_address, rdg_defs_used_in_other_loops_p, have_similar_memory_accesses, have_similar_memory_accesses_1, ref_base_address_1, remove_similar_memory_refs): New. * tree-data-ref.h: Depend on tree-chrec.h. (debug_data_dependence_relations, free_data_ref): Declared. (same_access_functions): ... here. (ddr_is_anti_dependent, ddrs_have_anti_deps, ddr_dependence_level): New. (struct rdg_vertex): Add has_mem_write and has_mem_reads. (RDGV_HAS_MEM_WRITE, RDGV_HAS_MEM_READS, RDG_STMT, RDG_MEM_WRITE_STMT, RDG_MEM_READS_STMT): New. (dump_rdg_vertex, debug_rdg_vertex, dump_rdg_component, debug_rdg_component, dump_rdg, debug_rdg, dot_rdg, rdg_vertex_for_stmt): Declared. (struct rdg_edge): Add level. (RDGE_LEVEL): New. (free_rdg, stores_from_loop, remove_similar_memory_refs, rdg_defs_used_in_other_loops_p, have_similar_memory_accesses): Declared. (rdg_has_similar_memory_accesses): New. * tree-vect-analyze.c: Remove unused static decls. * lambda.h (dependence_level): New. * common.opt (ftree-loop-distribution): New. * tree-flow.h (mark_virtual_ops_in_bb, slpeel_tree_duplicate_loop_to_edge_cfg, rename_variables_in_loop): Declared. * Makefile.in (TREE_DATA_REF_H): Depend on tree-chrec.h. (OBJS-common): Add tree-loop-distribution.o. (tree-loop-distribution.o): New rule. * tree-cfg.c (mark_virtual_ops_in_bb): New. (mark_virtual_ops_in_region): Use mark_virtual_ops_in_bb. * passes.c (init_optimization_passes): Schedule pass_loop_distribution. * testsuite/gcc.dg/tree-ssa/ldist-{1..12}.c: New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@132745 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-data-ref.c')
-rw-r--r--gcc/tree-data-ref.c538
1 files changed, 484 insertions, 54 deletions
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index 2f17ed1deb4..70266034aab 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -88,7 +88,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dump.h"
#include "timevar.h"
#include "cfgloop.h"
-#include "tree-chrec.h"
#include "tree-data-ref.h"
#include "tree-scalar-evolution.h"
#include "tree-pass.h"
@@ -157,6 +156,14 @@ dump_data_references (FILE *file, VEC (data_reference_p, heap) *datarefs)
dump_data_reference (file, dr);
}
+/* Dump to STDERR all the dependence relations from DDRS. */
+
+void
+debug_data_dependence_relations (VEC (ddr_p, heap) *ddrs)
+{
+ dump_data_dependence_relations (stderr, ddrs);
+}
+
/* Dump into FILE all the dependence relations from DDRS. */
void
@@ -354,6 +361,10 @@ dump_data_dependence_relation (FILE *outf,
dra = DDR_A (ddr);
drb = DDR_B (ddr);
fprintf (outf, "(Data Dep: \n");
+
+ dump_data_reference (outf, dra);
+ dump_data_reference (outf, drb);
+
if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
fprintf (outf, " (don't know)\n");
@@ -808,7 +819,7 @@ dr_address_invariant_p (struct data_reference *dr)
/* Frees data reference DR. */
-static void
+void
free_data_ref (data_reference_p dr)
{
BITMAP_FREE (DR_VOPS (dr));
@@ -2787,22 +2798,6 @@ build_classic_dist_vector_1 (struct data_dependence_relation *ddr,
return true;
}
-/* Return true when the DDR contains two data references that have the
- same access functions. */
-
-static bool
-same_access_functions (const struct data_dependence_relation *ddr)
-{
- unsigned i;
-
- for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
- if (!eq_evolutions_p (DR_ACCESS_FN (DDR_A (ddr), i),
- DR_ACCESS_FN (DDR_B (ddr), i)))
- return false;
-
- return true;
-}
-
/* Return true when the DDR contains only constant access functions. */
static bool
@@ -4371,48 +4366,219 @@ free_data_refs (VEC (data_reference_p, heap) *datarefs)
-/* Returns the index of STMT in RDG. */
+/* Dump vertex I in RDG to FILE. */
-static int
-find_vertex_for_stmt (const struct graph *rdg, const_tree stmt)
+void
+dump_rdg_vertex (FILE *file, struct graph *rdg, int i)
+{
+ struct vertex *v = &(rdg->vertices[i]);
+ struct graph_edge *e;
+
+ fprintf (file, "(vertex %d: (%s%s) (in:", i,
+ RDG_MEM_WRITE_STMT (rdg, i) ? "w" : "",
+ RDG_MEM_READS_STMT (rdg, i) ? "r" : "");
+
+ if (v->pred)
+ for (e = v->pred; e; e = e->pred_next)
+ fprintf (file, " %d", e->src);
+
+ fprintf (file, ") (out:");
+
+ if (v->succ)
+ for (e = v->succ; e; e = e->succ_next)
+ fprintf (file, " %d", e->dest);
+
+ fprintf (file, ") \n");
+ print_generic_stmt (file, RDGV_STMT (v), TDF_VOPS|TDF_MEMSYMS);
+ fprintf (file, ")\n");
+}
+
+/* Call dump_rdg_vertex on stderr. */
+
+void
+debug_rdg_vertex (struct graph *rdg, int i)
+{
+ dump_rdg_vertex (stderr, rdg, i);
+}
+
+/* Dump component C of RDG to FILE. If DUMPED is non-null, set the
+ dumped vertices to that bitmap. */
+
+void dump_rdg_component (FILE *file, struct graph *rdg, int c, bitmap dumped)
+{
+ int i;
+
+ fprintf (file, "(%d\n", c);
+
+ for (i = 0; i < rdg->n_vertices; i++)
+ if (rdg->vertices[i].component == c)
+ {
+ if (dumped)
+ bitmap_set_bit (dumped, i);
+
+ dump_rdg_vertex (file, rdg, i);
+ }
+
+ fprintf (file, ")\n");
+}
+
+/* Call dump_rdg_vertex on stderr. */
+
+void
+debug_rdg_component (struct graph *rdg, int c)
+{
+ dump_rdg_component (stderr, rdg, c, NULL);
+}
+
+/* Dump the reduced dependence graph RDG to FILE. */
+
+void
+dump_rdg (FILE *file, struct graph *rdg)
{
int i;
+ bitmap dumped = BITMAP_ALLOC (NULL);
+
+ fprintf (file, "(rdg\n");
for (i = 0; i < rdg->n_vertices; i++)
- if (RDGV_STMT (&(rdg->vertices[i])) == stmt)
- return i;
+ if (!bitmap_bit_p (dumped, i))
+ dump_rdg_component (file, rdg, rdg->vertices[i].component, dumped);
- gcc_unreachable ();
- return 0;
+ fprintf (file, ")\n");
+ BITMAP_FREE (dumped);
}
-/* Creates an edge in RDG for each distance vector from DDR. */
+/* Call dump_rdg on stderr. */
+
+void
+debug_rdg (struct graph *rdg)
+{
+ dump_rdg (stderr, rdg);
+}
static void
-create_rdg_edge_for_ddr (struct graph *rdg, ddr_p ddr)
+dot_rdg_1 (FILE *file, struct graph *rdg)
{
- int va, vb;
- data_reference_p dra;
- data_reference_p drb;
- struct graph_edge *e;
+ int i;
+
+ fprintf (file, "digraph RDG {\n");
- if (DDR_REVERSED_P (ddr))
+ for (i = 0; i < rdg->n_vertices; i++)
{
- dra = DDR_B (ddr);
- drb = DDR_A (ddr);
+ struct vertex *v = &(rdg->vertices[i]);
+ struct graph_edge *e;
+
+ /* Highlight reads from memory. */
+ if (RDG_MEM_READS_STMT (rdg, i))
+ fprintf (file, "%d [style=filled, fillcolor=green]\n", i);
+
+ /* Highlight stores to memory. */
+ if (RDG_MEM_WRITE_STMT (rdg, i))
+ fprintf (file, "%d [style=filled, fillcolor=red]\n", i);
+
+ if (v->succ)
+ for (e = v->succ; e; e = e->succ_next)
+ switch (RDGE_TYPE (e))
+ {
+ case input_dd:
+ fprintf (file, "%d -> %d [label=input] \n", i, e->dest);
+ break;
+
+ case output_dd:
+ fprintf (file, "%d -> %d [label=output] \n", i, e->dest);
+ break;
+
+ case flow_dd:
+ /* These are the most common dependences: don't print these. */
+ fprintf (file, "%d -> %d \n", i, e->dest);
+ break;
+
+ case anti_dd:
+ fprintf (file, "%d -> %d [label=anti] \n", i, e->dest);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
}
- else
+
+ fprintf (file, "}\n\n");
+}
+
+/* Display SCOP using dotty. */
+
+void
+dot_rdg (struct graph *rdg)
+{
+ FILE *file = fopen ("/tmp/rdg.dot", "w");
+ gcc_assert (file != NULL);
+
+ dot_rdg_1 (file, rdg);
+ fclose (file);
+
+ system ("dotty /tmp/rdg.dot");
+}
+
+
+/* This structure is used for recording the mapping statement index in
+ the RDG. */
+
+struct rdg_vertex_info GTY(())
+{
+ tree stmt;
+ int index;
+};
+
+/* Returns the index of STMT in RDG. */
+
+int
+rdg_vertex_for_stmt (struct graph *rdg, tree stmt)
+{
+ struct rdg_vertex_info rvi, *slot;
+
+ rvi.stmt = stmt;
+ slot = (struct rdg_vertex_info *) htab_find (rdg->indices, &rvi);
+
+ if (!slot)
+ return -1;
+
+ return slot->index;
+}
+
+/* Creates an edge in RDG for each distance vector from DDR. The
+ order that we keep track of in the RDG is the order in which
+ statements have to be executed. */
+
+static void
+create_rdg_edge_for_ddr (struct graph *rdg, ddr_p ddr)
+{
+ struct graph_edge *e;
+ int va, vb;
+ data_reference_p dra = DDR_A (ddr);
+ data_reference_p drb = DDR_B (ddr);
+ unsigned level = ddr_dependence_level (ddr);
+
+ /* For non scalar dependences, when the dependence is REVERSED,
+ statement B has to be executed before statement A. */
+ if (level > 0
+ && !DDR_REVERSED_P (ddr))
{
- dra = DDR_A (ddr);
- drb = DDR_B (ddr);
+ data_reference_p tmp = dra;
+ dra = drb;
+ drb = tmp;
}
- va = find_vertex_for_stmt (rdg, DR_STMT (dra));
- vb = find_vertex_for_stmt (rdg, DR_STMT (drb));
+ va = rdg_vertex_for_stmt (rdg, DR_STMT (dra));
+ vb = rdg_vertex_for_stmt (rdg, DR_STMT (drb));
+
+ if (va < 0 || vb < 0)
+ return;
e = add_edge (rdg, va, vb);
e->data = XNEW (struct rdg_edge);
+ RDGE_LEVEL (e) = level;
+
/* Determines the type of the data dependence. */
if (DR_IS_READ (dra) && DR_IS_READ (drb))
RDGE_TYPE (e) = input_dd;
@@ -4435,9 +4601,13 @@ create_rdg_edges_for_scalar (struct graph *rdg, tree def, int idef)
FOR_EACH_IMM_USE_FAST (imm_use_p, iterator, def)
{
- int use = find_vertex_for_stmt (rdg, USE_STMT (imm_use_p));
- struct graph_edge *e = add_edge (rdg, idef, use);
+ struct graph_edge *e;
+ int use = rdg_vertex_for_stmt (rdg, USE_STMT (imm_use_p));
+ if (use < 0)
+ continue;
+
+ e = add_edge (rdg, idef, use);
e->data = XNEW (struct rdg_edge);
RDGE_TYPE (e) = flow_dd;
}
@@ -4458,8 +4628,8 @@ create_rdg_edges (struct graph *rdg, VEC (ddr_p, heap) *ddrs)
create_rdg_edge_for_ddr (rdg, ddr);
for (i = 0; i < rdg->n_vertices; i++)
- FOR_EACH_PHI_OR_STMT_DEF (def_p, RDGV_STMT (&(rdg->vertices[i])),
- iter, SSA_OP_ALL_DEFS)
+ FOR_EACH_PHI_OR_STMT_DEF (def_p, RDG_STMT (rdg, i),
+ iter, SSA_OP_DEF)
create_rdg_edges_for_scalar (rdg, DEF_FROM_PTR (def_p), i);
}
@@ -4468,19 +4638,50 @@ create_rdg_edges (struct graph *rdg, VEC (ddr_p, heap) *ddrs)
static void
create_rdg_vertices (struct graph *rdg, VEC (tree, heap) *stmts)
{
- int i;
- tree s;
+ int i, j;
+ tree stmt;
- for (i = 0; VEC_iterate (tree, stmts, i, s); i++)
+ for (i = 0; VEC_iterate (tree, stmts, i, stmt); i++)
{
+ VEC (data_ref_loc, heap) *references;
+ data_ref_loc *ref;
struct vertex *v = &(rdg->vertices[i]);
+ struct rdg_vertex_info *rvi = XNEW (struct rdg_vertex_info);
+ struct rdg_vertex_info **slot;
+
+ rvi->stmt = stmt;
+ rvi->index = i;
+ slot = (struct rdg_vertex_info **) htab_find_slot (rdg->indices, rvi, INSERT);
+
+ if (!*slot)
+ *slot = rvi;
+ else
+ free (rvi);
v->data = XNEW (struct rdg_vertex);
- RDGV_STMT (v) = s;
+ RDG_STMT (rdg, i) = stmt;
+
+ RDG_MEM_WRITE_STMT (rdg, i) = false;
+ RDG_MEM_READS_STMT (rdg, i) = false;
+ if (TREE_CODE (stmt) == PHI_NODE)
+ continue;
+
+ get_references_in_stmt (stmt, &references);
+ for (j = 0; VEC_iterate (data_ref_loc, references, j, ref); j++)
+ if (!ref->is_read)
+ RDG_MEM_WRITE_STMT (rdg, i) = true;
+ else
+ RDG_MEM_READS_STMT (rdg, i) = true;
+
+ VEC_free (data_ref_loc, heap, references);
}
}
-/* Initialize STMTS with all the statements and PHI nodes of LOOP. */
+/* Initialize STMTS with all the statements of LOOP. When
+ INCLUDE_PHIS is true, include also the PHI nodes. The order in
+ which we discover statements is important as
+ generate_loops_for_partition is using the same traversal for
+ identifying statements. */
static void
stmts_from_loop (struct loop *loop, VEC (tree, heap) **stmts)
@@ -4490,7 +4691,7 @@ stmts_from_loop (struct loop *loop, VEC (tree, heap) **stmts)
for (i = 0; i < loop->num_nodes; i++)
{
- tree phi;
+ tree phi, stmt;
basic_block bb = bbs[i];
block_stmt_iterator bsi;
@@ -4498,7 +4699,8 @@ stmts_from_loop (struct loop *loop, VEC (tree, heap) **stmts)
VEC_safe_push (tree, heap, *stmts, phi);
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- VEC_safe_push (tree, heap, *stmts, bsi_stmt (bsi));
+ if (TREE_CODE (stmt = bsi_stmt (bsi)) != LABEL_EXPR)
+ VEC_safe_push (tree, heap, *stmts, stmt);
}
free (bbs);
@@ -4519,8 +4721,39 @@ known_dependences_p (VEC (ddr_p, heap) *dependence_relations)
return true;
}
-/* Build a Reduced Dependence Graph with one vertex per statement of the
- loop nest and one edge per data dependence or scalar dependence. */
+/* Computes a hash function for element ELT. */
+
+static hashval_t
+hash_stmt_vertex_info (const void *elt)
+{
+ struct rdg_vertex_info *rvi = (struct rdg_vertex_info *) elt;
+ tree stmt = rvi->stmt;
+
+ return htab_hash_pointer (stmt);
+}
+
+/* Compares database elements E1 and E2. */
+
+static int
+eq_stmt_vertex_info (const void *e1, const void *e2)
+{
+ const struct rdg_vertex_info *elt1 = (const struct rdg_vertex_info *) e1;
+ const struct rdg_vertex_info *elt2 = (const struct rdg_vertex_info *) e2;
+
+ return elt1->stmt == elt2->stmt;
+}
+
+/* Free the element E. */
+
+static void
+hash_stmt_vertex_del (void *e)
+{
+ free (e);
+}
+
+/* Build the Reduced Dependence Graph (RDG) with one vertex per
+ statement of the loop nest, and one edge per data dependence or
+ scalar dependence. */
struct graph *
build_rdg (struct loop *loop)
@@ -4529,7 +4762,7 @@ build_rdg (struct loop *loop)
struct graph *rdg = NULL;
VEC (ddr_p, heap) *dependence_relations;
VEC (data_reference_p, heap) *datarefs;
- VEC (tree, heap) *stmts = VEC_alloc (tree, heap, 10);
+ VEC (tree, heap) *stmts = VEC_alloc (tree, heap, nb_data_refs);
dependence_relations = VEC_alloc (ddr_p, heap, nb_data_refs * nb_data_refs) ;
datarefs = VEC_alloc (data_reference_p, heap, nb_data_refs);
@@ -4537,12 +4770,15 @@ build_rdg (struct loop *loop)
false,
&datarefs,
&dependence_relations);
-
+
if (!known_dependences_p (dependence_relations))
goto end_rdg;
stmts_from_loop (loop, &stmts);
rdg = new_graph (VEC_length (tree, stmts));
+
+ rdg->indices = htab_create (nb_data_refs, hash_stmt_vertex_info,
+ eq_stmt_vertex_info, hash_stmt_vertex_del);
create_rdg_vertices (rdg, stmts);
create_rdg_edges (rdg, dependence_relations);
@@ -4553,3 +4789,197 @@ build_rdg (struct loop *loop)
return rdg;
}
+
+/* Free the reduced dependence graph RDG. */
+
+void
+free_rdg (struct graph *rdg)
+{
+ int i;
+
+ for (i = 0; i < rdg->n_vertices; i++)
+ free (rdg->vertices[i].data);
+
+ htab_delete (rdg->indices);
+ free_graph (rdg);
+}
+
+/* Initialize STMTS with all the statements of LOOP that contain a
+ store to memory. */
+
+void
+stores_from_loop (struct loop *loop, VEC (tree, heap) **stmts)
+{
+ unsigned int i;
+ basic_block *bbs = get_loop_body_in_dom_order (loop);
+
+ for (i = 0; i < loop->num_nodes; i++)
+ {
+ basic_block bb = bbs[i];
+ block_stmt_iterator bsi;
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ if (!ZERO_SSA_OPERANDS (bsi_stmt (bsi), SSA_OP_VDEF))
+ VEC_safe_push (tree, heap, *stmts, bsi_stmt (bsi));
+ }
+
+ free (bbs);
+}
+
+/* For a data reference REF, return the declaration of its base
+ address or NULL_TREE if the base is not determined. */
+
+static inline tree
+ref_base_address (tree stmt, data_ref_loc *ref)
+{
+ tree base = NULL_TREE;
+ tree base_address;
+ struct data_reference *dr = XCNEW (struct data_reference);
+
+ DR_STMT (dr) = stmt;
+ DR_REF (dr) = *ref->pos;
+ dr_analyze_innermost (dr);
+ base_address = DR_BASE_ADDRESS (dr);
+
+ if (!base_address)
+ goto end;
+
+ switch (TREE_CODE (base_address))
+ {
+ case ADDR_EXPR:
+ base = TREE_OPERAND (base_address, 0);
+ break;
+
+ default:
+ base = base_address;
+ break;
+ }
+
+ end:
+ free_data_ref (dr);
+ return base;
+}
+
+/* Determines whether the statement from vertex V of the RDG has a
+ definition used outside the loop that contains this statement. */
+
+bool
+rdg_defs_used_in_other_loops_p (struct graph *rdg, int v)
+{
+ tree stmt = RDG_STMT (rdg, v);
+ struct loop *loop = loop_containing_stmt (stmt);
+ use_operand_p imm_use_p;
+ imm_use_iterator iterator;
+ ssa_op_iter it;
+ def_operand_p def_p;
+
+ if (!loop)
+ return true;
+
+ FOR_EACH_PHI_OR_STMT_DEF (def_p, stmt, it, SSA_OP_DEF)
+ {
+ FOR_EACH_IMM_USE_FAST (imm_use_p, iterator, DEF_FROM_PTR (def_p))
+ {
+ if (loop_containing_stmt (USE_STMT (imm_use_p)) != loop)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Determines whether statements S1 and S2 access to similar memory
+ locations. Two memory accesses are considered similar when they
+ have the same base address declaration, i.e. when their
+ ref_base_address is the same. */
+
+bool
+have_similar_memory_accesses (tree s1, tree s2)
+{
+ bool res = false;
+ unsigned i, j;
+ VEC (data_ref_loc, heap) *refs1, *refs2;
+ data_ref_loc *ref1, *ref2;
+
+ get_references_in_stmt (s1, &refs1);
+ get_references_in_stmt (s2, &refs2);
+
+ for (i = 0; VEC_iterate (data_ref_loc, refs1, i, ref1); i++)
+ {
+ tree base1 = ref_base_address (s1, ref1);
+
+ if (base1)
+ for (j = 0; VEC_iterate (data_ref_loc, refs2, j, ref2); j++)
+ if (base1 == ref_base_address (s2, ref2))
+ {
+ res = true;
+ goto end;
+ }
+ }
+
+ end:
+ VEC_free (data_ref_loc, heap, refs1);
+ VEC_free (data_ref_loc, heap, refs2);
+ return res;
+}
+
+/* Helper function for the hashtab. */
+
+static int
+have_similar_memory_accesses_1 (const void *s1, const void *s2)
+{
+ return have_similar_memory_accesses ((tree) s1, (tree) s2);
+}
+
+/* Helper function for the hashtab. */
+
+static hashval_t
+ref_base_address_1 (const void *s)
+{
+ tree stmt = (tree) s;
+ unsigned i;
+ VEC (data_ref_loc, heap) *refs;
+ data_ref_loc *ref;
+ hashval_t res = 0;
+
+ get_references_in_stmt (stmt, &refs);
+
+ for (i = 0; VEC_iterate (data_ref_loc, refs, i, ref); i++)
+ if (!ref->is_read)
+ {
+ res = htab_hash_pointer (ref_base_address (stmt, ref));
+ break;
+ }
+
+ VEC_free (data_ref_loc, heap, refs);
+ return res;
+}
+
+/* Try to remove duplicated write data references from STMTS. */
+
+void
+remove_similar_memory_refs (VEC (tree, heap) **stmts)
+{
+ unsigned i;
+ tree stmt;
+ htab_t seen = htab_create (VEC_length (tree, *stmts), ref_base_address_1,
+ have_similar_memory_accesses_1, NULL);
+
+ for (i = 0; VEC_iterate (tree, *stmts, i, stmt); )
+ {
+ void **slot;
+
+ slot = htab_find_slot (seen, stmt, INSERT);
+
+ if (*slot)
+ VEC_ordered_remove (tree, *stmts, i);
+ else
+ {
+ *slot = (void *) stmt;
+ i++;
+ }
+ }
+
+ htab_delete (seen);
+}
+