/mono/mini/dominators.c
C | 471 lines | 341 code | 89 blank | 41 comment | 99 complexity | 509b1d21f6de32ea7e7ceecfc2685e68 MD5 | raw file
- /*
- * dominators.c: Dominator computation on the control flow graph
- *
- * Author:
- * Dietmar Maurer (dietmar@ximian.com)
- * Paolo Molaro (lupus@ximian.com)
- *
- * (C) 2003 Ximian, Inc.
- * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
- */
- #include <string.h>
- #include <mono/metadata/debug-helpers.h>
- #include <mono/metadata/mempool.h>
- #include <mono/metadata/mempool-internals.h>
- #include "mini.h"
- #ifndef DISABLE_JIT
- //#define DEBUG_DOMINATORS
- /*
- * bb->dfn == 0 means either the bblock is ignored by the dfn calculation, or
- * it is the entry bblock.
- */
- #define HAS_DFN(bb, entry) ((bb)->dfn || ((bb) == entry))
- /*
- * Compute dominators and immediate dominators using the algorithm in the
- * paper "A Simple, Fast Dominance Algorithm" by Keith D. Cooper,
- * Timothy J. Harvey, and Ken Kennedy:
- * http://citeseer.ist.psu.edu/cooper01simple.html
- */
- static void
- compute_dominators (MonoCompile *cfg)
- {
- int bindex, i, bitsize;
- MonoBasicBlock *entry;
- MonoBasicBlock **doms;
- gboolean changed;
- g_assert (!(cfg->comp_done & MONO_COMP_DOM));
- bitsize = mono_bitset_alloc_size (cfg->num_bblocks, 0);
- entry = cfg->bblocks [0];
- doms = g_new0 (MonoBasicBlock*, cfg->num_bblocks);
- doms [entry->dfn] = entry;
- #ifdef DEBUG_DOMINATORS
- for (i = 0; i < cfg->num_bblocks; ++i) {
- MonoBasicBlock *bb = cfg->bblocks [i];
- printf ("BB%d IN: ", bb->block_num);
- for (j = 0; j < bb->in_count; ++j)
- printf ("%d ", bb->in_bb [j]->block_num);
- printf ("\n");
- }
- #endif
- changed = TRUE;
- while (changed) {
- changed = FALSE;
- for (bindex = 0; bindex < cfg->num_bblocks; ++bindex) {
- MonoBasicBlock *bb = cfg->bblocks [bindex];
- MonoBasicBlock *idom;
- idom = NULL;
- for (i = 0; i < bb->in_count; ++i) {
- MonoBasicBlock *in_bb = bb->in_bb [i];
- if ((in_bb != bb) && doms [in_bb->dfn]) {
- idom = in_bb;
- break;
- }
- }
- if (bb != cfg->bblocks [0])
- g_assert (idom);
- while (i < bb->in_count) {
- MonoBasicBlock *in_bb = bb->in_bb [i];
- if (HAS_DFN (in_bb, entry) && doms [in_bb->dfn]) {
- /* Intersect */
- MonoBasicBlock *f1 = idom;
- MonoBasicBlock *f2 = in_bb;
- while (f1 != f2) {
- if (f1->dfn < f2->dfn)
- f2 = doms [f2->dfn];
- else
- f1 = doms [f1->dfn];
- }
- idom = f1;
- }
- i ++;
- }
- if (idom != doms [bb->dfn]) {
- if (bb == cfg->bblocks [0])
- doms [bb->dfn] = bb;
- else {
- doms [bb->dfn] = idom;
- changed = TRUE;
- }
- //printf ("A: bb=%d dfn=%d dom:%d\n", bb->block_num, bb->dfn, doms [bb->dfn]->block_num);
- }
- }
- }
- /* Compute bb->dominators for each bblock */
- for (i = 0; i < cfg->num_bblocks; ++i) {
- MonoBasicBlock *bb = cfg->bblocks [i];
- MonoBasicBlock *cbb;
- MonoBitSet *dominators;
- char *mem;
- mem = mono_mempool_alloc0 (cfg->mempool, bitsize);
- bb->dominators = dominators = mono_bitset_mem_new (mem, cfg->num_bblocks, 0);
- mem += bitsize;
- mono_bitset_set_fast (dominators, bb->dfn);
- if (bb->dfn) {
- for (cbb = doms [bb->dfn]; cbb->dfn; cbb = doms [cbb->dfn])
- mono_bitset_set_fast (dominators, cbb->dfn);
- bb->idom = doms [bb->dfn];
- if (bb->idom)
- bb->idom->dominated = g_slist_prepend_mempool (cfg->mempool, bb->idom->dominated, bb);
- }
- /* The entry bb */
- mono_bitset_set_fast (dominators, 0);
- }
- g_free (doms);
- cfg->comp_done |= MONO_COMP_DOM | MONO_COMP_IDOM;
- #ifdef DEBUG_DOMINATORS
- printf ("DTREE %s %d\n", mono_method_full_name (cfg->method, TRUE),
- cfg->header->num_clauses);
- for (i = 0; i < cfg->num_bblocks; ++i) {
- MonoBasicBlock *bb = cfg->bblocks [i];
- printf ("BB%d(dfn=%d) (IDOM=BB%d): ", bb->block_num, bb->dfn, bb->idom ? bb->idom->block_num : -1);
- mono_blockset_print (cfg, bb->dominators, NULL, -1);
- }
- #endif
- }
- #if 0
- static void
- check_dominance_frontier (MonoBasicBlock *x, MonoBasicBlock *t)
- {
- int i, j;
- t->flags |= BB_VISITED;
- if (mono_bitset_test_fast (t->dominators, x->dfn)) {
- for (i = 0; i < t->out_count; ++i) {
- if (!(t->flags & BB_VISITED)) {
- int found = FALSE;
- check_dominance_frontier (x, t->out_bb [i]);
-
- for (j = 0; j < t->out_bb [i]->in_count; j++) {
- if (t->out_bb [i]->in_bb [j] == t)
- found = TRUE;
- }
- g_assert (found);
- }
- }
- } else {
- if (!mono_bitset_test_fast (x->dfrontier, t->dfn)) {
- printf ("BB%d not in frontier of BB%d\n", t->block_num, x->block_num);
- g_assert_not_reached ();
- }
- }
- }
- #endif
- /**
- * Compute dominance frontiers using the algorithm from the same paper.
- */
- static void
- compute_dominance_frontier (MonoCompile *cfg)
- {
- char *mem;
- int i, j, bitsize;
- g_assert (!(cfg->comp_done & MONO_COMP_DFRONTIER));
- for (i = 0; i < cfg->num_bblocks; ++i)
- cfg->bblocks [i]->flags &= ~BB_VISITED;
- bitsize = mono_bitset_alloc_size (cfg->num_bblocks, 0);
- mem = mono_mempool_alloc0 (cfg->mempool, bitsize * cfg->num_bblocks);
-
- for (i = 0; i < cfg->num_bblocks; ++i) {
- MonoBasicBlock *bb = cfg->bblocks [i];
- bb->dfrontier = mono_bitset_mem_new (mem, cfg->num_bblocks, 0);
- mem += bitsize;
- }
- for (i = 0; i < cfg->num_bblocks; ++i) {
- MonoBasicBlock *bb = cfg->bblocks [i];
- if (bb->in_count > 1) {
- for (j = 0; j < bb->in_count; ++j) {
- MonoBasicBlock *p = bb->in_bb [j];
- if (p->dfn || (p == cfg->bblocks [0])) {
- while (p != bb->idom) {
- mono_bitset_set_fast (p->dfrontier, bb->dfn);
- p = p->idom;
- }
- }
- }
- }
- }
- #if 0
- for (i = 0; i < cfg->num_bblocks; ++i) {
- MonoBasicBlock *bb = cfg->bblocks [i];
-
- printf ("DFRONT %s BB%d: ", mono_method_full_name (cfg->method, TRUE), bb->block_num);
- mono_blockset_print (cfg, bb->dfrontier, NULL, -1);
- }
- #endif
- #if 0
- /* this is a check for the dominator frontier */
- for (i = 0; i < m->num_bblocks; ++i) {
- MonoBasicBlock *x = m->bblocks [i];
-
- mono_bitset_foreach_bit ((x->dfrontier), j, (m->num_bblocks)) {
- MonoBasicBlock *w = m->bblocks [j];
- int k;
- /* x must not strictly dominates w */
- if (mono_bitset_test_fast (w->dominators, x->dfn) && w != x)
- g_assert_not_reached ();
-
- for (k = 0; k < m->num_bblocks; ++k)
- m->bblocks [k]->flags &= ~BB_VISITED;
- check_dominance_frontier (x, x);
- }
- }
- #endif
- cfg->comp_done |= MONO_COMP_DFRONTIER;
- }
- static inline void
- df_set (MonoCompile *m, MonoBitSet* dest, MonoBitSet *set)
- {
- int i;
- mono_bitset_foreach_bit (set, i, m->num_bblocks) {
- mono_bitset_union_fast (dest, m->bblocks [i]->dfrontier);
- }
- }
- MonoBitSet*
- mono_compile_iterated_dfrontier (MonoCompile *m, MonoBitSet *set)
- {
- MonoBitSet *result;
- int bitsize, count1, count2;
- bitsize = mono_bitset_alloc_size (m->num_bblocks, 0);
- result = mono_bitset_mem_new (mono_mempool_alloc0 (m->mempool, bitsize), m->num_bblocks, 0);
- df_set (m, result, set);
- count2 = mono_bitset_count (result);
- do {
- count1 = count2;
- df_set (m, result, result);
- count2 = mono_bitset_count (result);
- } while (count2 > count1);
-
- return result;
- }
- void
- mono_compile_dominator_info (MonoCompile *cfg, int dom_flags)
- {
- if ((dom_flags & MONO_COMP_DOM) && !(cfg->comp_done & MONO_COMP_DOM))
- compute_dominators (cfg);
- if ((dom_flags & MONO_COMP_DFRONTIER) && !(cfg->comp_done & MONO_COMP_DFRONTIER))
- compute_dominance_frontier (cfg);
- }
- //#define DEBUG_NATURAL_LOOPS
- /*
- * code to detect loops and loop nesting level
- */
- void
- mono_compute_natural_loops (MonoCompile *cfg)
- {
- int i, j, k;
- MonoBitSet *in_loop_blocks;
- int *bb_indexes;
- g_assert (!(cfg->comp_done & MONO_COMP_LOOPS));
- in_loop_blocks = mono_bitset_new (cfg->num_bblocks + 1, 0);
- for (i = 0; i < cfg->num_bblocks; ++i) {
- MonoBasicBlock *n = cfg->bblocks [i];
- for (j = 0; j < n->out_count; j++) {
- MonoBasicBlock *h = n->out_bb [j];
- /* check for back-edge from n to h */
- if (n != h && mono_bitset_test_fast (n->dominators, h->dfn)) {
- GSList *todo;
- /* already in loop_blocks? */
- if (h->loop_blocks && g_list_find (h->loop_blocks, n)) {
- continue;
- }
- mono_bitset_clear_all (in_loop_blocks);
- if (h->loop_blocks) {
- GList *l;
- for (l = h->loop_blocks; l; l = l->next) {
- MonoBasicBlock *b = l->data;
- if (b->dfn)
- mono_bitset_set_fast (in_loop_blocks, b->dfn);
- }
- }
- todo = g_slist_prepend (NULL, n);
-
- while (todo) {
- MonoBasicBlock *cb = (MonoBasicBlock *)todo->data;
- todo = g_slist_delete_link (todo, todo);
- if ((cb->dfn && mono_bitset_test_fast (in_loop_blocks, cb->dfn)) || (!cb->dfn && g_list_find (h->loop_blocks, cb)))
- continue;
- h->loop_blocks = g_list_prepend_mempool (cfg->mempool, h->loop_blocks, cb);
- cb->nesting++;
- if (cb->dfn)
- mono_bitset_set_fast (in_loop_blocks, cb->dfn);
- for (k = 0; k < cb->in_count; k++) {
- MonoBasicBlock *prev = cb->in_bb [k];
- /* add all previous blocks */
- if (prev != h && !((prev->dfn && mono_bitset_test_fast (in_loop_blocks, prev->dfn)) || (!prev->dfn && g_list_find (h->loop_blocks, prev)))) {
- todo = g_slist_prepend (todo, prev);
- }
- }
- }
- /* add the header if not already there */
- if (!((h->dfn && mono_bitset_test_fast (in_loop_blocks, h->dfn)) || (!h->dfn && g_list_find (h->loop_blocks, h)))) {
- h->loop_blocks = g_list_prepend_mempool (cfg->mempool, h->loop_blocks, h);
- h->nesting++;
- }
- }
- }
- }
- mono_bitset_free (in_loop_blocks);
- cfg->comp_done |= MONO_COMP_LOOPS;
- /* Compute loop_body_start for each loop */
- bb_indexes = g_new0 (int, cfg->num_bblocks);
- {
- MonoBasicBlock *bb;
- for (i = 0, bb = cfg->bb_entry; bb; i ++, bb = bb->next_bb) {
- if (bb->dfn)
- bb_indexes [bb->dfn] = i;
- }
- }
- for (i = 0; i < cfg->num_bblocks; ++i) {
- if (cfg->bblocks [i]->loop_blocks) {
- /* The loop body start is the first bblock in the order they will be emitted */
- MonoBasicBlock *h = cfg->bblocks [i];
- MonoBasicBlock *body_start = h;
- #if defined(__native_client_codegen__)
- MonoInst *inst;
- #endif
- GList *l;
- for (l = h->loop_blocks; l; l = l->next) {
- MonoBasicBlock *cb = (MonoBasicBlock *)l->data;
- if (cb->dfn && bb_indexes [cb->dfn] < bb_indexes [body_start->dfn]) {
- body_start = cb;
- }
- }
- #if defined(__native_client_codegen__)
- /* Instrument the loop (GC back branch safe point) */
- MONO_INST_NEW (cfg, inst, OP_NACL_GC_SAFE_POINT);
- inst->dreg = mono_alloc_dreg (cfg, STACK_I4);
- mono_bblock_insert_before_ins (body_start, NULL, inst);
- #endif
- body_start->loop_body_start = 1;
- }
- }
- g_free (bb_indexes);
- #ifdef DEBUG_NATURAL_LOOPS
- for (i = 0; i < cfg->num_bblocks; ++i) {
- if (cfg->bblocks [i]->loop_blocks) {
- MonoBasicBlock *h = (MonoBasicBlock *)cfg->bblocks [i]->loop_blocks->data;
- GList *l;
- printf ("LOOP START %d\n", h->block_num);
- for (l = h->loop_blocks; l; l = l->next) {
- MonoBasicBlock *cb = (MonoBasicBlock *)l->data;
- printf (" BB%d %d %p\n", cb->block_num, cb->nesting, cb->loop_blocks);
- }
- }
- }
- #endif
- }
- static void
- clear_idominators (MonoCompile *cfg)
- {
- guint i;
-
- for (i = 0; i < cfg->num_bblocks; ++i) {
- if (cfg->bblocks[i]->dominated) {
- cfg->bblocks[i]->dominated = NULL;
- }
- }
- cfg->comp_done &= ~MONO_COMP_IDOM;
- }
- static void
- clear_loops (MonoCompile *cfg)
- {
- guint i;
-
- for (i = 0; i < cfg->num_bblocks; ++i) {
- cfg->bblocks[i]->nesting = 0;
- cfg->bblocks[i]->loop_blocks = NULL;
- }
- cfg->comp_done &= ~MONO_COMP_LOOPS;
- }
- void
- mono_free_loop_info (MonoCompile *cfg)
- {
- if (cfg->comp_done & MONO_COMP_IDOM)
- clear_idominators (cfg);
- if (cfg->comp_done & MONO_COMP_LOOPS)
- clear_loops (cfg);
- }
- #else /* DISABLE_JIT */
- void
- mono_free_loop_info (MonoCompile *cfg)
- {
- }
- #endif /* DISABLE_JIT */