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

implemented scc algorithm. Added datastructure to mark

  backedges (ana/backedge.h) and to represent loops
  (ana/irloop.h).  The scc algorithm (ana/irscc.c) builds
  both datastructures.
  The algorithm does not yet work properly for interprocedural
  graphs.  Finds more loops than only recursions.

  Improved place_code: now moves nodes out of loops.
  Fixed bug in iropt.c:  wrong parameter in debug info: iropt_dbg.c
  Now flag set_opt_control_flow can be set to 1 again.

[r457]
parent 60478f1c
......@@ -27,8 +27,7 @@
# include "array.h"
/* memset belongs to string.h */
# include "string.h"
/* # include "exc.h" */
# include "irbackedge_t.h"
#if USE_EXPLICIT_PHI_IN_STACK
/* A stack needed for the automatic Phi node construction in constructor
......@@ -57,7 +56,9 @@ new_rd_Block (dbg_info* db, ir_graph *irg, int arity, ir_node **in)
res->attr.block.exc = exc_normal;
res->attr.block.handler_entry = 0;
res->attr.block.backedge = new_backedge_arr(irg->obst, arity);
res->attr.block.in_cg = NULL;
res->attr.block.cg_backedge = NULL;
irn_vrfy (res);
return res;
......@@ -97,6 +98,8 @@ new_rd_Phi (dbg_info* db, ir_graph *irg, ir_node *block, int arity, ir_node **in
res = new_ir_node (db, irg, block, op_Phi, mode, arity, in);
res->attr.phi_backedge = new_backedge_arr(irg->obst, arity);
res = optimize (res);
irn_vrfy (res);
......@@ -692,6 +695,7 @@ new_rd_Filter (dbg_info *db, ir_graph *irg, ir_node *block, ir_node *arg, ir_mod
res = new_ir_node (db, irg, block, op_Filter, mode, 1, in);
res->attr.filter.proj = proj;
res->attr.filter.in_cg = NULL;
res->attr.filter.backedge = NULL;
assert(res);
assert(get_Proj_pred(res));
......@@ -1044,6 +1048,7 @@ alloc_or_pop_from_Phi_in_stack(ir_graph *irg, ir_node *block, ir_mode *mode,
if (pos == 0) {
/* We need to allocate a new node */
res = new_ir_node (db, irg, block, op_Phi, mode, arity, in);
res->attr.phi_backedge = new_backedge_arr(irg->obst, arity);
} else {
/* reuse the old node and initialize it again. */
res = stack[pos-1];
......@@ -1054,7 +1059,7 @@ alloc_or_pop_from_Phi_in_stack(ir_graph *irg, ir_node *block, ir_mode *mode,
res->visited = 0;
res->link = NULL;
assert (arity >= 0);
/* ???!!! How to free the old in array?? */
/* ???!!! How to free the old in array?? Not at all: on obstack ?!! */
res->in = NEW_ARR_D (ir_node *, irg->obst, (arity+1));
res->in[0] = block;
memcpy (&res->in[1], in, sizeof (ir_node *) * arity);
......@@ -1102,6 +1107,7 @@ new_rd_Phi_in (ir_graph *irg, ir_node *block, ir_mode *mode,
res = known = alloc_or_pop_from_Phi_in_stack(irg, block, mode, ins, in);
#else
res = known = new_ir_node (NULL, irg, block, op_Phi, mode, ins, in);
res->attr.phi_backedge = new_backedge_arr(irg->obst, ins);
#endif
/* The in-array can contain NULLs. These were returned by
get_r_value_internal if it reached the same block/definition on a
......@@ -1326,6 +1332,7 @@ new_rd_Phi_in (ir_graph *irg, ir_node *block, ir_mode *mode,
/* Allocate a new node on the obstack. The allocation copies the in
array. */
res = new_ir_node (NULL, irg, block, op_Phi, mode, ins, in);
res->attr.phi_backedge = new_backedge_arr(irg->obst, ins);
/* This loop checks whether the Phi has more than one predecessor.
If so, it is a real Phi node and we break the loop. Else the
......@@ -1652,9 +1659,11 @@ mature_block (ir_node *block)
assert (!get_Block_matured(block) && "Block already matured"); */
if (!get_Block_matured(block)) {
ins = ARR_LEN (block->in)-1;
/* Fix block parameters */
block->attr.block.backedge = new_backedge_arr(current_ir_graph->obst, ins);
/* An array for building the Phi nodes. */
ins = ARR_LEN (block->in)-1;
NEW_ARR_A (ir_node *, nin, ins);
/* Traverse a chain of Phi nodes attached to this block and mature
......@@ -2090,7 +2099,9 @@ ir_node *new_d_immBlock (dbg_info* db) {
res->attr.block.matured = 0;
res->attr.block.exc = exc_normal;
res->attr.block.handler_entry = 0;
res->attr.block.backedge = NULL;
res->attr.block.in_cg = NULL;
res->attr.block.cg_backedge = NULL;
set_Block_block_visited(res, 0);
/* Create and initialize array for Phi-node construction. */
......
......@@ -29,6 +29,7 @@
# include "irouts.h"
# include "irdom.h"
# include "common_t.h"
# include "irloop.h"
# include "exc.h"
......@@ -44,6 +45,8 @@
#define MEM_EDGE_ATTR "color: blue"
#define DOMINATOR_EDGE_ATTR "color: red"
#define BACK_EDGE_ATTR "linestyle: dashed "
/* Attributes of edges between Firm nodes and type/entity nodes */
#define NODE2TYPE_EDGE_ATTR "class: 2 priority: 2 linestyle: dotted"
......@@ -85,14 +88,14 @@ int edge_label = 1;
int const_entities = 1;
/* A compiler option to dump the keep alive edges */
int dump_keepalive = 0;
/* A compiler option to dump the out edges in dump_ir_graph */
/* Compiler options to dump analysis information in dump_ir_graph */
int dump_out_edge_flag = 0;
int dump_dominator_information_flag = 0;
int dump_loop_information_flag = 0;
/* A global variable to record output of the Bad node. */
int Bad_dumped;
void dump_ir_blocks_nodes (ir_node *n, void *env);
void dump_whole_node (ir_node *n, void* env);
......@@ -163,10 +166,20 @@ dump_node_mode (ir_node *n)
}
}
void dump_node_loop_info(ir_node *n) {
// if (get_irn_loop(n))
// xfprintf(F, "\n in loop %d", get_loop_depth(get_irn_loop(n)));
}
INLINE void
dump_node_nodeattr (ir_node *n)
{
switch (n->op->code) {
case iro_Start:
if (false && interprocedural_view) {
xfprintf (F, "%I", get_entity_ident(get_irg_ent(current_ir_graph)));
}
break;
case iro_Proj:
if (n->in[1]->op->code == iro_Cmp) {
xfprintf (F, "%s", get_pnc_string(n->attr.proj));
......@@ -222,6 +235,7 @@ dump_node (ir_node *n) {
dump_node_opcode(n);
dump_node_mode (n);
//if (dump_loop_information_flag) dump_node_loop_info(n);
xfprintf (F, " ");
dump_node_nodeattr(n);
#ifdef DEBUG_libfirm
......@@ -441,6 +455,8 @@ dump_ir_block_edge(ir_node *n) {
void print_edge_vcgattr(ir_node *from, int to) {
assert(from);
if (is_backedge(from, to)) xfprintf (F, BACK_EDGE_ATTR);
switch (get_irn_opcode(from)) {
case iro_Block:
xfprintf (F, CF_EDGE_ATTR);
......@@ -533,8 +549,12 @@ dump_ir_data_edges(ir_node *n) {
for (i = 0; i < get_irn_arity(n); i++) {
ir_node * pred = get_irn_n(n, i);
assert(pred);
if (interprocedural_view && get_irn_visited(pred) < visited) continue; /* pred not dumped */
fprintf (F, "edge: {sourcename: \"");
if (interprocedural_view && get_irn_visited(pred) < visited)
continue; /* pred not dumped */
if (is_backedge(n, i))
fprintf (F, "backedge: {sourcename: \"");
else
fprintf (F, "edge: {sourcename: \"");
PRINT_NODEID(n);
fprintf (F, "\" targetname: \"");
PRINT_NODEID(pred);
......@@ -560,6 +580,43 @@ dump_out_edge (ir_node *n, void* env) {
}
}
static INLINE void
dump_loop_node_edge (ir_loop *loop, int i) {
assert(loop);
fprintf (F, "edge: {sourcename: \"%p\" targetname: \"", loop);
PRINT_NODEID(get_loop_node(loop, i));
fprintf (F, "\" color: green");
fprintf (F, "}\n");
}
static
void dump_loops (ir_loop *loop) {
int i;
/* dump this loop node */
xfprintf (F, "node: {title: \"%p\" label: \"loop %d, %d sons, %d nodes\" }\n",
loop, get_loop_depth(loop), get_loop_n_sons(loop), get_loop_n_nodes(loop));
/* dump edges to nodes in loop -- only if it is a real loop */
if (get_loop_depth(loop) != 0) {
for (i = 0; i < get_loop_n_nodes(loop); i++) {
dump_loop_node_edge(loop, i);
}
}
for (i = 0; i < get_loop_n_sons(loop); i++) {
dump_loops(get_loop_son(loop, i));
}
}
static INLINE
void dump_loop_info(ir_graph *irg) {
ir_graph *rem = current_ir_graph;
current_ir_graph = irg;
if (get_irg_loop(irg))
dump_loops(get_irg_loop(irg));
current_ir_graph = rem;
}
/* dumps the edges between nodes and their type or entity attributes. */
void dump_node2type_edges (ir_node *n, void *env)
......@@ -947,7 +1004,6 @@ vcg_close () {
/************************************************************************/
int node_floats(ir_node *n) {
return ((get_op_pinned(get_irn_op(n)) == floats) &&
(get_irg_pinned(current_ir_graph) == floats));
}
......@@ -1071,6 +1127,10 @@ dump_ir_block_graph (ir_graph *irg)
dump_ir_block_graph_2 (irg);
if (dump_loop_information_flag) {
dump_loop_info(irg);
}
vcg_close();
current_ir_graph = rem;
}
......@@ -1268,6 +1328,13 @@ void dump_dominator_information() {
dump_dominator_information_flag = 1;
}
void dump_loop_information() {
dump_loop_information_flag = 1;
}
void dont_dump_loop_information() {
dump_loop_information_flag = 0;
}
static void clear_link(ir_node * node, void * env) {
set_irn_link(node, NULL);
......@@ -1349,8 +1416,11 @@ void dump_cg_block_graph(ir_graph * irg) {
for (i = ARR_LEN(arr) - 1; i >= 0; --i) {
ir_node * node = arr[i];
if (is_Block(node)) {
/* Dumps the block and all the nodes in the block , with are to be found in
Block->link. */
dump_cg_ir_block(node, NULL);
} else {
/* Node that are not in a Block. */
dump_node(node);
dump_ir_data_edges(node);
}
......@@ -1364,6 +1434,10 @@ void dump_cg_block_graph(ir_graph * irg) {
pmap_destroy(map);
if (dump_loop_information_flag) {
dump_loop_info(irg);
}
vcg_close();
}
......
......@@ -351,5 +351,7 @@ void dump_out_edges();
*/
void dump_dominator_information();
void dump_loop_information();
void dont_dump_loop_information();
# endif /* _IRDUMP_H_ */
......@@ -27,6 +27,8 @@
# include "pset.h"
# include "pdeq.h" /* Fuer code placement */
# include "irouts.h"
# include "irloop.h"
# include "irbackedge_t.h"
/* Defined in iropt.c */
pset *new_identities (void);
......@@ -128,13 +130,29 @@ compute_new_arity(ir_node *b) {
}
}
static INLINE new_backedge_info(ir_node *n) {
switch(get_irn_opcode(n)) {
case iro_Block:
n->attr.block.cg_backedge = NULL;
n->attr.block.backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
break;
case iro_Phi:
n->attr.phi_backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
break;
case iro_Filter:
n->attr.filter.backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
break;
default: ;
}
}
/* Copies the node to the new obstack. The Ins of the new node point to
the predecessors on the old obstack. For block/phi nodes not all
predecessors might be copied. n->link points to the new node.
For Phi and Block nodes the function allocates in-arrays with an arity
only for useful predecessors. The arity is determined by counting
the non-bad predecessors of the block. */
void
static void
copy_node (ir_node *n, void *env) {
ir_node *nn, *block;
int new_arity;
......@@ -142,6 +160,7 @@ copy_node (ir_node *n, void *env) {
if (get_irn_opcode(n) == iro_Block) {
block = NULL;
new_arity = compute_new_arity(n);
n->attr.block.graph_arr = NULL;
} else {
block = get_nodes_Block(n);
if (get_irn_opcode(n) == iro_Phi) {
......@@ -161,6 +180,7 @@ copy_node (ir_node *n, void *env) {
was allocated on the old obstack the pointers now are dangling. This
frees e.g. the memory of the graph_arr allocated in new_immBlock. */
copy_attrs(n, nn);
new_backedge_info(nn);
set_new_node(n, nn);
/* printf("\n old node: "); DDMSG2(n);
......@@ -170,7 +190,7 @@ copy_node (ir_node *n, void *env) {
/* Copies new predecessors of old node to new node remembered in link.
Spare the Bad predecessors of Phi and Block nodes. */
void
static void
copy_preds (ir_node *n, void *env) {
ir_node *nn, *block;
int i, j;
......@@ -187,6 +207,7 @@ copy_preds (ir_node *n, void *env) {
for (i = 0; i < get_irn_arity(n); i++)
if (get_irn_opcode(get_irn_n(n, i)) != iro_Bad) {
set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
//if (is_backedge(n, i)) set_backedge(nn, j);
j++;
}
/* repair the block visited flag from above misuse. Repair it in both
......@@ -210,6 +231,7 @@ copy_preds (ir_node *n, void *env) {
for (i = 0; i < get_irn_arity(n); i++)
if (get_irn_opcode(get_irn_n(block, i)) != iro_Bad) {
set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
//if (is_backedge(n, i)) set_backedge(nn, j);
j++;
}
/* If the pre walker reached this Phi after the post walker visited the
......@@ -230,7 +252,7 @@ copy_preds (ir_node *n, void *env) {
}
/* Copies the graph recursively, compacts the keepalive of the end node. */
void
static void
copy_graph () {
ir_node *oe, *ne; /* old end, new end */
ir_node *ka; /* keep alive */
......@@ -288,6 +310,7 @@ copy_graph () {
graph. */
void
copy_graph_env () {
ir_node *old_end;
/* Not all nodes remembered in current_ir_graph might be reachable
from the end node. Assure their link is set to NULL, so that
we can test whether new nodes have been computed. */
......@@ -302,8 +325,9 @@ copy_graph_env () {
copy_graph();
/* fix the fields in current_ir_graph */
free_End(get_irg_end(current_ir_graph));
set_irg_end (current_ir_graph, get_new_node(get_irg_end(current_ir_graph)));
old_end = get_irg_end(current_ir_graph);
set_irg_end (current_ir_graph, get_new_node(old_end));
free_End(old_end);
set_irg_end_block (current_ir_graph, get_new_node(get_irg_end_block(current_ir_graph)));
if (get_irn_link(get_irg_frame(current_ir_graph)) == NULL) {
copy_node (get_irg_frame(current_ir_graph), NULL);
......@@ -357,6 +381,9 @@ dead_node_elimination(ir_graph *irg) {
assert(get_irg_phase_state(current_ir_graph) != phase_building);
free_outs(current_ir_graph);
/* @@@ so far we loose loops when copying */
set_irg_loop(current_ir_graph, NULL);
if (get_optimize() && get_opt_dead_node_elimination()) {
/* A quiet place, where the old obstack can rest in peace,
......@@ -391,7 +418,7 @@ dead_node_elimination(ir_graph *irg) {
then updates the entity if it's a local one. env must be a pointer
to the frame type of the procedure. The new entities must be in
the link field of the entities. */
void
static INLINE void
copy_node_inline (ir_node *n, void *env) {
ir_node *new;
type *frame_tp = (type *)env;
......@@ -443,9 +470,9 @@ void inline_method(ir_node *call, ir_graph *called_graph) {
/** Part the Call node into two nodes. Pre_call collects the parameters of
the procedure and later replaces the Start node of the called graph.
Post_call is the old Call node and collects the results of the called
graph. Both will end up being a tuple. **/
the procedure and later replaces the Start node of the called graph.
Post_call is the old Call node and collects the results of the called
graph. Both will end up being a tuple. **/
post_bl = get_nodes_Block(call);
set_irg_current_block(current_ir_graph, post_bl);
/* XxMxPxP of Start + parameter of Call */
......@@ -604,7 +631,7 @@ void inline_method(ir_node *call, ir_graph *called_graph) {
}
}
if (n_exc > 0) {
new_Block(n_exc, cf_pred); /* whatch it: current_block is changed! */
new_Block(n_exc, cf_pred); /* watch it: current_block is changed! */
set_Tuple_pred(call, 1, new_Jmp());
/* The Phi for the memories with the exception objects */
n_exc = 0;
......@@ -877,28 +904,41 @@ consumer_dom_dca (ir_node *dca, ir_node *consumer, ir_node *producer)
return dca;
}
#if 0
/* @@@ Needs loop informations. Will implement later interprocedural. */
int get_irn_loop_depth(ir_node *n) {
return get_loop_depth(get_irn_loop(n));
}
/* Move n to a block with less loop depth than it's current block. The
new block must be dominated by early. */
static void
move_out_of_loops (ir_node *n, ir_node *dca)
move_out_of_loops (ir_node *n, ir_node *early)
{
assert(dca);
ir_node *best, *dca;
assert(n && early);
/* Find the region deepest in the dominator tree dominating
dca with the least loop nesting depth, but still dominated
by our early placement. */
ir_node *best = dca;
while (dca != get_nodes_Block(n)) {
dca = get_nodes_Block(n);
best = dca;
while (dca != early) {
dca = get_Block_idom(dca);
if (!dca) break; /* should we put assert(dca)? */
if (get_Block_loop_depth(dca) < get_Block_loop_depth(best)) {
if (get_irn_loop_depth(dca) < get_irn_loop_depth(best)) {
best = dca;
}
}
if (get_Block_dom_depth(best) >= get_Block_dom_depth(get_nodes_Block(n)))
if (best != get_nodes_Block(n)) {
/* debug output
printf("Moving out of loop: "); DDMN(n);
printf(" Outermost block: "); DDMN(early);
printf(" Best block: "); DDMN(best);
printf(" Innermost block: "); DDMN(get_nodes_Block(n));
*/
set_nodes_Block(n, best);
}
}
#endif
/* Find the latest legal block for N and place N into the
`optimal' Block between the latest and earliest legal block.
......@@ -910,11 +950,17 @@ static void
place_floats_late (ir_node *n)
{
int i;
ir_node *early;
assert (irn_not_visited(n)); /* no multiple placement */
/* no need to place block nodes, control nodes are already placed. */
if ((get_irn_op(n) != op_Block) && (!is_cfop(n)) && (get_irn_mode(n) != mode_X)) {
if ((get_irn_op(n) != op_Block) &&
(!is_cfop(n)) &&
(get_irn_mode(n) != mode_X)) {
/* Remember the early palacement of this block to move it
out of loop no further than the early placement. */
early = get_nodes_Block(n);
/* Assure that our users are all placed, except the Phi-nodes.
--- Each dataflow cycle contains at least one Phi-node. We
have to break the `user has to be placed before the
......@@ -929,7 +975,8 @@ place_floats_late (ir_node *n)
place_floats_late (succ);
}
/* We have to determine the final block of this node... except for constants. */
/* We have to determine the final block of this node... except for
constants. */
if ((get_op_pinned(get_irn_op(n)) == floats) &&
(get_irn_op(n) != op_Const) &&
(get_irn_op(n) != op_SymConst)) {
......@@ -941,8 +988,8 @@ place_floats_late (ir_node *n)
dca = consumer_dom_dca (dca, get_irn_out(n, i), n);
}
set_nodes_Block(n, dca);
#if 0
move_out_of_loops (n, dca);
#if 1
move_out_of_loops (n, early);
#endif
}
}
......@@ -971,6 +1018,8 @@ INLINE void place_late() {
}
}
#include "irdump.h"
void place_code(ir_graph *irg) {
ir_graph *rem = current_ir_graph;
current_ir_graph = irg;
......@@ -982,6 +1031,8 @@ void place_code(ir_graph *irg) {
if (get_irg_dom_state(irg) != dom_consistent)
compute_doms(irg);
construct_backedges(irg);
/* Place all floating nodes as early as possible. This guarantees
a legal code placement. */
worklist = new_pdeq ();
......@@ -1107,14 +1158,14 @@ void optimize_blocks(ir_node *b, void *env) {
ir_node *pred, *phi;
ir_node **in;
/* Count the number of predecessor if this block is merged with pred blocks
that are empty. */
max_preds = 0;
for (i = 0; i < get_Block_n_cfgpreds(b); i++) {
pred = get_Block_cfgpred(b, i);
max_preds += test_whether_dispensable(b, i);
}
in = (ir_node **) malloc(max_preds * sizeof(ir_node *));
/** Debug output **
printf(" working on "); DDMN(b);
for (i = 0; i < get_Block_n_cfgpreds(b); i++) {
......@@ -1126,7 +1177,7 @@ void optimize_blocks(ir_node *b, void *env) {
printf(" removing pred %i ", i); DDMN(pred);
} else { printf(" Nothing to do for "); DDMN(pred); }
}
** end Debug output **/
** end Debug output **/
/** Fix the Phi nodes **/
phi = get_irn_link(b);
......
......@@ -23,6 +23,7 @@ void local_optimize_graph (ir_graph *irg);
`opt_dead_node_elimination' are set.
The graph may not be in state phase_building. The outs datasturcture
is freed, the outs state set to no_outs. (@@@ Change this? -> inconsistent.)
Backedge information is conserved.
Removes old attributes of nodes. Sets link field to NULL.
Attention: the numbers assigned to nodes if the library is compiled for
development/debugging are not conserved by copying. */
......
......@@ -412,14 +412,22 @@ void set_irg_dom_inconsistent(ir_graph *irg) {
}
INLINE void
set_irg_pinned (ir_graph *irg, op_pinned p)
{
set_irg_pinned (ir_graph *irg, op_pinned p) {
irg->pinned = p;
}
/* maximum of all ir_graphs */
static int max_irg_visited = 0;
INLINE void
set_irg_link (ir_graph *irg, void *thing) {
irg->link = thing;
}
INLINE void *
get_irg_link (ir_graph *irg) {
return irg->link;
}
/* maximum visited flag content of all ir_graph visited fields. */
static int max_irg_visited = 0;
unsigned long
get_irg_visited (ir_graph *irg)
......@@ -431,6 +439,9 @@ void
set_irg_visited (ir_graph *irg, unsigned long visited)
{
irg->visited = visited;
if (irg->visited > max_irg_visited) {
max_irg_visited = irg->visited;
}
}
void
......@@ -444,6 +455,19 @@ inc_irg_visited (ir_graph *irg)
unsigned long
get_max_irg_visited(void)
{
int i;
for(i = 0; i < get_irp_n_irgs(); i++)
assert(max_irg_visited >= get_irg_visited(get_irp_irg(i)));
return max_irg_visited;
}
unsigned long
inc_max_irg_visited(void)
{
int i;
for(i = 0; i < get_irp_n_irgs(); i++)
assert(max_irg_visited >= get_irg_visited(get_irp_irg(i)));
max_irg_visited++;
return max_irg_visited;
}
......
......@@ -205,11 +205,28 @@ typedef enum {
irg_dom_state get_irg_dom_state(ir_graph *irg);
void set_irg_dom_inconsistent(ir_graph *irg);
/* state: loopinfo_state
Loop information describes the loops within the control and
data flow of the procedure.
typedef enum {
no_loopinfo,
loopinfo_consistent,
loopinfo_inconsistent
} irg_loopinfo_state;
irg_loopinfo_state get_irg_loopinfo_state(ir_graph *irg);
void set_irg_loopinfo_inconsistent(ir_graph *irg);
*/
/* A void * field to link arbritary information to the node. */