diff options
author | spop <spop@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-02-28 12:37:24 +0000 |
---|---|---|
committer | spop <spop@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-02-28 12:37:24 +0000 |
commit | 801c5610886591ce60ea92d2073a0f8cf2caea31 (patch) | |
tree | 9b84bf0f68098103bdd76fd0c6c2fa17afc3dd07 /gcc/tree-data-ref.c | |
parent | 9c467f1355d2f806a7ac06c22a18fd1d2e7e748f (diff) | |
download | gcc-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.c | 538 |
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); +} + |