From 21034c0d65fa00bcd0eba94c416408f5f461a07b Mon Sep 17 00:00:00 2001 From: David Given Date: Wed, 5 Oct 2016 23:52:54 +0200 Subject: [PATCH] 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. --- mach/proto/mcg/basicblock.h | 2 +- mach/proto/mcg/dominance.c | 123 +++++++++++++++++++++++++++++ mach/proto/mcg/dominance.h | 13 +++ mach/proto/mcg/mcg.h | 1 + mach/proto/mcg/pass_ssa.c | 110 +------------------------- mach/proto/mcg/registerallocator.c | 31 ++++---- 6 files changed, 154 insertions(+), 126 deletions(-) create mode 100644 mach/proto/mcg/dominance.c create mode 100644 mach/proto/mcg/dominance.h diff --git a/mach/proto/mcg/basicblock.h b/mach/proto/mcg/basicblock.h index 7935c9ede..75aa38e84 100644 --- a/mach/proto/mcg/basicblock.h +++ b/mach/proto/mcg/basicblock.h @@ -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; diff --git a/mach/proto/mcg/dominance.c b/mach/proto/mcg/dominance.c new file mode 100644 index 000000000..9843f376c --- /dev/null +++ b/mach/proto/mcg/dominance.c @@ -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; inexts.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; iname); + } +} + +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; jprevs.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 %s\n", + ((struct basicblock*)dominators.item[i].left)->name, + ((struct basicblock*)dominators.item[i].right)->name); + } +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/dominance.h b/mach/proto/mcg/dominance.h new file mode 100644 index 000000000..ee5d39b68 --- /dev/null +++ b/mach/proto/mcg/dominance.h @@ -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 : */ + diff --git a/mach/proto/mcg/mcg.h b/mach/proto/mcg/mcg.h index 601249f07..1fdb7d96c 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -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]; diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 265ade1f5..2a030b132 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -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; inexts.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; iname); - } -} - -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; jprevs.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 %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; ilocals.count; i++) diff --git a/mach/proto/mcg/registerallocator.c b/mach/proto/mcg/registerallocator.c index eae72fac6..664245826 100644 --- a/mach/proto/mcg/registerallocator.c +++ b/mach/proto/mcg/registerallocator.c @@ -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; inexts.count; i++) - recursively_walk_blocks(bb->nexts.item[i]); -} - -static void order_blocks(struct procedure* proc) -{ - /* 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). */ + /* Skip the entry block (which is its own dominator). */ - blocks.count = 0; - recursively_walk_blocks(proc->blocks.item[0]); - assert(blocks.count == proc->blocks.count); + for (i=1; iblocks.item[0]); + assert(blocks.count == proc->blocks.count); } /* vim: set sw=4 ts=4 expandtab : */