PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/mono/mini/dominators.c

https://github.com/hollow87/mono
C | 471 lines | 341 code | 89 blank | 41 comment | 99 complexity | 509b1d21f6de32ea7e7ceecfc2685e68 MD5 | raw file
  1. /*
  2. * dominators.c: Dominator computation on the control flow graph
  3. *
  4. * Author:
  5. * Dietmar Maurer (dietmar@ximian.com)
  6. * Paolo Molaro (lupus@ximian.com)
  7. *
  8. * (C) 2003 Ximian, Inc.
  9. * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
  10. */
  11. #include <string.h>
  12. #include <mono/metadata/debug-helpers.h>
  13. #include <mono/metadata/mempool.h>
  14. #include <mono/metadata/mempool-internals.h>
  15. #include "mini.h"
  16. #ifndef DISABLE_JIT
  17. //#define DEBUG_DOMINATORS
  18. /*
  19. * bb->dfn == 0 means either the bblock is ignored by the dfn calculation, or
  20. * it is the entry bblock.
  21. */
  22. #define HAS_DFN(bb, entry) ((bb)->dfn || ((bb) == entry))
  23. /*
  24. * Compute dominators and immediate dominators using the algorithm in the
  25. * paper "A Simple, Fast Dominance Algorithm" by Keith D. Cooper,
  26. * Timothy J. Harvey, and Ken Kennedy:
  27. * http://citeseer.ist.psu.edu/cooper01simple.html
  28. */
  29. static void
  30. compute_dominators (MonoCompile *cfg)
  31. {
  32. int bindex, i, bitsize;
  33. MonoBasicBlock *entry;
  34. MonoBasicBlock **doms;
  35. gboolean changed;
  36. g_assert (!(cfg->comp_done & MONO_COMP_DOM));
  37. bitsize = mono_bitset_alloc_size (cfg->num_bblocks, 0);
  38. entry = cfg->bblocks [0];
  39. doms = g_new0 (MonoBasicBlock*, cfg->num_bblocks);
  40. doms [entry->dfn] = entry;
  41. #ifdef DEBUG_DOMINATORS
  42. for (i = 0; i < cfg->num_bblocks; ++i) {
  43. MonoBasicBlock *bb = cfg->bblocks [i];
  44. printf ("BB%d IN: ", bb->block_num);
  45. for (j = 0; j < bb->in_count; ++j)
  46. printf ("%d ", bb->in_bb [j]->block_num);
  47. printf ("\n");
  48. }
  49. #endif
  50. changed = TRUE;
  51. while (changed) {
  52. changed = FALSE;
  53. for (bindex = 0; bindex < cfg->num_bblocks; ++bindex) {
  54. MonoBasicBlock *bb = cfg->bblocks [bindex];
  55. MonoBasicBlock *idom;
  56. idom = NULL;
  57. for (i = 0; i < bb->in_count; ++i) {
  58. MonoBasicBlock *in_bb = bb->in_bb [i];
  59. if ((in_bb != bb) && doms [in_bb->dfn]) {
  60. idom = in_bb;
  61. break;
  62. }
  63. }
  64. if (bb != cfg->bblocks [0])
  65. g_assert (idom);
  66. while (i < bb->in_count) {
  67. MonoBasicBlock *in_bb = bb->in_bb [i];
  68. if (HAS_DFN (in_bb, entry) && doms [in_bb->dfn]) {
  69. /* Intersect */
  70. MonoBasicBlock *f1 = idom;
  71. MonoBasicBlock *f2 = in_bb;
  72. while (f1 != f2) {
  73. if (f1->dfn < f2->dfn)
  74. f2 = doms [f2->dfn];
  75. else
  76. f1 = doms [f1->dfn];
  77. }
  78. idom = f1;
  79. }
  80. i ++;
  81. }
  82. if (idom != doms [bb->dfn]) {
  83. if (bb == cfg->bblocks [0])
  84. doms [bb->dfn] = bb;
  85. else {
  86. doms [bb->dfn] = idom;
  87. changed = TRUE;
  88. }
  89. //printf ("A: bb=%d dfn=%d dom:%d\n", bb->block_num, bb->dfn, doms [bb->dfn]->block_num);
  90. }
  91. }
  92. }
  93. /* Compute bb->dominators for each bblock */
  94. for (i = 0; i < cfg->num_bblocks; ++i) {
  95. MonoBasicBlock *bb = cfg->bblocks [i];
  96. MonoBasicBlock *cbb;
  97. MonoBitSet *dominators;
  98. char *mem;
  99. mem = mono_mempool_alloc0 (cfg->mempool, bitsize);
  100. bb->dominators = dominators = mono_bitset_mem_new (mem, cfg->num_bblocks, 0);
  101. mem += bitsize;
  102. mono_bitset_set_fast (dominators, bb->dfn);
  103. if (bb->dfn) {
  104. for (cbb = doms [bb->dfn]; cbb->dfn; cbb = doms [cbb->dfn])
  105. mono_bitset_set_fast (dominators, cbb->dfn);
  106. bb->idom = doms [bb->dfn];
  107. if (bb->idom)
  108. bb->idom->dominated = g_slist_prepend_mempool (cfg->mempool, bb->idom->dominated, bb);
  109. }
  110. /* The entry bb */
  111. mono_bitset_set_fast (dominators, 0);
  112. }
  113. g_free (doms);
  114. cfg->comp_done |= MONO_COMP_DOM | MONO_COMP_IDOM;
  115. #ifdef DEBUG_DOMINATORS
  116. printf ("DTREE %s %d\n", mono_method_full_name (cfg->method, TRUE),
  117. cfg->header->num_clauses);
  118. for (i = 0; i < cfg->num_bblocks; ++i) {
  119. MonoBasicBlock *bb = cfg->bblocks [i];
  120. printf ("BB%d(dfn=%d) (IDOM=BB%d): ", bb->block_num, bb->dfn, bb->idom ? bb->idom->block_num : -1);
  121. mono_blockset_print (cfg, bb->dominators, NULL, -1);
  122. }
  123. #endif
  124. }
  125. #if 0
  126. static void
  127. check_dominance_frontier (MonoBasicBlock *x, MonoBasicBlock *t)
  128. {
  129. int i, j;
  130. t->flags |= BB_VISITED;
  131. if (mono_bitset_test_fast (t->dominators, x->dfn)) {
  132. for (i = 0; i < t->out_count; ++i) {
  133. if (!(t->flags & BB_VISITED)) {
  134. int found = FALSE;
  135. check_dominance_frontier (x, t->out_bb [i]);
  136. for (j = 0; j < t->out_bb [i]->in_count; j++) {
  137. if (t->out_bb [i]->in_bb [j] == t)
  138. found = TRUE;
  139. }
  140. g_assert (found);
  141. }
  142. }
  143. } else {
  144. if (!mono_bitset_test_fast (x->dfrontier, t->dfn)) {
  145. printf ("BB%d not in frontier of BB%d\n", t->block_num, x->block_num);
  146. g_assert_not_reached ();
  147. }
  148. }
  149. }
  150. #endif
  151. /**
  152. * Compute dominance frontiers using the algorithm from the same paper.
  153. */
  154. static void
  155. compute_dominance_frontier (MonoCompile *cfg)
  156. {
  157. char *mem;
  158. int i, j, bitsize;
  159. g_assert (!(cfg->comp_done & MONO_COMP_DFRONTIER));
  160. for (i = 0; i < cfg->num_bblocks; ++i)
  161. cfg->bblocks [i]->flags &= ~BB_VISITED;
  162. bitsize = mono_bitset_alloc_size (cfg->num_bblocks, 0);
  163. mem = mono_mempool_alloc0 (cfg->mempool, bitsize * cfg->num_bblocks);
  164. for (i = 0; i < cfg->num_bblocks; ++i) {
  165. MonoBasicBlock *bb = cfg->bblocks [i];
  166. bb->dfrontier = mono_bitset_mem_new (mem, cfg->num_bblocks, 0);
  167. mem += bitsize;
  168. }
  169. for (i = 0; i < cfg->num_bblocks; ++i) {
  170. MonoBasicBlock *bb = cfg->bblocks [i];
  171. if (bb->in_count > 1) {
  172. for (j = 0; j < bb->in_count; ++j) {
  173. MonoBasicBlock *p = bb->in_bb [j];
  174. if (p->dfn || (p == cfg->bblocks [0])) {
  175. while (p != bb->idom) {
  176. mono_bitset_set_fast (p->dfrontier, bb->dfn);
  177. p = p->idom;
  178. }
  179. }
  180. }
  181. }
  182. }
  183. #if 0
  184. for (i = 0; i < cfg->num_bblocks; ++i) {
  185. MonoBasicBlock *bb = cfg->bblocks [i];
  186. printf ("DFRONT %s BB%d: ", mono_method_full_name (cfg->method, TRUE), bb->block_num);
  187. mono_blockset_print (cfg, bb->dfrontier, NULL, -1);
  188. }
  189. #endif
  190. #if 0
  191. /* this is a check for the dominator frontier */
  192. for (i = 0; i < m->num_bblocks; ++i) {
  193. MonoBasicBlock *x = m->bblocks [i];
  194. mono_bitset_foreach_bit ((x->dfrontier), j, (m->num_bblocks)) {
  195. MonoBasicBlock *w = m->bblocks [j];
  196. int k;
  197. /* x must not strictly dominates w */
  198. if (mono_bitset_test_fast (w->dominators, x->dfn) && w != x)
  199. g_assert_not_reached ();
  200. for (k = 0; k < m->num_bblocks; ++k)
  201. m->bblocks [k]->flags &= ~BB_VISITED;
  202. check_dominance_frontier (x, x);
  203. }
  204. }
  205. #endif
  206. cfg->comp_done |= MONO_COMP_DFRONTIER;
  207. }
  208. static inline void
  209. df_set (MonoCompile *m, MonoBitSet* dest, MonoBitSet *set)
  210. {
  211. int i;
  212. mono_bitset_foreach_bit (set, i, m->num_bblocks) {
  213. mono_bitset_union_fast (dest, m->bblocks [i]->dfrontier);
  214. }
  215. }
  216. MonoBitSet*
  217. mono_compile_iterated_dfrontier (MonoCompile *m, MonoBitSet *set)
  218. {
  219. MonoBitSet *result;
  220. int bitsize, count1, count2;
  221. bitsize = mono_bitset_alloc_size (m->num_bblocks, 0);
  222. result = mono_bitset_mem_new (mono_mempool_alloc0 (m->mempool, bitsize), m->num_bblocks, 0);
  223. df_set (m, result, set);
  224. count2 = mono_bitset_count (result);
  225. do {
  226. count1 = count2;
  227. df_set (m, result, result);
  228. count2 = mono_bitset_count (result);
  229. } while (count2 > count1);
  230. return result;
  231. }
  232. void
  233. mono_compile_dominator_info (MonoCompile *cfg, int dom_flags)
  234. {
  235. if ((dom_flags & MONO_COMP_DOM) && !(cfg->comp_done & MONO_COMP_DOM))
  236. compute_dominators (cfg);
  237. if ((dom_flags & MONO_COMP_DFRONTIER) && !(cfg->comp_done & MONO_COMP_DFRONTIER))
  238. compute_dominance_frontier (cfg);
  239. }
  240. //#define DEBUG_NATURAL_LOOPS
  241. /*
  242. * code to detect loops and loop nesting level
  243. */
  244. void
  245. mono_compute_natural_loops (MonoCompile *cfg)
  246. {
  247. int i, j, k;
  248. MonoBitSet *in_loop_blocks;
  249. int *bb_indexes;
  250. g_assert (!(cfg->comp_done & MONO_COMP_LOOPS));
  251. in_loop_blocks = mono_bitset_new (cfg->num_bblocks + 1, 0);
  252. for (i = 0; i < cfg->num_bblocks; ++i) {
  253. MonoBasicBlock *n = cfg->bblocks [i];
  254. for (j = 0; j < n->out_count; j++) {
  255. MonoBasicBlock *h = n->out_bb [j];
  256. /* check for back-edge from n to h */
  257. if (n != h && mono_bitset_test_fast (n->dominators, h->dfn)) {
  258. GSList *todo;
  259. /* already in loop_blocks? */
  260. if (h->loop_blocks && g_list_find (h->loop_blocks, n)) {
  261. continue;
  262. }
  263. mono_bitset_clear_all (in_loop_blocks);
  264. if (h->loop_blocks) {
  265. GList *l;
  266. for (l = h->loop_blocks; l; l = l->next) {
  267. MonoBasicBlock *b = l->data;
  268. if (b->dfn)
  269. mono_bitset_set_fast (in_loop_blocks, b->dfn);
  270. }
  271. }
  272. todo = g_slist_prepend (NULL, n);
  273. while (todo) {
  274. MonoBasicBlock *cb = (MonoBasicBlock *)todo->data;
  275. todo = g_slist_delete_link (todo, todo);
  276. if ((cb->dfn && mono_bitset_test_fast (in_loop_blocks, cb->dfn)) || (!cb->dfn && g_list_find (h->loop_blocks, cb)))
  277. continue;
  278. h->loop_blocks = g_list_prepend_mempool (cfg->mempool, h->loop_blocks, cb);
  279. cb->nesting++;
  280. if (cb->dfn)
  281. mono_bitset_set_fast (in_loop_blocks, cb->dfn);
  282. for (k = 0; k < cb->in_count; k++) {
  283. MonoBasicBlock *prev = cb->in_bb [k];
  284. /* add all previous blocks */
  285. if (prev != h && !((prev->dfn && mono_bitset_test_fast (in_loop_blocks, prev->dfn)) || (!prev->dfn && g_list_find (h->loop_blocks, prev)))) {
  286. todo = g_slist_prepend (todo, prev);
  287. }
  288. }
  289. }
  290. /* add the header if not already there */
  291. if (!((h->dfn && mono_bitset_test_fast (in_loop_blocks, h->dfn)) || (!h->dfn && g_list_find (h->loop_blocks, h)))) {
  292. h->loop_blocks = g_list_prepend_mempool (cfg->mempool, h->loop_blocks, h);
  293. h->nesting++;
  294. }
  295. }
  296. }
  297. }
  298. mono_bitset_free (in_loop_blocks);
  299. cfg->comp_done |= MONO_COMP_LOOPS;
  300. /* Compute loop_body_start for each loop */
  301. bb_indexes = g_new0 (int, cfg->num_bblocks);
  302. {
  303. MonoBasicBlock *bb;
  304. for (i = 0, bb = cfg->bb_entry; bb; i ++, bb = bb->next_bb) {
  305. if (bb->dfn)
  306. bb_indexes [bb->dfn] = i;
  307. }
  308. }
  309. for (i = 0; i < cfg->num_bblocks; ++i) {
  310. if (cfg->bblocks [i]->loop_blocks) {
  311. /* The loop body start is the first bblock in the order they will be emitted */
  312. MonoBasicBlock *h = cfg->bblocks [i];
  313. MonoBasicBlock *body_start = h;
  314. #if defined(__native_client_codegen__)
  315. MonoInst *inst;
  316. #endif
  317. GList *l;
  318. for (l = h->loop_blocks; l; l = l->next) {
  319. MonoBasicBlock *cb = (MonoBasicBlock *)l->data;
  320. if (cb->dfn && bb_indexes [cb->dfn] < bb_indexes [body_start->dfn]) {
  321. body_start = cb;
  322. }
  323. }
  324. #if defined(__native_client_codegen__)
  325. /* Instrument the loop (GC back branch safe point) */
  326. MONO_INST_NEW (cfg, inst, OP_NACL_GC_SAFE_POINT);
  327. inst->dreg = mono_alloc_dreg (cfg, STACK_I4);
  328. mono_bblock_insert_before_ins (body_start, NULL, inst);
  329. #endif
  330. body_start->loop_body_start = 1;
  331. }
  332. }
  333. g_free (bb_indexes);
  334. #ifdef DEBUG_NATURAL_LOOPS
  335. for (i = 0; i < cfg->num_bblocks; ++i) {
  336. if (cfg->bblocks [i]->loop_blocks) {
  337. MonoBasicBlock *h = (MonoBasicBlock *)cfg->bblocks [i]->loop_blocks->data;
  338. GList *l;
  339. printf ("LOOP START %d\n", h->block_num);
  340. for (l = h->loop_blocks; l; l = l->next) {
  341. MonoBasicBlock *cb = (MonoBasicBlock *)l->data;
  342. printf (" BB%d %d %p\n", cb->block_num, cb->nesting, cb->loop_blocks);
  343. }
  344. }
  345. }
  346. #endif
  347. }
  348. static void
  349. clear_idominators (MonoCompile *cfg)
  350. {
  351. guint i;
  352. for (i = 0; i < cfg->num_bblocks; ++i) {
  353. if (cfg->bblocks[i]->dominated) {
  354. cfg->bblocks[i]->dominated = NULL;
  355. }
  356. }
  357. cfg->comp_done &= ~MONO_COMP_IDOM;
  358. }
  359. static void
  360. clear_loops (MonoCompile *cfg)
  361. {
  362. guint i;
  363. for (i = 0; i < cfg->num_bblocks; ++i) {
  364. cfg->bblocks[i]->nesting = 0;
  365. cfg->bblocks[i]->loop_blocks = NULL;
  366. }
  367. cfg->comp_done &= ~MONO_COMP_LOOPS;
  368. }
  369. void
  370. mono_free_loop_info (MonoCompile *cfg)
  371. {
  372. if (cfg->comp_done & MONO_COMP_IDOM)
  373. clear_idominators (cfg);
  374. if (cfg->comp_done & MONO_COMP_LOOPS)
  375. clear_loops (cfg);
  376. }
  377. #else /* DISABLE_JIT */
  378. void
  379. mono_free_loop_info (MonoCompile *cfg)
  380. {
  381. }
  382. #endif /* DISABLE_JIT */