Commit ce280749 authored by Götz Lindenmaier's avatar Götz Lindenmaier
Browse files

mode loop analyses

[r3795]
parent 90e75f9f
......@@ -23,6 +23,27 @@
#include "irgwalk.h"
/* For callees, we want to remember the Call nodes, too. */
struct ana_entry {
ir_graph *irg;
ir_node *call_list;
int max_depth;
};
typedef struct ana_entry ana_entry;
static int master_cg_visited = 0;
static INLINE int cg_irg_visited (ir_graph *n);
static INLINE void mark_cg_irg_visited(ir_graph *n);
static INLINE void set_cg_irg_visited (ir_graph *n, int i);
irp_callgraph_state get_irp_callgraph_state(void) {
return irp->callgraph_state;
}
void set_irp_callgraph_state(irp_callgraph_state s) {
irp->callgraph_state = s;
}
/* The functions that call irg. */
int get_irg_n_callers(ir_graph *irg) {
if (irg->callers) return ARR_LEN(irg->callers);
......@@ -37,11 +58,43 @@ int is_irg_caller_backedge(ir_graph *irg, int pos) {
assert (pos >= 0 && pos < get_irg_n_callers(irg));
return irg->caller_isbe[pos];
}
static void set_irg_caller_backedge(ir_graph *irg, int pos) {
assert (pos >= 0 && pos < get_irg_n_callers(irg));
irg->caller_isbe[pos] = 1;
static void set_irg_caller_backedge(ir_graph *irg, ir_graph *caller) {
int i, n_callers = get_irg_n_callers(irg);
for (i = 0; i < n_callers; ++i) {
if (get_irg_caller(irg, i) == caller) {
irg->caller_isbe[i] = 1;
break;
}
}
}
int has_irg_caller_backedge(ir_graph *irg) {
int i, n_callers = get_irg_n_callers(irg);
for (i = 0; i < n_callers; ++i)
if (is_irg_caller_backedge(irg, i)) return 1;
return 0;
}
int get_irg_caller_loop_depth(ir_graph *irg, int pos) {
ir_graph *caller = get_irg_caller(irg, pos);
/* search the other relation for the corresponding edge. */
int pos_callee = -1;
int i, n_callees = get_irg_n_callees(caller);
for (i = 0; i < n_callees; ++i) {
if (get_irg_callee(caller, i) == irg) {
pos_callee = i;
break;
}
}
assert(pos_callee >= 0);
return get_irg_callee_loop_depth(caller, pos_callee);
}
/* The functions called by irg. */
int get_irg_n_callees(ir_graph *irg) {
if (irg->callees) return ARR_LEN(irg->callees);
......@@ -49,18 +102,32 @@ int get_irg_n_callees(ir_graph *irg) {
}
ir_graph *get_irg_callee(ir_graph *irg, int pos) {
assert (pos >= 0 && pos < get_irg_n_callees(irg));
if (irg->callees) return irg->callees[pos];
if (irg->callees) return ((ana_entry *)irg->callees[pos])->irg;
return NULL;
}
int is_irg_callee_backedge(ir_graph *irg, int pos) {
assert (pos >= 0 && pos < get_irg_n_callees(irg));
return irg->callee_isbe[pos];
}
int has_irg_callee_backedge(ir_graph *irg) {
int i, n_callees = get_irg_n_callees(irg);
for (i = 0; i < n_callees; ++i)
if (is_irg_callee_backedge(irg, i)) return 1;
return 0;
}
void set_irg_callee_backedge(ir_graph *irg, int pos) {
assert (pos >= 0 && pos < get_irg_n_callees(irg));
irg->callee_isbe[pos] = 1;
}
int get_irg_callee_loop_depth(ir_graph *irg, int pos) {
assert (pos >= 0 && pos < get_irg_n_callees(irg));
if (irg->callees) return ((ana_entry *)irg->callees[pos])->max_depth;
return -1;
}
/* --------------------- Compute the callgraph ------------------------ */
static void ana_Call(ir_node *n, void *env) {
int i, n_callees;
......@@ -72,14 +139,32 @@ static void ana_Call(ir_node *n, void *env) {
n_callees = get_Call_n_callees(n);
for (i = 0; i < n_callees; ++i) {
entity *callee_e = get_Call_callee(n, i);
if (callee_e) {
if (callee_e) { /* Null for unknown caller */
ir_graph *callee = get_entity_irg(callee_e);
pset_insert((pset *)irg->callees, callee, (unsigned)callee >> 3);
pset_insert((pset *)callee->callers, irg, (unsigned)irg >> 3);
pset_insert((pset *)callee->callers, irg, (unsigned)irg >> 3);
ana_entry buf = { callee, NULL, 0};
ana_entry *found = pset_find((pset *)irg->callees, &buf, (unsigned)callee >> 3);
if (found) { /* add Call node to list, compute new nesting. */
} else { /* New node, add Call node and init nesting. */
found = (ana_entry *) obstack_alloc (irg->obst, sizeof (ana_entry));
found->irg = callee;
found->call_list = NULL;
found->max_depth = 0;
pset_insert((pset *)irg->callees, found, (unsigned)callee >> 3);
}
int depth = get_loop_depth(get_irn_loop(get_nodes_block(n)));
found->max_depth = (depth > found->max_depth) ? depth : found->max_depth;
}
}
}
/* compare two ir graphs */
static int ana_entry_cmp(const void *elt, const void *key) {
ana_entry *e1 = (ana_entry *)elt;
ana_entry *e2 = (ana_entry *)key;
return e1->irg != e2->irg;
}
/* compare two ir graphs */
static int graph_cmp(const void *elt, const void *key) {
......@@ -98,13 +183,15 @@ void compute_callgraph(void) {
for (i = 0; i < n_irgs; ++i) {
ir_graph *irg = get_irp_irg(i);
assert(get_irg_callee_info_state(irg) == irg_callee_info_consistent);
irg->callees = (ir_graph **)new_pset(graph_cmp, 8);
irg->callees = (ir_graph **)new_pset(ana_entry_cmp, 8);
irg->callers = (ir_graph **)new_pset(graph_cmp, 8);
construct_cf_backedges(irg);
}
/* Compute the call graph */
for (i = 0; i < n_irgs; ++i) {
ir_graph *irg = get_irp_irg(i);
construct_cf_backedges(irg);
irg_walk_graph(irg, ana_Call, NULL, NULL);
}
......@@ -137,6 +224,7 @@ void compute_callgraph(void) {
del_pset(caller_set);
assert(c == NULL);
}
set_irp_callgraph_state(irp_callgraph_consistent);
}
void free_callgraph(void) {
......@@ -152,8 +240,47 @@ void free_callgraph(void) {
irg->callee_isbe = NULL;
irg->caller_isbe = NULL;
}
set_irp_callgraph_state(irp_callgraph_none);
}
/* ----------------------------------------------------------------------------------- */
/* A walker for the callgraph */
/* ----------------------------------------------------------------------------------- */
static void do_walk(ir_graph *irg, callgraph_walk_func *pre, callgraph_walk_func *post, void *env) {
int i, n_callees;
if (cg_irg_visited(irg)) return;
mark_cg_irg_visited(irg);
pre(irg, env);
n_callees = get_irg_n_callees(irg);
for (i = 0; i < n_callees; i++) {
ir_graph *m = get_irg_callee(irg, i);
do_walk(m, pre, post, env);
}
post(irg, env);
}
void callgraph_walk(callgraph_walk_func *pre, callgraph_walk_func *post, void *env) {
int i, n_irgs = get_irp_n_irgs();
master_cg_visited++;
do_walk(get_irp_main_irg(), pre, post, env);
for (i = 0; i < n_irgs; i++) {
ir_graph *irg = get_irp_irg(i);
if (!cg_irg_visited(irg) && get_irg_n_callers(irg) == 0)
do_walk(irg, pre, post, env);
}
for (i = 0; i < n_irgs; i++) {
ir_graph *irg = get_irp_irg(i);
if (!cg_irg_visited(irg))
do_walk(irg, pre, post, env);
}
}
/* ----------------------------------------------------------------------------------- */
/* loop construction algorithm */
......@@ -189,12 +316,12 @@ static INLINE scc_info* new_scc_info(void) {
static INLINE int
cg_irg_visited(ir_graph *n) {
return ((scc_info *)n->link)->visited;
return (((scc_info *)n->link)->visited >= master_cg_visited);
}
static INLINE void
mark_cg_irg_visited(ir_graph *n) {
((scc_info *)n->link)->visited = 1;
((scc_info *)n->link)->visited = master_cg_visited;
}
static INLINE void
......@@ -202,6 +329,11 @@ set_cg_irg_visited(ir_graph *n, int i) {
((scc_info *)n->link)->visited = i;
}
static INLINE int
get_cg_irg_visited(ir_graph *n) {
return ((scc_info *)n->link)->visited;
}
static INLINE void
mark_irg_in_stack (ir_graph *n) {
assert(get_irg_link(n));
......@@ -287,14 +419,13 @@ pop_scc_to_loop (ir_graph *n)
{
ir_graph *m;
/*for (;;) {*/
do {
m = pop();
loop_node_cnt++;
set_irg_dfn(m, loop_node_cnt);
add_loop_node(current_loop, (ir_node *)m);
set_irg_loop(m, current_loop);
/* if (m==n) break;*/
m->l = current_loop;
//m->callgraph_loop_depth = current_loop->depth;
} while(m != n);
}
......@@ -380,13 +511,16 @@ static ir_loop *new_loop (void) {
/* Initialization steps. **********************************************/
static INLINE void
init_scc (ir_graph *irg) {
init_scc (void) {
int i;
current_dfn = 1;
loop_node_cnt = 0;
init_stack();
for (i = 0; i < get_irp_n_irgs(); ++i) {
set_irg_link(get_irp_irg(i), new_scc_info());
get_irp_irg(i)->callgraph_recursion_depth = 0;
get_irp_irg(i)->callgraph_loop_depth = 0;
get_irp_irg(i)->callgraph_weighted_loop_depth = 0;
}
}
......@@ -447,6 +581,39 @@ is_endless_head (ir_graph *n, ir_graph *root)
return !some_outof_loop && some_in_loop;
}
/* Check whether there is a parallel edge in the ip control flow.
Only */
static bool
is_ip_head (ir_graph *n, ir_graph *pred)
{
int iv_rem = interprocedural_view;
interprocedural_view = 1;
ir_node *sblock = get_irg_start_block(n);
int i, arity = get_Block_n_cfgpreds(sblock);
int is_be = 0;
//printf(" edge from "); DDMG(n);
//printf(" to pred "); DDMG(pred);
//printf(" sblock "); DDMN(sblock);
for (i = 0; i < arity; i++) {
ir_node *pred_cfop = skip_Proj(get_Block_cfgpred(sblock, i));
//printf(" "); DDMN(pred_cfop);
if (get_irn_op(pred_cfop) == op_CallBegin) { /* could be Unknown */
ir_graph *ip_pred = get_irn_irg(pred_cfop);
//printf(" "); DDMG(ip_pred);
if ((ip_pred == pred) && is_backedge(sblock, i)) {
//printf(" found\n");
is_be = 1;
}
}
}
interprocedural_view = iv_rem;
return is_be;
}
/* Returns index of the predecessor with the smallest dfn number
greater-equal than limit. */
static int
......@@ -486,6 +653,7 @@ largest_dfn_pred (ir_graph *n)
return index;
}
#if 0
static ir_graph *
find_tail (ir_graph *n) {
ir_graph *m;
......@@ -498,7 +666,7 @@ find_tail (ir_graph *n) {
if (is_head (m, n)) {
res_index = smallest_dfn_pred(m, 0);
if ((res_index == -2) && /* no smallest dfn pred found. */
(n == m))
(n == m))
return NULL;
} else {
if (m == n) return NULL; // Is this to catch Phi - self loops?
......@@ -546,7 +714,74 @@ find_tail (ir_graph *n) {
set_irg_callee_backedge (m, res_index);
return get_irg_callee(m, res_index);
}
#else
static ir_graph *
find_tail (ir_graph *n) {
ir_graph *m;
int i, res_index = -2;
ir_graph *in_and_out = NULL;
ir_graph *only_in = NULL;
ir_graph *ip_in_and_out = NULL;
ir_graph *ip_only_in = NULL;
//printf("find tail for "); DDMG(n);
for (i = tos-1; i >= 0; --i) {
ir_graph *pred = (i < tos -1) ? stack[i+1] : n;
m = stack[i];
if (is_head (m, n)) {
//printf(" found 1a! "); DDM;
in_and_out = m;
if (is_ip_head(pred, m)) {
//printf(" found 1b! "); DDM;
ip_in_and_out = m;
}
} else if (!ip_only_in && is_endless_head(m, n)) {
only_in = m;
//printf(" found 2a! "); DDM;
if (is_ip_head(pred, m)) {
//printf(" found 2b! "); DDM;
ip_only_in = m;
}
} else if (is_ip_head(pred, m)) {
//printf(" found 3! "); DDM; This happens for self recursions in the second
//assert(0); scc iteration (the one to flip the loop.)
}
if (ip_in_and_out) break; /* That's what we really want. */
if (m == n) break; /* Don't walk past n on the stack! */
}
if (!in_and_out && !only_in)
/* There is no loop */
return NULL;
/* Is there a head in the callgraph without a head in the
ip cf graph? */
assert(in_and_out || only_in);
m = (ip_in_and_out) ? ip_in_and_out : ip_only_in;
if (!m)
m = (in_and_out) ? in_and_out : only_in;
//printf("*** head is "); DDMG(m);
res_index = smallest_dfn_pred (m, get_irg_dfn(m) + 1);
if (res_index == -2) /* no smallest dfn pred found. */
res_index = largest_dfn_pred (m);
set_irg_callee_backedge (m, res_index);
ir_graph *res = get_irg_callee(m, res_index);
//printf("*** tail is "); DDMG(res);
return res;
}
#endif
/*-----------------------------------------------------------*
......@@ -563,7 +798,6 @@ static void cgscc (ir_graph *n) {
/* Initialize the node */
set_irg_dfn(n, current_dfn); /* Depth first number for this node */
set_irg_uplink(n, current_dfn); /* ... is default uplink. */
set_irg_loop(n, NULL);
current_dfn ++;
push(n);
......@@ -575,7 +809,7 @@ static void cgscc (ir_graph *n) {
m = get_irg_callee(n, i);
/** This marks the backedge, but does it guarantee a correct loop tree? */
if (m == n) { set_irg_callee_backedge(n, i); continue; }
//if (m == n) { set_irg_callee_backedge(n, i); continue; }
cgscc (m);
if (irg_is_in_stack(m)) {
......@@ -646,27 +880,202 @@ static void reset_isbe(void) {
}
}
static int in_same_loop(ir_graph *irg1, ir_graph *irg2) {
return irg1->l == irg2->l;
}
/* Returns true if loop depth of low < high and low on
a path from high to tree root. */
static int in_lower_loop(ir_graph *high, ir_graph *low) {
ir_loop *highl = high->l;
ir_loop *lowl = low->l;
if (get_loop_depth(lowl) < get_loop_depth(highl)) {
while (get_loop_outer_loop(highl) != highl) {
highl = get_loop_outer_loop(highl);
if (highl == lowl) return 1;
}
}
return 0;
}
/* compute nesting depth */
static void cnd(ir_loop *loop) {
int i, n_elems = get_loop_n_elements(loop);
int same_sum = 0;
int max_lower_edge_max = 0;
/* Compute the value for this loop. Deeper loops use this value. */
for (i = 0; i < n_elems; i++) {
loop_element le = get_loop_element(loop, i);
if (*le.kind == k_ir_graph) {
ir_graph *irg = (ir_graph *)le.node;
int j, n_callers = get_irg_n_callers(irg);
int same_edge_max = 0;
int loop_entry_max = 0;
for (j = 0; j < n_callers; ++j) {
ir_graph *caller = get_irg_caller(irg, j);
int caller_loop_depth = get_irg_caller_loop_depth(irg, j);
if (in_same_loop(irg, caller))
same_edge_max = (same_edge_max < caller_loop_depth) ? caller_loop_depth
: same_edge_max;
if (in_lower_loop(irg, caller)) {
int loop_entry_this = caller_loop_depth + caller->l->weighted_depth;
loop_entry_max = (loop_entry_max < loop_entry_this) ? loop_entry_this
: loop_entry_max;
}
}
max_lower_edge_max = (max_lower_edge_max < loop_entry_max) ? max_lower_edge_max
: loop_entry_max;
same_sum += same_edge_max;
}
/* This loop is as expensive as the most expensive entry edge + the count of the cycle. */
loop->weighted_depth = max_lower_edge_max + same_sum + 1; /* 1 for the recursion itself */
}
/* Recur. */
for (i = 0; i < n_elems; i++) {
loop_element le = get_loop_element(loop, i);
if (*le.kind == k_ir_loop)
cnd(le.son);
}
}
/* ----------------------------------------------------------------------------------- */
/* Another algorithm to compute recursion nesting depth */
/* Walk the callgraph. For each crossed edge increase the loop depth by the edge */
/* weight. Assign graphs the maximal depth. */
/* ----------------------------------------------------------------------------------- */
void compute_loop_depth (ir_graph *irg, void *env) {
int current_nesting = *(int *) env;
int i, n_callees;
if (cg_irg_visited(irg)) return;
mark_cg_irg_visited(irg);
if (current_nesting == 0 || irg->callgraph_loop_depth < current_nesting) {
/* Don't walk the graph, but a tree that is an unfolded graph. */
n_callees = get_irg_n_callees(irg);
for (i = 0; i < n_callees; i++) {
ir_graph *m = get_irg_callee(irg, i);
*(int *)env += get_irg_callee_loop_depth(irg, i);
compute_loop_depth(m, env);
*(int *)env -= get_irg_callee_loop_depth(irg, i);
}
}
if (irg->callgraph_loop_depth < current_nesting)
irg->callgraph_loop_depth = current_nesting;
set_cg_irg_visited(irg, master_cg_visited-1);
}
/* ----------------------------------------------------------------------------------- */
/* Another algorithm to compute recursion nesting depth */
/* Walk the callgraph. For each crossed loop increase the nesting depth by one. */
/* Assign graphs the maximal nesting depth. Don't increas if passing loops more than */
/* once. */
/* ----------------------------------------------------------------------------------- */
/* For callees, we want to remember the Call nodes, too. */
struct ana_entry2 {
ir_loop **loop_stack;
int tos;
int recursion_nesting;
};
typedef struct ana_entry2 ana_entry2;
static void push2(ana_entry2 *e, ir_loop *g) {
if (ARR_LEN(e->loop_stack) == e->tos) {
ARR_APP1(ir_loop *, e->loop_stack, g);
} else {
e->loop_stack[e->tos] = g;
}
e->tos ++;
}
static ir_loop *pop2(ana_entry2 *e) {
e->tos --;
return e->loop_stack[e->tos+1];
}
static int in_stack(ana_entry2 *e, ir_loop *g) {
int i;
for (i = e->tos-1; i >= 0; --i) {
if (e->loop_stack[i] == g) return 1;
}
return 0;
}
void compute_rec_depth (ir_graph *irg, void *env) {
ana_entry2 *e = (ana_entry2 *)env;
ir_loop *l = irg->l;
int depth;
int i, n_callees;
int pushed = 0;
if (cg_irg_visited(irg)) return;
mark_cg_irg_visited(irg);
if ((l != irp->outermost_cg_loop) && !in_stack(e, l)) {
push2(e, l);
e->recursion_nesting++;
pushed = 1;
}
depth = e->recursion_nesting;
if (depth == 0 || irg->callgraph_recursion_depth < depth) {
/* Don't walk the graph, but a tree that is an unfolded graph. */
n_callees = get_irg_n_callees(irg);
for (i = 0; i < n_callees; i++) {
ir_graph *m = get_irg_callee(irg, i);
compute_rec_depth(m, env);
}
}
if (irg->callgraph_recursion_depth < depth)
irg->callgraph_recursion_depth = depth;
if (pushed) {
pop2(e);
e->recursion_nesting--;
}
set_cg_irg_visited(irg, master_cg_visited-1);
}
/* Compute the backedges that represent recursions. */
void find_callgraph_recursions(void) {
int i, n_irgs = get_irp_n_irgs();
reset_isbe();
assert(get_irp_main_irg()); /* The outermost graph. We start here. Then we start at all
external visible functions in irg list, then at the remaining
unvisited ones. */
outermost_ir_graph = get_irp_main_irg();
assert(!interprocedural_view &&
"use construct_ip_backedges");
/* -- Compute the looptree -- */
init_scc(current_ir_graph);
/* The outermost graph. We start here. Then we start at all
functions in irg list that are never called, then at the remaining
unvisited ones. */
assert(get_irp_main_irg());
outermost_ir_graph = get_irp_main_irg();
init_scc();
current_loop = NULL;