1// SPDX-License-Identifier: MIT 2// 3// Various utilities for flowgraphs. 4// 5// Copyright (c) 2017 Luc Van Oostenryck. 6// 7 8#include "flowgraph.h" 9#include "linearize.h" 10#include "flow.h" // for bb_generation 11#include <assert.h> 12#include <stdio.h> 13#include <stdlib.h> 14 15 16struct cfg_info { 17 struct basic_block_list *list; 18 unsigned long gen; 19 unsigned int nr; 20}; 21 22 23static void label_postorder(struct basic_block *bb, struct cfg_info *info) 24{ 25 struct basic_block *child; 26 27 if (bb->generation == info->gen) 28 return; 29 30 bb->generation = info->gen; 31 FOR_EACH_PTR_REVERSE(bb->children, child) { 32 label_postorder(child, info); 33 } END_FOR_EACH_PTR_REVERSE(child); 34 35 bb->postorder_nr = info->nr++; 36 add_bb(&info->list, bb); 37} 38 39static void reverse_bbs(struct basic_block_list **dst, struct basic_block_list *src) 40{ 41 struct basic_block *bb; 42 FOR_EACH_PTR_REVERSE(src, bb) { 43 add_bb(dst, bb); 44 } END_FOR_EACH_PTR_REVERSE(bb); 45} 46 47static void debug_postorder(struct entrypoint *ep) 48{ 49 struct basic_block *bb; 50 51 printf("%s's reverse postorder:\n", show_ident(ep->name->ident)); 52 FOR_EACH_PTR(ep->bbs, bb) { 53 printf("\t.L%u: %u\n", bb->nr, bb->postorder_nr); 54 } END_FOR_EACH_PTR(bb); 55} 56 57// 58// cfg_postorder - Set the BB's reverse postorder links 59// 60// Do a postorder DFS walk and set the links 61// (which will do the reverse part). 62// 63int cfg_postorder(struct entrypoint *ep) 64{ 65 struct cfg_info info = { 66 .gen = ++bb_generation, 67 }; 68 69 label_postorder(ep->entry->bb, &info); 70 71 // OK, now info.list contains the node in postorder 72 // Reuse ep->bbs for the reverse postorder. 73 free_ptr_list(&ep->bbs); 74 ep->bbs = NULL; 75 reverse_bbs(&ep->bbs, info.list); 76 free_ptr_list(&info.list); 77 if (dbg_postorder) 78 debug_postorder(ep); 79 return info.nr; 80} 81 82// 83// Calculate the dominance tree following: 84// "A simple, fast dominance algorithm" 85// by K. D. Cooper, T. J. Harvey, and K. Kennedy. 86// cfr. http://www.cs.rice.edu/∼keith/EMBED/dom.pdf 87// 88static struct basic_block *intersect_dom(struct basic_block *doms[], 89 struct basic_block *b1, struct basic_block *b2) 90{ 91 int f1 = b1->postorder_nr, f2 = b2->postorder_nr; 92 while (f1 != f2) { 93 while (f1 < f2) { 94 b1 = doms[f1]; 95 f1 = b1->postorder_nr; 96 } 97 while (f2 < f1) { 98 b2 = doms[f2]; 99 f2 = b2->postorder_nr; 100 } 101 } 102 return b1; 103} 104 105static void debug_domtree(struct entrypoint *ep) 106{ 107 struct basic_block *bb = ep->entry->bb; 108 109 printf("%s's idoms:\n", show_ident(ep->name->ident)); 110 FOR_EACH_PTR(ep->bbs, bb) { 111 if (bb == ep->entry->bb) 112 continue; // entry node has no idom 113 printf("\t%s <- %s\n", show_label(bb), show_label(bb->idom)); 114 } END_FOR_EACH_PTR(bb); 115} 116 117void domtree_build(struct entrypoint *ep) 118{ 119 struct basic_block *entry = ep->entry->bb; 120 struct basic_block **doms; 121 struct basic_block *bb; 122 unsigned int size; 123 int max_level = 0; 124 int changed; 125 126 // First calculate the (reverse) postorder. 127 // This will give use us: 128 // - the links to do a reverse postorder traversal 129 // - the order number for each block 130 size = cfg_postorder(ep); 131 132 // initialize the dominators array 133 doms = calloc(size, sizeof(*doms)); 134 assert(entry->postorder_nr == size-1); 135 doms[size-1] = entry; 136 137 do { 138 struct basic_block *b; 139 140 changed = 0; 141 FOR_EACH_PTR(ep->bbs, b) { 142 struct basic_block *p; 143 int bnr = b->postorder_nr; 144 struct basic_block *new_idom = NULL; 145 146 if (b == entry) 147 continue; // ignore entry node 148 149 FOR_EACH_PTR(b->parents, p) { 150 unsigned int pnr = p->postorder_nr; 151 if (!doms[pnr]) 152 continue; 153 if (!new_idom) { 154 new_idom = p; 155 continue; 156 } 157 158 new_idom = intersect_dom(doms, p, new_idom); 159 } END_FOR_EACH_PTR(p); 160 161 assert(new_idom); 162 if (doms[bnr] != new_idom) { 163 doms[bnr] = new_idom; 164 changed = 1; 165 } 166 } END_FOR_EACH_PTR(b); 167 } while (changed); 168 169 FOR_EACH_PTR(ep->bbs, bb) { 170 free_ptr_list(&bb->doms); 171 } END_FOR_EACH_PTR(bb); 172 173 // set the idom links 174 FOR_EACH_PTR(ep->bbs, bb) { 175 struct basic_block *idom = doms[bb->postorder_nr]; 176 177 if (bb == entry) 178 continue; // ignore entry node 179 180 bb->idom = idom; 181 add_bb(&idom->doms, bb); 182 } END_FOR_EACH_PTR(bb); 183 entry->idom = NULL; 184 185 // set the dominance levels 186 FOR_EACH_PTR(ep->bbs, bb) { 187 struct basic_block *idom = bb->idom; 188 int level = idom ? idom->dom_level + 1 : 0; 189 190 bb->dom_level = level; 191 if (max_level < level) 192 max_level = level; 193 } END_FOR_EACH_PTR(bb); 194 ep->dom_levels = max_level + 1; 195 196 free(doms); 197 if (dbg_domtree) 198 debug_domtree(ep); 199} 200 201// dt_dominates - does BB a dominates BB b? 202bool domtree_dominates(struct basic_block *a, struct basic_block *b) 203{ 204 if (a == b) // dominance is reflexive 205 return true; 206 if (a == b->idom) 207 return true; 208 if (b == a->idom) 209 return false; 210 211 // can't dominate if deeper in the DT 212 if (a->dom_level >= b->dom_level) 213 return false; 214 215 // FIXME: can be faster if we have the DFS in-out numbers 216 217 // walk up the dominator tree 218 for (b = b->idom; b; b = b->idom) { 219 if (b == a) 220 return true; 221 } 222 return false; 223} 224