ack/mach/proto/mcg/dominance.c
David Given 21034c0d65 No, dammit, for register allocation I need to walk the blocks in *dominance*
order. Since the dominance tree has changed when I fiddled with the graph, I
need to recompute it, so factor it out of the SSA pass. Code is uglier than I'd
like but at least the RET statement goes last in the generated code now.
2016-10-05 23:52:54 +02:00

123 lines
3 KiB
C

#include "mcg.h"
struct array postorder;
struct array preorder;
struct pmap dominators;
static void recursively_walk_blocks(struct basicblock* bb);
static void recursively_walk_graph(struct basicblock* bb)
{
static ARRAYOF(struct basicblock) pending;
int i;
if (array_contains(&postorder, bb) || array_contains(&pending, bb))
return;
array_appendu(&preorder, bb);
array_appendu(&pending, bb);
i = 0;
for (i=0; i<bb->nexts.count; i++)
recursively_walk_graph(bb->nexts.item[i]);
array_remove(&pending, bb);
bb->order = postorder.count;
array_appendu(&postorder, bb);
}
static void walk_graph_postorder(struct basicblock* entry)
{
int i;
preorder.count = 0;
postorder.count = 0;
recursively_walk_graph(entry);
for (i=0; i<postorder.count; i++)
{
tracef('D', "D: postorder: %s\n",
((struct basicblock*)postorder.item[i])->name);
}
}
static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2)
{
while (p1 != p2)
{
while (p1->order < p2->order)
p1 = pmap_get(&dominators, p1);
while (p2->order < p1->order)
p2 = pmap_get(&dominators, p2);
}
return p1;
}
void calculate_dominance_graph(struct procedure* proc)
{
/* This is the algorithm described here:
*
* Cooper, Keith D., Timothy J. Harvey, and Ken Kennedy.
* "A simple, fast dominance algorithm."
* Software Practice & Experience 4.1-10 (2001): 1-8.
*
* https://www.cs.rice.edu/~keith/EMBED/dom.pdf
*/
int i, j;
bool changed;
struct basicblock* entry = proc->blocks.item[0];
entry = proc->blocks.item[0];
walk_graph_postorder(entry);
assert(postorder.count == proc->blocks.count);
dominators.count = 0;
/* The entry block dominates itself. */
pmap_put(&dominators, entry, entry);
do
{
changed = false;
for (i = postorder.count-2; i >= 0; i--)
{
struct basicblock* b = postorder.item[i];
struct basicblock* new_idom = NULL;
for (j=0; j<b->prevs.count; j++)
{
struct basicblock* p = b->prevs.item[j];
/* Skip unprocessed blocks. */
if (!pmap_get(&dominators, p))
continue;
if (!new_idom)
new_idom = p;
else if (pmap_get(&dominators, p))
new_idom = intersect(p, new_idom);
}
if (pmap_get(&dominators, b) != new_idom)
{
pmap_put(&dominators, b, new_idom);
changed = true;
}
}
}
while (changed);
for (i=0; i<dominators.count; i++)
{
tracef('D', "D: domination: %s -> %s\n",
((struct basicblock*)dominators.item[i].left)->name,
((struct basicblock*)dominators.item[i].right)->name);
}
}
/* vim: set sw=4 ts=4 expandtab : */