From ee93389c5fa01c2105d7d518472e7506748f6974 Mon Sep 17 00:00:00 2001 From: David Given Date: Thu, 6 Oct 2016 21:34:21 +0200 Subject: [PATCH] Refactor the cfg and dominance stuff to make it a lot nicer. --- mach/proto/mcg/dominance.c | 123 -------------- mach/proto/mcg/dominance.h | 13 -- mach/proto/mcg/graph.c | 208 +++++++++++++++++++++++ mach/proto/mcg/graph.h | 26 +++ mach/proto/mcg/mcg.h | 2 +- mach/proto/mcg/pass_convertstackops.c | 1 - mach/proto/mcg/pass_registerallocator.c | 10 +- mach/proto/mcg/pass_splitcriticaledges.c | 8 +- mach/proto/mcg/pass_ssa.c | 19 +-- mach/proto/mcg/procedure.c | 52 +----- 10 files changed, 258 insertions(+), 204 deletions(-) delete mode 100644 mach/proto/mcg/dominance.c delete mode 100644 mach/proto/mcg/dominance.h create mode 100644 mach/proto/mcg/graph.c create mode 100644 mach/proto/mcg/graph.h diff --git a/mach/proto/mcg/dominance.c b/mach/proto/mcg/dominance.c deleted file mode 100644 index 9843f376c..000000000 --- a/mach/proto/mcg/dominance.c +++ /dev/null @@ -1,123 +0,0 @@ -#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 deleted file mode 100644 index ee5d39b68..000000000 --- a/mach/proto/mcg/dominance.h +++ /dev/null @@ -1,13 +0,0 @@ -#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/graph.c b/mach/proto/mcg/graph.c new file mode 100644 index 000000000..2897bc78a --- /dev/null +++ b/mach/proto/mcg/graph.c @@ -0,0 +1,208 @@ +#include "mcg.h" + +struct graph_data cfg; +struct dominance_data dominance; + +static ARRAYOF(struct basicblock) pending; + +static bool collect_outputs_cb(struct ir* ir, void* user) +{ + struct basicblock* caller = user; + + if (ir->opcode == IR_BLOCK) + { + array_appendu(&caller->nexts, ir->u.bvalue); + array_appendu(&ir->u.bvalue->prevs, caller); + } + return false; +} + +static void update_block_pointers_from_ir(struct procedure* proc) +{ + int i, j; + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + bb->prevs.count = bb->nexts.count = 0; + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + for (j=0; jirs.count; j++) + ir_walk(bb->irs.item[j], collect_outputs_cb, bb); + } + + for (i=0; iblocks.count; i++) + { + struct basicblock* bb = proc->blocks.item[i]; + + for (j=0; jnexts.count; j++) + { + tracef('D', "D: cfg graph %s -> %s\n", + bb->name, + bb->nexts.item[j]->name); + } + } +} + +static void recursively_walk_cfg_graph(struct basicblock* bb) +{ + int i; + + if (array_contains(&cfg.postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&cfg.preorder, bb); + array_appendu(&pending, bb); + + for (i=0; inexts.count; i++) + recursively_walk_cfg_graph(bb->nexts.item[i]); + + array_remove(&pending, bb); + bb->order = cfg.postorder.count; + array_appendu(&cfg.postorder, bb); +} + +static void walk_cfg_graph(void) +{ + int i; + + cfg.preorder.count = 0; + cfg.postorder.count = 0; + pending.count = 0; + recursively_walk_cfg_graph(cfg.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(&dominance.graph, p1); + + while (p2->order < p1->order) + p2 = pmap_get(&dominance.graph, 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; + + dominance.graph.count = 0; + + /* The entry block dominates itself. */ + + pmap_put(&dominance.graph, cfg.entry, cfg.entry); + + do + { + changed = false; + + for (i = cfg.postorder.count-2; i >= 0; i--) + { + struct basicblock* b = cfg.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(&dominance.graph, p)) + continue; + + if (!new_idom) + new_idom = p; + else if (pmap_get(&dominance.graph, p)) + new_idom = intersect(p, new_idom); + } + + if (pmap_get(&dominance.graph, b) != new_idom) + { + pmap_put(&dominance.graph, b, new_idom); + changed = true; + } + } + } + while (changed); + + for (i=0; i %s\n", + dominance.graph.item[i].right->name, + dominance.graph.item[i].left->name); + } +} + +static void recursively_walk_dominance_graph(struct basicblock* bb) +{ + int i; + + if (array_contains(&dominance.postorder, bb) || array_contains(&pending, bb)) + return; + + array_appendu(&dominance.preorder, bb); + array_appendu(&pending, bb); + + for (i=0; iname); + } +} + +void update_graph_data(struct procedure* proc) +{ + cfg.entry = proc->blocks.item[0]; + update_block_pointers_from_ir(proc); + + walk_cfg_graph(); + assert(cfg.postorder.count == proc->blocks.count); + assert(cfg.preorder.count == proc->blocks.count); + + calculate_dominance_graph(); + + walk_dominance_graph(); + assert(dominance.postorder.count == dominance.graph.count); + assert(dominance.preorder.count == dominance.graph.count); +} + +/* vim: set sw=4 ts=4 expandtab : */ + diff --git a/mach/proto/mcg/graph.h b/mach/proto/mcg/graph.h new file mode 100644 index 000000000..59c93137e --- /dev/null +++ b/mach/proto/mcg/graph.h @@ -0,0 +1,26 @@ +#ifndef GRAPH_H +#define GRAPH_H + +struct graph_data +{ + struct basicblock* entry; + ARRAYOF(struct basicblock) preorder; + ARRAYOF(struct basicblock) postorder; +}; + +struct dominance_data +{ + PMAPOF(struct basicblock, struct basicblock) graph; + ARRAYOF(struct basicblock) preorder; + ARRAYOF(struct basicblock) postorder; +}; + +extern struct graph_data cfg; +extern struct dominance_data dominance; + +extern void update_graph_data(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 5d631e224..bad088ee3 100644 --- a/mach/proto/mcg/mcg.h +++ b/mach/proto/mcg/mcg.h @@ -27,7 +27,7 @@ #include "reg.h" #include "basicblock.h" #include "procedure.h" -#include "dominance.h" +#include "graph.h" extern char em_pseu[][4]; extern char em_mnem[][4]; diff --git a/mach/proto/mcg/pass_convertstackops.c b/mach/proto/mcg/pass_convertstackops.c index d555b58ba..dbc1f8276 100644 --- a/mach/proto/mcg/pass_convertstackops.c +++ b/mach/proto/mcg/pass_convertstackops.c @@ -1,6 +1,5 @@ #include "mcg.h" -static PMAPOF(struct basicblock, struct basicblock) graph; static ARRAYOF(struct ir) pops; static ARRAYOF(struct ir) pushes; diff --git a/mach/proto/mcg/pass_registerallocator.c b/mach/proto/mcg/pass_registerallocator.c index 27e421418..23121bc42 100644 --- a/mach/proto/mcg/pass_registerallocator.c +++ b/mach/proto/mcg/pass_registerallocator.c @@ -11,10 +11,10 @@ static void recursively_walk_dominance_graph(struct basicblock* bb) /* Skip the entry block (which is its own dominator). */ - for (i=1; iblocks.item[0]); + recursively_walk_dominance_graph(cfg.entry); assert(blocks.count == proc->blocks.count); } diff --git a/mach/proto/mcg/pass_splitcriticaledges.c b/mach/proto/mcg/pass_splitcriticaledges.c index 9237be750..7962974cc 100644 --- a/mach/proto/mcg/pass_splitcriticaledges.c +++ b/mach/proto/mcg/pass_splitcriticaledges.c @@ -36,12 +36,14 @@ static void split_edge(struct basicblock* source, struct basicblock* sink) struct rewrite_params rwp; struct basicblock* bb = bb_get(NULL); - array_append(&bb->irs, + struct ir* jump = new_ir1( IR_JUMP, 0, new_bbir(sink) - ) - ); + ); + + jump->root = jump->left->root = jump; + array_append(&bb->irs, jump); rwp.find = sink; rwp.replace = bb; diff --git a/mach/proto/mcg/pass_ssa.c b/mach/proto/mcg/pass_ssa.c index 2a030b132..0f7fc2d37 100644 --- a/mach/proto/mcg/pass_ssa.c +++ b/mach/proto/mcg/pass_ssa.c @@ -1,6 +1,5 @@ #include "mcg.h" -static struct basicblock* entry; static PMAPOF(struct basicblock, struct basicblock) dominancefrontiers; static struct local* current_local; @@ -24,10 +23,10 @@ static void calculate_dominance_frontier_graph(void) dominancefrontiers.count = 0; - for (i=0; iprevs.count >= 2) { for (j=0; jprevs.count; j++) @@ -38,7 +37,7 @@ static void calculate_dominance_frontier_graph(void) tracef('S', "S: %s is in %s's dominance frontier\n", b->name, runner->name); pmap_add(&dominancefrontiers, runner, b); - runner = pmap_get(&dominators, runner); + runner = pmap_get(&dominance.graph, runner); } } } @@ -158,7 +157,7 @@ static void ssa_convert(void) ir->left->root = ir; ir->right->root = ir; ir->right->left->root = ir; - array_insert(&entry->irs, ir, 0); + array_insert(&cfg.entry->irs, ir, 0); } defining.count = 0; @@ -166,9 +165,9 @@ static void ssa_convert(void) /* Find everwhere where the variable is *defined*. */ - for (i=0; iirs.count; j++) { struct ir* ir = bb->irs.item[j]; @@ -210,15 +209,13 @@ static void ssa_convert(void) definitions.count = 0; rewritten.count = 0; - recursively_rewrite_tree(entry); + recursively_rewrite_tree(cfg.entry); } void pass_convert_locals_to_ssa(struct procedure* proc) { int i; - entry = proc->blocks.item[0]; - calculate_dominance_graph(proc); calculate_dominance_frontier_graph(); for (i=0; ilocals.count; i++) diff --git a/mach/proto/mcg/procedure.c b/mach/proto/mcg/procedure.c index 8685df54d..69aba0af8 100644 --- a/mach/proto/mcg/procedure.c +++ b/mach/proto/mcg/procedure.c @@ -48,66 +48,26 @@ void procedure_compile(struct procedure* proc) pass_eliminate_trivial_blocks(proc); pass_remove_dead_blocks(proc); - procedure_update_bb_graph(proc); + update_graph_data(proc); /* Passes from here on can't alter the BB graph without also updating prevs - * and nexts. */ + * and nexts (and then calling update_graph_data()). */ print_blocks('2', proc); pass_convert_stack_ops(proc); print_blocks('3', proc); pass_convert_locals_to_ssa(proc); print_blocks('4', proc); - pass_split_critical_edges(proc); - print_blocks('5', proc); pass_promote_float_ops(proc); + print_blocks('5', proc); + pass_split_critical_edges(proc); print_blocks('6', proc); + update_graph_data(proc); + pass_instruction_selector(proc); pass_register_allocator(proc); } -static bool collect_outputs_cb(struct ir* ir, void* user) -{ - struct basicblock* caller = user; - - if (ir->opcode == IR_BLOCK) - { - array_appendu(&caller->nexts, ir->u.bvalue); - array_appendu(&ir->u.bvalue->prevs, caller); - } - return false; -} - -void procedure_update_bb_graph(struct procedure* proc) -{ - int i, j; - - for (i=0; iblocks.count; i++) - { - struct basicblock* bb = proc->blocks.item[i]; - bb->prevs.count = bb->nexts.count = 0; - } - - for (i=0; iblocks.count; i++) - { - struct basicblock* bb = proc->blocks.item[i]; - for (j=0; jirs.count; j++) - ir_walk(bb->irs.item[j], collect_outputs_cb, bb); - } - - for (i=0; iblocks.count; i++) - { - struct basicblock* bb = proc->blocks.item[i]; - - for (j=0; jnexts.count; j++) - { - tracef('G', "G: graph %s -> %s\n", - bb->name, - bb->nexts.item[j]->name); - } - } -} - /* vim: set sw=4 ts=4 expandtab : */