* @brief Representation and computation of the callgraph.
* @author Goetz Lindenmaier
* @date 21.7.2004
- * @version $Id$
*/
#include "config.h"
#include "irnode_t.h"
#include "cgana.h"
-#include "execution_frequency.h"
#include "array.h"
#include "pmap.h"
static inline int cg_irg_visited (ir_graph *n);
static inline void mark_cg_irg_visited(ir_graph *n);
-/** Returns the callgraph state of the program representation. */
irp_callgraph_state get_irp_callgraph_state(void)
{
return irp->callgraph_state;
}
-/* Sets the callgraph state of the program representation. */
void set_irp_callgraph_state(irp_callgraph_state s)
{
irp->callgraph_state = s;
}
-/* Returns the number of procedures that call the given irg. */
size_t get_irg_n_callers(const ir_graph *irg)
{
assert(irg->callers);
return irg->callers ? ARR_LEN(irg->callers) : 0;
}
-/* Returns the caller at position pos. */
ir_graph *get_irg_caller(const ir_graph *irg, size_t pos)
{
assert(pos < get_irg_n_callers(irg));
return irg->callers ? irg->callers[pos] : NULL;
}
-/* Returns non-zero if the caller at position pos is "a backedge", i.e. a recursion. */
int is_irg_caller_backedge(const ir_graph *irg, size_t pos)
{
assert(pos < get_irg_n_callers(irg));
}
}
-/* Returns non-zero if the irg has a backedge caller. */
int has_irg_caller_backedge(const ir_graph *irg)
{
size_t i, n_callers = get_irg_n_callers(irg);
return 0;
}
-/* Returns the maximal loop depth of call nodes that call along this edge. */
size_t get_irg_caller_loop_depth(const ir_graph *irg, size_t pos)
{
ir_graph *caller = get_irg_caller(irg, pos);
return get_irg_callee_loop_depth(caller, pos_callee);
}
-
-/* Returns the number of procedures that are called by the given irg. */
size_t get_irg_n_callees(const ir_graph *irg)
{
assert(irg->callees);
return irg->callees ? ARR_LEN(irg->callees) : 0;
}
-/* Returns the callee at position pos. */
ir_graph *get_irg_callee(const ir_graph *irg, size_t pos)
{
assert(pos < get_irg_n_callees(irg));
return irg->callees ? irg->callees[pos]->irg : NULL;
}
-/* Returns non-zero if the callee at position pos is "a backedge", i.e. a recursion. */
int is_irg_callee_backedge(const ir_graph *irg, size_t pos)
{
assert(pos < get_irg_n_callees(irg));
return irg->callee_isbe != NULL ? rbitset_is_set(irg->callee_isbe, pos) : 0;
}
-/* Returns non-zero if the irg has a backedge callee. */
int has_irg_callee_backedge(const ir_graph *irg)
{
size_t i, n_callees = get_irg_n_callees(irg);
rbitset_set(irg->callee_isbe, pos);
}
-/* Returns the maximal loop depth of call nodes that call along this edge. */
size_t get_irg_callee_loop_depth(const ir_graph *irg, size_t pos)
{
assert(pos < get_irg_n_callees(irg));
return irg->callees ? irg->callees[pos]->max_depth : 0;
}
-static double get_irg_callee_execution_frequency(const ir_graph *irg, size_t pos)
-{
- ir_node **arr = irg->callees[pos]->call_list;
- size_t i, n_Calls = ARR_LEN(arr);
- double freq = 0.0;
-
- for (i = 0; i < n_Calls; ++i) {
- freq += get_irn_exec_freq(arr[i]);
- }
- return freq;
-}
-
-static double get_irg_callee_method_execution_frequency(const ir_graph *irg,
- size_t pos)
-{
- double call_freq = get_irg_callee_execution_frequency(irg, pos);
- double meth_freq = get_irg_method_execution_frequency(irg);
- return call_freq * meth_freq;
-}
-
-static double get_irg_caller_method_execution_frequency(const ir_graph *irg,
- size_t pos)
-{
- ir_graph *caller = get_irg_caller(irg, pos);
- size_t pos_callee = reverse_pos(irg, pos);
-
- return get_irg_callee_method_execution_frequency(caller, pos_callee);
-}
-
-
-/* --------------------- Compute the callgraph ------------------------ */
/**
* Pre-Walker called by compute_callgraph(), analyses all Call nodes.
buf.irg = callee;
- pset_insert((pset *)callee->callers, irg, HASH_PTR(irg));
- found = (cg_callee_entry*) pset_find((pset *)irg->callees, &buf, HASH_PTR(callee));
+ pset_insert((pset *)callee->callers, irg, hash_ptr(irg));
+ found = (cg_callee_entry*) pset_find((pset *)irg->callees, &buf, hash_ptr(callee));
if (found) { /* add Call node to list, compute new nesting. */
ir_node **arr = found->call_list;
ARR_APP1(ir_node *, arr, n);
found->call_list = arr;
} else { /* New node, add Call node and init nesting. */
- found = OALLOC(irg->obst, cg_callee_entry);
+ found = OALLOC(get_irg_obstack(irg), cg_callee_entry);
found->irg = callee;
found->call_list = NEW_ARR_F(ir_node *, 1);
found->call_list[0] = n;
found->max_depth = 0;
- pset_insert((pset *)irg->callees, found, HASH_PTR(callee));
+ pset_insert((pset *)irg->callees, found, hash_ptr(callee));
}
depth = get_loop_depth(get_irn_loop(get_nodes_block(n)));
found->max_depth = (depth > found->max_depth) ? depth : found->max_depth;
return e1 != e2;
}
-
-/* Construct and destruct the callgraph. */
void compute_callgraph(void)
{
size_t i, n_irgs;
/* Change the sets to arrays. */
for (i = 0; i < n_irgs; ++i) {
size_t j, count;
- cg_callee_entry *callee;
- ir_graph *c, *irg = get_irp_irg(i);
+ ir_graph *irg = get_irp_irg(i);
pset *callee_set, *caller_set;
callee_set = (pset *)irg->callees;
count = pset_count(callee_set);
irg->callees = NEW_ARR_F(cg_callee_entry *, count);
irg->callee_isbe = NULL;
- callee = (cg_callee_entry*) pset_first(callee_set);
- for (j = 0; j < count; ++j) {
- irg->callees[j] = callee;
- callee = (cg_callee_entry*) pset_next(callee_set);
+ j = 0;
+ foreach_pset(callee_set, cg_callee_entry, callee) {
+ irg->callees[j++] = callee;
}
del_pset(callee_set);
- assert(callee == NULL);
+ assert(j == count);
caller_set = (pset *)irg->callers;
count = pset_count(caller_set);
irg->callers = NEW_ARR_F(ir_graph *, count);
irg->caller_isbe = NULL;
- c = (ir_graph*) pset_first(caller_set);
- for (j = 0; j < count; ++j) {
- irg->callers[j] = c;
- c = (ir_graph*) pset_next(caller_set);
+ j = 0;
+ foreach_pset(caller_set, ir_graph, c) {
+ irg->callers[j++] = c;
}
del_pset(caller_set);
- assert(c == NULL);
+ assert(j == count);
}
set_irp_callgraph_state(irp_callgraph_consistent);
}
-/* Destruct the callgraph. */
void free_callgraph(void)
{
size_t i, n_irgs = get_irp_n_irgs();
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)
{
}
}
-/* ----------------------------------------------------------------------------------- */
-/* loop construction algorithm */
-/* ----------------------------------------------------------------------------------- */
-
static ir_graph *outermost_ir_graph; /**< The outermost graph the scc is computed
for */
static ir_loop *current_loop; /**< Current cfloop construction is working
static size_t current_dfn = 1; /**< Counter to generate depth first numbering
of visited nodes. */
-/*-----------------*/
-/* Node attributes */
-/*-----------------*/
-
typedef struct scc_info {
size_t dfn; /**< Depth first search number. */
size_t uplink; /**< dfn number of ancestor. */
return info->dfn;
}
-/**********************************************************************/
-/* A stack. **/
-/**********************************************************************/
-
static ir_graph **stack = NULL;
static size_t tos = 0; /**< top of stack */
}
}
-/**********************************************************************/
-/* The loop data structure. **/
-/**********************************************************************/
-
/**
* Allocates a new loop as son of current_loop. Sets current_loop
* to the new loop and returns the father.
static ir_loop *new_loop(void)
{
ir_loop *father = current_loop;
- ir_loop *son = alloc_loop(father, outermost_ir_graph->obst);
+ ir_loop *son = alloc_loop(father, get_irg_obstack(outermost_ir_graph));
current_loop = son;
return father;
}
-/**********************************************************************/
-/* Constructing and destructing the loop/backedge information. **/
-/**********************************************************************/
-
-/* Initialization steps. **********************************************/
-
static void init_scc(struct obstack *obst)
{
size_t i, n_irgs;
found = largest_dfn_pred(m, &res_index);
break;
}
- if (m == n) { break; } /* It's not an unreachable loop, either. */
+ /* It's not an unreachable loop, either. */
+ if (m == n)
+ break;
}
//assert(0 && "no head found on stack");
}
return get_irg_callee(m, res_index);
}
-/*-----------------------------------------------------------*
- * The core algorithm. *
- *-----------------------------------------------------------*/
-
-
static void cgscc(ir_graph *n)
{
size_t i, n_callees;
}
}
-/* ----------------------------------------------------------------------------------- */
-/* 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. */
-/* ----------------------------------------------------------------------------------- */
-
-static void compute_loop_depth(ir_graph *irg, void *env)
-{
- size_t current_nesting = *(size_t *) env;
- size_t old_nesting = irg->callgraph_loop_depth;
- ir_visited_t old_visited = get_cg_irg_visited(irg);
-
- if (cg_irg_visited(irg)) return;
-
- mark_cg_irg_visited(irg);
-
- if (old_nesting < current_nesting)
- irg->callgraph_loop_depth = current_nesting;
-
- if (current_nesting > irp->max_callgraph_loop_depth)
- irp->max_callgraph_loop_depth = current_nesting;
-
- if ((old_visited +1 < get_cg_irg_visited(irg)) || /* not yet visited */
- (old_nesting < current_nesting)) { /* propagate larger nesting */
- size_t i, n_callees;
-
- /* 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);
- *(size_t *)env += get_irg_callee_loop_depth(irg, i);
- compute_loop_depth(m, env);
- *(size_t *)env -= get_irg_callee_loop_depth(irg, i);
- }
- }
-
- 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 increase if passing loops more than */
-/* once. */
-/* ------------------------------------------------------------------------------------ */
-
-
-/* For callees, we want to remember the Call nodes, too. */
-typedef struct ana_entry2 {
- ir_loop **loop_stack; /**< a stack of ir_loop entries */
- size_t tos; /**< the top of stack entry */
- size_t recursion_nesting;
-} ana_entry2;
-
-/**
- * push a loop entry on the stack
- */
-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;
-}
-
-/**
- * returns the top of stack and pop it
- */
-static ir_loop *pop2(ana_entry2 *e)
-{
- return e->loop_stack[--e->tos];
-}
-
-/**
- * check if a loop g in on the stack. Did not check the TOS.
- */
-static int in_stack(ana_entry2 *e, ir_loop *g)
-{
- size_t i;
- for (i = e->tos; i != 0;) {
- if (e->loop_stack[--i] == g) return 1;
- }
- return 0;
-}
-
-static void compute_rec_depth(ir_graph *irg, void *env)
-{
- ana_entry2 *e = (ana_entry2 *)env;
- ir_loop *l = irg->l;
- size_t depth, old_depth = irg->callgraph_recursion_depth;
- int pushed = 0;
-
- if (cg_irg_visited(irg))
- return;
- mark_cg_irg_visited(irg);
-
- /* -- compute and set the new nesting value -- */
- if ((l != irp->outermost_cg_loop) && !in_stack(e, l)) {
- push2(e, l);
- ++e->recursion_nesting;
- pushed = 1;
- }
- depth = e->recursion_nesting;
-
- if (old_depth < depth)
- irg->callgraph_recursion_depth = depth;
-
- if (depth > irp->max_callgraph_recursion_depth)
- irp->max_callgraph_recursion_depth = depth;
-
- /* -- spread the nesting value -- */
- if (depth == 0 || old_depth < depth) {
- size_t i, n_callees;
-
- /* Don't walk the graph, but a tree that is an unfolded graph.
- Therefore we unset the visited flag at the end. */
- 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);
- }
- }
-
- /* -- clean up -- */
- if (pushed) {
- pop2(e);
- --e->recursion_nesting;
- }
- set_cg_irg_visited(irg, master_cg_visited-1);
-}
-
-
-/* ----------------------------------------------------------------------------------- */
-/* Another algorithm to compute the execution frequency of methods ignoring recursions. */
-/* Walk the callgraph. Ignore backedges. Use sum of execution frequencies of Call */
-/* nodes to evaluate a callgraph edge. */
-/* ----------------------------------------------------------------------------------- */
-
-/* Returns the method execution frequency of a graph. */
-double get_irg_method_execution_frequency(const ir_graph *irg)
-{
- return irg->method_execution_frequency;
-}
-
-/**
- * Increase the method execution frequency to freq if its current value is
- * smaller then this.
- */
-static void set_irg_method_execution_frequency(ir_graph *irg, double freq)
-{
- irg->method_execution_frequency = freq;
-
- if (irp->max_method_execution_frequency < freq)
- irp->max_method_execution_frequency = freq;
-}
-
-static void compute_method_execution_frequency(ir_graph *irg, void *env)
-{
- size_t i, n_callers;
- double freq;
- int found_edge;
- size_t n_callees;
- (void) env;
-
- if (cg_irg_visited(irg))
- return;
-
- /* We need the values of all predecessors (except backedges).
- So they must be marked. Else we will reach the node through
- one of the unmarked ones. */
- n_callers = get_irg_n_callers(irg);
- for (i = 0; i < n_callers; ++i) {
- ir_graph *m = get_irg_caller(irg, i);
- if (is_irg_caller_backedge(irg, i))
- continue;
- if (!cg_irg_visited(m)) {
- return;
- }
- }
- mark_cg_irg_visited(irg);
-
- /* Compute the new frequency. */
- freq = 0;
- found_edge = 0;
- for (i = 0; i < n_callers; ++i) {
- if (! is_irg_caller_backedge(irg, i)) {
- double edge_freq = get_irg_caller_method_execution_frequency(irg, i);
- assert(edge_freq >= 0);
- freq += edge_freq;
- found_edge = 1;
- }
- }
-
- if (!found_edge) {
- /* A starting point: method only called from outside,
- or only backedges as predecessors. */
- freq = 1;
- }
-
- set_irg_method_execution_frequency(irg, freq);
-
- /* recur */
- n_callees = get_irg_n_callees(irg);
- for (i = 0; i < n_callees; ++i) {
- compute_method_execution_frequency(get_irg_callee(irg, i), NULL);
- }
-}
-
-
-/* ----------------------------------------------------------------------------------- */
-/* The recursion stuff driver. */
-/* ----------------------------------------------------------------------------------- */
-
-/* Compute the backedges that represent recursions. */
void find_callgraph_recursions(void)
{
size_t i, n_irgs;
obstack_free(&temp, NULL);
irp->outermost_cg_loop = current_loop;
- mature_loops(current_loop, outermost_ir_graph->obst);
+ mature_loops(current_loop, get_irg_obstack(outermost_ir_graph));
/* -- Reverse the backedge information. -- */
for (i = 0; i < n_irgs; ++i) {
irp->callgraph_state = irp_callgraph_and_calltree_consistent;
}
-/* Compute interprocedural performance estimates. */
-void compute_performance_estimates(void)
-{
- size_t i, n_irgs = get_irp_n_irgs();
- size_t current_nesting;
- ana_entry2 e;
-
- assert(get_irp_exec_freq_state() != exec_freq_none && "execution frequency not calculated");
-
- /* -- compute the loop depth -- */
- current_nesting = 0;
- irp->max_callgraph_loop_depth = 0;
- master_cg_visited += 2;
- compute_loop_depth(get_irp_main_irg(), ¤t_nesting);
- for (i = 0; i < n_irgs; ++i) {
- ir_graph *irg = get_irp_irg(i);
- if ((get_cg_irg_visited(irg) < master_cg_visited-1) &&
- get_irg_n_callers(irg) == 0) {
- compute_loop_depth(irg, ¤t_nesting);
- }
- }
- for (i = 0; i < n_irgs; ++i) {
- ir_graph *irg = get_irp_irg(i);
- if (get_cg_irg_visited(irg) < master_cg_visited-1) {
- compute_loop_depth(irg, ¤t_nesting);
- }
- }
-
-
- /* -- compute the recursion depth -- */
- e.loop_stack = NEW_ARR_F(ir_loop *, 0);
- e.tos = 0;
- e.recursion_nesting = 0;
-
- irp->max_callgraph_recursion_depth = 0;
-
- master_cg_visited += 2;
- compute_rec_depth(get_irp_main_irg(), &e);
- for (i = 0; i < n_irgs; ++i) {
- ir_graph *irg = get_irp_irg(i);
- if ((get_cg_irg_visited(irg) < master_cg_visited-1) &&
- get_irg_n_callers(irg) == 0) {
- compute_rec_depth(irg, &e);
- }
- }
- for (i = 0; i < n_irgs; ++i) {
- ir_graph *irg = get_irp_irg(i);
- if (get_cg_irg_visited(irg) < master_cg_visited-1) {
- compute_rec_depth(irg, &e);
- }
- }
-
- DEL_ARR_F(e.loop_stack);
-
- /* -- compute the execution frequency -- */
- irp->max_method_execution_frequency = 0;
- master_cg_visited += 2;
- assert(get_irg_n_callers(get_irp_main_irg()) == 0);
- compute_method_execution_frequency(get_irp_main_irg(), NULL);
- for (i = 0; i < n_irgs; ++i) {
- ir_graph *irg = get_irp_irg(i);
- if ((get_cg_irg_visited(irg) < master_cg_visited-1) &&
- get_irg_n_callers(irg) == 0) {
- compute_method_execution_frequency(irg, NULL);
- }
- }
- for (i = 0; i < n_irgs; ++i) {
- ir_graph *irg = get_irp_irg(i);
- if (get_cg_irg_visited(irg) < master_cg_visited-1) {
- compute_method_execution_frequency(irg, NULL);
- }
- }
-}
-
-/* Returns the maximal loop depth of all paths from an external visible method to
- this irg. */
size_t get_irg_loop_depth(const ir_graph *irg)
{
assert(irp->callgraph_state == irp_callgraph_consistent ||
return irg->callgraph_loop_depth;
}
-/* Returns the maximal recursion depth of all paths from an external visible method to
- this irg. */
size_t get_irg_recursion_depth(const ir_graph *irg)
{
assert(irp->callgraph_state == irp_callgraph_and_calltree_consistent);
return irg->callgraph_recursion_depth;
}
-/* Computes the interprocedural loop nesting information. */
void analyse_loop_nesting_depth(void)
{
/* establish preconditions. */
find_callgraph_recursions();
- compute_performance_estimates();
-
set_irp_loop_nesting_depth_state(loop_nesting_depth_consistent);
}