1 // SPDX-License-Identifier: MIT
3 // dominate.c - compute the (iterated) dominance frontier of (a set of) nodes.
5 // Copyright (C) 2017 - Luc Van Oostenryck
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
13 #include "flowgraph.h"
14 #include "linearize.h"
23 struct basic_block_list
*lists
[0];
26 static struct piggy
*bank_init(unsigned levels
)
29 bank
= calloc(1, sizeof(*bank
) + levels
* sizeof(bank
->lists
[0]));
30 bank
->max
= levels
- 1;
34 static void bank_free(struct piggy
*bank
, unsigned int levels
)
37 free_ptr_list(&bank
->lists
[levels
]);
41 static void bank_put(struct piggy
*bank
, struct basic_block
*bb
)
43 unsigned int level
= bb
->dom_level
;
44 assert(level
<= bank
->max
);
45 add_bb(&bank
->lists
[level
], bb
);
48 static inline struct basic_block
*pop_bb(struct basic_block_list
**list
)
50 return delete_ptr_list_last((struct ptr_list
**)list
);
53 static struct basic_block
*bank_get(struct piggy
*bank
)
55 int level
= bank
->max
;
57 struct basic_block
*bb
= pop_bb(&bank
->lists
[level
]);
72 static void visit(struct piggy
*bank
, struct basic_block_list
**idf
, struct basic_block
*x
, int curr_level
)
74 struct basic_block
*y
;
77 FOR_EACH_PTR(x
->children
, y
) {
78 unsigned flags
= y
->generation
& FLAGS
;
79 if (y
->idom
== x
) // J-edges will be processed later
81 if (y
->dom_level
> curr_level
)
85 y
->generation
|= INPHI
;
90 } END_FOR_EACH_PTR(y
);
92 FOR_EACH_PTR(x
->doms
, y
) {
93 if (y
->generation
& VISITED
)
95 visit(bank
, idf
, y
, curr_level
);
96 } END_FOR_EACH_PTR(y
);
99 void idf_compute(struct entrypoint
*ep
, struct basic_block_list
**idf
, struct basic_block_list
*alpha
)
101 int levels
= ep
->dom_levels
;
102 struct piggy
*bank
= bank_init(levels
);
103 struct basic_block
*bb
;
104 unsigned long generation
= bb_generation
;
106 generation
= bb_generation
;
107 generation
+= -generation
& FLAGS
;
108 bb_generation
= generation
+ (FLAGS
+ 1);
110 // init all the nodes
111 FOR_EACH_PTR(ep
->bbs
, bb
) {
112 // FIXME: this should be removed and the tests for
113 // visited/in_phi/alpha should use a sparse set
114 bb
->generation
= generation
;
115 } END_FOR_EACH_PTR(bb
);
117 FOR_EACH_PTR(alpha
, bb
) {
118 bb
->generation
= generation
| ALPHA
;
120 } END_FOR_EACH_PTR(bb
);
122 while ((bb
= bank_get(bank
))) {
123 visit(bank
, idf
, bb
, bb
->dom_level
);
126 bank_free(bank
, levels
);
129 void idf_dump(struct entrypoint
*ep
)
131 struct basic_block
*bb
;
135 printf("%s's IDF:\n", show_ident(ep
->name
->ident
));
136 FOR_EACH_PTR(ep
->bbs
, bb
) {
137 struct basic_block_list
*alpha
= NULL
;
138 struct basic_block_list
*idf
= NULL
;
139 struct basic_block
*df
;
142 idf_compute(ep
, &idf
, alpha
);
144 printf("\t%s\t<-", show_label(bb
));
145 FOR_EACH_PTR(idf
, df
) {
146 printf(" %s", show_label(df
));
147 } END_FOR_EACH_PTR(df
);
151 free_ptr_list(&alpha
);
152 } END_FOR_EACH_PTR(bb
);