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.
This commit is contained in:
parent
d95c75dfd7
commit
21034c0d65
|
@ -10,7 +10,7 @@ struct basicblock
|
|||
|
||||
ARRAYOF(struct basicblock) prevs;
|
||||
ARRAYOF(struct basicblock) nexts;
|
||||
int order; /* used by SSA code */
|
||||
int order; /* used by dominance graph code */
|
||||
|
||||
ARRAYOF(struct vreg) liveins;
|
||||
|
||||
|
|
123
mach/proto/mcg/dominance.c
Normal file
123
mach/proto/mcg/dominance.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
#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 : */
|
||||
|
13
mach/proto/mcg/dominance.h
Normal file
13
mach/proto/mcg/dominance.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef DOMINANCE_H
|
||||
#define DOMINANCE_H
|
||||
|
||||
extern struct array postorder;
|
||||
extern struct array preorder;
|
||||
extern struct pmap dominators;
|
||||
|
||||
extern void calculate_dominance_graph(struct procedure* proc);
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include "reg.h"
|
||||
#include "basicblock.h"
|
||||
#include "procedure.h"
|
||||
#include "dominance.h"
|
||||
|
||||
extern char em_pseu[][4];
|
||||
extern char em_mnem[][4];
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#include "mcg.h"
|
||||
|
||||
static struct basicblock* entry;
|
||||
static ARRAYOF(struct basicblock) postorder;
|
||||
static PMAPOF(struct basicblock, struct basicblock) dominators;
|
||||
static PMAPOF(struct basicblock, struct basicblock) dominancefrontiers;
|
||||
|
||||
static struct local* current_local;
|
||||
|
@ -11,110 +9,6 @@ static ARRAYOF(struct basicblock) needsphis;
|
|||
static ARRAYOF(struct ir) definitions;
|
||||
static ARRAYOF(struct basicblock) rewritten;
|
||||
|
||||
static void recursively_walk_blocks(struct basicblock* bb);
|
||||
|
||||
static void recursively_walk_graph_postorder(struct basicblock* bb)
|
||||
{
|
||||
static ARRAYOF(struct basicblock) pending;
|
||||
int i;
|
||||
|
||||
if (array_contains(&postorder, bb) || array_contains(&pending, bb))
|
||||
return;
|
||||
|
||||
array_appendu(&pending, bb);
|
||||
|
||||
i = 0;
|
||||
for (i=0; i<bb->nexts.count; i++)
|
||||
recursively_walk_graph_postorder(bb->nexts.item[i]);
|
||||
|
||||
array_remove(&pending, bb);
|
||||
bb->order = postorder.count;
|
||||
array_appendu(&postorder, bb);
|
||||
}
|
||||
|
||||
static void walk_graph_postorder()
|
||||
{
|
||||
int i;
|
||||
|
||||
postorder.count = 0;
|
||||
recursively_walk_graph_postorder(entry);
|
||||
|
||||
for (i=0; i<postorder.count; i++)
|
||||
{
|
||||
tracef('S', "S: postorder: %s\n",
|
||||
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;
|
||||
}
|
||||
|
||||
static void calculate_dominance_graph(void)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
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];
|
||||
|
||||
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('S', "S: domination: %s -> %s\n",
|
||||
dominators.item[i].left->name,
|
||||
dominators.item[i].right->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void calculate_dominance_frontier_graph(void)
|
||||
{
|
||||
/* This is the algorithm described here:
|
||||
|
@ -324,9 +218,7 @@ void pass_convert_locals_to_ssa(struct procedure* proc)
|
|||
int i;
|
||||
|
||||
entry = proc->blocks.item[0];
|
||||
walk_graph_postorder();
|
||||
assert(postorder.count == proc->blocks.count);
|
||||
calculate_dominance_graph();
|
||||
calculate_dominance_graph(proc);
|
||||
calculate_dominance_frontier_graph();
|
||||
|
||||
for (i=0; i<proc->locals.count; i++)
|
||||
|
|
|
@ -2,32 +2,31 @@
|
|||
|
||||
static ARRAYOF(struct basicblock) blocks;
|
||||
|
||||
static void recursively_walk_blocks(struct basicblock* bb)
|
||||
static void recursively_walk_dominance_graph(struct basicblock* bb)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (array_appendu(&blocks, bb))
|
||||
return;
|
||||
array_append(&blocks, bb);
|
||||
tracef('R', "R: considering block %s\n", bb->name);
|
||||
|
||||
for (i=0; i<bb->nexts.count; i++)
|
||||
recursively_walk_blocks(bb->nexts.item[i]);
|
||||
}
|
||||
/* Skip the entry block (which is its own dominator). */
|
||||
|
||||
static void order_blocks(struct procedure* proc)
|
||||
for (i=1; i<dominators.count; i++)
|
||||
{
|
||||
/* Put them into preorder; this ensures that when we do the allocation,
|
||||
* we do all of a block's predecessors before the block (except for
|
||||
* backward edges). */
|
||||
|
||||
blocks.count = 0;
|
||||
recursively_walk_blocks(proc->blocks.item[0]);
|
||||
assert(blocks.count == proc->blocks.count);
|
||||
struct basicblock* left = dominators.item[i].left;
|
||||
struct basicblock* right = dominators.item[i].right;
|
||||
if (right == bb)
|
||||
recursively_walk_dominance_graph(left);
|
||||
}
|
||||
}
|
||||
|
||||
void register_allocator(struct procedure* proc)
|
||||
{
|
||||
order_blocks(proc);
|
||||
calculate_dominance_graph(proc);
|
||||
|
||||
blocks.count = 0;
|
||||
recursively_walk_dominance_graph(proc->blocks.item[0]);
|
||||
assert(blocks.count == proc->blocks.count);
|
||||
}
|
||||
|
||||
/* vim: set sw=4 ts=4 expandtab : */
|
||||
|
|
Loading…
Reference in a new issue