#include <string.h>
#include "irloop_t.h"
-#include "irnode_t.h"
+
+#include "irprog_t.h"
#include "irgraph_t.h"
+#include "irnode_t.h"
+#include "irgwalk.h"
#include "array.h"
#include "pmap.h"
-#include "irgwalk.h"
-#include "irprog_t.h"
+
#include "irdump.h"
-ir_graph *outermost_ir_graph; /* The outermost graph the scc is computed
- for */
+/* 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_node(ir_loop *loop, ir_node *n);
+
+static ir_graph *outermost_ir_graph; /* The outermost graph the scc is computed
+ for */
static ir_loop *current_loop; /* Current loop construction is working
- on. */
+ on. */
static int loop_node_cnt = 0; /* Counts the number of allocated loop nodes.
- Each loop node gets a unique number.
- What for? ev. remove. @@@ */
+ Each loop node gets a unique number.
+ What for? ev. remove. @@@ */
static int current_dfn = 1; /* Counter to generate depth first numbering
- of visited nodes. */
+ of visited nodes. */
+
+static int max_loop_depth = 0;
void link_to_reg_end (ir_node *n, void *env);
void set_projx_link(ir_node *cb_projx, ir_node *end_projx);
/* Node attributes **/
/**********************************************************************/
-/* A map to get from irnodes to loop nodes. */
-static pmap *node_loop_map = NULL;
-
/**********************************************************************/
/* Node attributes needed for the construction. **/
/**********************************************************************/
return ((scc_info *)n->link)->dfn;
}
-#if 0
-/* Replaced node loop map by real field as hash access dominates runtime
- * of the algorithm. ! */
-/* Uses temporary information to set the loop */
-INLINE void
-set_irn_loop (ir_node *n, ir_loop* loop) {
- assert(node_loop_map && "not initialized!");
- pmap_insert(node_loop_map, (void *)n, (void *)loop);
-}
-/* Uses temporary information to get the loop */
-INLINE ir_loop *
-get_irn_loop (ir_node *n) {
- ir_loop *res = NULL;
- if (!node_loop_map) return NULL;
-
- if (pmap_contains(node_loop_map, (void *)n))
- res = (ir_loop *) pmap_get(node_loop_map, (void *)n);
-
- return res;
-}
-#else
INLINE void
set_irn_loop (ir_node *n, ir_loop* loop) {
n->loop = loop;
get_irn_loop (ir_node *n) {
return n->loop;
}
-#endif
#if 0
ir_node *m;
int i = 0;
- /*for (;;) {*/
- do
- {
+ do {
m = pop();
//printf(" dfn: %d, upl %d upl-new %d ", get_irn_dfn(m), get_irn_uplink(m), loop_node_cnt+1); DDMN(m);
set_irn_loop(m, current_loop);
i++;
/* if (m==n) break;*/
- } while(m != n);
+ } while(m != n);
- if(i > 1)
+ /* i might be bigger than 1 for dead (and that's why bad) loops */
+ /* if(i > 1)
printf("Mehr als eine Iteration!!!!!!!!!!!!!!!!!!!!!!!!!!!!11111\n");
+ */
}
/* GL ??? my last son is my grandson??? Removes loops with no
son->outer_loop = father;
add_loop_son(father, son);
son->depth = father->depth+1;
+ if (son->depth > max_loop_depth) max_loop_depth = son->depth;
} else { /* The root loop */
son->outer_loop = son;
son->depth = 0;
loop_element ln;
ln.node = n;
assert(loop && loop->kind == k_ir_loop);
- assert(get_kind(n) == k_ir_node);
+ assert(get_kind(n) == k_ir_node || get_kind(n) == k_ir_graph); /* used in callgraph.c */
ARR_APP1 (loop_element, loop->children, ln);
loop->n_nodes++;
}
(get_irn_op(cb) == op_EndReg) ||
(get_irn_op(cb) == op_EndExcept)) {
init_node(cb, NULL);
- init_node(get_nodes_Block(cb), NULL);
+ init_node(get_nodes_block(cb), NULL);
}
}
#endif
init_scc_common (void) {
current_dfn = 1;
loop_node_cnt = 0;
- if (!node_loop_map) node_loop_map = pmap_create();
init_stack();
}
if ((get_irn_op(n) == op_Block) &&
(get_Block_n_cfgpreds(n) == 1) &&
(get_irn_op(skip_Proj(get_Block_cfgpred(n, 0))) == op_Start) &&
- (get_nodes_Block(skip_Proj(get_Block_cfgpred(n, 0))) == n)) {
+ (get_nodes_block(skip_Proj(get_Block_cfgpred(n, 0))) == n)) {
return true;
}
#if 0
if (get_irn_op(n) == op_Phi ||
get_irn_op(n) == op_Block ||
(get_irn_op(n) == op_Filter && interprocedural_view) ||
- (get_irg_pinned(get_irn_irg(n)) == floats &&
- get_op_pinned(get_irn_op(n)) == floats))
+ (get_irg_pinned(get_irn_irg(n)) == op_pin_state_floats &&
+ get_op_pinned(get_irn_op(n)) == op_pin_state_floats))
// Here we could test for backedge at -1 which is illegal
return 0;
else
if (res_index == -2) /* no smallest dfn pred found. */
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;
}
break;
}
}
- if (res_index <= -2) return NULL;
+ if (res_index <= -2) {
+ /* It's a completely bad loop: without Phi/Block nodes that can
+ be a head. I.e., the code is "dying". We break the loop by
+ setting Bad nodes. */
+ int arity = get_irn_arity(n);
+ for (i = -1; i < arity; ++i) {
+ set_irn_n(n, i, get_irg_bad(get_irn_irg(n)));
+ }
+ return NULL;
+ }
assert (res_index > -2);
set_backedge (m, res_index);
printf("FOUND PROJ!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
ir_node *end_projx = stack[i];
- for(j = 0; j < get_irn_arity(start_block); j++)
+ int arity = get_irn_arity(start_block);
+ 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);
if(get_irn_n(start_block, j) == begin_projx)
{
static pmap *projx_link = NULL;
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 */
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");
DDMN(begin_projx);
DDMN(end_projx);
#endif
+INLINE static int
+is_outermost_loop(ir_loop *l) {
+ return l == get_loop_outer_loop(l);
+}
/*-----------------------------------------------------------*
if (!is_outermost_Start(n)) {
int arity = get_irn_arity(n);
-#if EXPERIMENTAL_LOOP_TREE
+ for (i = get_start_index(n); i < arity; i++) {
+ ir_node *m;
+ if (is_backedge(n, i)) continue;
+ m = get_irn_n(n, i); /* get_irn_ip_pred(n, i); */
+ /* if ((!m) || (get_irn_op(m) == op_Unknown)) continue; */
+ scc (m);
+ if (irn_is_in_stack(m)) {
+ /* Uplink of m is smaller if n->m is a backedge.
+ Propagate the uplink to mark the loop. */
+ if (get_irn_uplink(m) < get_irn_uplink(n))
+ set_irn_uplink(n, get_irn_uplink(m));
+ }
+ }
+ }
- /* This is meant to be used with the experimenatl code above.
- If the above code is not used any more, this can be deleted, too.... */
+ if (get_irn_dfn(n) == get_irn_uplink(n)) {
+ /* This condition holds for
+ 1) the node with the incoming backedge.
+ That is: We found a loop!
+ 2) Straight line code, because no uplink has been propagated, so the
+ uplink still is the same as the dfn.
- if(interprocedural_view &&
- is_Block(n) &&
- get_irn_op(get_irn_n(n, 0)) == op_Proj &&
- get_irn_op(get_irn_n(get_irn_n(n, 0), 0)) == op_CallBegin)
- {
- /* We are at the start node of a function:
- Walk to the callers in the correct order! */
- DDMN(n);
- DDMN(get_irn_n(get_irn_n(n, 0), 0));
- for(i = 0; i < arity; i++)
- {
- int pred_nr;
- ir_node *m;
-
- pred_nr = search_endproj_in_stack(n);
- assert(pred_nr >= 0);
- if(is_backedge(n, pred_nr))
- continue;
- m = get_irn_n(n, pred_nr);
- scc(m);
-
- if (irn_is_in_stack(m)) {
- /* Uplink of m is smaller if n->m is a backedge.
- Propagate the uplink to mark the loop. */
- if (get_irn_uplink(m) < get_irn_uplink(n))
- set_irn_uplink(n, get_irn_uplink(m));
- }
- }
- }
- else
+ But n might not be a proper loop head for the analysis. Proper loop
+ heads are Block and Phi nodes. find_tail searches the stack for
+ Block's and Phi's and takes those nodes as loop heads for the current
+ loop instead and marks the incoming edge as backedge. */
+
+ ir_node *tail = find_tail(n);
+ if (tail) {
+ /* We have a loop, that is no straight line code,
+ because we found a loop head!
+ Next actions: Open a new loop on the loop tree and
+ try to find inner loops */
+
+#if NO_LOOPS_WITHOUT_HEAD
+ /* This is an adaption of the algorithm from fiasco / optscc to
+ * avoid loops without Block or Phi as first node. This should
+ * severely reduce the number of evaluations of nodes to detect
+ * a fixpoint in the heap analysis.
+ * Further it avoids loops without firm nodes that cause errors
+ * 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;
+ int close;
+ if ((get_loop_n_elements(current_loop) > 0) || (is_outermost_loop(current_loop))) {
+ l = new_loop();
+ close = 1;
+ } else {
+ l = current_loop;
+ close = 0;
+ }
+#else
+ ir_loop *l = new_loop();
#endif
+ /* Remove the loop from the stack ... */
+ pop_scc_unmark_visit (n);
+
+ /* The current backedge has been marked, that is temporarily eliminated,
+ by find tail. Start the scc algorithm
+ anew on the subgraph thats left (the current loop without the backedge)
+ in order to find more inner loops. */
+ scc (tail);
+
+ assert (irn_visited(n));
+#if NO_LOOPS_WITHOUT_HEAD
+ if (close)
+#endif
+ close_loop(l);
+ }
+ else
{
- for (i = get_start_index(n); i < arity; i++) {
- ir_node *m;
- if (is_backedge(n, i)) continue;
- m = get_irn_n(n, i); /* get_irn_ip_pred(n, i); */
- /* if ((!m) || (get_irn_op(m) == op_Unknown)) continue; */
- scc (m);
- if (irn_is_in_stack(m)) {
- /* Uplink of m is smaller if n->m is a backedge.
- Propagate the uplink to mark the loop. */
- if (get_irn_uplink(m) < get_irn_uplink(n))
- set_irn_uplink(n, get_irn_uplink(m));
- }
- }
+ /* No loop head was found, that is we have straightline code.
+ Pop all nodes from the stack to the current loop. */
+ pop_scc_to_loop(n);
+ }
+ }
+}
+
+static void my_scc (ir_node *n) {
+ int i;
+ if (irn_visited(n)) return;
+ mark_irn_visited(n);
+
+ /* Initialize the node */
+ set_irn_dfn(n, current_dfn); /* Depth first number for this node */
+ set_irn_uplink(n, current_dfn); /* ... is default uplink. */
+ set_irn_loop(n, NULL);
+ current_dfn ++;
+ push(n);
+
+ /* AS: get_start_index might return -1 for Control Flow Nodes, and thus a negative
+ array index would be passed to is_backedge(). But CFG Nodes dont't have a backedge array,
+ so is_backedge does not access array[-1] but correctly returns false! */
+
+ if (!is_outermost_Start(n)) {
+ int arity = get_irn_arity(n);
+
+ for (i = get_start_index(n); i < arity; i++) {
+ ir_node *m;
+ if (is_backedge(n, i)) continue;
+ m = get_irn_n(n, i); /* get_irn_ip_pred(n, i); */
+ /* if ((!m) || (get_irn_op(m) == op_Unknown)) continue; */
+ my_scc (m);
+ if (irn_is_in_stack(m)) {
+ /* Uplink of m is smaller if n->m is a backedge.
+ Propagate the uplink to mark the loop. */
+ if (get_irn_uplink(m) < get_irn_uplink(n))
+ set_irn_uplink(n, get_irn_uplink(m));
}
+ }
}
if (get_irn_dfn(n) == get_irn_uplink(n)) {
Next actions: Open a new loop on the loop tree and
try to find inner loops */
-
-#define NO_LOOPS_WITHOUT_HEAD 1
#if NO_LOOPS_WITHOUT_HEAD
-
/* This is an adaption of the algorithm from fiasco / optscc to
* avoid loops without Block or Phi as first node. This should
* severely reduce the number of evaluations of nodes to detect
ir_loop *l;
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();
close = 1;
} else {
l = current_loop;
close = 0;
}
-
#else
-
ir_loop *l = new_loop();
-
#endif
/* Remove the loop from the stack ... */
pop_scc_unmark_visit (n);
- /* GL @@@ remove experimental stuff rem = find_irg_on_stack(tail); */
-
/* The current backedge has been marked, that is temporarily eliminated,
by find tail. Start the scc algorithm
anew on the subgraph thats left (the current loop without the backedge)
in order to find more inner loops. */
-
- scc (tail);
-
- /* GL @@@ remove experimental stuff current_ir_graph = rem; */
+ my_scc (tail);
assert (irn_visited(n));
#if NO_LOOPS_WITHOUT_HEAD
}
else
{
- /* AS: No loop head was found, that is we have straightline code.
- Pop all nodes from the stack to the current loop. */
+ /* No loop head was found, that is we have straightline code.
+ Pop all nodes from the stack to the current loop. */
pop_scc_to_loop(n);
}
}
/* Constructs backedge information for irg. In interprocedural view constructs
backedges for all methods called by irg, too. */
-void construct_backedges(ir_graph *irg) {
+int construct_backedges(ir_graph *irg) {
ir_graph *rem = current_ir_graph;
ir_loop *head_rem;
assert(!interprocedural_view &&
"not implemented, use construct_ip_backedges");
- current_ir_graph = irg;
+ max_loop_depth = 0;
+ current_ir_graph = irg;
outermost_ir_graph = irg;
init_scc(current_ir_graph);
new_loop(); /* sets current_loop */
head_rem = current_loop; /* Just for assertion */
- if (interprocedural_view) {
- set_irg_visited(current_ir_graph, inc_max_irg_visited());
- init_ip_walk ();
- } else {
- inc_irg_visited(current_ir_graph);
- }
+ inc_irg_visited(current_ir_graph);
scc(get_irg_end(current_ir_graph));
- if (interprocedural_view) finish_ip_walk();
-
assert(head_rem == current_loop);
set_irg_loop(current_ir_graph, current_loop);
set_irg_loopinfo_state(current_ir_graph, loopinfo_consistent);
}
*/
current_ir_graph = rem;
+
+ return max_loop_depth;
}
-#if 0
-void construct_ip_backedges (void) {
+int construct_ip_backedges (void) {
ir_graph *rem = current_ir_graph;
int rem_ipv = interprocedural_view;
- int i, j;
+ int i;
+
+ max_loop_depth = 0;
+ assert(get_irp_ip_view_state() == ip_view_valid);
outermost_ir_graph = get_irp_main_irg();
for (i = 0; i < get_irp_n_irgs(); i++)
set_irg_visited(get_irp_irg(i), get_max_irg_visited());
+ /** We have to start the walk at the same nodes as cg_walk. **/
+ /* Walk starting at unreachable procedures. Only these
+ * have End blocks visible in interprocedural view. */
for (i = 0; i < get_irp_n_irgs(); i++) {
ir_node *sb;
current_ir_graph = get_irp_irg(i);
- /* Find real entry points */
+
sb = get_irg_start_block(current_ir_graph);
+
if ((get_Block_n_cfgpreds(sb) > 1) ||
- (get_nodes_Block(get_Block_cfgpred(sb, 0)) != sb)) continue;
- /* Compute scc for this graph */
- outermost_ir_graph = current_ir_graph;
- set_irg_visited(outermost_ir_graph, get_max_irg_visited());
+ (get_nodes_block(get_Block_cfgpred(sb, 0)) != sb)) continue;
+
scc(get_irg_end(current_ir_graph));
- for (j = 0; j < get_End_n_keepalives(get_irg_end(outermost_ir_graph)); j++)
- scc(get_End_keepalive(get_irg_end(outermost_ir_graph), j));
+ }
+
+ /* Check whether we walked all procedures: there could be procedures
+ with cyclic calls but no call from the outside. */
+ for (i = 0; i < get_irp_n_irgs(); i++) {
+ ir_node *sb;
+ current_ir_graph = get_irp_irg(i);
+
+ /* Test start block: if inner procedure end and end block are not
+ * visible and therefore not marked. */
+ sb = get_irg_start_block(current_ir_graph);
+ if (get_irn_visited(sb) < get_irg_visited(current_ir_graph)) scc(sb);
+ }
+
+ /* Walk all endless loops in inner procedures.
+ * We recognize an inner procedure if the End node is not visited. */
+ for (i = 0; i < get_irp_n_irgs(); i++) {
+ ir_node *e;
+ current_ir_graph = get_irp_irg(i);
+
+ e = get_irg_end(current_ir_graph);
+ if (get_irn_visited(e) < get_irg_visited(current_ir_graph)) {
+ int j;
+ /* Don't visit the End node. */
+ for (j = 0; j < get_End_n_keepalives(e); j++) scc(get_End_keepalive(e, j));
+ }
}
set_irg_loop(outermost_ir_graph, current_loop);
current_ir_graph = rem;
interprocedural_view = rem_ipv;
+ return max_loop_depth;
}
-#else
-void construct_ip_backedges (void) {
+
+void my_construct_ip_backedges (void) {
ir_graph *rem = current_ir_graph;
int rem_ipv = interprocedural_view;
int i;
if ((get_Block_n_cfgpreds(sb) > 1) ||
(get_nodes_block(get_Block_cfgpred(sb, 0)) != sb)) continue;
- scc(get_irg_end(current_ir_graph));
+ my_scc(get_irg_end(current_ir_graph));
}
/* Check whether we walked all procedures: there could be procedures
current_ir_graph = rem;
interprocedural_view = rem_ipv;
}
-#endif
static void reset_backedges(ir_node *n) {
if (is_possible_loop_head(n)) {
for (i = 0; i < get_irp_n_irgs(); i++) {
free_loop_information(get_irp_irg(i));
}
- pmap_destroy(node_loop_map);
- node_loop_map = NULL;
interprocedural_view = rem;
}