blob: c88baa8610f5caf5b8e1626a8fab61cc0ac4df3f [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) {
Aart Bika8b8e9b2018-01-09 11:01:02 -080034 // Anything that returns is allowed to jump into the exit block.
35 if (instruction->IsReturn() || instruction->IsReturnVoid()) {
36 return true;
37 }
38 // Anything that always throws is allowed to jump into the exit block.
39 if (instruction->IsGoto() && instruction->GetPrevious() != nullptr) {
40 instruction = instruction->GetPrevious();
41 }
42 return instruction->AlwaysThrows();
David Brazdil86ea7ee2016-02-16 09:26:07 +000043}
44
45static bool IsExitTryBoundaryIntoExitBlock(HBasicBlock* block) {
46 if (!block->IsSingleTryBoundary()) {
47 return false;
48 }
49
50 HTryBoundary* boundary = block->GetLastInstruction()->AsTryBoundary();
51 return block->GetPredecessors().size() == 1u &&
52 boundary->GetNormalFlowSuccessor()->IsExitBlock() &&
53 !boundary->IsEntry();
54}
55
Roland Levillainccc07a92014-09-16 14:48:16 +010056void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
57 current_block_ = block;
58
Vladimir Marko009d1662017-10-10 13:21:15 +010059 // Use local allocator for allocating memory.
60 ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
61
Roland Levillainccc07a92014-09-16 14:48:16 +010062 // Check consistency with respect to predecessors of `block`.
Vladimir Marko0f49c822016-03-22 17:51:29 +000063 // Note: Counting duplicates with a sorted vector uses up to 6x less memory
Vladimir Marko947eb702016-03-25 15:31:35 +000064 // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
Vladimir Marko009d1662017-10-10 13:21:15 +010065 ScopedArenaVector<HBasicBlock*> sorted_predecessors(allocator.Adapter(kArenaAllocGraphChecker));
Vladimir Marko947eb702016-03-25 15:31:35 +000066 sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end());
Vladimir Marko0f49c822016-03-22 17:51:29 +000067 std::sort(sorted_predecessors.begin(), sorted_predecessors.end());
68 for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end; ) {
69 HBasicBlock* p = *it++;
70 size_t p_count_in_block_predecessors = 1u;
71 for (; it != end && *it == p; ++it) {
72 ++p_count_in_block_predecessors;
Vladimir Marko655e5852015-10-12 10:38:28 +010073 }
Vladimir Marko655e5852015-10-12 10:38:28 +010074 size_t block_count_in_p_successors =
75 std::count(p->GetSuccessors().begin(), p->GetSuccessors().end(), block);
Roland Levillainccc07a92014-09-16 14:48:16 +010076 if (p_count_in_block_predecessors != block_count_in_p_successors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +000077 AddError(StringPrintf(
78 "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
79 "block %d lists %zu occurrences of block %d in its successors.",
80 block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(),
81 p->GetBlockId(), block_count_in_p_successors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010082 }
83 }
84
85 // Check consistency with respect to successors of `block`.
Vladimir Marko0f49c822016-03-22 17:51:29 +000086 // Note: Counting duplicates with a sorted vector uses up to 6x less memory
Vladimir Marko947eb702016-03-25 15:31:35 +000087 // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
Vladimir Marko009d1662017-10-10 13:21:15 +010088 ScopedArenaVector<HBasicBlock*> sorted_successors(allocator.Adapter(kArenaAllocGraphChecker));
Vladimir Marko947eb702016-03-25 15:31:35 +000089 sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end());
Vladimir Marko0f49c822016-03-22 17:51:29 +000090 std::sort(sorted_successors.begin(), sorted_successors.end());
91 for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end; ) {
92 HBasicBlock* s = *it++;
93 size_t s_count_in_block_successors = 1u;
94 for (; it != end && *it == s; ++it) {
95 ++s_count_in_block_successors;
Vladimir Marko655e5852015-10-12 10:38:28 +010096 }
Vladimir Marko655e5852015-10-12 10:38:28 +010097 size_t block_count_in_s_predecessors =
98 std::count(s->GetPredecessors().begin(), s->GetPredecessors().end(), block);
Roland Levillainccc07a92014-09-16 14:48:16 +010099 if (s_count_in_block_successors != block_count_in_s_predecessors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000100 AddError(StringPrintf(
101 "Block %d lists %zu occurrences of block %d in its successors, whereas "
102 "block %d lists %zu occurrences of block %d in its predecessors.",
103 block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(),
104 s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100105 }
106 }
107
108 // Ensure `block` ends with a branch instruction.
David Brazdilfc6a86a2015-06-26 10:33:45 +0000109 // This invariant is not enforced on non-SSA graphs. Graph built from DEX with
110 // dead code that falls out of the method will not end with a control-flow
111 // instruction. Such code is removed during the SSA-building DCE phase.
112 if (GetGraph()->IsInSsaForm() && !block->EndsWithControlFlowInstruction()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000113 AddError(StringPrintf("Block %d does not end with a branch instruction.",
114 block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100115 }
116
David Brazdil86ea7ee2016-02-16 09:26:07 +0000117 // Ensure that only Return(Void) and Throw jump to Exit. An exiting TryBoundary
118 // may be between the instructions if the Throw/Return(Void) is in a try block.
David Brazdilb618ade2015-07-29 10:31:29 +0100119 if (block->IsExitBlock()) {
Vladimir Marko60584552015-09-03 13:35:12 +0000120 for (HBasicBlock* predecessor : block->GetPredecessors()) {
David Brazdil86ea7ee2016-02-16 09:26:07 +0000121 HInstruction* last_instruction = IsExitTryBoundaryIntoExitBlock(predecessor) ?
122 predecessor->GetSinglePredecessor()->GetLastInstruction() :
123 predecessor->GetLastInstruction();
124 if (!IsAllowedToJumpToExitBlock(last_instruction)) {
125 AddError(StringPrintf("Unexpected instruction %s:%d jumps into the exit block.",
126 last_instruction->DebugName(),
127 last_instruction->GetId()));
David Brazdilb618ade2015-07-29 10:31:29 +0100128 }
129 }
130 }
131
Roland Levillainccc07a92014-09-16 14:48:16 +0100132 // Visit this block's list of phis.
133 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
David Brazdilc3d743f2015-04-22 13:40:50 +0100134 HInstruction* current = it.Current();
Roland Levillainccc07a92014-09-16 14:48:16 +0100135 // Ensure this block's list of phis contains only phis.
David Brazdilc3d743f2015-04-22 13:40:50 +0100136 if (!current->IsPhi()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000137 AddError(StringPrintf("Block %d has a non-phi in its phi list.",
138 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100139 }
David Brazdilc3d743f2015-04-22 13:40:50 +0100140 if (current->GetNext() == nullptr && current != block->GetLastPhi()) {
141 AddError(StringPrintf("The recorded last phi of block %d does not match "
142 "the actual last phi %d.",
143 current_block_->GetBlockId(),
144 current->GetId()));
145 }
146 current->Accept(this);
Roland Levillainccc07a92014-09-16 14:48:16 +0100147 }
148
149 // Visit this block's list of instructions.
David Brazdilc3d743f2015-04-22 13:40:50 +0100150 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
151 HInstruction* current = it.Current();
Roland Levillainccc07a92014-09-16 14:48:16 +0100152 // Ensure this block's list of instructions does not contains phis.
David Brazdilc3d743f2015-04-22 13:40:50 +0100153 if (current->IsPhi()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000154 AddError(StringPrintf("Block %d has a phi in its non-phi list.",
155 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100156 }
David Brazdilc3d743f2015-04-22 13:40:50 +0100157 if (current->GetNext() == nullptr && current != block->GetLastInstruction()) {
158 AddError(StringPrintf("The recorded last instruction of block %d does not match "
159 "the actual last instruction %d.",
160 current_block_->GetBlockId(),
161 current->GetId()));
162 }
163 current->Accept(this);
Roland Levillainccc07a92014-09-16 14:48:16 +0100164 }
David Brazdilbadd8262016-02-02 16:28:56 +0000165
166 // Ensure that catch blocks are not normal successors, and normal blocks are
167 // never exceptional successors.
168 for (HBasicBlock* successor : block->GetNormalSuccessors()) {
169 if (successor->IsCatchBlock()) {
170 AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
171 successor->GetBlockId(),
172 block->GetBlockId()));
173 }
174 }
175 for (HBasicBlock* successor : block->GetExceptionalSuccessors()) {
176 if (!successor->IsCatchBlock()) {
177 AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
178 successor->GetBlockId(),
179 block->GetBlockId()));
180 }
181 }
182
183 // Ensure dominated blocks have `block` as the dominator.
184 for (HBasicBlock* dominated : block->GetDominatedBlocks()) {
185 if (dominated->GetDominator() != block) {
186 AddError(StringPrintf("Block %d should be the dominator of %d.",
187 block->GetBlockId(),
188 dominated->GetBlockId()));
189 }
190 }
191
192 // Ensure there is no critical edge (i.e., an edge connecting a
193 // block with multiple successors to a block with multiple
194 // predecessors). Exceptional edges are synthesized and hence
195 // not accounted for.
196 if (block->GetSuccessors().size() > 1) {
David Brazdil86ea7ee2016-02-16 09:26:07 +0000197 if (IsExitTryBoundaryIntoExitBlock(block)) {
198 // Allowed critical edge (Throw/Return/ReturnVoid)->TryBoundary->Exit.
199 } else {
200 for (HBasicBlock* successor : block->GetNormalSuccessors()) {
201 if (successor->GetPredecessors().size() > 1) {
202 AddError(StringPrintf("Critical edge between blocks %d and %d.",
203 block->GetBlockId(),
204 successor->GetBlockId()));
205 }
David Brazdilbadd8262016-02-02 16:28:56 +0000206 }
207 }
208 }
209
210 // Ensure try membership information is consistent.
211 if (block->IsCatchBlock()) {
212 if (block->IsTryBlock()) {
213 const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry();
214 AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
215 "has try entry %s:%d.",
216 block->GetBlockId(),
217 try_entry.DebugName(),
218 try_entry.GetId()));
219 }
220
221 if (block->IsLoopHeader()) {
222 AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
223 block->GetBlockId()));
224 }
225 } else {
226 for (HBasicBlock* predecessor : block->GetPredecessors()) {
227 const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
228 if (block->IsTryBlock()) {
229 const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry();
230 if (incoming_try_entry == nullptr) {
231 AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
232 "from predecessor %d.",
233 block->GetBlockId(),
234 stored_try_entry.DebugName(),
235 stored_try_entry.GetId(),
236 predecessor->GetBlockId()));
237 } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) {
238 AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
239 "with %s:%d that follows from predecessor %d.",
240 block->GetBlockId(),
241 stored_try_entry.DebugName(),
242 stored_try_entry.GetId(),
243 incoming_try_entry->DebugName(),
244 incoming_try_entry->GetId(),
245 predecessor->GetBlockId()));
246 }
247 } else if (incoming_try_entry != nullptr) {
248 AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows "
249 "from predecessor %d.",
250 block->GetBlockId(),
251 incoming_try_entry->DebugName(),
252 incoming_try_entry->GetId(),
253 predecessor->GetBlockId()));
254 }
255 }
256 }
257
258 if (block->IsLoopHeader()) {
259 HandleLoop(block);
260 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100261}
262
Mark Mendell1152c922015-04-24 17:06:35 -0400263void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) {
264 if (!GetGraph()->HasBoundsChecks()) {
265 AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, "
266 "but HasBoundsChecks() returns false",
267 check->DebugName(),
268 check->GetId()));
269 }
270
271 // Perform the instruction base checks too.
272 VisitInstruction(check);
273}
274
Nicolas Geoffray93a18c52016-04-22 13:16:14 +0100275void GraphChecker::VisitDeoptimize(HDeoptimize* deopt) {
276 if (GetGraph()->IsCompilingOsr()) {
277 AddError(StringPrintf("A graph compiled OSR cannot have a HDeoptimize instruction"));
278 }
279
280 // Perform the instruction base checks too.
281 VisitInstruction(deopt);
282}
283
David Brazdilffee3d32015-07-06 11:48:53 +0100284void GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) {
David Brazdild26a4112015-11-10 11:07:31 +0000285 ArrayRef<HBasicBlock* const> handlers = try_boundary->GetExceptionHandlers();
286
287 // Ensure that all exception handlers are catch blocks.
David Brazdilffee3d32015-07-06 11:48:53 +0100288 // Note that a normal-flow successor may be a catch block before CFG
David Brazdilbadd8262016-02-02 16:28:56 +0000289 // simplification. We only test normal-flow successors in GraphChecker.
David Brazdild26a4112015-11-10 11:07:31 +0000290 for (HBasicBlock* handler : handlers) {
David Brazdilffee3d32015-07-06 11:48:53 +0100291 if (!handler->IsCatchBlock()) {
292 AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which "
293 "is not a catch block.",
294 current_block_->GetBlockId(),
295 try_boundary->DebugName(),
296 try_boundary->GetId(),
297 handler->GetBlockId()));
298 }
David Brazdild26a4112015-11-10 11:07:31 +0000299 }
300
301 // Ensure that handlers are not listed multiple times.
302 for (size_t i = 0, e = handlers.size(); i < e; ++i) {
David Brazdild8ef0c62015-11-10 18:49:28 +0000303 if (ContainsElement(handlers, handlers[i], i + 1)) {
304 AddError(StringPrintf("Exception handler block %d of %s:%d is listed multiple times.",
David Brazdild26a4112015-11-10 11:07:31 +0000305 handlers[i]->GetBlockId(),
David Brazdilffee3d32015-07-06 11:48:53 +0100306 try_boundary->DebugName(),
307 try_boundary->GetId()));
308 }
309 }
310
311 VisitInstruction(try_boundary);
312}
313
David Brazdil9bc43612015-11-05 21:25:24 +0000314void GraphChecker::VisitLoadException(HLoadException* load) {
315 // Ensure that LoadException is the first instruction in a catch block.
316 if (!load->GetBlock()->IsCatchBlock()) {
317 AddError(StringPrintf("%s:%d is in a non-catch block %d.",
318 load->DebugName(),
319 load->GetId(),
320 load->GetBlock()->GetBlockId()));
321 } else if (load->GetBlock()->GetFirstInstruction() != load) {
322 AddError(StringPrintf("%s:%d is not the first instruction in catch block %d.",
323 load->DebugName(),
324 load->GetId(),
325 load->GetBlock()->GetBlockId()));
326 }
327}
328
Roland Levillainccc07a92014-09-16 14:48:16 +0100329void GraphChecker::VisitInstruction(HInstruction* instruction) {
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000330 if (seen_ids_.IsBitSet(instruction->GetId())) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000331 AddError(StringPrintf("Instruction id %d is duplicate in graph.",
332 instruction->GetId()));
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000333 } else {
334 seen_ids_.SetBit(instruction->GetId());
335 }
336
Roland Levillainccc07a92014-09-16 14:48:16 +0100337 // Ensure `instruction` is associated with `current_block_`.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000338 if (instruction->GetBlock() == nullptr) {
339 AddError(StringPrintf("%s %d in block %d not associated with any block.",
340 instruction->IsPhi() ? "Phi" : "Instruction",
341 instruction->GetId(),
342 current_block_->GetBlockId()));
343 } else if (instruction->GetBlock() != current_block_) {
344 AddError(StringPrintf("%s %d in block %d associated with block %d.",
345 instruction->IsPhi() ? "Phi" : "Instruction",
346 instruction->GetId(),
347 current_block_->GetBlockId(),
348 instruction->GetBlock()->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100349 }
Roland Levillain6b469232014-09-25 10:10:38 +0100350
351 // Ensure the inputs of `instruction` are defined in a block of the graph.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100352 for (HInstruction* input : instruction->GetInputs()) {
Igor Murashkind01745e2017-04-05 16:40:31 -0700353 if (input->GetBlock() == nullptr) {
354 AddError(StringPrintf("Input %d of instruction %d is not in any "
355 "basic block of the control-flow graph.",
356 input->GetId(),
357 instruction->GetId()));
Igor Murashkin4ae432d2017-05-04 14:15:08 -0700358 } else {
359 const HInstructionList& list = input->IsPhi()
360 ? input->GetBlock()->GetPhis()
361 : input->GetBlock()->GetInstructions();
362 if (!list.Contains(input)) {
363 AddError(StringPrintf("Input %d of instruction %d is not defined "
364 "in a basic block of the control-flow graph.",
365 input->GetId(),
366 instruction->GetId()));
367 }
Roland Levillain6b469232014-09-25 10:10:38 +0100368 }
369 }
370
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100371 // Ensure the uses of `instruction` are defined in a block of the graph,
372 // and the entry in the use list is consistent.
Vladimir Marko46817b82016-03-29 12:21:58 +0100373 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
374 HInstruction* user = use.GetUser();
375 const HInstructionList& list = user->IsPhi()
376 ? user->GetBlock()->GetPhis()
377 : user->GetBlock()->GetInstructions();
378 if (!list.Contains(user)) {
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000379 AddError(StringPrintf("User %s:%d of instruction %d is not defined "
Roland Levillain5c4405e2015-01-21 11:39:58 +0000380 "in a basic block of the control-flow graph.",
Vladimir Marko46817b82016-03-29 12:21:58 +0100381 user->DebugName(),
382 user->GetId(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000383 instruction->GetId()));
Roland Levillain6b469232014-09-25 10:10:38 +0100384 }
Vladimir Marko46817b82016-03-29 12:21:58 +0100385 size_t use_index = use.GetIndex();
Vladimir Markoe9004912016-06-16 16:50:52 +0100386 HConstInputsRef user_inputs = user->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100387 if ((use_index >= user_inputs.size()) || (user_inputs[use_index] != instruction)) {
Vladimir Markob554b5a2015-11-06 12:57:55 +0000388 AddError(StringPrintf("User %s:%d of instruction %s:%d has a wrong "
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100389 "UseListNode index.",
Vladimir Marko46817b82016-03-29 12:21:58 +0100390 user->DebugName(),
391 user->GetId(),
Vladimir Markob554b5a2015-11-06 12:57:55 +0000392 instruction->DebugName(),
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100393 instruction->GetId()));
394 }
395 }
396
397 // Ensure the environment uses entries are consistent.
Vladimir Marko46817b82016-03-29 12:21:58 +0100398 for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
399 HEnvironment* user = use.GetUser();
400 size_t use_index = use.GetIndex();
401 if ((use_index >= user->Size()) || (user->GetInstructionAt(use_index) != instruction)) {
Nicolas Geoffray5d7b7f82015-04-28 00:52:43 +0100402 AddError(StringPrintf("Environment user of %s:%d has a wrong "
403 "UseListNode index.",
404 instruction->DebugName(),
405 instruction->GetId()));
406 }
Roland Levillain6b469232014-09-25 10:10:38 +0100407 }
David Brazdil1abb4192015-02-17 18:33:36 +0000408
409 // Ensure 'instruction' has pointers to its inputs' use entries.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100410 auto&& input_records = instruction->GetInputRecords();
411 for (size_t i = 0; i < input_records.size(); ++i) {
412 const HUserRecord<HInstruction*>& input_record = input_records[i];
David Brazdil1abb4192015-02-17 18:33:36 +0000413 HInstruction* input = input_record.GetInstruction();
Vladimir Marko46817b82016-03-29 12:21:58 +0100414 if ((input_record.GetBeforeUseNode() == input->GetUses().end()) ||
415 (input_record.GetUseNode() == input->GetUses().end()) ||
416 !input->GetUses().ContainsNode(*input_record.GetUseNode()) ||
417 (input_record.GetUseNode()->GetIndex() != i)) {
418 AddError(StringPrintf("Instruction %s:%d has an invalid iterator before use entry "
David Brazdil1abb4192015-02-17 18:33:36 +0000419 "at input %u (%s:%d).",
420 instruction->DebugName(),
421 instruction->GetId(),
422 static_cast<unsigned>(i),
423 input->DebugName(),
424 input->GetId()));
425 }
426 }
David Brazdilbadd8262016-02-02 16:28:56 +0000427
428 // Ensure an instruction dominates all its uses.
Vladimir Marko46817b82016-03-29 12:21:58 +0100429 for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
430 HInstruction* user = use.GetUser();
431 if (!user->IsPhi() && !instruction->StrictlyDominates(user)) {
David Brazdilbadd8262016-02-02 16:28:56 +0000432 AddError(StringPrintf("Instruction %s:%d in block %d does not dominate "
433 "use %s:%d in block %d.",
434 instruction->DebugName(),
435 instruction->GetId(),
436 current_block_->GetBlockId(),
Vladimir Marko46817b82016-03-29 12:21:58 +0100437 user->DebugName(),
438 user->GetId(),
439 user->GetBlock()->GetBlockId()));
David Brazdilbadd8262016-02-02 16:28:56 +0000440 }
441 }
442
443 if (instruction->NeedsEnvironment() && !instruction->HasEnvironment()) {
444 AddError(StringPrintf("Instruction %s:%d in block %d requires an environment "
445 "but does not have one.",
446 instruction->DebugName(),
447 instruction->GetId(),
448 current_block_->GetBlockId()));
449 }
450
451 // Ensure an instruction having an environment is dominated by the
452 // instructions contained in the environment.
453 for (HEnvironment* environment = instruction->GetEnvironment();
454 environment != nullptr;
455 environment = environment->GetParent()) {
456 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
457 HInstruction* env_instruction = environment->GetInstructionAt(i);
458 if (env_instruction != nullptr
459 && !env_instruction->StrictlyDominates(instruction)) {
460 AddError(StringPrintf("Instruction %d in environment of instruction %d "
461 "from block %d does not dominate instruction %d.",
462 env_instruction->GetId(),
463 instruction->GetId(),
464 current_block_->GetBlockId(),
465 instruction->GetId()));
466 }
467 }
468 }
469
470 // Ensure that reference type instructions have reference type info.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100471 if (instruction->GetType() == DataType::Type::kReference) {
David Brazdilbadd8262016-02-02 16:28:56 +0000472 if (!instruction->GetReferenceTypeInfo().IsValid()) {
473 AddError(StringPrintf("Reference type instruction %s:%d does not have "
474 "valid reference type information.",
475 instruction->DebugName(),
476 instruction->GetId()));
477 }
478 }
479
480 if (instruction->CanThrowIntoCatchBlock()) {
481 // Find the top-level environment. This corresponds to the environment of
482 // the catch block since we do not inline methods with try/catch.
483 HEnvironment* environment = instruction->GetEnvironment();
484 while (environment->GetParent() != nullptr) {
485 environment = environment->GetParent();
486 }
487
488 // Find all catch blocks and test that `instruction` has an environment
489 // value for each one.
490 const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
491 for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) {
492 for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
493 HPhi* catch_phi = phi_it.Current()->AsPhi();
494 if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) {
495 AddError(StringPrintf("Instruction %s:%d throws into catch block %d "
496 "with catch phi %d for vreg %d but its "
497 "corresponding environment slot is empty.",
498 instruction->DebugName(),
499 instruction->GetId(),
500 catch_block->GetBlockId(),
501 catch_phi->GetId(),
502 catch_phi->GetRegNumber()));
503 }
504 }
505 }
506 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100507}
508
Roland Levillain4c0eb422015-04-24 16:43:49 +0100509void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
510 VisitInstruction(invoke);
511
512 if (invoke->IsStaticWithExplicitClinitCheck()) {
Vladimir Markoe9004912016-06-16 16:50:52 +0100513 const HInstruction* last_input = invoke->GetInputs().back();
Roland Levillain4c0eb422015-04-24 16:43:49 +0100514 if (last_input == nullptr) {
515 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
516 "has a null pointer as last input.",
517 invoke->DebugName(),
518 invoke->GetId()));
George Burgess IV72155d22017-04-25 15:17:16 -0700519 } else if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100520 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
521 "has a last instruction (%s:%d) which is neither a clinit check "
522 "nor a load class instruction.",
523 invoke->DebugName(),
524 invoke->GetId(),
525 last_input->DebugName(),
526 last_input->GetId()));
527 }
528 }
529}
530
David Brazdilfc6a86a2015-06-26 10:33:45 +0000531void GraphChecker::VisitReturn(HReturn* ret) {
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100532 VisitInstruction(ret);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000533 HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
534 if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
David Brazdilfc6a86a2015-06-26 10:33:45 +0000535 AddError(StringPrintf("%s:%d does not jump to the exit block.",
536 ret->DebugName(),
537 ret->GetId()));
538 }
539}
540
541void GraphChecker::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100542 VisitInstruction(ret);
David Brazdil86ea7ee2016-02-16 09:26:07 +0000543 HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
544 if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
David Brazdilfc6a86a2015-06-26 10:33:45 +0000545 AddError(StringPrintf("%s:%d does not jump to the exit block.",
546 ret->DebugName(),
547 ret->GetId()));
548 }
549}
550
Nicolas Geoffraybff7a522018-01-25 13:33:07 +0000551void GraphChecker::VisitCheckCast(HCheckCast* check) {
Vladimir Markoeb0ebed2018-01-10 18:26:38 +0000552 VisitInstruction(check);
553 HInstruction* input = check->InputAt(1);
Nicolas Geoffraybff7a522018-01-25 13:33:07 +0000554 if (!input->IsLoadClass()) {
555 AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
556 check->DebugName(),
557 check->GetId(),
558 input->DebugName(),
559 input->GetId()));
Nicolas Geoffrayf9a19952015-06-29 13:43:54 +0100560 }
561}
562
Vladimir Markoeb0ebed2018-01-10 18:26:38 +0000563void GraphChecker::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffraybff7a522018-01-25 13:33:07 +0000564 VisitInstruction(instruction);
565 HInstruction* input = instruction->InputAt(1);
566 if (!input->IsLoadClass()) {
567 AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
568 instruction->DebugName(),
569 instruction->GetId(),
570 input->DebugName(),
571 input->GetId()));
572 }
Vladimir Markoeb0ebed2018-01-10 18:26:38 +0000573}
574
David Brazdilbadd8262016-02-02 16:28:56 +0000575void GraphChecker::HandleLoop(HBasicBlock* loop_header) {
Roland Levillain6b879dd2014-09-22 17:13:44 +0100576 int id = loop_header->GetBlockId();
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100577 HLoopInformation* loop_information = loop_header->GetLoopInformation();
Roland Levillain6b879dd2014-09-22 17:13:44 +0100578
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000579 if (loop_information->GetPreHeader()->GetSuccessors().size() != 1) {
David Brazdildb51efb2015-11-06 01:36:20 +0000580 AddError(StringPrintf(
581 "Loop pre-header %d of loop defined by header %d has %zu successors.",
582 loop_information->GetPreHeader()->GetBlockId(),
583 id,
584 loop_information->GetPreHeader()->GetSuccessors().size()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100585 }
586
Nicolas Geoffray09aa1472016-01-19 10:52:54 +0000587 if (loop_information->GetSuspendCheck() == nullptr) {
588 AddError(StringPrintf(
589 "Loop with header %d does not have a suspend check.",
590 loop_header->GetBlockId()));
591 }
592
593 if (loop_information->GetSuspendCheck() != loop_header->GetFirstInstructionDisregardMoves()) {
594 AddError(StringPrintf(
595 "Loop header %d does not have the loop suspend check as the first instruction.",
596 loop_header->GetBlockId()));
597 }
598
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100599 // Ensure the loop header has only one incoming branch and the remaining
600 // predecessors are back edges.
Vladimir Marko60584552015-09-03 13:35:12 +0000601 size_t num_preds = loop_header->GetPredecessors().size();
Roland Levillain5c4405e2015-01-21 11:39:58 +0000602 if (num_preds < 2) {
603 AddError(StringPrintf(
604 "Loop header %d has less than two predecessors: %zu.",
605 id,
606 num_preds));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100607 } else {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100608 HBasicBlock* first_predecessor = loop_header->GetPredecessors()[0];
David Brazdil46e2a392015-03-16 17:31:52 +0000609 if (loop_information->IsBackEdge(*first_predecessor)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000610 AddError(StringPrintf(
611 "First predecessor of loop header %d is a back edge.",
612 id));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100613 }
Vladimir Marko60584552015-09-03 13:35:12 +0000614 for (size_t i = 1, e = loop_header->GetPredecessors().size(); i < e; ++i) {
Vladimir Markoec7802a2015-10-01 20:57:57 +0100615 HBasicBlock* predecessor = loop_header->GetPredecessors()[i];
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100616 if (!loop_information->IsBackEdge(*predecessor)) {
617 AddError(StringPrintf(
Nicolas Geoffray916cc1d2016-02-18 11:12:31 +0000618 "Loop header %d has multiple incoming (non back edge) blocks: %d.",
619 id,
620 predecessor->GetBlockId()));
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100621 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100622 }
623 }
624
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100625 const ArenaBitVector& loop_blocks = loop_information->GetBlocks();
David Brazdil2d7352b2015-04-20 14:52:42 +0100626
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100627 // Ensure back edges belong to the loop.
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100628 if (loop_information->NumberOfBackEdges() == 0) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000629 AddError(StringPrintf(
630 "Loop defined by header %d has no back edge.",
631 id));
David Brazdil2d7352b2015-04-20 14:52:42 +0100632 } else {
Vladimir Markofa6b93c2015-09-15 10:15:55 +0100633 for (HBasicBlock* back_edge : loop_information->GetBackEdges()) {
634 int back_edge_id = back_edge->GetBlockId();
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100635 if (!loop_blocks.IsBitSet(back_edge_id)) {
636 AddError(StringPrintf(
637 "Loop defined by header %d has an invalid back edge %d.",
638 id,
639 back_edge_id));
David Brazdildb51efb2015-11-06 01:36:20 +0000640 } else if (back_edge->GetLoopInformation() != loop_information) {
641 AddError(StringPrintf(
642 "Back edge %d of loop defined by header %d belongs to nested loop "
643 "with header %d.",
644 back_edge_id,
645 id,
646 back_edge->GetLoopInformation()->GetHeader()->GetBlockId()));
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100647 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100648 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100649 }
Roland Levillain7e53b412014-09-23 10:50:22 +0100650
David Brazdil7d275372015-04-21 16:36:35 +0100651 // If this is a nested loop, ensure the outer loops contain a superset of the blocks.
652 for (HLoopInformationOutwardIterator it(*loop_header); !it.Done(); it.Advance()) {
653 HLoopInformation* outer_info = it.Current();
654 if (!loop_blocks.IsSubsetOf(&outer_info->GetBlocks())) {
655 AddError(StringPrintf("Blocks of loop defined by header %d are not a subset of blocks of "
656 "an outer loop defined by header %d.",
David Brazdil2d7352b2015-04-20 14:52:42 +0100657 id,
David Brazdil7d275372015-04-21 16:36:35 +0100658 outer_info->GetHeader()->GetBlockId()));
659 }
660 }
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000661
662 // Ensure the pre-header block is first in the list of predecessors of a loop
663 // header and that the header block is its only successor.
664 if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
665 AddError(StringPrintf(
666 "Loop pre-header is not the first predecessor of the loop header %d.",
667 id));
668 }
669
670 // Ensure all blocks in the loop are live and dominated by the loop header in
671 // the case of natural loops.
672 for (uint32_t i : loop_blocks.Indexes()) {
673 HBasicBlock* loop_block = GetGraph()->GetBlocks()[i];
674 if (loop_block == nullptr) {
675 AddError(StringPrintf("Loop defined by header %d contains a previously removed block %d.",
676 id,
677 i));
678 } else if (!loop_information->IsIrreducible() && !loop_header->Dominates(loop_block)) {
679 AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
680 i,
681 id));
682 }
683 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100684}
685
Vladimir Markoe9004912016-06-16 16:50:52 +0100686static bool IsSameSizeConstant(const HInstruction* insn1, const HInstruction* insn2) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000687 return insn1->IsConstant()
688 && insn2->IsConstant()
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100689 && DataType::Is64BitType(insn1->GetType()) == DataType::Is64BitType(insn2->GetType());
David Brazdil77a48ae2015-09-15 12:34:04 +0000690}
691
Vladimir Markoe9004912016-06-16 16:50:52 +0100692static bool IsConstantEquivalent(const HInstruction* insn1,
693 const HInstruction* insn2,
694 BitVector* visited) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000695 if (insn1->IsPhi() &&
Vladimir Marko372f10e2016-05-17 16:30:10 +0100696 insn1->AsPhi()->IsVRegEquivalentOf(insn2)) {
Vladimir Markoe9004912016-06-16 16:50:52 +0100697 HConstInputsRef insn1_inputs = insn1->GetInputs();
698 HConstInputsRef insn2_inputs = insn2->GetInputs();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100699 if (insn1_inputs.size() != insn2_inputs.size()) {
700 return false;
701 }
702
David Brazdil77a48ae2015-09-15 12:34:04 +0000703 // Testing only one of the two inputs for recursion is sufficient.
704 if (visited->IsBitSet(insn1->GetId())) {
705 return true;
706 }
707 visited->SetBit(insn1->GetId());
708
Vladimir Marko372f10e2016-05-17 16:30:10 +0100709 for (size_t i = 0; i < insn1_inputs.size(); ++i) {
710 if (!IsConstantEquivalent(insn1_inputs[i], insn2_inputs[i], visited)) {
David Brazdil77a48ae2015-09-15 12:34:04 +0000711 return false;
712 }
713 }
714 return true;
715 } else if (IsSameSizeConstant(insn1, insn2)) {
716 return insn1->AsConstant()->GetValueAsUint64() == insn2->AsConstant()->GetValueAsUint64();
717 } else {
718 return false;
719 }
720}
721
David Brazdilbadd8262016-02-02 16:28:56 +0000722void GraphChecker::VisitPhi(HPhi* phi) {
Roland Levillain6b879dd2014-09-22 17:13:44 +0100723 VisitInstruction(phi);
724
725 // Ensure the first input of a phi is not itself.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100726 ArrayRef<HUserRecord<HInstruction*>> input_records = phi->GetInputRecords();
727 if (input_records[0].GetInstruction() == phi) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000728 AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
729 phi->GetId(),
730 phi->GetBlock()->GetBlockId()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100731 }
732
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000733 // Ensure that the inputs have the same primitive kind as the phi.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100734 for (size_t i = 0; i < input_records.size(); ++i) {
735 HInstruction* input = input_records[i].GetInstruction();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100736 if (DataType::Kind(input->GetType()) != DataType::Kind(phi->GetType())) {
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000737 AddError(StringPrintf(
738 "Input %d at index %zu of phi %d from block %d does not have the "
Roland Levillaina5c4a402016-03-15 15:02:50 +0000739 "same kind as the phi: %s versus %s",
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000740 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100741 DataType::PrettyDescriptor(input->GetType()),
742 DataType::PrettyDescriptor(phi->GetType())));
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000743 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000744 }
Nicolas Geoffraye0fe7ae2015-03-09 10:02:49 +0000745 if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
746 AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
747 phi->GetId(),
748 phi->GetBlock()->GetBlockId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100749 DataType::PrettyDescriptor(phi->GetType())));
Nicolas Geoffraye0fe7ae2015-03-09 10:02:49 +0000750 }
David Brazdilffee3d32015-07-06 11:48:53 +0100751
752 if (phi->IsCatchPhi()) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100753 // The number of inputs of a catch phi should be the total number of throwing
754 // instructions caught by this catch block. We do not enforce this, however,
755 // because we do not remove the corresponding inputs when we prove that an
756 // instruction cannot throw. Instead, we at least test that all phis have the
757 // same, non-zero number of inputs (b/24054676).
Vladimir Marko372f10e2016-05-17 16:30:10 +0100758 if (input_records.empty()) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100759 AddError(StringPrintf("Phi %d in catch block %d has zero inputs.",
760 phi->GetId(),
761 phi->GetBlock()->GetBlockId()));
762 } else {
763 HInstruction* next_phi = phi->GetNext();
764 if (next_phi != nullptr) {
765 size_t input_count_next = next_phi->InputCount();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100766 if (input_records.size() != input_count_next) {
David Brazdil3eaa32f2015-09-18 10:58:32 +0100767 AddError(StringPrintf("Phi %d in catch block %d has %zu inputs, "
768 "but phi %d has %zu inputs.",
769 phi->GetId(),
770 phi->GetBlock()->GetBlockId(),
Vladimir Marko372f10e2016-05-17 16:30:10 +0100771 input_records.size(),
David Brazdil3eaa32f2015-09-18 10:58:32 +0100772 next_phi->GetId(),
773 input_count_next));
774 }
775 }
776 }
David Brazdilffee3d32015-07-06 11:48:53 +0100777 } else {
778 // Ensure the number of inputs of a non-catch phi is the same as the number
779 // of its predecessors.
Vladimir Marko60584552015-09-03 13:35:12 +0000780 const ArenaVector<HBasicBlock*>& predecessors = phi->GetBlock()->GetPredecessors();
Vladimir Marko372f10e2016-05-17 16:30:10 +0100781 if (input_records.size() != predecessors.size()) {
David Brazdilffee3d32015-07-06 11:48:53 +0100782 AddError(StringPrintf(
783 "Phi %d in block %d has %zu inputs, "
784 "but block %d has %zu predecessors.",
Vladimir Marko372f10e2016-05-17 16:30:10 +0100785 phi->GetId(), phi->GetBlock()->GetBlockId(), input_records.size(),
Vladimir Marko60584552015-09-03 13:35:12 +0000786 phi->GetBlock()->GetBlockId(), predecessors.size()));
David Brazdilffee3d32015-07-06 11:48:53 +0100787 } else {
788 // Ensure phi input at index I either comes from the Ith
789 // predecessor or from a block that dominates this predecessor.
Vladimir Marko372f10e2016-05-17 16:30:10 +0100790 for (size_t i = 0; i < input_records.size(); ++i) {
791 HInstruction* input = input_records[i].GetInstruction();
Vladimir Marko60584552015-09-03 13:35:12 +0000792 HBasicBlock* predecessor = predecessors[i];
David Brazdilffee3d32015-07-06 11:48:53 +0100793 if (!(input->GetBlock() == predecessor
794 || input->GetBlock()->Dominates(predecessor))) {
795 AddError(StringPrintf(
796 "Input %d at index %zu of phi %d from block %d is not defined in "
797 "predecessor number %zu nor in a block dominating it.",
798 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
799 i));
800 }
801 }
802 }
803 }
David Brazdil77a48ae2015-09-15 12:34:04 +0000804
805 // Ensure that catch phis are sorted by their vreg number, as required by
806 // the register allocator and code generator. This does not apply to normal
807 // phis which can be constructed artifically.
808 if (phi->IsCatchPhi()) {
809 HInstruction* next_phi = phi->GetNext();
810 if (next_phi != nullptr && phi->GetRegNumber() > next_phi->AsPhi()->GetRegNumber()) {
811 AddError(StringPrintf("Catch phis %d and %d in block %d are not sorted by their "
812 "vreg numbers.",
813 phi->GetId(),
814 next_phi->GetId(),
815 phi->GetBlock()->GetBlockId()));
816 }
817 }
818
Aart Bik3fc7f352015-11-20 22:03:03 -0800819 // Test phi equivalents. There should not be two of the same type and they should only be
820 // created for constants which were untyped in DEX. Note that this test can be skipped for
821 // a synthetic phi (indicated by lack of a virtual register).
822 if (phi->GetRegNumber() != kNoRegNumber) {
Aart Bik4a342772015-11-30 10:17:46 -0800823 for (HInstructionIterator phi_it(phi->GetBlock()->GetPhis());
824 !phi_it.Done();
825 phi_it.Advance()) {
Aart Bik3fc7f352015-11-20 22:03:03 -0800826 HPhi* other_phi = phi_it.Current()->AsPhi();
827 if (phi != other_phi && phi->GetRegNumber() == other_phi->GetRegNumber()) {
828 if (phi->GetType() == other_phi->GetType()) {
829 std::stringstream type_str;
830 type_str << phi->GetType();
831 AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s.",
David Brazdil77a48ae2015-09-15 12:34:04 +0000832 phi->GetId(),
Aart Bik3fc7f352015-11-20 22:03:03 -0800833 phi->GetRegNumber(),
834 type_str.str().c_str()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100835 } else if (phi->GetType() == DataType::Type::kReference) {
Nicolas Geoffrayf5f64ef2015-12-15 14:11:59 +0000836 std::stringstream type_str;
837 type_str << other_phi->GetType();
838 AddError(StringPrintf(
839 "Equivalent non-reference phi (%d) found for VReg %d with type: %s.",
840 phi->GetId(),
841 phi->GetRegNumber(),
842 type_str.str().c_str()));
Aart Bik3fc7f352015-11-20 22:03:03 -0800843 } else {
Vladimir Marko009d1662017-10-10 13:21:15 +0100844 // Use local allocator for allocating memory.
845 ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
Vladimir Marko947eb702016-03-25 15:31:35 +0000846 // If we get here, make sure we allocate all the necessary storage at once
847 // because the BitVector reallocation strategy has very bad worst-case behavior.
Vladimir Marko009d1662017-10-10 13:21:15 +0100848 ArenaBitVector visited(&allocator,
849 GetGraph()->GetCurrentInstructionId(),
850 /* expandable */ false,
851 kArenaAllocGraphChecker);
Vladimir Marko947eb702016-03-25 15:31:35 +0000852 visited.ClearAllBits();
Aart Bik3fc7f352015-11-20 22:03:03 -0800853 if (!IsConstantEquivalent(phi, other_phi, &visited)) {
854 AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they "
855 "are not equivalents of constants.",
856 phi->GetId(),
857 other_phi->GetId(),
858 phi->GetRegNumber()));
859 }
David Brazdil77a48ae2015-09-15 12:34:04 +0000860 }
861 }
862 }
863 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000864}
865
David Brazdilbadd8262016-02-02 16:28:56 +0000866void GraphChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
David Brazdil13b47182015-04-15 16:29:32 +0100867 HInstruction* input = instruction->InputAt(input_index);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000868 if (input->IsIntConstant()) {
David Brazdil13b47182015-04-15 16:29:32 +0100869 int32_t value = input->AsIntConstant()->GetValue();
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000870 if (value != 0 && value != 1) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000871 AddError(StringPrintf(
David Brazdil13b47182015-04-15 16:29:32 +0100872 "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
873 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000874 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100875 static_cast<int>(input_index),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000876 value));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000877 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100878 } else if (DataType::Kind(input->GetType()) != DataType::Type::kInt32) {
David Brazdil11edec72016-03-24 12:40:52 +0000879 // TODO: We need a data-flow analysis to determine if an input like Phi,
880 // Select or a binary operation is actually Boolean. Allow for now.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000881 AddError(StringPrintf(
David Brazdil11edec72016-03-24 12:40:52 +0000882 "%s instruction %d has a non-integer input %d whose type is: %s.",
David Brazdil13b47182015-04-15 16:29:32 +0100883 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000884 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100885 static_cast<int>(input_index),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100886 DataType::PrettyDescriptor(input->GetType())));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000887 }
888}
889
David Brazdilbadd8262016-02-02 16:28:56 +0000890void GraphChecker::VisitPackedSwitch(HPackedSwitch* instruction) {
Mark Mendellfe57faa2015-09-18 09:26:15 -0400891 VisitInstruction(instruction);
892 // Check that the number of block successors matches the switch count plus
893 // one for the default block.
894 HBasicBlock* block = instruction->GetBlock();
895 if (instruction->GetNumEntries() + 1u != block->GetSuccessors().size()) {
896 AddError(StringPrintf(
897 "%s instruction %d in block %d expects %u successors to the block, but found: %zu.",
898 instruction->DebugName(),
899 instruction->GetId(),
900 block->GetBlockId(),
901 instruction->GetNumEntries() + 1u,
902 block->GetSuccessors().size()));
903 }
904}
905
David Brazdilbadd8262016-02-02 16:28:56 +0000906void GraphChecker::VisitIf(HIf* instruction) {
David Brazdil13b47182015-04-15 16:29:32 +0100907 VisitInstruction(instruction);
908 HandleBooleanInput(instruction, 0);
909}
910
David Brazdilbadd8262016-02-02 16:28:56 +0000911void GraphChecker::VisitSelect(HSelect* instruction) {
David Brazdil74eb1b22015-12-14 11:44:01 +0000912 VisitInstruction(instruction);
913 HandleBooleanInput(instruction, 2);
914}
915
David Brazdilbadd8262016-02-02 16:28:56 +0000916void GraphChecker::VisitBooleanNot(HBooleanNot* instruction) {
David Brazdil13b47182015-04-15 16:29:32 +0100917 VisitInstruction(instruction);
918 HandleBooleanInput(instruction, 0);
919}
920
David Brazdilbadd8262016-02-02 16:28:56 +0000921void GraphChecker::VisitCondition(HCondition* op) {
Nicolas Geoffray31596742014-11-24 15:28:45 +0000922 VisitInstruction(op);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100923 if (op->GetType() != DataType::Type::kBool) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000924 AddError(StringPrintf(
925 "Condition %s %d has a non-Boolean result type: %s.",
926 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100927 DataType::PrettyDescriptor(op->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000928 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000929 HInstruction* lhs = op->InputAt(0);
930 HInstruction* rhs = op->InputAt(1);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100931 if (DataType::Kind(lhs->GetType()) != DataType::Kind(rhs->GetType())) {
Calin Juravlea4f88312015-04-16 12:57:19 +0100932 AddError(StringPrintf(
Roland Levillaina5c4a402016-03-15 15:02:50 +0000933 "Condition %s %d has inputs of different kinds: %s, and %s.",
Calin Juravlea4f88312015-04-16 12:57:19 +0100934 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100935 DataType::PrettyDescriptor(lhs->GetType()),
936 DataType::PrettyDescriptor(rhs->GetType())));
Calin Juravlea4f88312015-04-16 12:57:19 +0100937 }
938 if (!op->IsEqual() && !op->IsNotEqual()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100939 if ((lhs->GetType() == DataType::Type::kReference)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000940 AddError(StringPrintf(
941 "Condition %s %d uses an object as left-hand side input.",
942 op->DebugName(), op->GetId()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100943 } else if (rhs->GetType() == DataType::Type::kReference) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000944 AddError(StringPrintf(
945 "Condition %s %d uses an object as right-hand side input.",
946 op->DebugName(), op->GetId()));
Roland Levillainaecbd262015-01-19 12:44:01 +0000947 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000948 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000949}
950
Roland Levillain937e6cd2016-03-22 11:54:37 +0000951void GraphChecker::VisitNeg(HNeg* instruction) {
952 VisitInstruction(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100953 DataType::Type input_type = instruction->InputAt(0)->GetType();
954 DataType::Type result_type = instruction->GetType();
955 if (result_type != DataType::Kind(input_type)) {
Roland Levillain937e6cd2016-03-22 11:54:37 +0000956 AddError(StringPrintf("Binary operation %s %d has a result type different "
957 "from its input kind: %s vs %s.",
958 instruction->DebugName(), instruction->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100959 DataType::PrettyDescriptor(result_type),
960 DataType::PrettyDescriptor(input_type)));
Roland Levillain937e6cd2016-03-22 11:54:37 +0000961 }
962}
963
David Brazdilbadd8262016-02-02 16:28:56 +0000964void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
Nicolas Geoffray31596742014-11-24 15:28:45 +0000965 VisitInstruction(op);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100966 DataType::Type lhs_type = op->InputAt(0)->GetType();
967 DataType::Type rhs_type = op->InputAt(1)->GetType();
968 DataType::Type result_type = op->GetType();
Roland Levillain5b5b9312016-03-22 14:57:31 +0000969
970 // Type consistency between inputs.
Scott Wakeling40a04bf2015-12-11 09:50:36 +0000971 if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100972 if (DataType::Kind(rhs_type) != DataType::Type::kInt32) {
Roland Levillain5b5b9312016-03-22 14:57:31 +0000973 AddError(StringPrintf("Shift/rotate operation %s %d has a non-int kind second input: "
974 "%s of type %s.",
Roland Levillaina5c4a402016-03-15 15:02:50 +0000975 op->DebugName(), op->GetId(),
976 op->InputAt(1)->DebugName(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100977 DataType::PrettyDescriptor(rhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000978 }
979 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100980 if (DataType::Kind(lhs_type) != DataType::Kind(rhs_type)) {
Roland Levillaina5c4a402016-03-15 15:02:50 +0000981 AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.",
982 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100983 DataType::PrettyDescriptor(lhs_type),
984 DataType::PrettyDescriptor(rhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000985 }
986 }
987
Roland Levillain5b5b9312016-03-22 14:57:31 +0000988 // Type consistency between result and input(s).
Nicolas Geoffray31596742014-11-24 15:28:45 +0000989 if (op->IsCompare()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100990 if (result_type != DataType::Type::kInt32) {
Roland Levillaina5c4a402016-03-15 15:02:50 +0000991 AddError(StringPrintf("Compare operation %d has a non-int result type: %s.",
992 op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100993 DataType::PrettyDescriptor(result_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000994 }
Roland Levillain5b5b9312016-03-22 14:57:31 +0000995 } else if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
996 // Only check the first input (value), as the second one (distance)
997 // must invariably be of kind `int`.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100998 if (result_type != DataType::Kind(lhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +0000999 AddError(StringPrintf("Shift/rotate operation %s %d has a result type different "
1000 "from its left-hand side (value) input kind: %s vs %s.",
Roland Levillaina5c4a402016-03-15 15:02:50 +00001001 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001002 DataType::PrettyDescriptor(result_type),
1003 DataType::PrettyDescriptor(lhs_type)));
Nicolas Geoffray31596742014-11-24 15:28:45 +00001004 }
Roland Levillain5b5b9312016-03-22 14:57:31 +00001005 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001006 if (DataType::Kind(result_type) != DataType::Kind(lhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00001007 AddError(StringPrintf("Binary operation %s %d has a result kind different "
1008 "from its left-hand side input kind: %s vs %s.",
1009 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001010 DataType::PrettyDescriptor(result_type),
1011 DataType::PrettyDescriptor(lhs_type)));
Roland Levillain5b5b9312016-03-22 14:57:31 +00001012 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001013 if (DataType::Kind(result_type) != DataType::Kind(rhs_type)) {
Roland Levillain5b5b9312016-03-22 14:57:31 +00001014 AddError(StringPrintf("Binary operation %s %d has a result kind different "
1015 "from its right-hand side input kind: %s vs %s.",
1016 op->DebugName(), op->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001017 DataType::PrettyDescriptor(result_type),
1018 DataType::PrettyDescriptor(rhs_type)));
Roland Levillain5b5b9312016-03-22 14:57:31 +00001019 }
Nicolas Geoffray31596742014-11-24 15:28:45 +00001020 }
1021}
1022
David Brazdilbadd8262016-02-02 16:28:56 +00001023void GraphChecker::VisitConstant(HConstant* instruction) {
David Brazdil8d5b8b22015-03-24 10:51:52 +00001024 HBasicBlock* block = instruction->GetBlock();
1025 if (!block->IsEntryBlock()) {
1026 AddError(StringPrintf(
1027 "%s %d should be in the entry block but is in block %d.",
1028 instruction->DebugName(),
1029 instruction->GetId(),
1030 block->GetBlockId()));
1031 }
1032}
1033
David Brazdilbadd8262016-02-02 16:28:56 +00001034void GraphChecker::VisitBoundType(HBoundType* instruction) {
David Brazdilf5552582015-12-27 13:36:12 +00001035 VisitInstruction(instruction);
1036
David Brazdilf5552582015-12-27 13:36:12 +00001037 if (!instruction->GetUpperBound().IsValid()) {
1038 AddError(StringPrintf(
1039 "%s %d does not have a valid upper bound RTI.",
1040 instruction->DebugName(),
1041 instruction->GetId()));
1042 }
1043}
1044
Roland Levillainf355c3f2016-03-30 19:09:03 +01001045void GraphChecker::VisitTypeConversion(HTypeConversion* instruction) {
1046 VisitInstruction(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001047 DataType::Type result_type = instruction->GetResultType();
1048 DataType::Type input_type = instruction->GetInputType();
Roland Levillainf355c3f2016-03-30 19:09:03 +01001049 // Invariant: We should never generate a conversion to a Boolean value.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001050 if (result_type == DataType::Type::kBool) {
Roland Levillainf355c3f2016-03-30 19:09:03 +01001051 AddError(StringPrintf(
1052 "%s %d converts to a %s (from a %s).",
1053 instruction->DebugName(),
1054 instruction->GetId(),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001055 DataType::PrettyDescriptor(result_type),
1056 DataType::PrettyDescriptor(input_type)));
Roland Levillainf355c3f2016-03-30 19:09:03 +01001057 }
1058}
1059
Roland Levillainccc07a92014-09-16 14:48:16 +01001060} // namespace art