• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "optimizer/ir/basicblock.h"
17 #include "optimizer/ir/graph.h"
18 #include "dominators_tree.h"
19 
20 namespace panda::compiler {
DominatorsTree(Graph * graph)21 DominatorsTree::DominatorsTree(Graph *graph) : Analysis(graph) {}
22 
RunImpl()23 bool DominatorsTree::RunImpl()
24 {
25     for (auto block : GetGraph()->GetBlocksRPO()) {
26         block->ClearDominatedBlocks();
27         block->ClearDominator();
28     }
29 
30     Init(GetGraph()->GetVectorBlocks().size());
31     DfsNumbering(GetGraph()->GetStartBlock());
32     auto dfs_blocks = static_cast<size_t>(dfs_num_);
33     ASSERT_PRINT(dfs_blocks == (GetGraph()->GetBlocksRPO().size() - 1), "There is an unreachable block");
34 
35     for (size_t i = dfs_blocks; i > 0; i--) {
36         ComputeImmediateDominators(GetVertex(i));
37     }
38 
39     for (size_t i = 1; i <= dfs_blocks; i++) {
40         AdjustImmediateDominators(GetVertex(i));
41     }
42     return true;
43 }
44 
45 /*
46  * Adjust immediate dominators,
47  * Update dominator information for 'block'
48  */
AdjustImmediateDominators(BasicBlock * block)49 void DominatorsTree::AdjustImmediateDominators(BasicBlock *block)
50 {
51     ASSERT(block != nullptr);
52 
53     if (GetIdom(block) != GetVertex(GetSemi(block))) {
54         SetIdom(block, GetIdom(GetIdom(block)));
55     }
56     SetDomPair(GetIdom(block), block);
57 }
58 
59 /*
60  * Compute initial values for semidominators,
61  * store blocks with the same semidominator in the same bucket,
62  * compute immediate dominators for blocks in the bucket of 'block' parent
63  */
ComputeImmediateDominators(BasicBlock * block)64 void DominatorsTree::ComputeImmediateDominators(BasicBlock *block)
65 {
66     ASSERT(block != nullptr);
67 
68     for (auto pred : block->GetPredsBlocks()) {
69         auto eval = Eval(pred);
70         if (GetSemi(eval) < GetSemi(block)) {
71             SetSemi(block, GetSemi(eval));
72         }
73     }
74 
75     auto vertex = GetVertex(GetSemi(block));
76     GetBucket(vertex).push_back(block);
77     auto parent = GetParent(block);
78     Link(parent, block);
79 
80     auto &bucket = GetBucket(parent);
81     while (!bucket.empty()) {
82         auto v = *bucket.rbegin();
83         auto eval = Eval(v);
84         if (GetSemi(eval) < GetSemi(v)) {
85             SetIdom(v, eval);
86         } else {
87             SetIdom(v, parent);
88         }
89         bucket.pop_back();
90     }
91 }
92 
93 /*
94  * Compress ancestor path to 'block' to the block whose label has the maximal semidominator number
95  */
Compress(BasicBlock * block)96 void DominatorsTree::Compress(BasicBlock *block)
97 {
98     auto anc = GetAncestor(block);
99     ASSERT(anc != nullptr);
100 
101     if (GetAncestor(anc) != nullptr) {
102         Compress(anc);
103         if (GetSemi(GetLabel(anc)) < GetSemi(GetLabel(block))) {
104             SetLabel(block, GetLabel(anc));
105         }
106         SetAncestor(block, GetAncestor(anc));
107     }
108 }
109 
110 /*
111  *  Depth-first search with numbering blocks in order they are reaching
112  */
DfsNumbering(BasicBlock * block)113 void DominatorsTree::DfsNumbering(BasicBlock *block)
114 {
115     dfs_num_++;
116     ASSERT_PRINT(static_cast<size_t>(dfs_num_) < vertices_->size(), "DFS-number overflow");
117     ASSERT(block != nullptr);
118 
119     SetVertex(dfs_num_, block);
120     SetLabel(block, block);
121     SetSemi(block, dfs_num_);
122     SetAncestor(block, nullptr);
123 
124     for (auto succ : block->GetSuccsBlocks()) {
125         if (GetSemi(succ) == DEFAULT_DFS_VAL) {
126             SetParent(succ, block);
127             DfsNumbering(succ);
128         }
129     }
130 }
131 
132 /*
133  * Return 'block' if it is the root of a tree
134  * Otherwise, after tree compressing
135  * return the block in the ancestors chain with the minimal semidominator DFS-number
136  */
Eval(BasicBlock * block)137 BasicBlock *DominatorsTree::Eval(BasicBlock *block)
138 {
139     ASSERT(block != nullptr);
140     if (GetAncestor(block) == nullptr) {
141         return block;
142     }
143     Compress(block);
144     return GetLabel(block);
145 }
146 
147 /*
148  * Initialize data structures to start DFS
149  */
Init(size_t blocks_count)150 void DominatorsTree::Init(size_t blocks_count)
151 {
152     auto allocator = GetGraph()->GetLocalAllocator();
153     ancestors_ = allocator->New<BlocksVector>(allocator->Adapter());
154     buckets_ = allocator->New<ArenaVector<BlocksVector>>(allocator->Adapter());
155     idoms_ = allocator->New<BlocksVector>(allocator->Adapter());
156     labels_ = allocator->New<BlocksVector>(allocator->Adapter());
157     parents_ = allocator->New<BlocksVector>(allocator->Adapter());
158     semi_ = allocator->New<ArenaVector<int32_t>>(allocator->Adapter());
159     vertices_ = allocator->New<BlocksVector>(allocator->Adapter());
160     CHECK_NOT_NULL(ancestors_);
161     CHECK_NOT_NULL(buckets_);
162     CHECK_NOT_NULL(idoms_);
163     CHECK_NOT_NULL(labels_);
164     CHECK_NOT_NULL(parents_);
165     CHECK_NOT_NULL(semi_);
166     CHECK_NOT_NULL(vertices_);
167 
168     ancestors_->resize(blocks_count);
169     idoms_->resize(blocks_count);
170     labels_->resize(blocks_count);
171     parents_->resize(blocks_count);
172     vertices_->resize(blocks_count);
173     semi_->resize(blocks_count);
174 
175     std::fill(vertices_->begin(), vertices_->end(), nullptr);
176     std::fill(semi_->begin(), semi_->end(), DEFAULT_DFS_VAL);
177 
178     buckets_->resize(blocks_count, BlocksVector(allocator->Adapter()));
179     for (auto &bucket : *buckets_) {
180         bucket.clear();
181     }
182 
183     dfs_num_ = DEFAULT_DFS_VAL;
184 }
185 
186 /* static */
SetDomPair(BasicBlock * dominator,BasicBlock * block)187 void DominatorsTree::SetDomPair(BasicBlock *dominator, BasicBlock *block)
188 {
189     block->SetDominator(dominator);
190     dominator->AddDominatedBlock(block);
191 }
192 
193 /*
194  * Check if there is path from `start_block` to `target_block` excluding `exclude_block`
195  */
IsPathBetweenBlocks(BasicBlock * start_block,BasicBlock * target_block,BasicBlock * exclude_block)196 static bool IsPathBetweenBlocks(BasicBlock *start_block, BasicBlock *target_block, BasicBlock *exclude_block)
197 {
198     auto marker_holder = MarkerHolder(target_block->GetGraph());
199     auto marker = marker_holder.GetMarker();
200     return BlocksPathDfsSearch(marker, start_block, target_block, exclude_block);
201 }
202 
UpdateAfterResolverInsertion(BasicBlock * predecessor,BasicBlock * successor,BasicBlock * resolver)203 void DominatorsTree::UpdateAfterResolverInsertion(BasicBlock *predecessor, BasicBlock *successor, BasicBlock *resolver)
204 {
205     SetValid(true);
206     SetDomPair(predecessor, resolver);
207 
208     if (successor->GetDominator() == predecessor) {
209         bool resolver_dominate_phi_block = true;
210         for (auto succ : predecessor->GetSuccsBlocks()) {
211             if (succ == resolver) {
212                 continue;
213             }
214             if (IsPathBetweenBlocks(succ, successor, resolver)) {
215                 resolver_dominate_phi_block = false;
216                 break;
217             }
218         }
219 
220         if (resolver_dominate_phi_block) {
221             predecessor->RemoveDominatedBlock(successor);
222             SetDomPair(resolver, successor);
223         }
224     }
225 }
226 
227 /* static */
GetBlockId(BasicBlock * block)228 inline uint32_t DominatorsTree::GetBlockId(BasicBlock *block)
229 {
230     return block->GetId();
231 }
232 }  // namespace panda::compiler
233