210 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#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);
 | 
						|
        pmap_add(&cfg.graph, caller, ir->u.bvalue);
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
static void update_block_pointers_from_ir(void)
 | 
						|
{
 | 
						|
    int i, j;
 | 
						|
 | 
						|
    for (i=0; i<current_proc->blocks.count; i++)
 | 
						|
    {
 | 
						|
        struct basicblock* bb = current_proc->blocks.item[i];
 | 
						|
        bb->prevs.count = bb->nexts.count = 0;
 | 
						|
    }
 | 
						|
 | 
						|
    for (i=0; i<current_proc->blocks.count; i++)
 | 
						|
    {
 | 
						|
        struct basicblock* bb = current_proc->blocks.item[i];
 | 
						|
        for (j=0; j<bb->irs.count; j++)
 | 
						|
            ir_walk(bb->irs.item[j], collect_outputs_cb, bb);
 | 
						|
    }
 | 
						|
 | 
						|
    for (i=0; i<current_proc->blocks.count; i++)
 | 
						|
    {
 | 
						|
        struct basicblock* bb = current_proc->blocks.item[i];
 | 
						|
 | 
						|
        for (j=0; j<bb->nexts.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; i<bb->nexts.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; i<cfg.preorder.count; i++)
 | 
						|
    {
 | 
						|
        tracef('G', "G: cfg preorder: %s\n",
 | 
						|
            cfg.preorder.item[i]->name);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static struct basicblock* intersect(struct basicblock* p1, struct basicblock* p2)
 | 
						|
{
 | 
						|
    while (p1 != p2)
 | 
						|
    {
 | 
						|
        while (p1->order < p2->order)
 | 
						|
            p1 = pmap_findleft(&dominance.graph, p1);
 | 
						|
 | 
						|
        while (p2->order < p1->order)
 | 
						|
            p2 = pmap_findleft(&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; j<b->prevs.count; j++)
 | 
						|
            {
 | 
						|
                struct basicblock* p = b->prevs.item[j];
 | 
						|
                
 | 
						|
                /* Skip unprocessed blocks. */
 | 
						|
                if (!pmap_findleft(&dominance.graph, p))
 | 
						|
                    continue;
 | 
						|
 | 
						|
                if (!new_idom)
 | 
						|
                    new_idom = p;
 | 
						|
                else if (pmap_findleft(&dominance.graph, p))
 | 
						|
                    new_idom = intersect(p, new_idom);
 | 
						|
            }
 | 
						|
 | 
						|
            if (pmap_findleft(&dominance.graph, b) != new_idom)
 | 
						|
            {
 | 
						|
                pmap_put(&dominance.graph, b, new_idom);
 | 
						|
                changed = true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    while (changed);
 | 
						|
 | 
						|
    for (i=0; i<dominance.graph.count; i++)
 | 
						|
    {
 | 
						|
        tracef('G', "G: dominance graph: %s -> %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; i<dominance.graph.count; i++)
 | 
						|
        if (dominance.graph.item[i].right == bb)
 | 
						|
            recursively_walk_dominance_graph(dominance.graph.item[i].left);
 | 
						|
 | 
						|
    array_remove(&pending, bb);
 | 
						|
    array_appendu(&dominance.postorder, bb);
 | 
						|
}
 | 
						|
 | 
						|
static void walk_dominance_graph(void)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    dominance.preorder.count = 0;
 | 
						|
    dominance.postorder.count = 0;
 | 
						|
    pending.count = 0;
 | 
						|
    recursively_walk_dominance_graph(cfg.entry);
 | 
						|
 | 
						|
    for (i=0; i<dominance.preorder.count; i++)
 | 
						|
    {
 | 
						|
        tracef('G', "G: dominance preorder: %s\n",
 | 
						|
            dominance.preorder.item[i]->name);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void update_graph_data(void)
 | 
						|
{
 | 
						|
    cfg.entry = current_proc->blocks.item[0];
 | 
						|
    cfg.graph.count = 0;
 | 
						|
    update_block_pointers_from_ir();
 | 
						|
 | 
						|
    walk_cfg_graph();
 | 
						|
    assert(cfg.postorder.count == current_proc->blocks.count);
 | 
						|
    assert(cfg.preorder.count == current_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 : */
 | 
						|
 |