blob: 743ffc46bf0b3f23994a48bdeb748c3c5ac9727d [file] [log] [blame]
Roland Levillainccc07a92014-09-16 14:48:16 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "graph_checker.h"
18
19#include <string>
20#include <map>
21#include <sstream>
22
Roland Levillain7e53b412014-09-23 10:50:22 +010023#include "base/bit_vector-inl.h"
24
Roland Levillainccc07a92014-09-16 14:48:16 +010025namespace art {
26
27void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
28 current_block_ = block;
29
30 // Check consistency with respect to predecessors of `block`.
31 const GrowableArray<HBasicBlock*>& predecessors = block->GetPredecessors();
32 std::map<HBasicBlock*, size_t> predecessors_count;
33 for (size_t i = 0, e = predecessors.Size(); i < e; ++i) {
34 HBasicBlock* p = predecessors.Get(i);
35 ++predecessors_count[p];
36 }
37 for (auto& pc : predecessors_count) {
38 HBasicBlock* p = pc.first;
39 size_t p_count_in_block_predecessors = pc.second;
40 const GrowableArray<HBasicBlock*>& p_successors = p->GetSuccessors();
41 size_t block_count_in_p_successors = 0;
42 for (size_t j = 0, f = p_successors.Size(); j < f; ++j) {
43 if (p_successors.Get(j) == block) {
44 ++block_count_in_p_successors;
45 }
46 }
47 if (p_count_in_block_predecessors != block_count_in_p_successors) {
48 std::stringstream error;
49 error << "Block " << block->GetBlockId()
50 << " lists " << p_count_in_block_predecessors
51 << " occurrences of block " << p->GetBlockId()
52 << " in its predecessors, whereas block " << p->GetBlockId()
53 << " lists " << block_count_in_p_successors
54 << " occurrences of block " << block->GetBlockId()
55 << " in its successors.";
56 errors_.Insert(error.str());
57 }
58 }
59
60 // Check consistency with respect to successors of `block`.
61 const GrowableArray<HBasicBlock*>& successors = block->GetSuccessors();
62 std::map<HBasicBlock*, size_t> successors_count;
63 for (size_t i = 0, e = successors.Size(); i < e; ++i) {
64 HBasicBlock* s = successors.Get(i);
65 ++successors_count[s];
66 }
67 for (auto& sc : successors_count) {
68 HBasicBlock* s = sc.first;
69 size_t s_count_in_block_successors = sc.second;
70 const GrowableArray<HBasicBlock*>& s_predecessors = s->GetPredecessors();
71 size_t block_count_in_s_predecessors = 0;
72 for (size_t j = 0, f = s_predecessors.Size(); j < f; ++j) {
73 if (s_predecessors.Get(j) == block) {
74 ++block_count_in_s_predecessors;
75 }
76 }
77 if (s_count_in_block_successors != block_count_in_s_predecessors) {
78 std::stringstream error;
79 error << "Block " << block->GetBlockId()
80 << " lists " << s_count_in_block_successors
81 << " occurrences of block " << s->GetBlockId()
82 << " in its successors, whereas block " << s->GetBlockId()
83 << " lists " << block_count_in_s_predecessors
84 << " occurrences of block " << block->GetBlockId()
85 << " in its predecessors.";
86 errors_.Insert(error.str());
87 }
88 }
89
90 // Ensure `block` ends with a branch instruction.
91 HInstruction* last_inst = block->GetLastInstruction();
92 if (last_inst == nullptr || !last_inst->IsControlFlow()) {
93 std::stringstream error;
94 error << "Block " << block->GetBlockId()
95 << " does not end with a branch instruction.";
96 errors_.Insert(error.str());
97 }
98
99 // Visit this block's list of phis.
100 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
101 // Ensure this block's list of phis contains only phis.
102 if (!it.Current()->IsPhi()) {
103 std::stringstream error;
104 error << "Block " << current_block_->GetBlockId()
105 << " has a non-phi in its phi list.";
106 errors_.Insert(error.str());
107 }
108 it.Current()->Accept(this);
109 }
110
111 // Visit this block's list of instructions.
112 for (HInstructionIterator it(block->GetInstructions()); !it.Done();
113 it.Advance()) {
114 // Ensure this block's list of instructions does not contains phis.
115 if (it.Current()->IsPhi()) {
116 std::stringstream error;
117 error << "Block " << current_block_->GetBlockId()
118 << " has a phi in its non-phi list.";
119 errors_.Insert(error.str());
120 }
121 it.Current()->Accept(this);
122 }
123}
124
125void GraphChecker::VisitInstruction(HInstruction* instruction) {
126 // Ensure `instruction` is associated with `current_block_`.
127 if (instruction->GetBlock() != current_block_) {
128 std::stringstream error;
129 if (instruction->IsPhi()) {
130 error << "Phi ";
131 } else {
132 error << "Instruction ";
133 }
134 error << instruction->GetId() << " in block "
135 << current_block_->GetBlockId();
136 if (instruction->GetBlock() != nullptr) {
137 error << " associated with block "
138 << instruction->GetBlock()->GetBlockId() << ".";
139 } else {
140 error << " not associated with any block.";
141 }
142 errors_.Insert(error.str());
143 }
Roland Levillain6b469232014-09-25 10:10:38 +0100144
145 // Ensure the inputs of `instruction` are defined in a block of the graph.
146 for (HInputIterator input_it(instruction); !input_it.Done();
147 input_it.Advance()) {
148 HInstruction* input = input_it.Current();
149 const HInstructionList& list = input->IsPhi()
150 ? input->GetBlock()->GetPhis()
151 : input->GetBlock()->GetInstructions();
152 if (!list.Contains(input)) {
153 std::stringstream error;
154 error << "Input " << input->GetId()
155 << " of instruction " << instruction->GetId()
156 << " is not defined in a basic block of the control-flow graph.";
157 errors_.Insert(error.str());
158 }
159 }
160
161 // Ensure the uses of `instruction` are defined in a block of the graph.
162 for (HUseIterator<HInstruction> use_it(instruction->GetUses());
163 !use_it.Done(); use_it.Advance()) {
164 HInstruction* use = use_it.Current()->GetUser();
165 const HInstructionList& list = use->IsPhi()
166 ? use->GetBlock()->GetPhis()
167 : use->GetBlock()->GetInstructions();
168 if (!list.Contains(use)) {
169 std::stringstream error;
170 error << "User " << use->GetId()
171 << " of instruction " << instruction->GetId()
172 << " is not defined in a basic block of the control-flow graph.";
173 errors_.Insert(error.str());
174 }
175 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100176}
177
178void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
179 super_type::VisitBasicBlock(block);
180
181 // Ensure there is no critical edge (i.e., an edge connecting a
182 // block with multiple successors to a block with multiple
183 // predecessors).
184 if (block->GetSuccessors().Size() > 1) {
185 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
186 HBasicBlock* successor = block->GetSuccessors().Get(j);
187 if (successor->GetPredecessors().Size() > 1) {
188 std::stringstream error;
189 error << "Critical edge between blocks " << block->GetBlockId()
190 << " and " << successor->GetBlockId() << ".";
191 errors_.Insert(error.str());
192 }
193 }
194 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100195
196 if (block->IsLoopHeader()) {
197 CheckLoop(block);
198 }
199}
200
201void SSAChecker::CheckLoop(HBasicBlock* loop_header) {
202 int id = loop_header->GetBlockId();
203
204 // Ensure the pre-header block is first in the list of
205 // predecessors of a loop header.
206 if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
207 std::stringstream error;
208 error << "Loop pre-header is not the first predecessor of the loop header "
209 << id << ".";
210 errors_.Insert(error.str());
211 }
212
213 // Ensure the loop header has only two predecessors and that only the
214 // second one is a back edge.
215 if (loop_header->GetPredecessors().Size() < 2) {
216 std::stringstream error;
217 error << "Loop header " << id << " has less than two predecessors.";
218 errors_.Insert(error.str());
219 } else if (loop_header->GetPredecessors().Size() > 2) {
220 std::stringstream error;
221 error << "Loop header " << id << " has more than two predecessors.";
222 errors_.Insert(error.str());
223 } else {
224 HLoopInformation* loop_information = loop_header->GetLoopInformation();
225 HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0);
226 if (loop_information->IsBackEdge(first_predecessor)) {
227 std::stringstream error;
228 error << "First predecessor of loop header " << id << " is a back edge.";
229 errors_.Insert(error.str());
230 }
231 HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1);
232 if (!loop_information->IsBackEdge(second_predecessor)) {
233 std::stringstream error;
234 error << "Second predecessor of loop header " << id
235 << " is not a back edge.";
236 errors_.Insert(error.str());
237 }
238 }
239
240 // Ensure there is only one back edge per loop.
241 size_t num_back_edges =
242 loop_header->GetLoopInformation()->GetBackEdges().Size();
243 if (num_back_edges != 1) {
244 std::stringstream error;
245 error << "Loop defined by header " << id << " has "
246 << num_back_edges << " back edge(s).";
247 errors_.Insert(error.str());
248 }
Roland Levillain7e53b412014-09-23 10:50:22 +0100249
250 // Ensure all blocks in the loop are dominated by the loop header.
251 const ArenaBitVector& loop_blocks =
252 loop_header->GetLoopInformation()->GetBlocks();
253 for (uint32_t i : loop_blocks.Indexes()) {
254 HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i);
255 if (!loop_header->Dominates(loop_block)) {
256 std::stringstream error;
257 error << "Loop block " << loop_block->GetBlockId()
258 << " not dominated by loop header " << id;
259 errors_.Insert(error.str());
260 }
261 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100262}
263
264void SSAChecker::VisitInstruction(HInstruction* instruction) {
265 super_type::VisitInstruction(instruction);
266
Roland Levillaina8069ce2014-10-01 10:48:29 +0100267 // Ensure an instruction dominates all its uses.
268 for (HUseIterator<HInstruction> use_it(instruction->GetUses());
269 !use_it.Done(); use_it.Advance()) {
270 HInstruction* use = use_it.Current()->GetUser();
Roland Levillain6c82d402014-10-13 16:10:27 +0100271 if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
Roland Levillainccc07a92014-09-16 14:48:16 +0100272 std::stringstream error;
Roland Levillaina8069ce2014-10-01 10:48:29 +0100273 error << "Instruction " << instruction->GetId()
274 << " in block " << current_block_->GetBlockId()
275 << " does not dominate use " << use->GetId()
276 << " in block " << use->GetBlock()->GetBlockId() << ".";
Roland Levillainccc07a92014-09-16 14:48:16 +0100277 errors_.Insert(error.str());
278 }
279 }
Roland Levillaina8069ce2014-10-01 10:48:29 +0100280
281 // Ensure an instruction having an environment is dominated by the
282 // instructions contained in the environment.
283 HEnvironment* environment = instruction->GetEnvironment();
284 if (environment != nullptr) {
285 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
286 HInstruction* env_instruction = environment->GetInstructionAt(i);
287 if (env_instruction != nullptr
Roland Levillain6c82d402014-10-13 16:10:27 +0100288 && !env_instruction->StrictlyDominates(instruction)) {
Roland Levillaina8069ce2014-10-01 10:48:29 +0100289 std::stringstream error;
290 error << "Instruction " << env_instruction->GetId()
291 << " in environment of instruction " << instruction->GetId()
292 << " from block " << current_block_->GetBlockId()
293 << " does not dominate instruction " << instruction->GetId()
294 << ".";
295 errors_.Insert(error.str());
296 }
297 }
298 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100299}
300
Roland Levillain6b879dd2014-09-22 17:13:44 +0100301void SSAChecker::VisitPhi(HPhi* phi) {
302 VisitInstruction(phi);
303
304 // Ensure the first input of a phi is not itself.
305 if (phi->InputAt(0) == phi) {
306 std::stringstream error;
307 error << "Loop phi " << phi->GetId()
308 << " in block " << phi->GetBlock()->GetBlockId()
309 << " is its own first input.";
310 errors_.Insert(error.str());
311 }
312
313 // Ensure the number of phi inputs is the same as the number of
314 // its predecessors.
315 const GrowableArray<HBasicBlock*>& predecessors =
316 phi->GetBlock()->GetPredecessors();
317 if (phi->InputCount() != predecessors.Size()) {
318 std::stringstream error;
319 error << "Phi " << phi->GetId()
320 << " in block " << phi->GetBlock()->GetBlockId()
321 << " has " << phi->InputCount() << " inputs, but block "
322 << phi->GetBlock()->GetBlockId() << " has "
323 << predecessors.Size() << " predecessors.";
324 errors_.Insert(error.str());
325 } else {
326 // Ensure phi input at index I either comes from the Ith
327 // predecessor or from a block that dominates this predecessor.
328 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
329 HInstruction* input = phi->InputAt(i);
330 HBasicBlock* predecessor = predecessors.Get(i);
331 if (!(input->GetBlock() == predecessor
332 || input->GetBlock()->Dominates(predecessor))) {
333 std::stringstream error;
334 error << "Input " << input->GetId() << " at index " << i
335 << " of phi " << phi->GetId()
336 << " from block " << phi->GetBlock()->GetBlockId()
337 << " is not defined in predecessor number " << i
338 << " nor in a block dominating it.";
339 errors_.Insert(error.str());
340 }
341 }
342 }
343}
344
Roland Levillainccc07a92014-09-16 14:48:16 +0100345} // namespace art