1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2018 Valve Corporation
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #ifndef ACO_DOMINANCE_CPP
8*61046927SAndroid Build Coastguard Worker #define ACO_DOMINANCE_CPP
9*61046927SAndroid Build Coastguard Worker
10*61046927SAndroid Build Coastguard Worker #include "aco_ir.h"
11*61046927SAndroid Build Coastguard Worker
12*61046927SAndroid Build Coastguard Worker /*
13*61046927SAndroid Build Coastguard Worker * Implements the algorithms for computing the dominator tree from
14*61046927SAndroid Build Coastguard Worker * "A Simple, Fast Dominance Algorithm" by Cooper, Harvey, and Kennedy.
15*61046927SAndroid Build Coastguard Worker *
16*61046927SAndroid Build Coastguard Worker * Different from the paper, our CFG allows to compute the dominator tree
17*61046927SAndroid Build Coastguard Worker * in a single pass as it is guaranteed that the dominating predecessors
18*61046927SAndroid Build Coastguard Worker * are processed before the current block.
19*61046927SAndroid Build Coastguard Worker */
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker namespace aco {
22*61046927SAndroid Build Coastguard Worker
23*61046927SAndroid Build Coastguard Worker namespace {
24*61046927SAndroid Build Coastguard Worker
25*61046927SAndroid Build Coastguard Worker struct block_dom_info {
26*61046927SAndroid Build Coastguard Worker uint32_t logical_descendants = 0;
27*61046927SAndroid Build Coastguard Worker uint32_t linear_descendants = 0;
28*61046927SAndroid Build Coastguard Worker uint32_t logical_depth = 0;
29*61046927SAndroid Build Coastguard Worker uint32_t linear_depth = 0;
30*61046927SAndroid Build Coastguard Worker small_vec<uint32_t, 4> logical_children;
31*61046927SAndroid Build Coastguard Worker small_vec<uint32_t, 4> linear_children;
32*61046927SAndroid Build Coastguard Worker };
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker void
calc_indices(Program * program)35*61046927SAndroid Build Coastguard Worker calc_indices(Program* program)
36*61046927SAndroid Build Coastguard Worker {
37*61046927SAndroid Build Coastguard Worker std::vector<block_dom_info> info(program->blocks.size());
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker /* Create the linear and logical dominance trees. Calculating logical_descendants and
40*61046927SAndroid Build Coastguard Worker * linear_descendants requires no recursion because the immediate dominator of each block has a
41*61046927SAndroid Build Coastguard Worker * lower index. */
42*61046927SAndroid Build Coastguard Worker for (int i = program->blocks.size() - 1; i >= 0; i--) {
43*61046927SAndroid Build Coastguard Worker Block& block = program->blocks[i];
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker /* Add this as a child node of the parent. */
46*61046927SAndroid Build Coastguard Worker if (block.logical_idom != i && block.logical_idom != -1) {
47*61046927SAndroid Build Coastguard Worker assert(i > block.logical_idom);
48*61046927SAndroid Build Coastguard Worker info[block.logical_idom].logical_children.push_back(i);
49*61046927SAndroid Build Coastguard Worker /* Add this node's descendants and itself to the parent. */
50*61046927SAndroid Build Coastguard Worker info[block.logical_idom].logical_descendants += info[i].logical_descendants + 1;
51*61046927SAndroid Build Coastguard Worker }
52*61046927SAndroid Build Coastguard Worker if (block.linear_idom != i) {
53*61046927SAndroid Build Coastguard Worker assert(i > block.linear_idom);
54*61046927SAndroid Build Coastguard Worker info[block.linear_idom].linear_children.push_back(i);
55*61046927SAndroid Build Coastguard Worker info[block.linear_idom].linear_descendants += info[i].linear_descendants + 1;
56*61046927SAndroid Build Coastguard Worker }
57*61046927SAndroid Build Coastguard Worker }
58*61046927SAndroid Build Coastguard Worker
59*61046927SAndroid Build Coastguard Worker /* Fill in the indices that would be obtained in a preorder and postorder traversal of the
60*61046927SAndroid Build Coastguard Worker * dominance trees. */
61*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < program->blocks.size(); i++) {
62*61046927SAndroid Build Coastguard Worker Block& block = program->blocks[i];
63*61046927SAndroid Build Coastguard Worker /* Because of block_kind_resume, the root node's indices start at the block index to avoid
64*61046927SAndroid Build Coastguard Worker * reusing indices. */
65*61046927SAndroid Build Coastguard Worker if (block.logical_idom == (int)i)
66*61046927SAndroid Build Coastguard Worker block.logical_dom_pre_index = i;
67*61046927SAndroid Build Coastguard Worker if (block.linear_idom == (int)i)
68*61046927SAndroid Build Coastguard Worker block.linear_dom_pre_index = i;
69*61046927SAndroid Build Coastguard Worker
70*61046927SAndroid Build Coastguard Worker /* Visit each child and assign it's preorder indices and depth. */
71*61046927SAndroid Build Coastguard Worker unsigned start = block.logical_dom_pre_index + 1;
72*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < info[i].logical_children.size(); j++) {
73*61046927SAndroid Build Coastguard Worker unsigned child = info[i].logical_children[j];
74*61046927SAndroid Build Coastguard Worker info[child].logical_depth = info[i].logical_depth + 1;
75*61046927SAndroid Build Coastguard Worker program->blocks[child].logical_dom_pre_index = start;
76*61046927SAndroid Build Coastguard Worker start += info[child].logical_descendants + 1;
77*61046927SAndroid Build Coastguard Worker }
78*61046927SAndroid Build Coastguard Worker start = block.linear_dom_pre_index + 1;
79*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < info[i].linear_children.size(); j++) {
80*61046927SAndroid Build Coastguard Worker unsigned child = info[i].linear_children[j];
81*61046927SAndroid Build Coastguard Worker info[child].linear_depth = info[i].linear_depth + 1;
82*61046927SAndroid Build Coastguard Worker program->blocks[child].linear_dom_pre_index = start;
83*61046927SAndroid Build Coastguard Worker start += info[child].linear_descendants + 1;
84*61046927SAndroid Build Coastguard Worker }
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Worker /* The postorder traversal is the same as the preorder traversal, except that when this block
87*61046927SAndroid Build Coastguard Worker * is visited, we haven't visited it's ancestors and have already visited it's descendants.
88*61046927SAndroid Build Coastguard Worker * This means that the postorder_index is preorder_index-depth+descendants. */
89*61046927SAndroid Build Coastguard Worker block.logical_dom_post_index =
90*61046927SAndroid Build Coastguard Worker block.logical_dom_pre_index - info[i].logical_depth + info[i].logical_descendants;
91*61046927SAndroid Build Coastguard Worker block.linear_dom_post_index =
92*61046927SAndroid Build Coastguard Worker block.linear_dom_pre_index - info[i].linear_depth + info[i].linear_descendants;
93*61046927SAndroid Build Coastguard Worker }
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker
96*61046927SAndroid Build Coastguard Worker } /* end namespace */
97*61046927SAndroid Build Coastguard Worker
98*61046927SAndroid Build Coastguard Worker void
dominator_tree(Program * program)99*61046927SAndroid Build Coastguard Worker dominator_tree(Program* program)
100*61046927SAndroid Build Coastguard Worker {
101*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < program->blocks.size(); i++) {
102*61046927SAndroid Build Coastguard Worker Block& block = program->blocks[i];
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker /* If this block has no predecessor, it dominates itself by definition */
105*61046927SAndroid Build Coastguard Worker if (block.linear_preds.empty()) {
106*61046927SAndroid Build Coastguard Worker block.linear_idom = block.index;
107*61046927SAndroid Build Coastguard Worker block.logical_idom = block.index;
108*61046927SAndroid Build Coastguard Worker continue;
109*61046927SAndroid Build Coastguard Worker }
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker int new_logical_idom = -1;
112*61046927SAndroid Build Coastguard Worker int new_linear_idom = -1;
113*61046927SAndroid Build Coastguard Worker for (unsigned pred_idx : block.logical_preds) {
114*61046927SAndroid Build Coastguard Worker if ((int)program->blocks[pred_idx].logical_idom == -1)
115*61046927SAndroid Build Coastguard Worker continue;
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker if (new_logical_idom == -1) {
118*61046927SAndroid Build Coastguard Worker new_logical_idom = pred_idx;
119*61046927SAndroid Build Coastguard Worker continue;
120*61046927SAndroid Build Coastguard Worker }
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker while ((int)pred_idx != new_logical_idom) {
123*61046927SAndroid Build Coastguard Worker if ((int)pred_idx > new_logical_idom)
124*61046927SAndroid Build Coastguard Worker pred_idx = program->blocks[pred_idx].logical_idom;
125*61046927SAndroid Build Coastguard Worker if ((int)pred_idx < new_logical_idom)
126*61046927SAndroid Build Coastguard Worker new_logical_idom = program->blocks[new_logical_idom].logical_idom;
127*61046927SAndroid Build Coastguard Worker }
128*61046927SAndroid Build Coastguard Worker }
129*61046927SAndroid Build Coastguard Worker
130*61046927SAndroid Build Coastguard Worker for (unsigned pred_idx : block.linear_preds) {
131*61046927SAndroid Build Coastguard Worker if ((int)program->blocks[pred_idx].linear_idom == -1)
132*61046927SAndroid Build Coastguard Worker continue;
133*61046927SAndroid Build Coastguard Worker
134*61046927SAndroid Build Coastguard Worker if (new_linear_idom == -1) {
135*61046927SAndroid Build Coastguard Worker new_linear_idom = pred_idx;
136*61046927SAndroid Build Coastguard Worker continue;
137*61046927SAndroid Build Coastguard Worker }
138*61046927SAndroid Build Coastguard Worker
139*61046927SAndroid Build Coastguard Worker while ((int)pred_idx != new_linear_idom) {
140*61046927SAndroid Build Coastguard Worker if ((int)pred_idx > new_linear_idom)
141*61046927SAndroid Build Coastguard Worker pred_idx = program->blocks[pred_idx].linear_idom;
142*61046927SAndroid Build Coastguard Worker if ((int)pred_idx < new_linear_idom)
143*61046927SAndroid Build Coastguard Worker new_linear_idom = program->blocks[new_linear_idom].linear_idom;
144*61046927SAndroid Build Coastguard Worker }
145*61046927SAndroid Build Coastguard Worker }
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker block.logical_idom = new_logical_idom;
148*61046927SAndroid Build Coastguard Worker block.linear_idom = new_linear_idom;
149*61046927SAndroid Build Coastguard Worker }
150*61046927SAndroid Build Coastguard Worker
151*61046927SAndroid Build Coastguard Worker calc_indices(program);
152*61046927SAndroid Build Coastguard Worker }
153*61046927SAndroid Build Coastguard Worker
154*61046927SAndroid Build Coastguard Worker } // namespace aco
155*61046927SAndroid Build Coastguard Worker #endif
156