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:
David Given 2016-10-05 23:52:54 +02:00
parent d95c75dfd7
commit 21034c0d65
6 changed files with 154 additions and 126 deletions

View file

@ -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
View 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 : */

View 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 : */

View file

@ -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];

View file

@ -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++)

View file

@ -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 : */