blob: b1ac027a6898233144632beb605f817ea39728f8 [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
Vladimir Marko655e5852015-10-12 10:38:28 +010019#include <algorithm>
Calin Juravlea4f88312015-04-16 12:57:19 +010020#include <sstream>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070021#include <string>
Roland Levillainccc07a92014-09-16 14:48:16 +010022
Andreas Gampe46ee31b2016-12-14 10:11:49 -080023#include "android-base/stringprintf.h"
24
Roland Levillain7e53b412014-09-23 10:50:22 +010025#include "base/bit_vector-inl.h"
Vladimir Marko009d1662017-10-10 13:21:15 +010026#include "base/scoped_arena_allocator.h"
27#include "base/scoped_arena_containers.h"
Roland Levillain7e53b412014-09-23 10:50:22 +010028
Roland Levillainccc07a92014-09-16 14:48:16 +010029namespace art {
30
Andreas Gampe46ee31b2016-12-14 10:11:49 -080031using android::base::StringPrintf;
32
David Brazdil86ea7ee2016-02-16 09:26:07 +000033static bool IsAllowedToJumpToExitBlock(HInstruction* instruction) {
34 return instruction->IsThrow() || instruction->IsReturn() || instruction->IsReturnVoid();
35}
36
37static bool IsExitTryBoundaryIntoExitBlock(HBasicBlock* block) {
38 if (!block->IsSingleTryBoundary()) {
39 return false;
40 }
41
42 HTryBoundary* boundary = block->GetLastInstruction()->AsTryBoundary();
43 return block->GetPredecessors().size() == 1u &&
44 boundary->GetNormalFlowSuccessor()->IsExitBlock() &&
45 !boundary->IsEntry();
46}
47
Roland Levillainccc07a92014-09-16 14:48:16 +010048void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
49 current_block_ = block;
50
Vladimir Marko009d1662017-10-10 13:21:15 +010051 // Use local allocator for allocating memory.
52 ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
53
Roland Levillainccc07a92014-09-16 14:48:16 +010054 // Check consistency with respect to predecessors of `block`.
Vladimir Marko0f49c822016-03-22 17:51:29 +000055 // Note: Counting duplicates with a sorted vector uses up to 6x less memory
Vladimir Marko947eb702016-03-25 15:31:35 +000056 // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
Vladimir Marko009d1662017-10-10 13:21:15 +010057 ScopedArenaVector<HBasicBlock*> sorted_predecessors(allocator.Adapter(kArenaAllocGraphChecker));
Vladimir Marko947eb702016-03-25 15:31:35 +000058 sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end());
Vladimir Marko0f49c822016-03-22 17:51:29 +000059 std::sort(sorted_predecessors.begin(), sorted_predecessors.end());
60 for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end; ) {
61 HBasicBlock* p = *it++;
62 size_t p_count_in_block_predecessors = 1u;
63 for (; it != end && *it == p; ++it) {
64 ++p_count_in_block_predecessors;
Vladimir Marko655e5852015-10-12 10:38:28 +010065 }
Vladimir Marko655e5852015-10-12 10:38:28 +010066 size_t block_count_in_p_successors =
67 std::count(p->GetSuccessors().begin(), p->GetSuccessors().end(), block);
Roland Levillainccc07a92014-09-16 14:48:16 +010068 if (p_count_in_block_predecessors != block_count_in_p_successors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +000069 AddError(StringPrintf(
70 "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
71 "block %d lists %zu occurrences of block %d in its successors.",
72 block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(),
73 p->GetBlockId(), block_count_in_p_successors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010074 }
75 }
76
77 // Check consistency with respect to successors of `block`.
Vladimir Marko0f49c822016-03-22 17:51:29 +000078 // Note: Counting duplicates with a sorted vector uses up to 6x less memory
Vladimir Marko947eb702016-03-25 15:31:35 +000079 // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
Vladimir Marko009d1662017-10-10 13:21:15 +010080 ScopedArenaVector<HBasicBlock*> sorted_successors(allocator.Adapter(kArenaAllocGraphChecker));
Vladimir Marko947eb702016-03-25 15:31:35 +000081 sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end());
Vladimir Marko0f49c822016-03-22 17:51:29 +000082 std::sort(sorted_successors.begin(), sorted_successors.end());
83 for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end; ) {
84 HBasicBlock* s = *it++;
85 size_t s_count_in_block_successors = 1u;
86 for (; it != end && *it == s; ++it) {
87 ++s_count_in_block_successors;
Vladimir Marko655e5852015-10-12 10:38:28 +010088 }
Vladimir Marko655e5852015-10-12 10:38:28 +010089 size_t block_count_in_s_predecessors =
90 std::count(s->GetPredecessors().begin(), s->GetPredecessors().end(), block);
Roland Levillainccc07a92014-09-16 14:48:16 +010091 if (s_count_in_block_successors != block_count_in_s_predecessors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +000092 AddError(StringPrintf(
93 "Block %d lists %zu occurrences of block %d in its successors, whereas "
94 "block %d lists %zu occurrences of block %d in its predecessors.",
95 block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(),
96 s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010097 }
98 }
99
100 // Ensure `block` ends with a branch instruction.
David Brazdilfc6a86a2015-06-26 10:33:45 +0000101 // This invariant is not enforced on non-SSA graphs. Graph built from DEX with
102 // dead code that falls out of the method will not end with a control-flow
103 // instruction. Such code is removed during the SSA-building DCE phase.
104 if (GetGraph()->IsInSsaForm() && !block->EndsWithControlFlowInstruction()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000105 AddError(StringPrintf("Block %d does not end with a branch instruction.",
106 block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100107 }
108
David Brazdil86ea7ee2016-02-16 09:26:07 +0000109 // Ensure that only Return(Void) and Throw jump to Exit. An exiting TryBoundary
110 // may be between the instructions if the Throw/Return(Void) is in a try block.
David Brazdilb618ade2015-07-29 10:31:29 +0100111 if (block->IsExitBlock()) {
Vladimir Marko60584552015-09-03 13:35:12 +0000112 for (HBasicBlock* predecessor : block->GetPredecessors()) {
David Brazdil86ea7ee2016-02-16 09:26:07 +0000113 HInstruction* last_instruction = IsExitTryBoundaryIntoExitBlock(predecessor) ?
114 predecessor->GetSinglePredecessor()->GetLastInstruction() :
115 predecessor->GetLastInstruction();
116 if (!IsAllowedToJumpToExitBlock(last_instruction)) {
117 AddError(StringPrintf("Unexpected instruction %s:%d jumps into the exit block.",
118 last_instruction->DebugName(),
119 last_instruction->GetId()));
David Brazdilb618ade2015-07-29 10:31:29 +0100120 }
121 }
122 }
123
Roland Levillainccc07a92014-09-16 14:48:16 +0100124 // Visit this block's list of phis.
125 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
David Brazdilc3d743f2015-04-22 13:40:50 +0100126 HInstruction* current = it.Current();
Roland Levillainccc07a92014-09-16 14:48:16 +0100127 // Ensure this block's list of phis contains only phis.
David Brazdilc3d743f2015-04-22 13:40:50 +0100128 if (!current->IsPhi()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000129 AddError(StringPrintf("Block %d has a non-phi in its phi list.",
130 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100131 }
David Brazdilc3d743f2015-04-22 13:40:50 +0100132 if (current->GetNext() == nullptr && current != block->GetLastPhi()) {
133 AddError(StringPrintf("The recorded last phi of block %d does not match "
134 "the actual last phi %d.",
135 current_block_->GetBlockId(),
136 current->GetId()));
137 }
138 current->Accept(this);
Roland Levillainccc07a92014-09-16 14:48:16 +0100139 }
140
141 // Visit this block's list of instructions.
David Brazdilc3d743f2015-04-22 13:40:50 +0100142 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
143 HInstruction* current = it.Current();
Roland Levillainccc07a92014-09-16 14:48:16 +0100144 // Ensure this block's list of instructions does not contains phis.
David Brazdilc3d743f2015-04-22 13:40:50 +0100145 if (current->IsPhi()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000146 AddError(StringPrintf("Block %d has a phi in its non-phi list.",
147 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100148 }
David Brazdilc3d743f2015-04-22 13:40:50 +0100149 if (current->GetNext() == nullptr && current != block->GetLastInstruction()) {
150 AddError(StringPrintf("The recorded last instruction of block %d does not match "
151 "the actual last instruction %d.",
152 current_block_->GetBlockId(),
153 current->GetId()));
154 }
155 current->Accept(this);
Roland Levillainccc07a92014-09-16 14:48:16 +0100156 }
David Brazdilbadd8262016-02-02 16:28:56 +0000157
158 // Ensure that catch blocks are not normal successors, and normal blocks are
159 // never exceptional successors.
160 for (HBasicBlock* successor : block->GetNormalSuccessors()) {
161 if (successor->IsCatchBlock()) {
162 AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
163 successor->GetBlockId(),
164 block->GetBlockId()));
165 }
166 }
167 for (HBasicBlock* successor : block->GetExceptionalSuccessors()) {
168 if (!successor->IsCatchBlock()) {
169 AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
170 successor->GetBlockId(),
171 block->GetBlockId()));
172 }
173 }
174
175 // Ensure dominated blocks have `block` as the dominator.
176 for (HBasicBlock* dominated : block->GetDominatedBlocks()) {
177 if (dominated->GetDominator() != block) {
178 AddError(StringPrintf("Block %d should be the dominator of %d.",
179 block->GetBlockId(),
180 dominated->GetBlockId()));
181 }
182 }
183
184 // Ensure there is no critical edge (i.e., an edge connecting a
185 // block with multiple successors to a block with multiple
186 // predecessors). Exceptional edges are synthesized and hence
187 // not accounted for.
188 if (block->GetSuccessors().size() > 1) {
David Brazdil86ea7ee2016-02-16 09:26:07 +0000189 if (IsExitTryBoundaryIntoExitBlock(block)) {
190 // Allowed critical edge (Throw/Return/ReturnVoid)->TryBoundary->Exit.
191 } else {
192 for (HBasicBlock* successor : block->GetNormalSuccessors()) {
193 if (successor->GetPredecessors().size() > 1) {
194 AddError(StringPrintf("Critical edge between blocks %d and %d.",
195 block->GetBlockId(),
196 successor->GetBlockId()));
197 }
David Brazdilbadd8262016-02-02 16:28:56 +0000198 }
199 }
200 }
201
202 // Ensure try membership information is consistent.
203 if (block->IsCatchBlock()) {
204 if (block->IsTryBlock()) {
205 const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry();
206 AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
207 "has try entry %s:%d.",
208 block->GetBlockId(),
209 try_entry.DebugName(),
210 try_entry.GetId()));
211 }
212
213 if (block->IsLoopHeader()) {
214 AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
215 block->GetBlockId()));
216 }
217 } else {
218 for (HBasicBlock* predecessor : block->GetPredecessors()) {
219 const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
220 if (block->IsTryBlock()) {
221 const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry();
222 if (incoming_try_entry == nullptr) {
223 AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
224 "from predecessor %d.",
225 block->GetBlockId(),
226 stored_try_entry.DebugName(),
227 stored_try_entry.GetId(),
228 predecessor->GetBlockId()));
229 } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) {
230 AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
231 "with %s:%d that follows from predecessor %d.",
232 block->GetBlockId(),
233 stored_try_entry.DebugName(),
234 stored_try_entry.GetId(),
235 incoming_try_entry->DebugName(),
236 incoming_try_entry->GetId(),
237 predecessor->GetBlockId()));
238 }
239 } else if (incoming_try_entry != nullptr) {
240 AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows "
241 "from predecessor %d.",
242 block->GetBlockId(),
243 incoming_try_entry->DebugName(),
244 incoming_try_entry->GetId(),
245 predecessor->GetBlockId()));
246 }
247 }
248 }
249
250 if (block->IsLoopHeader()) {
251 HandleLoop(block);
252 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100253}
254
Mark Mendell1152c922015-04-24 17:06:35 -0400255void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) {
256 if (!GetGraph()->HasBoundsChecks()) {
257 AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, "
258 "but HasBoundsChecks() returns false",
259 check->DebugName(),
260 check->GetId()));
261 }
262
263 // Perform the instruction base checks too.
264 VisitInstruction(check);
265}
266
Nicolas Geoffray93a18c52016-04-22 13:16:14 +0100267void GraphChecker::VisitDeoptimize(HDeoptimize* deopt) {
268 if (GetGraph()->IsCompilingOsr()) {
269 AddError(StringPrintf("A graph compiled OSR cannot have a HDeoptimize instruction"));
270 }
271
272 // Perform the instruction base checks too.
273 VisitInstruction(deopt);
274}
275
David Brazdilffee3d32015-07-06 11:48:53 +0100276void GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) {
David Brazdild26a4112015-11-10 11:07:31 +0000277 ArrayRef<HBasicBlock* const> handlers = try_boundary->GetExceptionHandlers();
278
279 // Ensure that all exception handlers are catch blocks.
David Brazdilffee3d32015-07-06 11:48:53 +0100280 // Note that a normal-flow successor may be a catch block before CFG
David Brazdilbadd8262016-02-02 16:28:56 +0000281 // simplification. We only test normal-flow successors in GraphChecker.
David Brazdild26a4112015-11-10 11:07:31 +0000282 for (HBasicBlock* handler : handlers) {
David Brazdilffee3d32015-07-06 11:48:53 +0100283 if (!handler->IsCatchBlock()) {
284 AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which "
285 "is not a catch block.",
286 current_block_->GetBlockId(),
287 try_boundary->DebugName(),
288 try_boundary->GetId(),
289 handler->GetBlockId()));
290 }
David Brazdild26a4112015-11-10 11:07:31 +0000291 }
292
293 // Ensure that handlers are not listed multiple times.
294 for (size_t i = 0, e = handlers.size(); i < e; ++i) {
David Brazdild8ef0c62015-11-10 18:49:28 +0000295 if (ContainsElement(handlers, handlers[i], i + 1)) {
296 AddError(StringPrintf("Exception handler block %d of %s:%d is listed multiple times.",
David Brazdild26a4112015-11-10 11:07:31 +0000297 handlers[i]->GetBlockId(),
David Brazdilffee3d32015-07-06 11:48:53 +0100298 try_boundary->DebugName(),
299 try_boundary->GetId()));
300 }
301 }
302
303 VisitInstruction(try_boundary);
304}
305
David Brazdil9bc43612015-11-05 21:25:24 +0000306void GraphChecker::VisitLoadException(HLoadException* load) {
307 // Ensure that LoadException is the first instruction in a catch block.
308 if (!load->GetBlock()->IsCatchBlock()) {
309 AddError(StringPrintf("%s:%d is in a non-catch block %d.",
310 load->DebugName(),
311 load->GetId(),
312 load->GetBlock()->GetBlockId()));
313 } else if (load->GetBlock()->GetFirstInstruction() != load) {
314 AddError(StringPrintf("%s:%d is not the first instruction in catch block %d.",
315 load->DebugName(),
316 load->GetId(),
317 load->GetBlock()->GetBlockId()));
318 }
319}
320
Roland Levillainccc07a92014-09-16 14:48:16 +0100321void GraphChecker::VisitInstruction(HInstruction* instruction) {
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000322 if (seen_ids_.IsBitSet(instruction->GetId())) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000323 AddError(StringPrintf("Instruction id %d is duplicate in graph.",
324 instruction->GetId()));
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000325 } else {
326 seen_ids_.SetBit(instruction->GetId());
327 }
328
Roland Levillainccc07a92014-09-16 14:48:16 +0100329 // Ensure `instruction` is associated with `current_block_`.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000330 if (instruction->GetBlock() == nullptr) {
331 AddError(StringPrintf("%s %d in block %d not associated with any block.",
332 instruction->IsPhi() ? "Phi" : "Instruction",
333 instruction->GetId(),
334 current_block_->GetBlockId()));
335 } else if (instruction->GetBlock() != current_block_) {
336 AddError(StringPrintf("%s %d in block %d associated with block %d.",
337 instruction->IsPhi() ? "Phi" : "Instruction",
338 instruction->GetId(),
339 current_block_->GetBlockId(),
340 instruction->GetBlock()->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100341 }
Roland Levillain6b469232014-09-25 10:10:38 +0100342
343 // Ensure the inputs of `instruction` are defined in a block of the graph.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100344 for (HInstruction* input : instruction->GetInputs()) {
Igor Murashkind01745e2017-04-05 16:40:31 -0700345 if (input->GetBlock() == nullptr) {
346 AddError(StringPrintf("Input %d of instruction %d is not in any "
347 "basic block of the control-flow graph.",
348 input->GetId(),
349 instruction->GetId()));
Igor Murashkin4ae432d2017-05-04 14:15:08 -0700350 } else {
351 const HInstructionList& list = input->IsPhi()
352 ? input->GetBlock()->GetPhis()
353 : input->GetBlock()->GetInstructions();
354 if (!list.Contains(input)) {
355 AddError(StringPrintf("Input %d of instruction %d is not defined "
356 "in a basic block of the control-flow graph.",
357 input->GetId(),
358 instruction->GetId()));
359 }
Roland Levillain6b469232014-09-25 10:10:38 +0100360 }
361 }
362
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100363 // Ensure the uses of `instruction` are defined in a block of the graph,
364 // and the entry in the use list is consistent.
Vladimir Marko46817b82016-03-29 12:21:58 +0100365 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
366 HInstruction* user = use.GetUser();
367 const HInstructionList& list = user->IsPhi()
368 ? user->GetBlock()->GetPhis()
369 : user->GetBlock()->GetInstructions();
370 if (!list.Contains(user)) {
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000371 AddError(StringPrintf("User %s:%d of instruction %d is not defined "
Roland Levillain5c4405e2015-01-21 11:39:58 +0000372 "in a basic block of the control-flow graph.",
Vladimir Marko46817b82016-03-29 12:21:58 +0100373 user->DebugName(),
374 user->GetId(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000375 instruction->GetId()));
Roland Levillain6b469232014-09-25 10:10:38 +0100376 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100377 size_t use_index = use.GetIndex();
Vladimir Markoe9004912016-06-16 16:50:52 +0100378 HConstInputsRef user_inputs = user->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100379 if ((use_index >= user_inputs.size()) || (user_inputs[use_index] != instruction)) {
Vladimir Markob554b5a2015-11-06 12:57:55 +0000380 AddError(StringPrintf("User %s:%d of instruction %s:%d has a wrong "
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100381 "UseListNode index.",
Vladimir Marko46817b82016-03-29 12:21:58 +0100382 user->DebugName(),
383 user->GetId(),
Vladimir Markob554b5a2015-11-06 12:57:55 +0000384 instruction->DebugName(),
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100385 instruction->GetId()));
386 }
387 }
388
389 // Ensure the environment uses entries are consistent.
Vladimir Marko46817b82016-03-29 12:21:58 +0100390 for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
391 HEnvironment* user = use.GetUser();
392 size_t use_index = use.GetIndex();
393 if ((use_index >= user->Size()) || (user->GetInstructionAt(use_index) != instruction)) {
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100394 AddError(StringPrintf("Environment user of %s:%d has a wrong "
395 "UseListNode index.",
396 instruction->DebugName(),
397 instruction->GetId()));
398 }
Roland Levillain6b469232014-09-25 10:10:38 +0100399 }
David Brazdil1abb4192015-02-17 18:33:36 +0000400
401 // Ensure 'instruction' has pointers to its inputs' use entries.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100402 auto&& input_records = instruction->GetInputRecords();
403 for (size_t i = 0; i < input_records.size(); ++i) {
404 const HUserRecord<HInstruction*>& input_record = input_records[i];
David Brazdil1abb4192015-02-17 18:33:36 +0000405 HInstruction* input = input_record.GetInstruction();
Vladimir Marko46817b82016-03-29 12:21:58 +0100406 if ((input_record.GetBeforeUseNode() == input->GetUses().end()) ||
407 (input_record.GetUseNode() == input->GetUses().end()) ||
408 !input->GetUses().ContainsNode(*input_record.GetUseNode()) ||
409 (input_record.GetUseNode()->GetIndex() != i)) {
410 AddError(StringPrintf("Instruction %s:%d has an invalid iterator before use entry "
David Brazdil1abb4192015-02-17 18:33:36 +0000411 "at input %u (%s:%d).",
412 instruction->DebugName(),
413 instruction->GetId(),
414 static_cast<unsigned>(i),
415 input->DebugName(),
416 input->GetId()));
417 }
418 }
David Brazdilbadd8262016-02-02 16:28:56 +0000419
420 // Ensure an instruction dominates all its uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100421 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
422 HInstruction* user = use.GetUser();
423 if (!user->IsPhi() && !instruction->StrictlyDominates(user)) {
David Brazdilbadd8262016-02-02 16:28:56 +0000424 AddError(StringPrintf("Instruction %s:%d in block %d does not dominate "
425 "use %s:%d in block %d.",
426 instruction->DebugName(),
427 instruction->GetId(),
428 current_block_->GetBlockId(),
Vladimir Marko46817b82016-03-29 12:21:58 +0100429 user->DebugName(),
430 user->GetId(),
431 user->GetBlock()->GetBlockId()));
David Brazdilbadd8262016-02-02 16:28:56 +0000432 }
433 }
434
435 if (instruction->NeedsEnvironment() && !instruction->HasEnvironment()) {
436 AddError(StringPrintf("Instruction %s:%d in block %d requires an environment "
437 "but does not have one.",
438 instruction->DebugName(),
439 instruction->GetId(),
440 current_block_->GetBlockId()));
441 }
442
443 // Ensure an instruction having an environment is dominated by the
444 // instructions contained in the environment.
445 for (HEnvironment* environment = instruction->GetEnvironment();
446 environment != nullptr;
447 environment = environment->GetParent()) {
448 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
449 HInstruction* env_instruction = environment->GetInstructionAt(i);
450 if (env_instruction != nullptr
451 && !env_instruction->StrictlyDominates(instruction)) {
452 AddError(StringPrintf("Instruction %d in environment of instruction %d "
453 "from block %d does not dominate instruction %d.",
454 env_instruction->GetId(),
455 instruction->GetId(),
456 current_block_->GetBlockId(),
457 instruction->GetId()));
458 }
459 }
460 }
461
462 // Ensure that reference type instructions have reference type info.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100463 if (instruction->GetType() == DataType::Type::kReference) {
David Brazdilbadd8262016-02-02 16:28:56 +0000464 if (!instruction->GetReferenceTypeInfo().IsValid()) {
465 AddError(StringPrintf("Reference type instruction %s:%d does not have "
466 "valid reference type information.",
467 instruction->DebugName(),
468 instruction->GetId()));
469 }
470 }
471
472 if (instruction->CanThrowIntoCatchBlock()) {
473 // Find the top-level environment. This corresponds to the environment of
474 // the catch block since we do not inline methods with try/catch.
475 HEnvironment* environment = instruction->GetEnvironment();
476 while (environment->GetParent() != nullptr) {
477 environment = environment->GetParent();
478 }
479
480 // Find all catch blocks and test that `instruction` has an environment
481 // value for each one.
482 const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
483 for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) {
484 for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
485 HPhi* catch_phi = phi_it.Current()->AsPhi();
486 if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) {
487 AddError(StringPrintf("Instruction %s:%d throws into catch block %d "
488 "with catch phi %d for vreg %d but its "
489 "corresponding environment slot is empty.",
490 instruction->DebugName(),
491 instruction->GetId(),
492 catch_block->GetBlockId(),
493 catch_phi->GetId(),
494 catch_phi->GetRegNumber()));
495 }
496 }
497 }
498 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100499}
500
Roland Levillain4c0eb422015-04-24 16:43:49 +0100501void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
502 VisitInstruction(invoke);
503
504 if (invoke->IsStaticWithExplicitClinitCheck()) {
Vladimir Markoe9004912016-06-16 16:50:52 +0100505 const HInstruction* last_input = invoke->GetInputs().back();
Roland Levillain4c0eb422015-04-24 16:43:49 +0100506 if (last_input == nullptr) {
507 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
508 "has a null pointer as last input.",
509 invoke->DebugName(),
510 invoke->GetId()));
George Burgess IV72155d22017-04-25 15:17:16 -0700511 } else if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100512 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
513 "has a last instruction (%s:%d) which is neither a clinit check "
514 "nor a load class instruction.",
515 invoke->DebugName(),
516 invoke->GetId(),
517 last_input->DebugName(),
518 last_input->GetId()));
519 }
520 }
521}
522
David Brazdilfc6a86a2015-06-26 10:33:45 +0000523void GraphChecker::VisitReturn(HReturn* ret) {
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100524 VisitInstruction(ret);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000525 HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
526 if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
David Brazdilfc6a86a2015-06-26 10:33:45 +0000527 AddError(StringPrintf("%s:%d does not jump to the exit block.",
528 ret->DebugName(),
529 ret->GetId()));
530 }
531}
532
533void GraphChecker::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100534 VisitInstruction(ret);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000535 HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
536 if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
David Brazdilfc6a86a2015-06-26 10:33:45 +0000537 AddError(StringPrintf("%s:%d does not jump to the exit block.",
538 ret->DebugName(),
539 ret->GetId()));
540 }
541}
542
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100543void GraphChecker::VisitCheckCast(HCheckCast* check) {
544 VisitInstruction(check);
545 HInstruction* input = check->InputAt(1);
546 if (!input->IsLoadClass()) {
547 AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
548 check->DebugName(),
549 check->GetId(),
550 input->DebugName(),
551 input->GetId()));
552 }
553}
554
555void GraphChecker::VisitInstanceOf(HInstanceOf* instruction) {
556 VisitInstruction(instruction);
557 HInstruction* input = instruction->InputAt(1);
558 if (!input->IsLoadClass()) {
559 AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
560 instruction->DebugName(),
561 instruction->GetId(),
562 input->DebugName(),
563 input->GetId()));
564 }
565}
566
David Brazdilbadd8262016-02-02 16:28:56 +0000567void GraphChecker::HandleLoop(HBasicBlock* loop_header) {
Roland Levillain6b879dd2014-09-22 17:13:44 +0100568 int id = loop_header->GetBlockId();
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100569 HLoopInformation* loop_information = loop_header->GetLoopInformation();
Roland Levillain6b879dd2014-09-22 17:13:44 +0100570
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000571 if (loop_information->GetPreHeader()->GetSuccessors().size() != 1) {
David Brazdildb51efb2015-11-06 01:36:20 +0000572 AddError(StringPrintf(
573 "Loop pre-header %d of loop defined by header %d has %zu successors.",
574 loop_information->GetPreHeader()->GetBlockId(),
575 id,
576 loop_information->GetPreHeader()->GetSuccessors().size()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100577 }
578
Nicolas Geoffray09aa1472016-01-19 10:52:54 +0000579 if (loop_information->GetSuspendCheck() == nullptr) {
580 AddError(StringPrintf(
581 "Loop with header %d does not have a suspend check.",
582 loop_header->GetBlockId()));
583 }
584
585 if (loop_information->GetSuspendCheck() != loop_header->GetFirstInstructionDisregardMoves()) {
586 AddError(StringPrintf(
587 "Loop header %d does not have the loop suspend check as the first instruction.",
588 loop_header->GetBlockId()));
589 }
590
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100591 // Ensure the loop header has only one incoming branch and the remaining
592 // predecessors are back edges.
Vladimir Marko60584552015-09-03 13:35:12 +0000593 size_t num_preds = loop_header->GetPredecessors().size();
Roland Levillain5c4405e2015-01-21 11:39:58 +0000594 if (num_preds < 2) {
595 AddError(StringPrintf(
596 "Loop header %d has less than two predecessors: %zu.",
597 id,
598 num_preds));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100599 } else {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100600 HBasicBlock* first_predecessor = loop_header->GetPredecessors()[0];
David Brazdil46e2a392015-03-16 17:31:52 +0000601 if (loop_information->IsBackEdge(*first_predecessor)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000602 AddError(StringPrintf(
603 "First predecessor of loop header %d is a back edge.",
604 id));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100605 }
Vladimir Marko60584552015-09-03 13:35:12 +0000606 for (size_t i = 1, e = loop_header->GetPredecessors().size(); i < e; ++i) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100607 HBasicBlock* predecessor = loop_header->GetPredecessors()[i];
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100608 if (!loop_information->IsBackEdge(*predecessor)) {
609 AddError(StringPrintf(
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000610 "Loop header %d has multiple incoming (non back edge) blocks: %d.",
611 id,
612 predecessor->GetBlockId()));
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100613 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100614 }
615 }
616
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100617 const ArenaBitVector& loop_blocks = loop_information->GetBlocks();
David Brazdil2d7352b2015-04-20 14:52:42 +0100618
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100619 // Ensure back edges belong to the loop.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100620 if (loop_information->NumberOfBackEdges() == 0) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000621 AddError(StringPrintf(
622 "Loop defined by header %d has no back edge.",
623 id));
David Brazdil2d7352b2015-04-20 14:52:42 +0100624 } else {
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100625 for (HBasicBlock* back_edge : loop_information->GetBackEdges()) {
626 int back_edge_id = back_edge->GetBlockId();
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100627 if (!loop_blocks.IsBitSet(back_edge_id)) {
628 AddError(StringPrintf(
629 "Loop defined by header %d has an invalid back edge %d.",
630 id,
631 back_edge_id));
David Brazdildb51efb2015-11-06 01:36:20 +0000632 } else if (back_edge->GetLoopInformation() != loop_information) {
633 AddError(StringPrintf(
634 "Back edge %d of loop defined by header %d belongs to nested loop "
635 "with header %d.",
636 back_edge_id,
637 id,
638 back_edge->GetLoopInformation()->GetHeader()->GetBlockId()));
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100639 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100640 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100641 }
Roland Levillain7e53b412014-09-23 10:50:22 +0100642
David Brazdil7d275372015-04-21 16:36:35 +0100643 // If this is a nested loop, ensure the outer loops contain a superset of the blocks.
644 for (HLoopInformationOutwardIterator it(*loop_header); !it.Done(); it.Advance()) {
645 HLoopInformation* outer_info = it.Current();
646 if (!loop_blocks.IsSubsetOf(&outer_info->GetBlocks())) {
647 AddError(StringPrintf("Blocks of loop defined by header %d are not a subset of blocks of "
648 "an outer loop defined by header %d.",
David Brazdil2d7352b2015-04-20 14:52:42 +0100649 id,
David Brazdil7d275372015-04-21 16:36:35 +0100650 outer_info->GetHeader()->GetBlockId()));
651 }
652 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000653
654 // Ensure the pre-header block is first in the list of predecessors of a loop
655 // header and that the header block is its only successor.
656 if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
657 AddError(StringPrintf(
658 "Loop pre-header is not the first predecessor of the loop header %d.",
659 id));
660 }
661
662 // Ensure all blocks in the loop are live and dominated by the loop header in
663 // the case of natural loops.
664 for (uint32_t i : loop_blocks.Indexes()) {
665 HBasicBlock* loop_block = GetGraph()->GetBlocks()[i];
666 if (loop_block == nullptr) {
667 AddError(StringPrintf("Loop defined by header %d contains a previously removed block %d.",
668 id,
669 i));
670 } else if (!loop_information->IsIrreducible() && !loop_header->Dominates(loop_block)) {
671 AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
672 i,
673 id));
674 }
675 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100676}
677
Vladimir Markoe9004912016-06-16 16:50:52 +0100678static bool IsSameSizeConstant(const HInstruction* insn1, const HInstruction* insn2) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000679 return insn1->IsConstant()
680 && insn2->IsConstant()
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100681 && DataType::Is64BitType(insn1->GetType()) == DataType::Is64BitType(insn2->GetType());
David Brazdil77a48ae2015-09-15 12:34:04 +0000682}
683
Vladimir Markoe9004912016-06-16 16:50:52 +0100684static bool IsConstantEquivalent(const HInstruction* insn1,
685 const HInstruction* insn2,
686 BitVector* visited) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000687 if (insn1->IsPhi() &&
Vladimir Marko372f10e2016-05-17 16:30:10 +0100688 insn1->AsPhi()->IsVRegEquivalentOf(insn2)) {
Vladimir Markoe9004912016-06-16 16:50:52 +0100689 HConstInputsRef insn1_inputs = insn1->GetInputs();
690 HConstInputsRef insn2_inputs = insn2->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100691 if (insn1_inputs.size() != insn2_inputs.size()) {
692 return false;
693 }
694
David Brazdil77a48ae2015-09-15 12:34:04 +0000695 // Testing only one of the two inputs for recursion is sufficient.
696 if (visited->IsBitSet(insn1->GetId())) {
697 return true;
698 }
699 visited->SetBit(insn1->GetId());
700
Vladimir Marko372f10e2016-05-17 16:30:10 +0100701 for (size_t i = 0; i < insn1_inputs.size(); ++i) {
702 if (!IsConstantEquivalent(insn1_inputs[i], insn2_inputs[i], visited)) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000703 return false;
704 }
705 }
706 return true;
707 } else if (IsSameSizeConstant(insn1, insn2)) {
708 return insn1->AsConstant()->GetValueAsUint64() == insn2->AsConstant()->GetValueAsUint64();
709 } else {
710 return false;
711 }
712}
713
David Brazdilbadd8262016-02-02 16:28:56 +0000714void GraphChecker::VisitPhi(HPhi* phi) {
Roland Levillain6b879dd2014-09-22 17:13:44 +0100715 VisitInstruction(phi);
716
717 // Ensure the first input of a phi is not itself.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100718 ArrayRef<HUserRecord<HInstruction*>> input_records = phi->GetInputRecords();
719 if (input_records[0].GetInstruction() == phi) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000720 AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
721 phi->GetId(),
722 phi->GetBlock()->GetBlockId()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100723 }
724
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000725 // Ensure that the inputs have the same primitive kind as the phi.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100726 for (size_t i = 0; i < input_records.size(); ++i) {
727 HInstruction* input = input_records[i].GetInstruction();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100728 if (DataType::Kind(input->GetType()) != DataType::Kind(phi->GetType())) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000729 AddError(StringPrintf(
730 "Input %d at index %zu of phi %d from block %d does not have the "
Roland Levillaina5c4a402016-03-15 15:02:50 +0000731 "same kind as the phi: %s versus %s",
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000732 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100733 DataType::PrettyDescriptor(input->GetType()),
734 DataType::PrettyDescriptor(phi->GetType())));
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000735 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000736 }
Nicolas Geoffraye0fe7ae2015-03-09 10:02:49 +0000737 if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
738 AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
739 phi->GetId(),
740 phi->GetBlock()->GetBlockId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100741 DataType::PrettyDescriptor(phi->GetType())));
Nicolas Geoffraye0fe7ae2015-03-09 10:02:49 +0000742 }
David Brazdilffee3d32015-07-06 11:48:53 +0100743
744 if (phi->IsCatchPhi()) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100745 // The number of inputs of a catch phi should be the total number of throwing
746 // instructions caught by this catch block. We do not enforce this, however,
747 // because we do not remove the corresponding inputs when we prove that an
748 // instruction cannot throw. Instead, we at least test that all phis have the
749 // same, non-zero number of inputs (b/24054676).
Vladimir Marko372f10e2016-05-17 16:30:10 +0100750 if (input_records.empty()) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100751 AddError(StringPrintf("Phi %d in catch block %d has zero inputs.",
752 phi->GetId(),
753 phi->GetBlock()->GetBlockId()));
754 } else {
755 HInstruction* next_phi = phi->GetNext();
756 if (next_phi != nullptr) {
757 size_t input_count_next = next_phi->InputCount();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100758 if (input_records.size() != input_count_next) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100759 AddError(StringPrintf("Phi %d in catch block %d has %zu inputs, "
760 "but phi %d has %zu inputs.",
761 phi->GetId(),
762 phi->GetBlock()->GetBlockId(),
Vladimir Marko372f10e2016-05-17 16:30:10 +0100763 input_records.size(),
David Brazdil3eaa32f2015-09-18 10:58:32 +0100764 next_phi->GetId(),
765 input_count_next));
766 }
767 }
768 }
David Brazdilffee3d32015-07-06 11:48:53 +0100769 } else {
770 // Ensure the number of inputs of a non-catch phi is the same as the number
771 // of its predecessors.
Vladimir Marko60584552015-09-03 13:35:12 +0000772 const ArenaVector<HBasicBlock*>& predecessors = phi->GetBlock()->GetPredecessors();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100773 if (input_records.size() != predecessors.size()) {
David Brazdilffee3d32015-07-06 11:48:53 +0100774 AddError(StringPrintf(
775 "Phi %d in block %d has %zu inputs, "
776 "but block %d has %zu predecessors.",
Vladimir Marko372f10e2016-05-17 16:30:10 +0100777 phi->GetId(), phi->GetBlock()->GetBlockId(), input_records.size(),
Vladimir Marko60584552015-09-03 13:35:12 +0000778 phi->GetBlock()->GetBlockId(), predecessors.size()));
David Brazdilffee3d32015-07-06 11:48:53 +0100779 } else {
780 // Ensure phi input at index I either comes from the Ith
781 // predecessor or from a block that dominates this predecessor.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100782 for (size_t i = 0; i < input_records.size(); ++i) {
783 HInstruction* input = input_records[i].GetInstruction();
Vladimir Marko60584552015-09-03 13:35:12 +0000784 HBasicBlock* predecessor = predecessors[i];
David Brazdilffee3d32015-07-06 11:48:53 +0100785 if (!(input->GetBlock() == predecessor
786 || input->GetBlock()->Dominates(predecessor))) {
787 AddError(StringPrintf(
788 "Input %d at index %zu of phi %d from block %d is not defined in "
789 "predecessor number %zu nor in a block dominating it.",
790 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
791 i));
792 }
793 }
794 }
795 }
David Brazdil77a48ae2015-09-15 12:34:04 +0000796
797 // Ensure that catch phis are sorted by their vreg number, as required by
798 // the register allocator and code generator. This does not apply to normal
799 // phis which can be constructed artifically.
800 if (phi->IsCatchPhi()) {
801 HInstruction* next_phi = phi->GetNext();
802 if (next_phi != nullptr && phi->GetRegNumber() > next_phi->AsPhi()->GetRegNumber()) {
803 AddError(StringPrintf("Catch phis %d and %d in block %d are not sorted by their "
804 "vreg numbers.",
805 phi->GetId(),
806 next_phi->GetId(),
807 phi->GetBlock()->GetBlockId()));
808 }
809 }
810
Aart Bik3fc7f352015-11-20 22:03:03 -0800811 // Test phi equivalents. There should not be two of the same type and they should only be
812 // created for constants which were untyped in DEX. Note that this test can be skipped for
813 // a synthetic phi (indicated by lack of a virtual register).
814 if (phi->GetRegNumber() != kNoRegNumber) {
Aart Bik4a342772015-11-30 10:17:46 -0800815 for (HInstructionIterator phi_it(phi->GetBlock()->GetPhis());
816 !phi_it.Done();
817 phi_it.Advance()) {
Aart Bik3fc7f352015-11-20 22:03:03 -0800818 HPhi* other_phi = phi_it.Current()->AsPhi();
819 if (phi != other_phi && phi->GetRegNumber() == other_phi->GetRegNumber()) {
820 if (phi->GetType() == other_phi->GetType()) {
821 std::stringstream type_str;
822 type_str << phi->GetType();
823 AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s.",
David Brazdil77a48ae2015-09-15 12:34:04 +0000824 phi->GetId(),
Aart Bik3fc7f352015-11-20 22:03:03 -0800825 phi->GetRegNumber(),
826 type_str.str().c_str()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100827 } else if (phi->GetType() == DataType::Type::kReference) {
Nicolas Geoffrayf5f64ef2015-12-15 14:11:59 +0000828 std::stringstream type_str;
829 type_str << other_phi->GetType();
830 AddError(StringPrintf(
831 "Equivalent non-reference phi (%d) found for VReg %d with type: %s.",
832 phi->GetId(),
833 phi->GetRegNumber(),
834 type_str.str().c_str()));
Aart Bik3fc7f352015-11-20 22:03:03 -0800835 } else {
Vladimir Marko009d1662017-10-10 13:21:15 +0100836 // Use local allocator for allocating memory.
837 ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
Vladimir Marko947eb702016-03-25 15:31:35 +0000838 // If we get here, make sure we allocate all the necessary storage at once
839 // because the BitVector reallocation strategy has very bad worst-case behavior.
Vladimir Marko009d1662017-10-10 13:21:15 +0100840 ArenaBitVector visited(&allocator,
841 GetGraph()->GetCurrentInstructionId(),
842 /* expandable */ false,
843 kArenaAllocGraphChecker);
Vladimir Marko947eb702016-03-25 15:31:35 +0000844 visited.ClearAllBits();
Aart Bik3fc7f352015-11-20 22:03:03 -0800845 if (!IsConstantEquivalent(phi, other_phi, &visited)) {
846 AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they "
847 "are not equivalents of constants.",
848 phi->GetId(),
849 other_phi->GetId(),
850 phi->GetRegNumber()));
851 }
David Brazdil77a48ae2015-09-15 12:34:04 +0000852 }
853 }
854 }
855 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000856}
857
David Brazdilbadd8262016-02-02 16:28:56 +0000858void GraphChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
David Brazdil13b47182015-04-15 16:29:32 +0100859 HInstruction* input = instruction->InputAt(input_index);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000860 if (input->IsIntConstant()) {
David Brazdil13b47182015-04-15 16:29:32 +0100861 int32_t value = input->AsIntConstant()->GetValue();
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000862 if (value != 0 && value != 1) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000863 AddError(StringPrintf(
David Brazdil13b47182015-04-15 16:29:32 +0100864 "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
865 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000866 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100867 static_cast<int>(input_index),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000868 value));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000869 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100870 } else if (DataType::Kind(input->GetType()) != DataType::Type::kInt32) {
David Brazdil11edec72016-03-24 12:40:52 +0000871 // TODO: We need a data-flow analysis to determine if an input like Phi,
872 // Select or a binary operation is actually Boolean. Allow for now.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000873 AddError(StringPrintf(
David Brazdil11edec72016-03-24 12:40:52 +0000874 "%s instruction %d has a non-integer input %d whose type is: %s.",
David Brazdil13b47182015-04-15 16:29:32 +0100875 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000876 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100877 static_cast<int>(input_index),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100878 DataType::PrettyDescriptor(input->GetType())));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000879 }
880}
881
David Brazdilbadd8262016-02-02 16:28:56 +0000882void GraphChecker::VisitPackedSwitch(HPackedSwitch* instruction) {
Mark Mendellfe57faa2015-09-18 09:26:15 -0400883 VisitInstruction(instruction);
884 // Check that the number of block successors matches the switch count plus
885 // one for the default block.
886 HBasicBlock* block = instruction->GetBlock();
887 if (instruction->GetNumEntries() + 1u != block->GetSuccessors().size()) {
888 AddError(StringPrintf(
889 "%s instruction %d in block %d expects %u successors to the block, but found: %zu.",
890 instruction->DebugName(),
891 instruction->GetId(),
892 block->GetBlockId(),
893 instruction->GetNumEntries() + 1u,
894 block->GetSuccessors().size()));
895 }
896}
897
David Brazdilbadd8262016-02-02 16:28:56 +0000898void GraphChecker::VisitIf(HIf* instruction) {
David Brazdil13b47182015-04-15 16:29:32 +0100899 VisitInstruction(instruction);
900 HandleBooleanInput(instruction, 0);
901}
902
David Brazdilbadd8262016-02-02 16:28:56 +0000903void GraphChecker::VisitSelect(HSelect* instruction) {
David Brazdil74eb1b22015-12-14 11:44:01 +0000904 VisitInstruction(instruction);
905 HandleBooleanInput(instruction, 2);
906}
907
David Brazdilbadd8262016-02-02 16:28:56 +0000908void GraphChecker::VisitBooleanNot(HBooleanNot* instruction) {
David Brazdil13b47182015-04-15 16:29:32 +0100909 VisitInstruction(instruction);
910 HandleBooleanInput(instruction, 0);
911}
912
David Brazdilbadd8262016-02-02 16:28:56 +0000913void GraphChecker::VisitCondition(HCondition* op) {
Nicolas Geoffray31596742014-11-24 15:28:45 +0000914 VisitInstruction(op);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100915 if (op->GetType() != DataType::Type::kBool) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000916 AddError(StringPrintf(
917 "Condition %s %d has a non-Boolean result type: %s.",
918 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100919 DataType::PrettyDescriptor(op->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000920 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000921 HInstruction* lhs = op->InputAt(0);
922 HInstruction* rhs = op->InputAt(1);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100923 if (DataType::Kind(lhs->GetType()) != DataType::Kind(rhs->GetType())) {
Calin Juravlea4f88312015-04-16 12:57:19 +0100924 AddError(StringPrintf(
Roland Levillaina5c4a402016-03-15 15:02:50 +0000925 "Condition %s %d has inputs of different kinds: %s, and %s.",
Calin Juravlea4f88312015-04-16 12:57:19 +0100926 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100927 DataType::PrettyDescriptor(lhs->GetType()),
928 DataType::PrettyDescriptor(rhs->GetType())));
Calin Juravlea4f88312015-04-16 12:57:19 +0100929 }
930 if (!op->IsEqual() && !op->IsNotEqual()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100931 if ((lhs->GetType() == DataType::Type::kReference)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000932 AddError(StringPrintf(
933 "Condition %s %d uses an object as left-hand side input.",
934 op->DebugName(), op->GetId()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100935 } else if (rhs->GetType() == DataType::Type::kReference) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000936 AddError(StringPrintf(
937 "Condition %s %d uses an object as right-hand side input.",
938 op->DebugName(), op->GetId()));
Roland Levillainaecbd262015-01-19 12:44:01 +0000939 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000940 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000941}
942
Roland Levillain937e6cd2016-03-22 11:54:37 +0000943void GraphChecker::VisitNeg(HNeg* instruction) {
944 VisitInstruction(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100945 DataType::Type input_type = instruction->InputAt(0)->GetType();
946 DataType::Type result_type = instruction->GetType();
947 if (result_type != DataType::Kind(input_type)) {
Roland Levillain937e6cd2016-03-22 11:54:37 +0000948 AddError(StringPrintf("Binary operation %s %d has a result type different "
949 "from its input kind: %s vs %s.",
950 instruction->DebugName(), instruction->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100951 DataType::PrettyDescriptor(result_type),
952 DataType::PrettyDescriptor(input_type)));
Roland Levillain937e6cd2016-03-22 11:54:37 +0000953 }
954}
955
David Brazdilbadd8262016-02-02 16:28:56 +0000956void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
Nicolas Geoffray31596742014-11-24 15:28:45 +0000957 VisitInstruction(op);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100958 DataType::Type lhs_type = op->InputAt(0)->GetType();
959 DataType::Type rhs_type = op->InputAt(1)->GetType();
960 DataType::Type result_type = op->GetType();
Roland Levillain5b5b9312016-03-22 14:57:31 +0000961
962 // Type consistency between inputs.
Scott Wakeling40a04bf2015-12-11 09:50:36 +0000963 if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100964 if (DataType::Kind(rhs_type) != DataType::Type::kInt32) {
Roland Levillain5b5b9312016-03-22 14:57:31 +0000965 AddError(StringPrintf("Shift/rotate operation %s %d has a non-int kind second input: "
966 "%s of type %s.",
Roland Levillaina5c4a402016-03-15 15:02:50 +0000967 op->DebugName(), op->GetId(),
968 op->InputAt(1)->DebugName(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100969 DataType::PrettyDescriptor(rhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000970 }
971 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100972 if (DataType::Kind(lhs_type) != DataType::Kind(rhs_type)) {
Roland Levillaina5c4a402016-03-15 15:02:50 +0000973 AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.",
974 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100975 DataType::PrettyDescriptor(lhs_type),
976 DataType::PrettyDescriptor(rhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000977 }
978 }
979
Roland Levillain5b5b9312016-03-22 14:57:31 +0000980 // Type consistency between result and input(s).
Nicolas Geoffray31596742014-11-24 15:28:45 +0000981 if (op->IsCompare()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100982 if (result_type != DataType::Type::kInt32) {
Roland Levillaina5c4a402016-03-15 15:02:50 +0000983 AddError(StringPrintf("Compare operation %d has a non-int result type: %s.",
984 op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100985 DataType::PrettyDescriptor(result_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000986 }
Roland Levillain5b5b9312016-03-22 14:57:31 +0000987 } else if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
988 // Only check the first input (value), as the second one (distance)
989 // must invariably be of kind `int`.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100990 if (result_type != DataType::Kind(lhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +0000991 AddError(StringPrintf("Shift/rotate operation %s %d has a result type different "
992 "from its left-hand side (value) input kind: %s vs %s.",
Roland Levillaina5c4a402016-03-15 15:02:50 +0000993 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100994 DataType::PrettyDescriptor(result_type),
995 DataType::PrettyDescriptor(lhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000996 }
Roland Levillain5b5b9312016-03-22 14:57:31 +0000997 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100998 if (DataType::Kind(result_type) != DataType::Kind(lhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +0000999 AddError(StringPrintf("Binary operation %s %d has a result kind different "
1000 "from its left-hand side input kind: %s vs %s.",
1001 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001002 DataType::PrettyDescriptor(result_type),
1003 DataType::PrettyDescriptor(lhs_type)));
Roland Levillain5b5b9312016-03-22 14:57:31 +00001004 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001005 if (DataType::Kind(result_type) != DataType::Kind(rhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00001006 AddError(StringPrintf("Binary operation %s %d has a result kind different "
1007 "from its right-hand side input kind: %s vs %s.",
1008 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001009 DataType::PrettyDescriptor(result_type),
1010 DataType::PrettyDescriptor(rhs_type)));
Roland Levillain5b5b9312016-03-22 14:57:31 +00001011 }
Nicolas Geoffray31596742014-11-24 15:28:45 +00001012 }
1013}
1014
David Brazdilbadd8262016-02-02 16:28:56 +00001015void GraphChecker::VisitConstant(HConstant* instruction) {
David Brazdil8d5b8b22015-03-24 10:51:52 +00001016 HBasicBlock* block = instruction->GetBlock();
1017 if (!block->IsEntryBlock()) {
1018 AddError(StringPrintf(
1019 "%s %d should be in the entry block but is in block %d.",
1020 instruction->DebugName(),
1021 instruction->GetId(),
1022 block->GetBlockId()));
1023 }
1024}
1025
David Brazdilbadd8262016-02-02 16:28:56 +00001026void GraphChecker::VisitBoundType(HBoundType* instruction) {
David Brazdilf5552582015-12-27 13:36:12 +00001027 VisitInstruction(instruction);
1028
David Brazdilf5552582015-12-27 13:36:12 +00001029 if (!instruction->GetUpperBound().IsValid()) {
1030 AddError(StringPrintf(
1031 "%s %d does not have a valid upper bound RTI.",
1032 instruction->DebugName(),
1033 instruction->GetId()));
1034 }
1035}
1036
Roland Levillainf355c3f2016-03-30 19:09:03 +01001037void GraphChecker::VisitTypeConversion(HTypeConversion* instruction) {
1038 VisitInstruction(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001039 DataType::Type result_type = instruction->GetResultType();
1040 DataType::Type input_type = instruction->GetInputType();
Roland Levillainf355c3f2016-03-30 19:09:03 +01001041 // Invariant: We should never generate a conversion to a Boolean value.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001042 if (result_type == DataType::Type::kBool) {
Roland Levillainf355c3f2016-03-30 19:09:03 +01001043 AddError(StringPrintf(
1044 "%s %d converts to a %s (from a %s).",
1045 instruction->DebugName(),
1046 instruction->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001047 DataType::PrettyDescriptor(result_type),
1048 DataType::PrettyDescriptor(input_type)));
Roland Levillainf355c3f2016-03-30 19:09:03 +01001049 }
1050}
1051
Roland Levillainccc07a92014-09-16 14:48:16 +01001052} // namespace art