#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "errors.h"
#include "ggc.h"
#include "tree.h"
#include "flags.h"
#include "timevar.h"
#include "varray.h"
#include "rtl.h"
#include "basic-block.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "tree-dump.h"
#include "cfgloop.h"
#include "tree-fold-const.h"
#include "tree-chrec.h"
#include "tree-data-ref.h"
#include "tree-scalar-evolution.h"
#include "tree-pass.h"
#include "tree-dg.h"
static void dg_init_graph (void);
static void set_dg_node_for_stmt (tree, dependence_node);
static dependence_node dg_get_node_for_stmt (tree, bool);
static dependence_node alloc_dependence_node (void);
static dependence_edge alloc_dependence_edge (void);
static dependence_node dg_create_node (tree);
static dependence_edge dg_find_edge (dependence_node, dependence_node, bool);
static void dump_dg (FILE *, int);
static void dg_delete_edges (void);
static void dg_delete_node (dependence_node);
static struct data_dependence_relation * find_ddr_between_stmts (tree, tree);
static int dependence_graph_size = 25;
static GTY (()) varray_type dependence_graph;
static GTY (()) varray_type datarefs;
static GTY (()) varray_type dependence_relations;
static GTY (()) varray_type classic_dist;
static GTY (()) varray_type classic_dir;
static int n_dependence_node = 0;
#define DEPENDENCE_GRAPH(N) (VARRAY_DG (dependence_graph, (N)))
static
void dg_init_graph (void)
{
VARRAY_DG_INIT (dependence_graph, dependence_graph_size, "dependence_graph");
}
void dg_create_graph (struct loops *loops)
{
unsigned int i;
VARRAY_GENERIC_PTR_INIT (classic_dist, 10, "classic_dist");
VARRAY_GENERIC_PTR_INIT (classic_dir, 10, "classic_dir");
VARRAY_GENERIC_PTR_INIT (datarefs, 10, "datarefs");
VARRAY_GENERIC_PTR_INIT (dependence_relations, 10 * 10,
"dependence_relations");
compute_data_dependences_for_loop (loops->num, loop_from_num (loops, 0),
&datarefs, &dependence_relations,
&classic_dist, &classic_dir);
dg_init_graph ();
for (i = 0; i < VARRAY_ACTIVE_SIZE (dependence_relations); i++)
{
dependence_edge connecting_edge;
struct data_reference *first_dr, *second_dr;
struct data_dependence_relation *ddr;
tree first_stmt, second_stmt;
ddr = VARRAY_GENERIC_PTR (dependence_relations, i);
if (DDR_ARE_DEPENDENT (ddr) == chrec_bot)
continue;
first_dr = DDR_A (ddr);
second_dr = DDR_B (ddr);
first_stmt = DR_STMT (first_dr);
second_stmt = DR_STMT(second_dr);
connecting_edge = dg_find_edge (dg_get_node_for_stmt (first_stmt, true),
dg_get_node_for_stmt (second_stmt, true),
true);
connecting_edge->ddr = ddr;
}
if (dump_file)
{
dump_dg (dump_file, dump_flags);
}
}
void
dg_delete_graph (void)
{
if (dependence_graph)
{
dg_delete_edges ();
n_dependence_node = 0;
if (datarefs)
VARRAY_CLEAR (datarefs);
if (dependence_relations)
VARRAY_CLEAR (dependence_relations);
if (classic_dir)
VARRAY_CLEAR (classic_dir);
if (classic_dist)
VARRAY_CLEAR (classic_dist);
VARRAY_CLEAR (dependence_graph);
datarefs = NULL;
dependence_relations = NULL;
dependence_graph = NULL;
}
}
static dependence_node
alloc_dependence_node (void)
{
dependence_node dg_node;
dg_node = ggc_alloc_cleared (sizeof (*dg_node));
return dg_node;
}
static dependence_node
dg_create_node (tree stmt)
{
dependence_node dg_node;
if (!stmt)
return NULL;
dg_node = alloc_dependence_node ();
dg_node->node_id = n_dependence_node;
VARRAY_PUSH_DG (dependence_graph, dg_node);
n_dependence_node++;
dg_node->stmt = stmt;
set_dg_node_for_stmt (stmt, dg_node);
return dg_node;
}
static void
dg_delete_node (dependence_node node)
{
stmt_ann_t ann = stmt_ann (node->stmt);
#ifdef ENABLE_CHECKING
if (node->succ || node->pred)
abort ();
#endif
if (ann)
ann->dg_node = NULL;
node = NULL;
}
static dependence_edge
alloc_dependence_edge (void)
{
dependence_edge dg_edge;
dg_edge = ggc_alloc_cleared (sizeof (*dg_edge));
return dg_edge;
}
static dependence_edge
dg_find_edge (dependence_node n1, dependence_node n2, bool create)
{
tree stmt1, stmt2;
dependence_edge e;
if (!n1 || !n2)
abort ();
stmt1 = DN_STMT (n1);
stmt2 = DN_STMT (n2);
if (!stmt1 || !stmt2)
abort ();
for (e = n1->succ; e; e = e->succ_next)
{
if (DN_STMT (e->dst) == stmt2)
return e;
}
for (e = n1->pred; e; e = e->pred_next)
{
if (DN_STMT (e->src) == stmt2)
return e;
}
if (!create)
return NULL;
e = alloc_dependence_edge ();
e->src = n1;
e->dst = n2;
if (n1->succ)
e->succ_next = n1->succ;
n1->succ = e;
if (n2->pred)
e->pred_next = n2->pred;
n2->pred = e;
return e;
}
void
dg_delete_edge (dependence_edge e)
{
dependence_edge current_edge,prev_edge;
dependence_node src, dst;
src = e->src;
dst = e->dst;
prev_edge = NULL;
for (current_edge = src->succ;
current_edge;
current_edge = current_edge->succ_next)
{
if (current_edge == e)
{
if (prev_edge)
prev_edge->succ_next = current_edge->succ_next;
else
src->succ = current_edge->succ_next;
}
else
prev_edge = current_edge;
}
if (!src->succ && !src->pred)
dg_delete_node (src);
prev_edge = NULL;
for (current_edge = dst->pred;
current_edge;
current_edge = current_edge->pred_next)
{
if (current_edge == e)
{
if (prev_edge)
prev_edge->pred_next = current_edge->pred_next;
else
dst->pred = current_edge->pred_next;
}
else
prev_edge = current_edge;
}
if (!dst->succ && !dst->pred)
dg_delete_node (dst);
e = NULL;
}
static void
dg_delete_edges (void)
{
unsigned int i;
for (i = 0; i < VARRAY_ACTIVE_SIZE (dependence_graph); i++)
{
dependence_edge e;
dependence_node dg_node = DEPENDENCE_GRAPH (i);
if (!dg_node)
continue;
for (e = dg_node->succ; e; e = e->succ_next)
dg_delete_edge (e);
}
}
static
dependence_node dg_get_node_for_stmt (tree t, bool create)
{
dependence_node dg_node = dg_node_for_stmt (t);
if (!dg_node && create)
dg_node = dg_create_node (t);
return dg_node;
}
static void
set_dg_node_for_stmt (tree t, dependence_node dg_node)
{
stmt_ann_t ann;
if (!t)
abort ();
ann = get_stmt_ann (t);
if (!ann)
abort ();
ann->dg_node = dg_node;
}
static struct data_dependence_relation *
find_ddr_between_stmts (tree stmt1, tree stmt2)
{
dependence_edge e = NULL;
dependence_node n1 = NULL;
dependence_node n2 = NULL;
#ifdef ENABLE_CHECKING
if (!stmt1 || !stmt2)
abort ();
#endif
n1 = dg_node_for_stmt (stmt1);
n2 = dg_node_for_stmt (stmt2);
if (!n1 || !n2)
return NULL;
e = dg_find_edge (n1, n2, false );
if (!e)
return NULL;
return e->ddr;
}
enum data_dependence_direction
ddg_direction_between_stmts (tree stmt1, tree stmt2, int loop_num)
{
struct subscript *sub = NULL;
struct data_dependence_relation *ddr = find_ddr_between_stmts (stmt1, stmt2);
if (!ddr)
return dir_independent;
sub = DDR_SUBSCRIPT (ddr, loop_num);
if (!sub)
abort ();
return SUB_DIRECTION (sub);
}
tree
ddg_distance_between_stmts (tree stmt1, tree stmt2, int loop_num)
{
struct subscript *sub = NULL;
struct data_dependence_relation *ddr = find_ddr_between_stmts (stmt1, stmt2);
if (!ddr)
return NULL_TREE;
sub = DDR_SUBSCRIPT (ddr, loop_num);
if (!sub)
abort ();
return SUB_DISTANCE (sub);
}
static void
dump_dg (FILE *file, int flags ATTRIBUTE_UNUSED)
{
unsigned int i, j;
for (i = 0; i < VARRAY_ACTIVE_SIZE (dependence_graph); i++)
{
dependence_edge e;
dependence_node dg_node = DEPENDENCE_GRAPH (i);
if (!dg_node)
abort ();
fprintf (file, "# Dependence Node %d\n", dg_node->node_id);
fprintf (file, "# Pred :");
for (e = dg_node->pred; e; e = e->pred_next)
if (e->dst == dg_node)
fprintf (file, "%d ", DN_ID(e->src));
fprintf (file, "\n");
fprintf (file, "# Succ :");
for (e = dg_node->succ; e; e = e->succ_next)
if (e->src == dg_node)
fprintf (file, "%d ", DN_ID(e->dst));
fprintf (file, "\n");
fprintf (file, "# Statement :");
print_generic_stmt (file, DN_STMT (dg_node), 0);
fprintf (file, "# From\tTo\tDirection Vector\n");
for (e = dg_node->succ; e; e = e->succ_next)
{
fprintf (file," %d\t", DN_ID(e->src));
fprintf (file,"%d\t", DN_ID(e->dst));
if (DDR_ARE_DEPENDENT (e->ddr) == chrec_top)
fprintf (file, "don't know\n");
for (j = 0; j < DDR_NUM_SUBSCRIPTS (e->ddr); j++)
{
struct subscript *sub = DDR_SUBSCRIPT (e->ddr, j);
dump_data_dependence_direction (file, SUB_DIRECTION (sub));
fprintf (file, " ");
}
fprintf (file,"\n");
}
fprintf (file, "\n");
}
}
void
debug_dg (int flags)
{
dump_dg (stderr, flags);
}