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