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