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

mode loop analyses

[r3795]
parent 90e75f9f
This diff is collapsed.
...@@ -14,42 +14,77 @@ ...@@ -14,42 +14,77 @@
#define _CALLGRAPH_H_ #define _CALLGRAPH_H_
/** /**
* @file callgraph.h * @file callgraph.h
* *
* This file contains defines the representation of the callgraph. * This file contains the representation of the callgraph.
* The nodes of the call graph are ir_graphs. The edges between * The nodes of the call graph are ir_graphs. The edges between
* The nodes are calling relation. I.e., if method a calls method * ghe nodes are calling relations. I.e., if method a calls method
* b at some point, there is an edge between a and b. * b at some point, there is an edge between a and b.
* *
* Further this file contains an algorithm to construct the call * Further this file contains an algorithm to construct the call
* graph. The construction of the callgraph uses the callee * graph. The construction of the callgraph uses the callee
* information in Call nodes to determine which methods are called. * information in Call nodes to determine which methods are called.
* *
* Finally this file contains an algorithm that computes backedges * Finally this file contains an algorithm that computes backedges
* in the callgraph, i.e., the algorithm finds possibly recursive calls. * in the callgraph, i.e., the algorithm finds possibly recursive calls.
* The algorithm computes an upper bound of all recursive calls. * The algorithm computes an upper bound of all recursive calls.
* *
*/ */
#include "irgraph.h" #include "irgraph.h"
/** Flag to indicate state of callgraph. */
typedef enum {
irp_callgraph_none,
irp_callgraph_consistent, /* calltree is inconsistent */
irp_callgraph_inconsistent,
irp_callgraph_and_calltree_consistent
} irp_callgraph_state;
irp_callgraph_state get_irp_callgraph_state(void);
void set_irp_callgraph_state(irp_callgraph_state s);
/** The functions that call irg. */ /** The functions that call irg. */
int get_irg_n_callers(ir_graph *irg); int get_irg_n_callers(ir_graph *irg);
ir_graph *get_irg_caller(ir_graph *irg, int pos); ir_graph *get_irg_caller(ir_graph *irg, int pos);
/* int is_irg_caller_backedge(ir_graph *irg, int pos); not implemented */
int is_irg_caller_backedge(ir_graph *irg, int pos);
int has_irg_caller_backedge(ir_graph *irg);
/** maximal loop depth of call nodes that call along this edge. */
int get_irg_caller_loop_depth(ir_graph *irg, int pos);
/** The functions called by irg. */ /** The functions called by irg. */
int get_irg_n_callees(ir_graph *irg); int get_irg_n_callees(ir_graph *irg);
ir_graph *get_irg_callee(ir_graph *irg, int pos); ir_graph *get_irg_callee(ir_graph *irg, int pos);
int is_irg_callee_backedge(ir_graph *irg, int pos); int is_irg_callee_backedge(ir_graph *irg, int pos);
int has_irg_callee_backedge(ir_graph *irg);
/** maximal loop depth of call nodes that call along this edge. */
int get_irg_callee_loop_depth(ir_graph *irg, int pos);
/** Maximal loop depth of all paths from an external visible method to
this irg. */
int get_irg_loop_depth(ir_graph *irg);
/** Maximal recursion depth of all paths from an external visible method to
this irg. */
int get_irg_recursion_depth(ir_graph *irg);
/** Construct and destruct the callgraph. */ /** Construct and destruct the callgraph. */
void compute_callgraph(void); void compute_callgraph(void);
void free_callgraph(void); void free_callgraph(void);
/** A function type for fuctions passed to the callgraph walker. */
typedef void callgraph_walk_func(ir_graph *g, void *env);
void callgraph_walk(callgraph_walk_func *pre, callgraph_walk_func *post, void *env);
/** Compute the backedges that represent recursions. */ /** Compute the backedges that represent recursions. */
void find_callgraph_recursions(void); void find_callgraph_recursions(void);
#endif /* _CALLGRAPH_H_ */ #endif /* _CALLGRAPH_H_ */
...@@ -568,7 +568,7 @@ static void callee_ana(void) { ...@@ -568,7 +568,7 @@ static void callee_ana(void) {
irg_walk_graph(get_irp_irg(i), callee_walker, remove_Tuples, NULL); irg_walk_graph(get_irp_irg(i), callee_walker, remove_Tuples, NULL);
set_irg_callee_info_state(get_irp_irg(i), irg_callee_info_consistent); set_irg_callee_info_state(get_irp_irg(i), irg_callee_info_consistent);
} }
//set_irp_callee_info_state(irg_callee_info_consistent); set_irp_callee_info_state(irg_callee_info_consistent);
} }
......
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
#include "irprog_t.h" #include "irprog_t.h"
#include "irdump.h" #include "irdump.h"
#define NO_CFLOOPS_WITHOUT_HEAD 1
static ir_graph *outermost_ir_graph; /* The outermost graph the scc is computed static ir_graph *outermost_ir_graph; /* The outermost graph the scc is computed
for */ for */
static ir_loop *current_loop; /* Current cfloop construction is working static ir_loop *current_loop; /* Current cfloop construction is working
...@@ -312,6 +314,39 @@ is_head (ir_node *n, ir_node *root) ...@@ -312,6 +314,39 @@ is_head (ir_node *n, ir_node *root)
return some_outof_loop && some_in_loop; return some_outof_loop && some_in_loop;
} }
/* Returns true if n is possible loop head of an endless loop.
I.e., it is a Block, Phi or Filter node and has only predecessors
within the loop.
@arg root: only needed for assertion. */
static bool
is_endless_head (ir_node *n, ir_node *root)
{
int i, arity;
int some_outof_loop = 0, some_in_loop = 0;
assert(is_Block(n));
/* Test for legal loop header: Block, Phi, ... */
if (!is_outermost_StartBlock(n)) {
arity = get_irn_arity(n);
for (i = 0; i < arity; i++) {
ir_node *pred = get_nodes_block(skip_Proj(get_irn_n(n, i)));
assert(pred);
if (is_backedge(n, i)) { continue; }
if (!irn_is_in_stack(pred)) {
some_outof_loop = 1; //printf(" some out of loop ");
} else {
if(get_irn_uplink(pred) < get_irn_uplink(root)) {
DDMN(pred); DDMN(root);
assert(get_irn_uplink(pred) >= get_irn_uplink(root));
}
some_in_loop = 1;
}
}
}
return !some_outof_loop && some_in_loop;
}
/* Returns index of the predecessor with the smallest dfn number /* Returns index of the predecessor with the smallest dfn number
greater-equal than limit. */ greater-equal than limit. */
static int static int
...@@ -356,8 +391,7 @@ largest_dfn_pred (ir_node *n) ...@@ -356,8 +391,7 @@ largest_dfn_pred (ir_node *n)
/* Searches the stack for possible loop heads. Tests these for backedges. /* Searches the stack for possible loop heads. Tests these for backedges.
If it finds a head with an unmarked backedge it marks this edge and If it finds a head with an unmarked backedge it marks this edge and
returns the tail of the loop. returns the tail of the loop.
If it finds no backedge returns NULL. If it finds no backedge returns NULL. */
("disable_backedge" in fiasco) */
static ir_node * static ir_node *
find_tail (ir_node *n) { find_tail (ir_node *n) {
ir_node *m; ir_node *m;
...@@ -371,15 +405,46 @@ find_tail (ir_node *n) { ...@@ -371,15 +405,46 @@ find_tail (ir_node *n) {
return NULL; return NULL;
} else { } else {
if (m == n) return NULL; if (m == n) return NULL;
for (i = tos-2; ; --i) { for (i = tos-2; i >= 0; --i) {
m = stack[i]; m = stack[i];
if (is_head (m, n)) { if (is_head (m, n)) {
res_index = smallest_dfn_pred (m, get_irn_dfn(m) + 1); res_index = smallest_dfn_pred (m, get_irn_dfn(m) + 1);
if (res_index == -2) /* no smallest dfn pred found. */ if (res_index == -2) /* no smallest dfn pred found. */
res_index = largest_dfn_pred (m); res_index = largest_dfn_pred (m);
if ((m == n) && (res_index == -2)) {
i = -1;
}
break; break;
} }
/* We should not walk past our selves on the stack: The upcoming nodes
are not in this loop. We assume a loop not reachable from Start. */
if (m == n) {
i = -1;
break;
}
} }
if (i < 0) {
/* A dead loop not reachable from Start. */
for (i = tos-2; i >= 0; --i) {
m = stack[i];
if (is_endless_head (m, n)) {
res_index = smallest_dfn_pred (m, get_irn_dfn(m) + 1);
if (res_index == -2) /* no smallest dfn pred found. */
res_index = largest_dfn_pred (m);
break;
}
if (m == n) { break; } /* It's not an unreachable loop, either. */
}
//assert(0 && "no head found on stack");
}
} }
assert (res_index > -2); assert (res_index > -2);
...@@ -387,6 +452,11 @@ find_tail (ir_node *n) { ...@@ -387,6 +452,11 @@ find_tail (ir_node *n) {
return is_outermost_StartBlock(n) ? NULL : get_nodes_block(skip_Proj(get_irn_n(m, res_index))); return is_outermost_StartBlock(n) ? NULL : get_nodes_block(skip_Proj(get_irn_n(m, res_index)));
} }
INLINE static int
is_outermost_loop(ir_loop *l) {
return l == get_loop_outer_loop(l);
}
/*-----------------------------------------------------------* /*-----------------------------------------------------------*
* The core algorithm. * * The core algorithm. *
*-----------------------------------------------------------*/ *-----------------------------------------------------------*/
...@@ -448,8 +518,6 @@ static void cfscc (ir_node *n) { ...@@ -448,8 +518,6 @@ static void cfscc (ir_node *n) {
Next actions: Open a new cfloop on the cfloop tree and Next actions: Open a new cfloop on the cfloop tree and
try to find inner cfloops */ try to find inner cfloops */
#define NO_CFLOOPS_WITHOUT_HEAD 1
#if NO_CFLOOPS_WITHOUT_HEAD #if NO_CFLOOPS_WITHOUT_HEAD
/* This is an adaption of the algorithm from fiasco / optscc to /* This is an adaption of the algorithm from fiasco / optscc to
...@@ -461,7 +529,7 @@ static void cfscc (ir_node *n) { ...@@ -461,7 +529,7 @@ static void cfscc (ir_node *n) {
ir_loop *l; ir_loop *l;
int close; int close;
if (get_loop_n_elements(current_loop) > 0) { if ((get_loop_n_elements(current_loop) > 0) || (is_outermost_loop(current_loop))) {
l = new_loop(); l = new_loop();
close = 1; close = 1;
} else { } else {
......
...@@ -30,6 +30,11 @@ ...@@ -30,6 +30,11 @@
#include "irdump.h" #include "irdump.h"
/* A variant of the loop tree that avoids loops without head.
This reduces the depth of the loop tree. */
#define NO_LOOPS_WITHOUT_HEAD 1
INLINE void add_loop_son(ir_loop *loop, ir_loop *son); INLINE void add_loop_son(ir_loop *loop, ir_loop *son);
INLINE void add_loop_node(ir_loop *loop, ir_node *n); INLINE void add_loop_node(ir_loop *loop, ir_node *n);
...@@ -788,7 +793,7 @@ find_tail (ir_node *n) { ...@@ -788,7 +793,7 @@ find_tail (ir_node *n) {
if (res_index == -2) /* no smallest dfn pred found. */ if (res_index == -2) /* no smallest dfn pred found. */
res_index = largest_dfn_pred (m); res_index = largest_dfn_pred (m);
if ((m == n) && (res_index == -2)) { if ((m == n) && (res_index == -2)) { /* dont walk past loop head. */
i = -1; i = -1;
} }
break; break;
...@@ -867,7 +872,8 @@ int search_endproj_in_stack(ir_node *start_block) ...@@ -867,7 +872,8 @@ int search_endproj_in_stack(ir_node *start_block)
int arity = get_irn_arity(start_block); int arity = get_irn_arity(start_block);
for(j = 0; j < arity; j++) for(j = 0; j < arity; j++)
{ {
ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)), get_Proj_proj(end_projx)); ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)),
get_Proj_proj(end_projx));
DDMN(begin_projx); DDMN(begin_projx);
if(get_irn_n(start_block, j) == begin_projx) if(get_irn_n(start_block, j) == begin_projx)
{ {
...@@ -884,11 +890,13 @@ int search_endproj_in_stack(ir_node *start_block) ...@@ -884,11 +890,13 @@ int search_endproj_in_stack(ir_node *start_block)
static pmap *projx_link = NULL; static pmap *projx_link = NULL;
void link_to_reg_end (ir_node *n, void *env) { void link_to_reg_end (ir_node *n, void *env) {
if(get_irn_op(n) == op_Proj && get_irn_mode(n) == mode_X && get_irn_op(get_irn_n(n, 0)) == op_EndReg) if(get_irn_op(n) == op_Proj &&
{ get_irn_mode(n) == mode_X &&
get_irn_op(get_irn_n(n, 0)) == op_EndReg) {
/* Reg End Projx -> Find the CallBegin Projx and hash it */ /* Reg End Projx -> Find the CallBegin Projx and hash it */
ir_node *end_projx = n; ir_node *end_projx = n;
ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)), get_Proj_proj(end_projx)); ir_node *begin_projx = get_Block_cfgpred(get_irg_start_block(get_irn_irg(end_projx)),
get_Proj_proj(end_projx));
printf("Linked the following ProjxNodes:\n"); printf("Linked the following ProjxNodes:\n");
DDMN(begin_projx); DDMN(begin_projx);
DDMN(end_projx); DDMN(end_projx);
...@@ -910,6 +918,10 @@ ir_node *get_projx_link(ir_node *cb_projx) ...@@ -910,6 +918,10 @@ ir_node *get_projx_link(ir_node *cb_projx)
#endif #endif
INLINE static int
is_outermost_loop(ir_loop *l) {
return l == get_loop_outer_loop(l);
}
/*-----------------------------------------------------------* /*-----------------------------------------------------------*
...@@ -970,18 +982,20 @@ static void scc (ir_node *n) { ...@@ -970,18 +982,20 @@ static void scc (ir_node *n) {
Next actions: Open a new loop on the loop tree and Next actions: Open a new loop on the loop tree and
try to find inner loops */ try to find inner loops */
#define NO_LOOPS_WITHOUT_HEAD 1
#if NO_LOOPS_WITHOUT_HEAD #if NO_LOOPS_WITHOUT_HEAD
/* This is an adaption of the algorithm from fiasco / optscc to /* This is an adaption of the algorithm from fiasco / optscc to
* avoid loops without Block or Phi as first node. This should * avoid loops without Block or Phi as first node. This should
* severely reduce the number of evaluations of nodes to detect * severely reduce the number of evaluations of nodes to detect
* a fixpoint in the heap analysis. * a fixpoint in the heap analysis.
* Further it avoids loops without firm nodes that cause errors * Further it avoids loops without firm nodes that cause errors
* in the heap analyses. */ * in the heap analyses.
* But attention: don't do it for the outermost loop: This loop
* is not iterated. A first block can be a loop head in case of
* an endless recursion. */
ir_loop *l; ir_loop *l;
int close; int close;
if (get_loop_n_elements(current_loop) > 0) { if ((get_loop_n_elements(current_loop) > 0) || (is_outermost_loop(current_loop))) {
l = new_loop(); l = new_loop();
close = 1; close = 1;
} else { } else {
...@@ -1069,7 +1083,6 @@ static void my_scc (ir_node *n) { ...@@ -1069,7 +1083,6 @@ static void my_scc (ir_node *n) {
Next actions: Open a new loop on the loop tree and Next actions: Open a new loop on the loop tree and
try to find inner loops */ try to find inner loops */
#define NO_LOOPS_WITHOUT_HEAD 1
#if NO_LOOPS_WITHOUT_HEAD #if NO_LOOPS_WITHOUT_HEAD
/* This is an adaption of the algorithm from fiasco / optscc to /* This is an adaption of the algorithm from fiasco / optscc to
* avoid loops without Block or Phi as first node. This should * avoid loops without Block or Phi as first node. This should
...@@ -1080,7 +1093,7 @@ static void my_scc (ir_node *n) { ...@@ -1080,7 +1093,7 @@ static void my_scc (ir_node *n) {
ir_loop *l; ir_loop *l;
int close; int close;
if (get_loop_n_elements(current_loop) > 0) { if ((get_loop_n_elements(current_loop) > 0) || (is_outermost_loop(current_loop))) {
l = new_loop(); l = new_loop();
close = 1; close = 1;
} else { } else {
...@@ -1133,17 +1146,10 @@ void construct_backedges(ir_graph *irg) { ...@@ -1133,17 +1146,10 @@ void construct_backedges(ir_graph *irg) {
new_loop(); /* sets current_loop */ new_loop(); /* sets current_loop */
head_rem = current_loop; /* Just for assertion */ head_rem = current_loop; /* Just for assertion */
if (interprocedural_view) { inc_irg_visited(current_ir_graph);
set_irg_visited(current_ir_graph, inc_max_irg_visited());
init_ip_walk ();
} else {
inc_irg_visited(current_ir_graph);
}
scc(get_irg_end(current_ir_graph)); scc(get_irg_end(current_ir_graph));
if (interprocedural_view) finish_ip_walk();
assert(head_rem == current_loop); assert(head_rem == current_loop);
set_irg_loop(current_ir_graph, current_loop); set_irg_loop(current_ir_graph, current_loop);
set_irg_loopinfo_state(current_ir_graph, loopinfo_consistent); set_irg_loopinfo_state(current_ir_graph, loopinfo_consistent);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment