blob: e36b1cdcfdd01f38cac3b0a511997914d8394b26 [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 }
144}
145
146void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
147 super_type::VisitBasicBlock(block);
148
149 // Ensure there is no critical edge (i.e., an edge connecting a
150 // block with multiple successors to a block with multiple
151 // predecessors).
152 if (block->GetSuccessors().Size() > 1) {
153 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
154 HBasicBlock* successor = block->GetSuccessors().Get(j);
155 if (successor->GetPredecessors().Size() > 1) {
156 std::stringstream error;
157 error << "Critical edge between blocks " << block->GetBlockId()
158 << " and " << successor->GetBlockId() << ".";
159 errors_.Insert(error.str());
160 }
161 }
162 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100163
164 if (block->IsLoopHeader()) {
165 CheckLoop(block);
166 }
167}
168
169void SSAChecker::CheckLoop(HBasicBlock* loop_header) {
170 int id = loop_header->GetBlockId();
171
172 // Ensure the pre-header block is first in the list of
173 // predecessors of a loop header.
174 if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
175 std::stringstream error;
176 error << "Loop pre-header is not the first predecessor of the loop header "
177 << id << ".";
178 errors_.Insert(error.str());
179 }
180
181 // Ensure the loop header has only two predecessors and that only the
182 // second one is a back edge.
183 if (loop_header->GetPredecessors().Size() < 2) {
184 std::stringstream error;
185 error << "Loop header " << id << " has less than two predecessors.";
186 errors_.Insert(error.str());
187 } else if (loop_header->GetPredecessors().Size() > 2) {
188 std::stringstream error;
189 error << "Loop header " << id << " has more than two predecessors.";
190 errors_.Insert(error.str());
191 } else {
192 HLoopInformation* loop_information = loop_header->GetLoopInformation();
193 HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0);
194 if (loop_information->IsBackEdge(first_predecessor)) {
195 std::stringstream error;
196 error << "First predecessor of loop header " << id << " is a back edge.";
197 errors_.Insert(error.str());
198 }
199 HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1);
200 if (!loop_information->IsBackEdge(second_predecessor)) {
201 std::stringstream error;
202 error << "Second predecessor of loop header " << id
203 << " is not a back edge.";
204 errors_.Insert(error.str());
205 }
206 }
207
208 // Ensure there is only one back edge per loop.
209 size_t num_back_edges =
210 loop_header->GetLoopInformation()->GetBackEdges().Size();
211 if (num_back_edges != 1) {
212 std::stringstream error;
213 error << "Loop defined by header " << id << " has "
214 << num_back_edges << " back edge(s).";
215 errors_.Insert(error.str());
216 }
Roland Levillain7e53b412014-09-23 10:50:22 +0100217
218 // Ensure all blocks in the loop are dominated by the loop header.
219 const ArenaBitVector& loop_blocks =
220 loop_header->GetLoopInformation()->GetBlocks();
221 for (uint32_t i : loop_blocks.Indexes()) {
222 HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i);
223 if (!loop_header->Dominates(loop_block)) {
224 std::stringstream error;
225 error << "Loop block " << loop_block->GetBlockId()
226 << " not dominated by loop header " << id;
227 errors_.Insert(error.str());
228 }
229 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100230}
231
232void SSAChecker::VisitInstruction(HInstruction* instruction) {
233 super_type::VisitInstruction(instruction);
234
235 // Ensure an instruction dominates all its uses (or in the present
236 // case, that all uses of an instruction (used as input) are
237 // dominated by its definition).
238 for (HInputIterator input_it(instruction); !input_it.Done();
239 input_it.Advance()) {
240 HInstruction* input = input_it.Current();
241 if (!input->Dominates(instruction)) {
242 std::stringstream error;
243 error << "Instruction " << input->GetId()
244 << " in block " << input->GetBlock()->GetBlockId()
245 << " does not dominate use " << instruction->GetId()
246 << " in block " << current_block_->GetBlockId() << ".";
247 errors_.Insert(error.str());
248 }
249 }
250}
251
Roland Levillain6b879dd2014-09-22 17:13:44 +0100252void SSAChecker::VisitPhi(HPhi* phi) {
253 VisitInstruction(phi);
254
255 // Ensure the first input of a phi is not itself.
256 if (phi->InputAt(0) == phi) {
257 std::stringstream error;
258 error << "Loop phi " << phi->GetId()
259 << " in block " << phi->GetBlock()->GetBlockId()
260 << " is its own first input.";
261 errors_.Insert(error.str());
262 }
263
264 // Ensure the number of phi inputs is the same as the number of
265 // its predecessors.
266 const GrowableArray<HBasicBlock*>& predecessors =
267 phi->GetBlock()->GetPredecessors();
268 if (phi->InputCount() != predecessors.Size()) {
269 std::stringstream error;
270 error << "Phi " << phi->GetId()
271 << " in block " << phi->GetBlock()->GetBlockId()
272 << " has " << phi->InputCount() << " inputs, but block "
273 << phi->GetBlock()->GetBlockId() << " has "
274 << predecessors.Size() << " predecessors.";
275 errors_.Insert(error.str());
276 } else {
277 // Ensure phi input at index I either comes from the Ith
278 // predecessor or from a block that dominates this predecessor.
279 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
280 HInstruction* input = phi->InputAt(i);
281 HBasicBlock* predecessor = predecessors.Get(i);
282 if (!(input->GetBlock() == predecessor
283 || input->GetBlock()->Dominates(predecessor))) {
284 std::stringstream error;
285 error << "Input " << input->GetId() << " at index " << i
286 << " of phi " << phi->GetId()
287 << " from block " << phi->GetBlock()->GetBlockId()
288 << " is not defined in predecessor number " << i
289 << " nor in a block dominating it.";
290 errors_.Insert(error.str());
291 }
292 }
293 }
294}
295
Roland Levillainccc07a92014-09-16 14:48:16 +0100296} // namespace art