dominate.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // SPDX-License-Identifier: MIT
  2. //
  3. // dominate.c - compute the (iterated) dominance frontier of (a set of) nodes.
  4. //
  5. // Copyright (C) 2017 - Luc Van Oostenryck
  6. //
  7. // The algorithm used is the one described in:
  8. // "A Linear Time Algorithm for Placing phi-nodes"
  9. // by Vugranam C. Sreedhar and Guang R. Gao
  10. //
  11. #include "dominate.h"
  12. #include "flowgraph.h"
  13. #include "linearize.h"
  14. #include "flow.h"
  15. #include <assert.h>
  16. #include <stdlib.h>
  17. #include <stdio.h>
  18. struct piggy {
  19. unsigned int max;
  20. struct basic_block_list *lists[0];
  21. };
  22. static struct piggy *bank_init(unsigned levels)
  23. {
  24. struct piggy *bank;
  25. bank = calloc(1, sizeof(*bank) + levels * sizeof(bank->lists[0]));
  26. bank->max = levels - 1;
  27. return bank;
  28. }
  29. static void bank_free(struct piggy *bank, unsigned int levels)
  30. {
  31. for (; levels-- ;)
  32. free_ptr_list(&bank->lists[levels]);
  33. free(bank);
  34. }
  35. static void bank_put(struct piggy *bank, struct basic_block *bb)
  36. {
  37. unsigned int level = bb->dom_level;
  38. assert(level <= bank->max);
  39. add_bb(&bank->lists[level], bb);
  40. }
  41. static inline struct basic_block *pop_bb(struct basic_block_list **list)
  42. {
  43. return delete_ptr_list_last((struct ptr_list **)list);
  44. }
  45. static struct basic_block *bank_get(struct piggy *bank)
  46. {
  47. int level = bank->max;
  48. do {
  49. struct basic_block *bb = pop_bb(&bank->lists[level]);
  50. if (bb)
  51. return bb;
  52. if (!level)
  53. return NULL;
  54. bank->max = --level;
  55. } while (1);
  56. }
  57. #define VISITED 0x1
  58. #define INPHI 0x2
  59. #define ALPHA 0x4
  60. #define FLAGS 0x7
  61. static void visit(struct piggy *bank, struct basic_block_list **idf, struct basic_block *x, int curr_level)
  62. {
  63. struct basic_block *y;
  64. x->generation |= 1;
  65. FOR_EACH_PTR(x->children, y) {
  66. unsigned flags = y->generation & FLAGS;
  67. if (y->idom == x) // J-edges will be processed later
  68. continue;
  69. if (y->dom_level > curr_level)
  70. continue;
  71. if (flags & INPHI)
  72. continue;
  73. y->generation |= INPHI;
  74. add_bb(idf, y);
  75. if (flags & ALPHA)
  76. continue;
  77. bank_put(bank, y);
  78. } END_FOR_EACH_PTR(y);
  79. FOR_EACH_PTR(x->doms, y) {
  80. if (y->generation & VISITED)
  81. continue;
  82. visit(bank, idf, y, curr_level);
  83. } END_FOR_EACH_PTR(y);
  84. }
  85. void idf_compute(struct entrypoint *ep, struct basic_block_list **idf, struct basic_block_list *alpha)
  86. {
  87. int levels = ep->dom_levels;
  88. struct piggy *bank = bank_init(levels);
  89. struct basic_block *bb;
  90. unsigned long generation = bb_generation;
  91. generation = bb_generation;
  92. generation += -generation & FLAGS;
  93. bb_generation = generation + (FLAGS + 1);
  94. // init all the nodes
  95. FOR_EACH_PTR(ep->bbs, bb) {
  96. // FIXME: this should be removed and the tests for
  97. // visited/in_phi/alpha should use a sparse set
  98. bb->generation = generation;
  99. } END_FOR_EACH_PTR(bb);
  100. FOR_EACH_PTR(alpha, bb) {
  101. bb->generation = generation | ALPHA;
  102. bank_put(bank, bb);
  103. } END_FOR_EACH_PTR(bb);
  104. while ((bb = bank_get(bank))) {
  105. visit(bank, idf, bb, bb->dom_level);
  106. }
  107. bank_free(bank, levels);
  108. }
  109. void idf_dump(struct entrypoint *ep)
  110. {
  111. struct basic_block *bb;
  112. domtree_build(ep);
  113. printf("%s's IDF:\n", show_ident(ep->name->ident));
  114. FOR_EACH_PTR(ep->bbs, bb) {
  115. struct basic_block_list *alpha = NULL;
  116. struct basic_block_list *idf = NULL;
  117. struct basic_block *df;
  118. add_bb(&alpha, bb);
  119. idf_compute(ep, &idf, alpha);
  120. printf("\t%s\t<-", show_label(bb));
  121. FOR_EACH_PTR(idf, df) {
  122. printf(" %s", show_label(df));
  123. } END_FOR_EACH_PTR(df);
  124. printf("\n");
  125. free_ptr_list(&idf);
  126. free_ptr_list(&alpha);
  127. } END_FOR_EACH_PTR(bb);
  128. }