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

block walk in irouts.

irdom implemented: dominator information.

[r321]
parent 92c1ca1c
......@@ -10,12 +10,12 @@ srcdir = @srcdir@
topdir = ../..
subdir := ir/ana
INSTALL_HEADERS = irouts.h
INSTALL_HEADERS = irouts.h irdom.h
SOURCES = $(INSTALL_HEADERS)
SOURCES += Makefile.in \
irouts.c
irouts.c irdom_t.h irdom.c
include $(topdir)/MakeRules
......
/* Copyright (C) 2002 by Universitaet Karlsruhe
** All rights reserved.
**
** Authors: Goetz Lindenmaier
**
** irdom.c --- Dominator tree.
**
*/
/* $Id$ */
#include "irouts.h"
#include "irdom_t.h"
#include "irgraph_t.h" /* To access state field. */
#include "irnode_t.h"
/**********************************************************************/
/** Accessing the dominator datastructures **/
/**********************************************************************/
ir_node *get_Block_idom(ir_node *bl) {
assert(get_irn_op(bl) == op_Block);
return bl->attr.block.dom.idom;
}
void set_Block_idom(ir_node *bl, ir_node *n) {
assert(get_irn_op(bl) == op_Block);
bl->attr.block.dom.idom = n;
}
int get_Block_pre_num(ir_node *bl) {
assert(get_irn_op(bl) == op_Block);
return bl->attr.block.dom.pre_num;
}
void set_Block_pre_num(ir_node *bl, int num) {
assert(get_irn_op(bl) == op_Block);
bl->attr.block.dom.pre_num = num;
}
int get_Block_dom_depth(ir_node *bl) {
assert(get_irn_op(bl) == op_Block);
return bl->attr.block.dom.dom_depth;
}
void set_Block_dom_depth(ir_node *bl, int depth) {
assert(get_irn_op(bl) == op_Block);
bl->attr.block.dom.dom_depth = depth;
}
/**********************************************************************/
/** Building and Removing the dominator datasturcture **/
/** **/
/** **/
/** **/
/** **/
/** **/
/** **/
/** **/
/** .**/
/** **/
/** **/
/** **/
/** **/
/** **/
/** **/
/**********************************************************************/
void count_and_init_blocks(ir_node *bl, void *env) {
int *n_blocks = (int *) env;
(*n_blocks) ++;
set_Block_idom(bl, NULL);
set_Block_pre_num(bl, -1);
set_Block_dom_depth(bl, -1);
}
/* temporary type used while constructing the dominator tree. */
typedef struct tmp_dom_info {
ir_node *block; /* backlink */
struct tmp_dom_info *semi; /* semidominator */
struct tmp_dom_info *parent;
struct tmp_dom_info *label; /* used for LINK and EVAL */
struct tmp_dom_info *ancestor;/* used for LINK and EVAL */
struct tmp_dom_info *dom; /* After step 3, if the semidominator of w is
its immediate dominator, then w->dom is the
immediate dominator of w. Otherwise w->dom
is a vertex v whose number is smaller than
w and whose immediate dominator is also w's
immediate dominator. After step 4, w->dom
is the immediate dominator of w. */
struct tmp_dom_info *bucket; /* set of vertices with same semidominator */
} tmp_dom_info;
/* Struct to pass info through walker. */
typedef struct {
tmp_dom_info *d;
int used;
} dom_env;
void init_tmp_dom_info(ir_node *bl, tmp_dom_info *parent, tmp_dom_info *tdi_list, int* used) {
tmp_dom_info *tdi;
int i;
assert(get_irn_op(bl) == op_Block);
if (get_irg_block_visited(current_ir_graph) == get_Block_block_visited(bl)) return;
mark_Block_block_visited(bl);
set_Block_pre_num(bl, *used);
//printf(" used: %d ", *used); DDMN(bl);
tdi = &tdi_list[*used];
++(*used);
tdi->semi = tdi;
tdi->label = tdi;
tdi->ancestor = NULL;
tdi->bucket = NULL;
tdi->parent = parent;
tdi->block = bl;
/* Iterate */
for(i = 0; i < get_Block_n_cfg_outs(bl); i++) {
ir_node *pred = get_Block_cfg_out(bl, i);
assert(get_irn_opcode(pred) == iro_Block);
init_tmp_dom_info(pred, tdi, tdi_list, used);
}
}
static void
dom_compress (tmp_dom_info *v)
{
assert (v->ancestor);
if (v->ancestor->ancestor) {
dom_compress (v->ancestor);
if (v->ancestor->label->semi < v->label->semi) {
v->label = v->ancestor->label;
}
v->ancestor = v->ancestor->ancestor;
}
}
/* if V is a root, return v, else return the vertex u, not being the
root, with minimum u->semi on the path from v to its root. */
inline static tmp_dom_info*
dom_eval (tmp_dom_info *v)
{
if (!v->ancestor) return v;
dom_compress (v);
return v->label;
}
/* make V W's ancestor */
inline static void
dom_link (tmp_dom_info *v, tmp_dom_info *w)
{
w->ancestor = v;
}
/* Computes the dominator trees. Sets a flag in irg to "dom_consistent".
If the control flow of the graph is changed this flag must be set to
"dom_inconsistent". */
void compute_doms(ir_graph *irg) {
ir_graph *rem = current_ir_graph;
int n_blocks, used, i, j;
tmp_dom_info *tdi_list; /* Ein Golf? */
dom_env de;
current_ir_graph = irg;
/* Update graph state */
assert(get_irg_phase_state(current_ir_graph) != phase_building);
current_ir_graph->dom_state = dom_consistent;
/* Count the number of blocks in the graph. */
n_blocks = 0;
irg_block_walk(get_irg_end(current_ir_graph), count_and_init_blocks, NULL, &n_blocks);
//printf("n_blocks is %d\n", n_blocks);
/* Memory for temporary information. */
tdi_list = (tmp_dom_info *) calloc(n_blocks, sizeof(tmp_dom_info));
/* We need the out datastructure. */
if (current_ir_graph->outs_state != outs_consistent)
compute_outs(current_ir_graph);
/** Initialize the temporary information, add link to parent. We don't do
this with a standard walker as passing the parent to the sons isn't
simple. **/
used = 0;
inc_irg_block_visited(current_ir_graph);
init_tmp_dom_info(get_irg_start_block(current_ir_graph), NULL, tdi_list, &used);
/* If not all blocks are reachable from Start by out edges this assertion
fails. */
//assert(used == n_blocks && "Precondition for dom construction violated");
n_blocks = used;
//printf("used is %d\n", used);
for (i = n_blocks-1; i > 0; i--) { /* Don't iterate the root, it's done. */
tmp_dom_info *w = &tdi_list[i];
tmp_dom_info *v;
//printf(" cfgpreds: %d ", get_Block_n_cfgpreds(w->block)); DDMN(w->block);
/* Step 2 */
for (j = 0; j < get_irn_arity(w->block); j++) {
ir_node *pred = get_nodes_Block(get_Block_cfgpred(w->block, j));
tmp_dom_info *u;
if ((is_Bad(pred)) || (get_Block_pre_num (pred) == -1))
continue; /* control-dead */
u = dom_eval (&tdi_list[get_Block_pre_num(pred)]);
if (u->semi < w->semi) w->semi = u->semi;
}
/* Add w to w->semi's bucket. w is in exactly one bucket, so
buckets can ben implemented as linked lists. */
w->bucket = w->semi->bucket;
w->semi->bucket = w;
dom_link (w->parent, w);
/* Step 3 */
while (w->parent->bucket) {
tmp_dom_info *u;
v = w->parent->bucket;
/* remove v from w->parent->bucket */
w->parent->bucket = v->bucket;
v->bucket = NULL;
u = dom_eval (v);
if (u->semi < v->semi)
v->dom = u;
else
v->dom = w->parent;
}
}
/* Step 4 */
tdi_list[0].dom = NULL;
set_Block_idom(tdi_list[0].block, NULL);
set_Block_dom_depth(tdi_list[0].block, 1);
for (i = 1; i < n_blocks; i++) {
tmp_dom_info *w = &tdi_list[i];
if (w->dom != w->semi) w->dom = w->dom->dom;
set_Block_idom(w->block, w->dom->block);
set_Block_dom_depth(w->block, get_Block_dom_depth(w->dom->block) + 1);
}
/* clean up */
free(tdi_list);
current_ir_graph = rem;
}
void free_dom_and_peace(ir_graph *irg) {
/* Update graph state */
assert(get_irg_phase_state(current_ir_graph) != phase_building);
current_ir_graph->dom_state = no_dom;
/* @@@ free */
}
#if 0
/* Dominator Tree */
/* temporary type used while constructing the dominator tree. */
typedef struct tmp_dom_info tmp_dom_info;
struct tmp_dom_info {
ir_node *region;
tmp_dom_info *semi; /* semidominator */
tmp_dom_info *parent;
tmp_dom_info *label; /* used for LINK and EVAL */
tmp_dom_info *ancestor; /* used for LINK and EVAL */
tmp_dom_info *dom; /* After step 3, if the semidominator
of w is its immediate dominator, then w->dom is the immediate
dominator of w. Otherwise w->dom is a vertex v whose number is
smaller than w and whose immediate dominator is also w's immediate
dominator. After step 4, w->dom is the immediate dominator of w. */
tmp_dom_info *bucket; /* set of vertices with same semidominator */
};
static int
dom_count_regions (ir_node *n)
{
int i, count = 1;
n->visit = ir_visited;
for (i = IR_ARITY (n); i > 0; --i) {
ir_node *pr = prev_region (n, i);
if (pr && pr->visit != ir_visited) {
count += dom_count_regions (pr);
}
}
return count;
}
struct dt_desc { tmp_dom_info *dt; int used;};
static void
dom_setup (ir_node *n, tmp_dom_info *parent, struct dt_desc *dt_desc)
{
tmp_dom_info *dt = &dt_desc->dt[dt_desc->used];
int i;
if (n->visit == ir_visited) return;
n->visit = ir_visited;
assert (IR_CFG_NODE (n));
n->data.r.pre_num = dt_desc->used;
dt->semi = dt;
dt->label = dt;
dt->ancestor = NULL;
dt->bucket = NULL;
dt->parent = parent;
dt->region = n;
++(dt_desc->used);
for (i = 0; i < n->data.r.cfg_outs; ++i) {
dom_setup (n->data.r.cfg_out[i], dt, dt_desc);
}
}
static void
dom_compress (tmp_dom_info *v)
{
assert (v->ancestor);
if (v->ancestor->ancestor) {
dom_compress (v->ancestor);
if (v->ancestor->label->semi < v->label->semi) {
v->label = v->ancestor->label;
}
v->ancestor = v->ancestor->ancestor;
}
}
/* if V is a root, return v, else return the vertex u, not being the
root, with minimum u->semi on the path from v to its root. */
static tmp_dom_info*
dom_eval (tmp_dom_info *v)
{
if (!v->ancestor) return v;
dom_compress (v);
return v->label;
}
/* make V W's ancestor */
static void
dom_link (tmp_dom_info *v, tmp_dom_info *w)
{
w->ancestor = v;
}
void
irg_gen_idom (ir_graph *irg)
{
int regions, i;
tmp_dom_info *dt;
struct dt_desc dt_desc;
if (!(irg->state & irgs_has_CFG)) irg_gen_out (irg);
++ir_visited;
regions = 0;
/* walk all the artificially kept alive parts of the CFG instead of
the CFG beginning from the Start just for fun and safety */
keep_alives_in_arr (irg);
for (i = ARR_LEN (irg->keep.alive) - 1; i >= 0; --i)
if ( IR_CFG_NODE (irg->keep.alive[i])
&& irg->keep.alive[i]->visit != ir_visited)
regions += dom_count_regions (irg->keep.alive[i]);
dt = alloca ((regions+1) * sizeof (tmp_dom_info));
memset (dt, 0, (regions+1) * sizeof (tmp_dom_info));
/* Step 1 */
dt_desc.dt = dt;
dt_desc.used = 1;
++ir_visited;
dom_setup (irg->start, NULL, &dt_desc);
/* This assert will fail, if not all Regions are reachable by
walking the CFG starting from Start, that is when there is
[control] dead code, violating the single entry precondition of
this algorithm. */
assert (dt_desc.used == regions + 1);
for (i = regions; i > 1; --i) {
tmp_dom_info *w = &dt[i];
tmp_dom_info *v;
int j, r_ins;
/* Step 2 */
r_ins = IR_ARITY (w->region);
for (j = 1; j <= r_ins; ++j) {
ir_node *prev = prev_region (w->region, j);
tmp_dom_info *u;
if (!prev) continue; /* control-dead */
u = dom_eval (&dt[prev->data.r.pre_num]);
if (u->semi < w->semi) w->semi = u->semi;
}
/* Add w to w->semi's bucket. w is in exactly one bucket, so
buckets can ben implemented as linked lists. */
w->bucket = w->semi->bucket;
w->semi->bucket = w;
dom_link (w->parent, w);
/* Step 3 */
while ((v = w->parent->bucket)) {
tmp_dom_info *u;
/* remove v from w->parent->bucket */
w->parent->bucket = v->bucket;
v->bucket = NULL;
u = dom_eval (v);
v->dom = u->semi < v->semi ? u : w->parent;
}
}
/* Step 4 */
dt[1].dom = NULL;
dt[1].region->data.r.idom = NULL;
dt[1].region->data.r.dom_depth = 1;
for (i = 2; i <= regions; ++i) {
tmp_dom_info *w = &dt[i];
if (w->dom != w->semi) w->dom = w->dom->dom;
w->region->data.r.idom = w->dom->region;
w->region->data.r.dom_depth = w->dom->region->data.r.dom_depth + 1;
}
current_ir_graph = sirg;
}
#endif
/* Copyright (C) 2002 by Universitaet Karlsruhe
** All rights reserved.
**
** Authors: Goetz Lindenmaier
**
** irdom.h: This file contains routines to construct and access dominator
** information.
** The dominator information is stored in three fields of block nodes:
** idom: a reference to the block that is the immediate dominator of
** this block.
** dom_depth: a number giving the depth of the block in the dominator
** tree.
** pre_num: Number in preorder traversal.
*/
/* $Id$ */
# ifndef _IRDOM_H_
# define _IRDOM_H_
# include "irgraph.h"
# include "irnode.h"
/**********************************************************************/
/** Accessing the dopminator datastructure. **/
/** These routines only work properly if the ir_graph is in state **/
/** outs_consistent or outs_inconsistent. **/
/**********************************************************************/
ir_node *get_Block_idom(ir_node *bl);
void set_Block_idom(ir_node *bl, ir_node *n);
int get_Block_dom_depth(ir_node *bl);
void set_Block_dom_depth(ir_node *bl, int depth);
int get_Block_pre_num(ir_node *bl);
void set_Block_pre_num(ir_node *bl, int num);
/**********************************************************************/
/* Building and Removing the dominator datasturcture **/
/**********************************************************************/
/* Computes the dominator trees. Sets a flag in irg to "dom_consistent".
If the control flow of the graph is changed this flag must be set to
"dom_inconsistent".
Does not compute dominator information for control dead code. Blocks
not reachable from Start contain the following information:
idom = NULL;
dom_depth = -1;
pre_num = -1; */
void compute_doms(ir_graph *irg);
/* Frees the dominator datastructures. Sets the flag in irg to "no_dom". */
void free_dom_and_peace(ir_graph *irg);
#endif /* _IRDOM_H_ */
/* Copyright (C) 2002 by Universitaet Karlsruhe
** All rights reserved.
**
** Authors: Goetz Lindenmaier
**
** irdom_t.h: private datastructures
*/
/* $Id$ */
# ifndef _IRDOM_T_H_
# define _IRDOM_T_H_
#include "irdom.h"
/* For dominator information */
typedef struct dom_info {
struct ir_node *idom; /* immediate CFG dominator */
int pre_num; /* pre-order graph-walk number */
int dom_depth; /* depth in dominator-tree */
} dom_info;
#endif /* _IRDOM_T_H_ */
......@@ -20,23 +20,48 @@
/**********************************************************************/
/* returns the number of successors of the node: */
inline int get_irn_n_outs (ir_node *node) {
inline int get_irn_n_outs (ir_node *node) {
return (int)(node->out[0]);
}
/* Access successor n */
inline ir_node *get_irn_out (ir_node *node, int pos) {
inline ir_node *get_irn_out (ir_node *node, int pos) {
assert(node);
assert(pos >= 0 && pos < get_irn_n_outs(node));
return node->out[pos+1];
}
inline void set_irn_out (ir_node *node, int pos, ir_node *out) {
inline void set_irn_out (ir_node *node, int pos, ir_node *out) {
assert(node && out);
assert(pos >= 0 && pos < get_irn_n_outs(node));
node->out[pos+1] = out;
}
inline int get_Block_n_cfg_outs (ir_node *bl) {
int i, n_cfg_outs = 0;
assert(bl && (get_irn_op(bl) == op_Block));
for (i = 0; i < (int)bl->out[0]; i++)
if ((get_irn_mode(bl->out[i+1]) == mode_X) &&
(get_irn_op(bl->out[i+1]) != op_End)) n_cfg_outs++;
return n_cfg_outs;
}
inline ir_node *get_Block_cfg_out (ir_node *bl, int pos) {
int i, out_pos = 0;
assert(bl && (get_irn_op(bl) == op_Block));
for (i = 0; i < (int)bl->out[0]; i++)
if (get_irn_mode(bl->out[i+1]) == mode_X)
if (out_pos == pos) {
ir_node *cfop = bl->out[i+1];
return cfop->out[0+1];
} else {
out_pos++;
}
return NULL;
}
void irg_out_walk_2(ir_node *node, void (pre)(ir_node*, void*),
void (post)(ir_node*, void*), void *env) {
int i;
......@@ -74,11 +99,50 @@ void irg_out_walk(ir_node *node,
return;
}
void irg_out_block_walk2(ir_node *bl,
void (pre)(ir_node*, void*), void (post)(ir_node*, void*),
void *env) {
int i, out_pos;
assert(get_irn_opcode(bl) == iro_Block);
if(get_Block_block_visited(bl) < get_irg_block_visited(current_ir_graph)) {
set_Block_block_visited(bl, get_irg_block_visited(current_ir_graph));
if(pre)
pre(bl, env);
for(i = 0; i < get_Block_n_cfg_outs(bl); i++) {
/* find the corresponding predecessor block. */
ir_node *pred = get_Block_cfg_out(bl, i);
assert(get_irn_opcode(pred) == iro_Block);
/* recursion */
irg_out_block_walk2(pred, pre, post, env);
}
if(post)
post(bl, env);
}
return;
}
/* Walks only over Block nodes in the graph. Has it's own visited
flag, so that it can be interleaved with the other walker. */
void irg_out_block_walk(ir_node *node,
void (pre)(ir_node*, void*), void (post)(ir_node*, void*),
void *