1ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain/* 2ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * Copyright (C) 2014 The Android Open Source Project 3ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * 4ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * Licensed under the Apache License, Version 2.0 (the "License"); 5ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * you may not use this file except in compliance with the License. 6ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * You may obtain a copy of the License at 7ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * 8ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * http://www.apache.org/licenses/LICENSE-2.0 9ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * 10ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * Unless required by applicable law or agreed to in writing, software 11ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * distributed under the License is distributed on an "AS IS" BASIS, 12ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * See the License for the specific language governing permissions and 14ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain * limitations under the License. 15ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain */ 16ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 17ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain#include "graph_checker.h" 18ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 19655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko#include <algorithm> 207c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray#include <string> 21a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle#include <sstream> 22ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 23655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko#include "base/arena_containers.h" 247e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain#include "base/bit_vector-inl.h" 255c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain#include "base/stringprintf.h" 26d9510dfc32349eeb4f2145c801f7ba1d5bccfb12David Brazdil#include "handle_scope-inl.h" 277e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain 28ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainnamespace art { 29ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 3086ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdilstatic bool IsAllowedToJumpToExitBlock(HInstruction* instruction) { 3186ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil return instruction->IsThrow() || instruction->IsReturn() || instruction->IsReturnVoid(); 3286ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil} 3386ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil 3486ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdilstatic bool IsExitTryBoundaryIntoExitBlock(HBasicBlock* block) { 3586ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil if (!block->IsSingleTryBoundary()) { 3686ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil return false; 3786ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil } 3886ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil 3986ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil HTryBoundary* boundary = block->GetLastInstruction()->AsTryBoundary(); 4086ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil return block->GetPredecessors().size() == 1u && 4186ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil boundary->GetNormalFlowSuccessor()->IsExitBlock() && 4286ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil !boundary->IsEntry(); 4386ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil} 4486ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil 45ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainvoid GraphChecker::VisitBasicBlock(HBasicBlock* block) { 46ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain current_block_ = block; 47ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 48ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Check consistency with respect to predecessors of `block`. 490f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko // Note: Counting duplicates with a sorted vector uses up to 6x less memory 50947eb700bec9e214a72d4747864398dc238da60cVladimir Marko // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse. 51947eb700bec9e214a72d4747864398dc238da60cVladimir Marko ArenaVector<HBasicBlock*>& sorted_predecessors = blocks_storage_; 52947eb700bec9e214a72d4747864398dc238da60cVladimir Marko sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end()); 530f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko std::sort(sorted_predecessors.begin(), sorted_predecessors.end()); 540f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end; ) { 550f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko HBasicBlock* p = *it++; 560f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko size_t p_count_in_block_predecessors = 1u; 570f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko for (; it != end && *it == p; ++it) { 580f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko ++p_count_in_block_predecessors; 59655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko } 60655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko size_t block_count_in_p_successors = 61655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko std::count(p->GetSuccessors().begin(), p->GetSuccessors().end(), block); 62ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (p_count_in_block_predecessors != block_count_in_p_successors) { 635c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 645c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "Block %d lists %zu occurrences of block %d in its predecessors, whereas " 655c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "block %d lists %zu occurrences of block %d in its successors.", 665c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(), 675c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain p->GetBlockId(), block_count_in_p_successors, block->GetBlockId())); 68ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 69ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 70ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 71ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Check consistency with respect to successors of `block`. 720f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko // Note: Counting duplicates with a sorted vector uses up to 6x less memory 73947eb700bec9e214a72d4747864398dc238da60cVladimir Marko // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse. 74947eb700bec9e214a72d4747864398dc238da60cVladimir Marko ArenaVector<HBasicBlock*>& sorted_successors = blocks_storage_; 75947eb700bec9e214a72d4747864398dc238da60cVladimir Marko sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end()); 760f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko std::sort(sorted_successors.begin(), sorted_successors.end()); 770f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end; ) { 780f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko HBasicBlock* s = *it++; 790f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko size_t s_count_in_block_successors = 1u; 800f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko for (; it != end && *it == s; ++it) { 810f49c82076b974f65ef37d5e72b04f5345b0d7cbVladimir Marko ++s_count_in_block_successors; 82655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko } 83655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko size_t block_count_in_s_predecessors = 84655e585073ac271cc9afa7c9d6ff5ab4dbe4b72eVladimir Marko std::count(s->GetPredecessors().begin(), s->GetPredecessors().end(), block); 85ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (s_count_in_block_successors != block_count_in_s_predecessors) { 865c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 875c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "Block %d lists %zu occurrences of block %d in its successors, whereas " 885c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "block %d lists %zu occurrences of block %d in its predecessors.", 895c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(), 905c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId())); 91ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 92ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 93ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 94ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure `block` ends with a branch instruction. 95fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil // This invariant is not enforced on non-SSA graphs. Graph built from DEX with 96fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil // dead code that falls out of the method will not end with a control-flow 97fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil // instruction. Such code is removed during the SSA-building DCE phase. 98fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil if (GetGraph()->IsInSsaForm() && !block->EndsWithControlFlowInstruction()) { 995c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("Block %d does not end with a branch instruction.", 1005c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain block->GetBlockId())); 101ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 102ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 10386ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil // Ensure that only Return(Void) and Throw jump to Exit. An exiting TryBoundary 10486ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil // may be between the instructions if the Throw/Return(Void) is in a try block. 105b618adebbc19e50d7b1aa2f11b84341beb3c64dcDavid Brazdil if (block->IsExitBlock()) { 1066058455d486219994921b63a2d774dc9908415a2Vladimir Marko for (HBasicBlock* predecessor : block->GetPredecessors()) { 10786ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil HInstruction* last_instruction = IsExitTryBoundaryIntoExitBlock(predecessor) ? 10886ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil predecessor->GetSinglePredecessor()->GetLastInstruction() : 10986ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil predecessor->GetLastInstruction(); 11086ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil if (!IsAllowedToJumpToExitBlock(last_instruction)) { 11186ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil AddError(StringPrintf("Unexpected instruction %s:%d jumps into the exit block.", 11286ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil last_instruction->DebugName(), 11386ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil last_instruction->GetId())); 114b618adebbc19e50d7b1aa2f11b84341beb3c64dcDavid Brazdil } 115b618adebbc19e50d7b1aa2f11b84341beb3c64dcDavid Brazdil } 116b618adebbc19e50d7b1aa2f11b84341beb3c64dcDavid Brazdil } 117b618adebbc19e50d7b1aa2f11b84341beb3c64dcDavid Brazdil 118ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Visit this block's list of phis. 119ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { 120c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil HInstruction* current = it.Current(); 121ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure this block's list of phis contains only phis. 122c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil if (!current->IsPhi()) { 1235c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("Block %d has a non-phi in its phi list.", 1245c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain current_block_->GetBlockId())); 125ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 126c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil if (current->GetNext() == nullptr && current != block->GetLastPhi()) { 127c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil AddError(StringPrintf("The recorded last phi of block %d does not match " 128c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil "the actual last phi %d.", 129c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil current_block_->GetBlockId(), 130c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil current->GetId())); 131c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil } 132c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil current->Accept(this); 133ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 134ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 135ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Visit this block's list of instructions. 136c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { 137c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil HInstruction* current = it.Current(); 138ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure this block's list of instructions does not contains phis. 139c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil if (current->IsPhi()) { 1405c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("Block %d has a phi in its non-phi list.", 1415c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain current_block_->GetBlockId())); 142ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 143c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil if (current->GetNext() == nullptr && current != block->GetLastInstruction()) { 144c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil AddError(StringPrintf("The recorded last instruction of block %d does not match " 145c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil "the actual last instruction %d.", 146c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil current_block_->GetBlockId(), 147c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil current->GetId())); 148c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil } 149c3d743fa2a26effcb35627d8a1338029c86e582aDavid Brazdil current->Accept(this); 150ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 151badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 152badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Ensure that catch blocks are not normal successors, and normal blocks are 153badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // never exceptional successors. 154badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (HBasicBlock* successor : block->GetNormalSuccessors()) { 155badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (successor->IsCatchBlock()) { 156badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Catch block %d is a normal successor of block %d.", 157badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil successor->GetBlockId(), 158badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId())); 159badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 160badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 161badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (HBasicBlock* successor : block->GetExceptionalSuccessors()) { 162badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (!successor->IsCatchBlock()) { 163badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.", 164badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil successor->GetBlockId(), 165badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId())); 166badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 167badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 168badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 169badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Ensure dominated blocks have `block` as the dominator. 170badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (HBasicBlock* dominated : block->GetDominatedBlocks()) { 171badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (dominated->GetDominator() != block) { 172badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Block %d should be the dominator of %d.", 173badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId(), 174badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil dominated->GetBlockId())); 175badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 176badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 177badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 178badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Ensure there is no critical edge (i.e., an edge connecting a 179badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // block with multiple successors to a block with multiple 180badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // predecessors). Exceptional edges are synthesized and hence 181badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // not accounted for. 182badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (block->GetSuccessors().size() > 1) { 18386ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil if (IsExitTryBoundaryIntoExitBlock(block)) { 18486ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil // Allowed critical edge (Throw/Return/ReturnVoid)->TryBoundary->Exit. 18586ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil } else { 18686ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil for (HBasicBlock* successor : block->GetNormalSuccessors()) { 18786ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil if (successor->GetPredecessors().size() > 1) { 18886ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil AddError(StringPrintf("Critical edge between blocks %d and %d.", 18986ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil block->GetBlockId(), 19086ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil successor->GetBlockId())); 19186ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil } 192badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 193badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 194badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 195badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 196badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Ensure try membership information is consistent. 197badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (block->IsCatchBlock()) { 198badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (block->IsTryBlock()) { 199badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry(); 200badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d " 201badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "has try entry %s:%d.", 202badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId(), 203badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil try_entry.DebugName(), 204badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil try_entry.GetId())); 205badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 206badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 207badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (block->IsLoopHeader()) { 208badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.", 209badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId())); 210badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 211badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } else { 212badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (HBasicBlock* predecessor : block->GetPredecessors()) { 213badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors(); 214badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (block->IsTryBlock()) { 215badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry(); 216badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (incoming_try_entry == nullptr) { 217badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows " 218badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "from predecessor %d.", 219badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId(), 220badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil stored_try_entry.DebugName(), 221badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil stored_try_entry.GetId(), 222badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil predecessor->GetBlockId())); 223badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) { 224badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent " 225badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "with %s:%d that follows from predecessor %d.", 226badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId(), 227badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil stored_try_entry.DebugName(), 228badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil stored_try_entry.GetId(), 229badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil incoming_try_entry->DebugName(), 230badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil incoming_try_entry->GetId(), 231badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil predecessor->GetBlockId())); 232badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 233badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } else if (incoming_try_entry != nullptr) { 234badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows " 235badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "from predecessor %d.", 236badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil block->GetBlockId(), 237badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil incoming_try_entry->DebugName(), 238badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil incoming_try_entry->GetId(), 239badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil predecessor->GetBlockId())); 240badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 241badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 242badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 243badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 244badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (block->IsLoopHeader()) { 245badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil HandleLoop(block); 246badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 247ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} 248ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 2491152c926076a760490085c4497c3f117fa8da891Mark Mendellvoid GraphChecker::VisitBoundsCheck(HBoundsCheck* check) { 2501152c926076a760490085c4497c3f117fa8da891Mark Mendell if (!GetGraph()->HasBoundsChecks()) { 2511152c926076a760490085c4497c3f117fa8da891Mark Mendell AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, " 2521152c926076a760490085c4497c3f117fa8da891Mark Mendell "but HasBoundsChecks() returns false", 2531152c926076a760490085c4497c3f117fa8da891Mark Mendell check->DebugName(), 2541152c926076a760490085c4497c3f117fa8da891Mark Mendell check->GetId())); 2551152c926076a760490085c4497c3f117fa8da891Mark Mendell } 2561152c926076a760490085c4497c3f117fa8da891Mark Mendell 2571152c926076a760490085c4497c3f117fa8da891Mark Mendell // Perform the instruction base checks too. 2581152c926076a760490085c4497c3f117fa8da891Mark Mendell VisitInstruction(check); 2591152c926076a760490085c4497c3f117fa8da891Mark Mendell} 2601152c926076a760490085c4497c3f117fa8da891Mark Mendell 26119b5021a49285627485675ef31276b8194269600Nicolas Geoffrayvoid GraphChecker::VisitDeoptimize(HDeoptimize* deopt) { 26219b5021a49285627485675ef31276b8194269600Nicolas Geoffray if (GetGraph()->IsCompilingOsr()) { 26319b5021a49285627485675ef31276b8194269600Nicolas Geoffray AddError(StringPrintf("A graph compiled OSR cannot have a HDeoptimize instruction")); 26419b5021a49285627485675ef31276b8194269600Nicolas Geoffray } 26519b5021a49285627485675ef31276b8194269600Nicolas Geoffray 26619b5021a49285627485675ef31276b8194269600Nicolas Geoffray // Perform the instruction base checks too. 26719b5021a49285627485675ef31276b8194269600Nicolas Geoffray VisitInstruction(deopt); 26819b5021a49285627485675ef31276b8194269600Nicolas Geoffray} 26919b5021a49285627485675ef31276b8194269600Nicolas Geoffray 270ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdilvoid GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) { 271d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil ArrayRef<HBasicBlock* const> handlers = try_boundary->GetExceptionHandlers(); 272d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil 273d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil // Ensure that all exception handlers are catch blocks. 274ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil // Note that a normal-flow successor may be a catch block before CFG 275badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // simplification. We only test normal-flow successors in GraphChecker. 276d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil for (HBasicBlock* handler : handlers) { 277ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil if (!handler->IsCatchBlock()) { 278ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which " 279ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil "is not a catch block.", 280ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil current_block_->GetBlockId(), 281ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil try_boundary->DebugName(), 282ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil try_boundary->GetId(), 283ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil handler->GetBlockId())); 284ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } 285d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil } 286d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil 287d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil // Ensure that handlers are not listed multiple times. 288d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil for (size_t i = 0, e = handlers.size(); i < e; ++i) { 289d8ef0c69330f74f325f7671236ca6bf44b7ec9c9David Brazdil if (ContainsElement(handlers, handlers[i], i + 1)) { 290d8ef0c69330f74f325f7671236ca6bf44b7ec9c9David Brazdil AddError(StringPrintf("Exception handler block %d of %s:%d is listed multiple times.", 291d26a411adee1e71b3f09dd604ab9b23018037138David Brazdil handlers[i]->GetBlockId(), 292ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil try_boundary->DebugName(), 293ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil try_boundary->GetId())); 294ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } 295ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } 296ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil 297ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil VisitInstruction(try_boundary); 298ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil} 299ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil 3009bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdilvoid GraphChecker::VisitLoadException(HLoadException* load) { 3019bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil // Ensure that LoadException is the first instruction in a catch block. 3029bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil if (!load->GetBlock()->IsCatchBlock()) { 3039bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil AddError(StringPrintf("%s:%d is in a non-catch block %d.", 3049bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil load->DebugName(), 3059bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil load->GetId(), 3069bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil load->GetBlock()->GetBlockId())); 3079bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil } else if (load->GetBlock()->GetFirstInstruction() != load) { 3089bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil AddError(StringPrintf("%s:%d is not the first instruction in catch block %d.", 3099bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil load->DebugName(), 3109bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil load->GetId(), 3119bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil load->GetBlock()->GetBlockId())); 3129bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil } 3139bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil} 3149bc436160b4af99067973affb0b1008de9a2b04cDavid Brazdil 315ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainvoid GraphChecker::VisitInstruction(HInstruction* instruction) { 3167c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray if (seen_ids_.IsBitSet(instruction->GetId())) { 3175c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("Instruction id %d is duplicate in graph.", 3185c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetId())); 3197c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray } else { 3207c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray seen_ids_.SetBit(instruction->GetId()); 3217c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray } 3227c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray 323ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure `instruction` is associated with `current_block_`. 3245c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain if (instruction->GetBlock() == nullptr) { 3255c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("%s %d in block %d not associated with any block.", 3265c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->IsPhi() ? "Phi" : "Instruction", 3275c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetId(), 3285c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain current_block_->GetBlockId())); 3295c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain } else if (instruction->GetBlock() != current_block_) { 3305c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("%s %d in block %d associated with block %d.", 3315c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->IsPhi() ? "Phi" : "Instruction", 3325c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetId(), 3335c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain current_block_->GetBlockId(), 3345c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetBlock()->GetBlockId())); 335ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 3366b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain 3376b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain // Ensure the inputs of `instruction` are defined in a block of the graph. 3386b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain for (HInputIterator input_it(instruction); !input_it.Done(); 3396b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain input_it.Advance()) { 3406b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain HInstruction* input = input_it.Current(); 3416b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain const HInstructionList& list = input->IsPhi() 3426b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain ? input->GetBlock()->GetPhis() 3436b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain : input->GetBlock()->GetInstructions(); 3446b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain if (!list.Contains(input)) { 3455c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("Input %d of instruction %d is not defined " 3465c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "in a basic block of the control-flow graph.", 3475c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain input->GetId(), 3485c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetId())); 3496b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 3506b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 3516b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain 3525d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray // Ensure the uses of `instruction` are defined in a block of the graph, 3535d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray // and the entry in the use list is consistent. 354d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) { 355d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko HInstruction* user = use.GetUser(); 356d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko const HInstructionList& list = user->IsPhi() 357d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko ? user->GetBlock()->GetPhis() 358d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko : user->GetBlock()->GetInstructions(); 359d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko if (!list.Contains(user)) { 360276d9daaedfbff716339f94d55e6eff98b7434c6Nicolas Geoffray AddError(StringPrintf("User %s:%d of instruction %d is not defined " 3615c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "in a basic block of the control-flow graph.", 362d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->DebugName(), 363d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->GetId(), 3645c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetId())); 3656b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 366d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko size_t use_index = use.GetIndex(); 367d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko if ((use_index >= user->InputCount()) || (user->InputAt(use_index) != instruction)) { 368b554b5a5ae3cdc66969d61be20783a8af816206eVladimir Marko AddError(StringPrintf("User %s:%d of instruction %s:%d has a wrong " 3695d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray "UseListNode index.", 370d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->DebugName(), 371d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->GetId(), 372b554b5a5ae3cdc66969d61be20783a8af816206eVladimir Marko instruction->DebugName(), 3735d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray instruction->GetId())); 3745d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray } 3755d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray } 3765d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray 3775d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray // Ensure the environment uses entries are consistent. 378d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) { 379d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko HEnvironment* user = use.GetUser(); 380d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko size_t use_index = use.GetIndex(); 381d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko if ((use_index >= user->Size()) || (user->GetInstructionAt(use_index) != instruction)) { 3825d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray AddError(StringPrintf("Environment user of %s:%d has a wrong " 3835d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray "UseListNode index.", 3845d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray instruction->DebugName(), 3855d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray instruction->GetId())); 3865d7b7f81ed5455893f984752c00571ef27cc97c5Nicolas Geoffray } 3876b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 3881abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil 3891abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil // Ensure 'instruction' has pointers to its inputs' use entries. 3901abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 3911abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil HUserRecord<HInstruction*> input_record = instruction->InputRecordAt(i); 3921abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil HInstruction* input = input_record.GetInstruction(); 393d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko if ((input_record.GetBeforeUseNode() == input->GetUses().end()) || 394d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko (input_record.GetUseNode() == input->GetUses().end()) || 395d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko !input->GetUses().ContainsNode(*input_record.GetUseNode()) || 396d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko (input_record.GetUseNode()->GetIndex() != i)) { 397d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko AddError(StringPrintf("Instruction %s:%d has an invalid iterator before use entry " 3981abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil "at input %u (%s:%d).", 3991abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil instruction->DebugName(), 4001abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil instruction->GetId(), 4011abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil static_cast<unsigned>(i), 4021abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil input->DebugName(), 4031abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil input->GetId())); 4041abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil } 4051abb4191a2e56d8dbf518efcaeefb266c1acdf2bDavid Brazdil } 406badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 407badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Ensure an instruction dominates all its uses. 408d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) { 409d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko HInstruction* user = use.GetUser(); 410d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko if (!user->IsPhi() && !instruction->StrictlyDominates(user)) { 411badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Instruction %s:%d in block %d does not dominate " 412badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "use %s:%d in block %d.", 413badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->DebugName(), 414badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->GetId(), 415badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil current_block_->GetBlockId(), 416d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->DebugName(), 417d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->GetId(), 418d59f3b1b7f5c1ab9f0731ff9dc60611e8d9a6edeVladimir Marko user->GetBlock()->GetBlockId())); 419badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 420badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 421badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 422badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (instruction->NeedsEnvironment() && !instruction->HasEnvironment()) { 423badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Instruction %s:%d in block %d requires an environment " 424badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "but does not have one.", 425badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->DebugName(), 426badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->GetId(), 427badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil current_block_->GetBlockId())); 428badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 429badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 430badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Ensure an instruction having an environment is dominated by the 431badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // instructions contained in the environment. 432badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (HEnvironment* environment = instruction->GetEnvironment(); 433badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil environment != nullptr; 434badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil environment = environment->GetParent()) { 435badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (size_t i = 0, e = environment->Size(); i < e; ++i) { 436badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil HInstruction* env_instruction = environment->GetInstructionAt(i); 437badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (env_instruction != nullptr 438badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil && !env_instruction->StrictlyDominates(instruction)) { 439badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Instruction %d in environment of instruction %d " 440badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "from block %d does not dominate instruction %d.", 441badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil env_instruction->GetId(), 442badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->GetId(), 443badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil current_block_->GetBlockId(), 444badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->GetId())); 445badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 446badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 447badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 448badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 449badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Ensure that reference type instructions have reference type info. 450badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (instruction->GetType() == Primitive::kPrimNot) { 451badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil ScopedObjectAccess soa(Thread::Current()); 452badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (!instruction->GetReferenceTypeInfo().IsValid()) { 453badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Reference type instruction %s:%d does not have " 454badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "valid reference type information.", 455badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->DebugName(), 456badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->GetId())); 457badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 458badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 459badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 460badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (instruction->CanThrowIntoCatchBlock()) { 461badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Find the top-level environment. This corresponds to the environment of 462badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // the catch block since we do not inline methods with try/catch. 463badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil HEnvironment* environment = instruction->GetEnvironment(); 464badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil while (environment->GetParent() != nullptr) { 465badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil environment = environment->GetParent(); 466badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 467badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil 468badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // Find all catch blocks and test that `instruction` has an environment 469badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil // value for each one. 470badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry(); 471badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) { 472badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) { 473badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil HPhi* catch_phi = phi_it.Current()->AsPhi(); 474badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) { 475badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil AddError(StringPrintf("Instruction %s:%d throws into catch block %d " 476badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "with catch phi %d for vreg %d but its " 477badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil "corresponding environment slot is empty.", 478badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->DebugName(), 479badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil instruction->GetId(), 480badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil catch_block->GetBlockId(), 481badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil catch_phi->GetId(), 482badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil catch_phi->GetRegNumber())); 483badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 484badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 485badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 486badd826664896d4a9628a5a89b78016894aa414bDavid Brazdil } 487ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} 488ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 4894c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillainvoid GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { 4904c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain VisitInstruction(invoke); 4914c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain 4924c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain if (invoke->IsStaticWithExplicitClinitCheck()) { 4934c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain size_t last_input_index = invoke->InputCount() - 1; 4944c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain HInstruction* last_input = invoke->InputAt(last_input_index); 4954c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain if (last_input == nullptr) { 4964c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check " 4974c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain "has a null pointer as last input.", 4984c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain invoke->DebugName(), 4994c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain invoke->GetId())); 5004c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain } 5014c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) { 5024c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check " 5034c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain "has a last instruction (%s:%d) which is neither a clinit check " 5044c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain "nor a load class instruction.", 5054c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain invoke->DebugName(), 5064c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain invoke->GetId(), 5074c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain last_input->DebugName(), 5084c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain last_input->GetId())); 5094c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain } 5104c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain } 5114c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain} 5124c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain 513fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdilvoid GraphChecker::VisitReturn(HReturn* ret) { 514f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray VisitInstruction(ret); 51586ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor(); 51686ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) { 517fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil AddError(StringPrintf("%s:%d does not jump to the exit block.", 518fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil ret->DebugName(), 519fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil ret->GetId())); 520fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil } 521fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil} 522fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil 523fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdilvoid GraphChecker::VisitReturnVoid(HReturnVoid* ret) { 524f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray VisitInstruction(ret); 52586ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor(); 52686ea7eeabe30c98bbe1651a51d03cb89776724e7David Brazdil if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) { 527fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil AddError(StringPrintf("%s:%d does not jump to the exit block.", 528fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil ret->DebugName(), 529fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil ret->GetId())); 530fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil } 531fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil} 532fc6a86ab2b70781e72b807c1798b83829ca7f931David Brazdil 533f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffrayvoid GraphChecker::VisitCheckCast(HCheckCast* check) { 534f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray VisitInstruction(check); 535f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray HInstruction* input = check->InputAt(1); 536f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray if (!input->IsLoadClass()) { 537f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.", 538f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray check->DebugName(), 539f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray check->GetId(), 540f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray input->DebugName(), 541f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray input->GetId())); 542f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray } 543f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray} 544f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray 545f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffrayvoid GraphChecker::VisitInstanceOf(HInstanceOf* instruction) { 546f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray VisitInstruction(instruction); 547f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray HInstruction* input = instruction->InputAt(1); 548f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray if (!input->IsLoadClass()) { 549f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.", 550f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray instruction->DebugName(), 551f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray instruction->GetId(), 552f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray input->DebugName(), 553f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray input->GetId())); 554f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray } 555f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray} 556f9a199571417b5a5a62d94d05a064077e14dd2c4Nicolas Geoffray 557badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::HandleLoop(HBasicBlock* loop_header) { 5586b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain int id = loop_header->GetBlockId(); 559db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray HLoopInformation* loop_information = loop_header->GetLoopInformation(); 5606b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 56115bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray if (loop_information->GetPreHeader()->GetSuccessors().size() != 1) { 562db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil AddError(StringPrintf( 563db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil "Loop pre-header %d of loop defined by header %d has %zu successors.", 564db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil loop_information->GetPreHeader()->GetBlockId(), 565db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil id, 566db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil loop_information->GetPreHeader()->GetSuccessors().size())); 5676b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 5686b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 56909aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray if (loop_information->GetSuspendCheck() == nullptr) { 57009aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray AddError(StringPrintf( 57109aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray "Loop with header %d does not have a suspend check.", 57209aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray loop_header->GetBlockId())); 57309aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray } 57409aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray 57509aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray if (loop_information->GetSuspendCheck() != loop_header->GetFirstInstructionDisregardMoves()) { 57609aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray AddError(StringPrintf( 57709aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray "Loop header %d does not have the loop suspend check as the first instruction.", 57809aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray loop_header->GetBlockId())); 57909aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray } 58009aa147f0891ef28a95d89e8ad61c429f82ddd5bNicolas Geoffray 581db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray // Ensure the loop header has only one incoming branch and the remaining 582db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray // predecessors are back edges. 5836058455d486219994921b63a2d774dc9908415a2Vladimir Marko size_t num_preds = loop_header->GetPredecessors().size(); 5845c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain if (num_preds < 2) { 5855c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 5865c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "Loop header %d has less than two predecessors: %zu.", 5875c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain id, 5885c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain num_preds)); 5896b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } else { 590ec7802a102d49ab5c17495118d4fe0bcc7287bebVladimir Marko HBasicBlock* first_predecessor = loop_header->GetPredecessors()[0]; 59146e2a3915aa68c77426b71e95b9f3658250646b7David Brazdil if (loop_information->IsBackEdge(*first_predecessor)) { 5925c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 5935c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "First predecessor of loop header %d is a back edge.", 5945c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain id)); 5956b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 5966058455d486219994921b63a2d774dc9908415a2Vladimir Marko for (size_t i = 1, e = loop_header->GetPredecessors().size(); i < e; ++i) { 597ec7802a102d49ab5c17495118d4fe0bcc7287bebVladimir Marko HBasicBlock* predecessor = loop_header->GetPredecessors()[i]; 598db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray if (!loop_information->IsBackEdge(*predecessor)) { 599db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray AddError(StringPrintf( 600916cc1d504f10a24f43b384e035fdecbe6a74b4cNicolas Geoffray "Loop header %d has multiple incoming (non back edge) blocks: %d.", 601916cc1d504f10a24f43b384e035fdecbe6a74b4cNicolas Geoffray id, 602916cc1d504f10a24f43b384e035fdecbe6a74b4cNicolas Geoffray predecessor->GetBlockId())); 603db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray } 6046b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 6056b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 6066b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 607db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray const ArenaBitVector& loop_blocks = loop_information->GetBlocks(); 6082d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil 609db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray // Ensure back edges belong to the loop. 610fa6b93c4b69e6d7ddfa2a4ed0aff01b0608c5a3aVladimir Marko if (loop_information->NumberOfBackEdges() == 0) { 6115c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 6125c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "Loop defined by header %d has no back edge.", 6135c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain id)); 6142d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil } else { 615fa6b93c4b69e6d7ddfa2a4ed0aff01b0608c5a3aVladimir Marko for (HBasicBlock* back_edge : loop_information->GetBackEdges()) { 616fa6b93c4b69e6d7ddfa2a4ed0aff01b0608c5a3aVladimir Marko int back_edge_id = back_edge->GetBlockId(); 617db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray if (!loop_blocks.IsBitSet(back_edge_id)) { 618db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray AddError(StringPrintf( 619db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray "Loop defined by header %d has an invalid back edge %d.", 620db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray id, 621db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray back_edge_id)); 622db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil } else if (back_edge->GetLoopInformation() != loop_information) { 623db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil AddError(StringPrintf( 624db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil "Back edge %d of loop defined by header %d belongs to nested loop " 625db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil "with header %d.", 626db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil back_edge_id, 627db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil id, 628db51efb3617d15f1cd9e5ff0cc2d934777014e9aDavid Brazdil back_edge->GetLoopInformation()->GetHeader()->GetBlockId())); 629db216f4d49ea1561a74261c29f1264952232728aNicolas Geoffray } 6302d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil } 6316b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 6327e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain 63315bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray // If this is a nested loop, ensure the outer loops contain a superset of the blocks. 63415bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray for (HLoopInformationOutwardIterator it(*loop_header); !it.Done(); it.Advance()) { 63515bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray HLoopInformation* outer_info = it.Current(); 63615bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray if (!loop_blocks.IsSubsetOf(&outer_info->GetBlocks())) { 63715bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray AddError(StringPrintf("Blocks of loop defined by header %d are not a subset of blocks of " 63815bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray "an outer loop defined by header %d.", 63915bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray id, 64015bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray outer_info->GetHeader()->GetBlockId())); 64115bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray } 64215bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray } 64315bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray 64415bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray // Ensure the pre-header block is first in the list of predecessors of a loop 64515bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray // header and that the header block is its only successor. 64615bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray if (!loop_header->IsLoopPreHeaderFirstPredecessor()) { 64715bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray AddError(StringPrintf( 64815bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray "Loop pre-header is not the first predecessor of the loop header %d.", 64915bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray id)); 65015bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray } 65115bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray 65215bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray // Ensure all blocks in the loop are live and dominated by the loop header in 65315bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray // the case of natural loops. 6547e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain for (uint32_t i : loop_blocks.Indexes()) { 655ec7802a102d49ab5c17495118d4fe0bcc7287bebVladimir Marko HBasicBlock* loop_block = GetGraph()->GetBlocks()[i]; 6562d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil if (loop_block == nullptr) { 6572d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil AddError(StringPrintf("Loop defined by header %d contains a previously removed block %d.", 6582d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil id, 6592d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil i)); 66015bd22849ee6a1ffb3fb3630f686c2870bdf1bbcNicolas Geoffray } else if (!loop_information->IsIrreducible() && !loop_header->Dominates(loop_block)) { 6615c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("Loop block %d not dominated by loop header %d.", 6622d7352ba5311b8f57427b91b7a891e61497373c1David Brazdil i, 6635c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain id)); 6647e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain } 6657d275379bf490a87805852129e3fe2e8afe961e7David Brazdil } 666ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} 667ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 66877a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdilstatic bool IsSameSizeConstant(HInstruction* insn1, HInstruction* insn2) { 66977a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil return insn1->IsConstant() 67077a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil && insn2->IsConstant() 67177a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil && Primitive::Is64BitType(insn1->GetType()) == Primitive::Is64BitType(insn2->GetType()); 67277a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil} 67377a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil 67477a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdilstatic bool IsConstantEquivalent(HInstruction* insn1, HInstruction* insn2, BitVector* visited) { 67577a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil if (insn1->IsPhi() && 67677a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil insn1->AsPhi()->IsVRegEquivalentOf(insn2) && 67777a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil insn1->InputCount() == insn2->InputCount()) { 67877a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil // Testing only one of the two inputs for recursion is sufficient. 67977a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil if (visited->IsBitSet(insn1->GetId())) { 68077a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil return true; 68177a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 68277a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil visited->SetBit(insn1->GetId()); 68377a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil 68477a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil for (size_t i = 0, e = insn1->InputCount(); i < e; ++i) { 68577a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil if (!IsConstantEquivalent(insn1->InputAt(i), insn2->InputAt(i), visited)) { 68677a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil return false; 68777a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 68877a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 68977a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil return true; 69077a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } else if (IsSameSizeConstant(insn1, insn2)) { 69177a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil return insn1->AsConstant()->GetValueAsUint64() == insn2->AsConstant()->GetValueAsUint64(); 69277a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } else { 69377a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil return false; 69477a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 69577a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil} 69677a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil 697badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitPhi(HPhi* phi) { 6986b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain VisitInstruction(phi); 6996b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 7006b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // Ensure the first input of a phi is not itself. 7016b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (phi->InputAt(0) == phi) { 7025c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf("Loop phi %d in block %d is its own first input.", 7035c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain phi->GetId(), 7045c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain phi->GetBlock()->GetBlockId())); 7056b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 7066b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 707d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray // Ensure that the inputs have the same primitive kind as the phi. 708d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { 709d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray HInstruction* input = phi->InputAt(i); 710a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain if (Primitive::PrimitiveKind(input->GetType()) != Primitive::PrimitiveKind(phi->GetType())) { 711d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray AddError(StringPrintf( 712d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray "Input %d at index %zu of phi %d from block %d does not have the " 713a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain "same kind as the phi: %s versus %s", 714d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(), 715d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray Primitive::PrettyDescriptor(input->GetType()), 716d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray Primitive::PrettyDescriptor(phi->GetType()))); 717d6138ef1ea13d07ae555542f8898b30d89e9ac9aNicolas Geoffray } 7183159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 719e0fe7ae36180863e45cbb9d1e6e9c30b1b1a949cNicolas Geoffray if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) { 720e0fe7ae36180863e45cbb9d1e6e9c30b1b1a949cNicolas Geoffray AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s", 721e0fe7ae36180863e45cbb9d1e6e9c30b1b1a949cNicolas Geoffray phi->GetId(), 722e0fe7ae36180863e45cbb9d1e6e9c30b1b1a949cNicolas Geoffray phi->GetBlock()->GetBlockId(), 723e0fe7ae36180863e45cbb9d1e6e9c30b1b1a949cNicolas Geoffray Primitive::PrettyDescriptor(phi->GetType()))); 724e0fe7ae36180863e45cbb9d1e6e9c30b1b1a949cNicolas Geoffray } 725ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil 726ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil if (phi->IsCatchPhi()) { 7273eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil // The number of inputs of a catch phi should be the total number of throwing 7283eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil // instructions caught by this catch block. We do not enforce this, however, 7293eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil // because we do not remove the corresponding inputs when we prove that an 7303eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil // instruction cannot throw. Instead, we at least test that all phis have the 7313eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil // same, non-zero number of inputs (b/24054676). 7323eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil size_t input_count_this = phi->InputCount(); 7333eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil if (input_count_this == 0u) { 7343eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil AddError(StringPrintf("Phi %d in catch block %d has zero inputs.", 7353eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil phi->GetId(), 7363eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil phi->GetBlock()->GetBlockId())); 7373eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil } else { 7383eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil HInstruction* next_phi = phi->GetNext(); 7393eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil if (next_phi != nullptr) { 7403eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil size_t input_count_next = next_phi->InputCount(); 7413eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil if (input_count_this != input_count_next) { 7423eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil AddError(StringPrintf("Phi %d in catch block %d has %zu inputs, " 7433eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil "but phi %d has %zu inputs.", 7443eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil phi->GetId(), 7453eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil phi->GetBlock()->GetBlockId(), 7463eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil input_count_this, 7473eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil next_phi->GetId(), 7483eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil input_count_next)); 7493eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil } 7503eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil } 7513eaa32f72b6abd807964134aad4c158946dc92e3David Brazdil } 752ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } else { 753ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil // Ensure the number of inputs of a non-catch phi is the same as the number 754ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil // of its predecessors. 7556058455d486219994921b63a2d774dc9908415a2Vladimir Marko const ArenaVector<HBasicBlock*>& predecessors = phi->GetBlock()->GetPredecessors(); 7566058455d486219994921b63a2d774dc9908415a2Vladimir Marko if (phi->InputCount() != predecessors.size()) { 757ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil AddError(StringPrintf( 758ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil "Phi %d in block %d has %zu inputs, " 759ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil "but block %d has %zu predecessors.", 760ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(), 7616058455d486219994921b63a2d774dc9908415a2Vladimir Marko phi->GetBlock()->GetBlockId(), predecessors.size())); 762ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } else { 763ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil // Ensure phi input at index I either comes from the Ith 764ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil // predecessor or from a block that dominates this predecessor. 765ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { 766ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil HInstruction* input = phi->InputAt(i); 7676058455d486219994921b63a2d774dc9908415a2Vladimir Marko HBasicBlock* predecessor = predecessors[i]; 768ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil if (!(input->GetBlock() == predecessor 769ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil || input->GetBlock()->Dominates(predecessor))) { 770ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil AddError(StringPrintf( 771ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil "Input %d at index %zu of phi %d from block %d is not defined in " 772ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil "predecessor number %zu nor in a block dominating it.", 773ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(), 774ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil i)); 775ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } 776ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } 777ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } 778ffee3d33f3ea39aa6031c3d2ff29c4806c8dcc51David Brazdil } 77977a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil 78077a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil // Ensure that catch phis are sorted by their vreg number, as required by 78177a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil // the register allocator and code generator. This does not apply to normal 78277a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil // phis which can be constructed artifically. 78377a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil if (phi->IsCatchPhi()) { 78477a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil HInstruction* next_phi = phi->GetNext(); 78577a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil if (next_phi != nullptr && phi->GetRegNumber() > next_phi->AsPhi()->GetRegNumber()) { 78677a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil AddError(StringPrintf("Catch phis %d and %d in block %d are not sorted by their " 78777a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil "vreg numbers.", 78877a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil phi->GetId(), 78977a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil next_phi->GetId(), 79077a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil phi->GetBlock()->GetBlockId())); 79177a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 79277a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 79377a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil 7943fc7f357170311689c4c31007a5e168ddea321d5Aart Bik // Test phi equivalents. There should not be two of the same type and they should only be 7953fc7f357170311689c4c31007a5e168ddea321d5Aart Bik // created for constants which were untyped in DEX. Note that this test can be skipped for 7963fc7f357170311689c4c31007a5e168ddea321d5Aart Bik // a synthetic phi (indicated by lack of a virtual register). 7973fc7f357170311689c4c31007a5e168ddea321d5Aart Bik if (phi->GetRegNumber() != kNoRegNumber) { 7984a34277c55279ba57ab361f7580db846a201d9b1Aart Bik for (HInstructionIterator phi_it(phi->GetBlock()->GetPhis()); 7994a34277c55279ba57ab361f7580db846a201d9b1Aart Bik !phi_it.Done(); 8004a34277c55279ba57ab361f7580db846a201d9b1Aart Bik phi_it.Advance()) { 8013fc7f357170311689c4c31007a5e168ddea321d5Aart Bik HPhi* other_phi = phi_it.Current()->AsPhi(); 8023fc7f357170311689c4c31007a5e168ddea321d5Aart Bik if (phi != other_phi && phi->GetRegNumber() == other_phi->GetRegNumber()) { 8033fc7f357170311689c4c31007a5e168ddea321d5Aart Bik if (phi->GetType() == other_phi->GetType()) { 8043fc7f357170311689c4c31007a5e168ddea321d5Aart Bik std::stringstream type_str; 8053fc7f357170311689c4c31007a5e168ddea321d5Aart Bik type_str << phi->GetType(); 8063fc7f357170311689c4c31007a5e168ddea321d5Aart Bik AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s.", 80777a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil phi->GetId(), 8083fc7f357170311689c4c31007a5e168ddea321d5Aart Bik phi->GetRegNumber(), 8093fc7f357170311689c4c31007a5e168ddea321d5Aart Bik type_str.str().c_str())); 810f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray } else if (phi->GetType() == Primitive::kPrimNot) { 811f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray std::stringstream type_str; 812f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray type_str << other_phi->GetType(); 813f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray AddError(StringPrintf( 814f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray "Equivalent non-reference phi (%d) found for VReg %d with type: %s.", 815f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray phi->GetId(), 816f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray phi->GetRegNumber(), 817f5f64efda943000168d34bfe44ccbbadd284e55fNicolas Geoffray type_str.str().c_str())); 8183fc7f357170311689c4c31007a5e168ddea321d5Aart Bik } else { 819947eb700bec9e214a72d4747864398dc238da60cVladimir Marko // If we get here, make sure we allocate all the necessary storage at once 820947eb700bec9e214a72d4747864398dc238da60cVladimir Marko // because the BitVector reallocation strategy has very bad worst-case behavior. 821947eb700bec9e214a72d4747864398dc238da60cVladimir Marko ArenaBitVector& visited = visited_storage_; 822947eb700bec9e214a72d4747864398dc238da60cVladimir Marko visited.SetBit(GetGraph()->GetCurrentInstructionId()); 823947eb700bec9e214a72d4747864398dc238da60cVladimir Marko visited.ClearAllBits(); 8243fc7f357170311689c4c31007a5e168ddea321d5Aart Bik if (!IsConstantEquivalent(phi, other_phi, &visited)) { 8253fc7f357170311689c4c31007a5e168ddea321d5Aart Bik AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they " 8263fc7f357170311689c4c31007a5e168ddea321d5Aart Bik "are not equivalents of constants.", 8273fc7f357170311689c4c31007a5e168ddea321d5Aart Bik phi->GetId(), 8283fc7f357170311689c4c31007a5e168ddea321d5Aart Bik other_phi->GetId(), 8293fc7f357170311689c4c31007a5e168ddea321d5Aart Bik phi->GetRegNumber())); 8303fc7f357170311689c4c31007a5e168ddea321d5Aart Bik } 83177a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 83277a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 83377a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 83477a48ae01bbc5b05ca009cf09e2fcb53e4c8ff23David Brazdil } 8353159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray} 8363159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 837badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) { 83813b4718ecd52a674b25eac106e654d8e89872750David Brazdil HInstruction* input = instruction->InputAt(input_index); 8399ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray if (input->IsIntConstant()) { 84013b4718ecd52a674b25eac106e654d8e89872750David Brazdil int32_t value = input->AsIntConstant()->GetValue(); 8419ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray if (value != 0 && value != 1) { 8425c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 84313b4718ecd52a674b25eac106e654d8e89872750David Brazdil "%s instruction %d has a non-Boolean constant input %d whose value is: %d.", 84413b4718ecd52a674b25eac106e654d8e89872750David Brazdil instruction->DebugName(), 8455c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetId(), 84613b4718ecd52a674b25eac106e654d8e89872750David Brazdil static_cast<int>(input_index), 8475c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain value)); 8489ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray } 84911edec7e7e8ac93f826d687b644fe700fab68993David Brazdil } else if (Primitive::PrimitiveKind(input->GetType()) != Primitive::kPrimInt) { 85011edec7e7e8ac93f826d687b644fe700fab68993David Brazdil // TODO: We need a data-flow analysis to determine if an input like Phi, 85111edec7e7e8ac93f826d687b644fe700fab68993David Brazdil // Select or a binary operation is actually Boolean. Allow for now. 8525c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 85311edec7e7e8ac93f826d687b644fe700fab68993David Brazdil "%s instruction %d has a non-integer input %d whose type is: %s.", 85413b4718ecd52a674b25eac106e654d8e89872750David Brazdil instruction->DebugName(), 8555c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain instruction->GetId(), 85613b4718ecd52a674b25eac106e654d8e89872750David Brazdil static_cast<int>(input_index), 85713b4718ecd52a674b25eac106e654d8e89872750David Brazdil Primitive::PrettyDescriptor(input->GetType()))); 8589ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray } 8599ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray} 8609ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray 861badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitPackedSwitch(HPackedSwitch* instruction) { 862fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell VisitInstruction(instruction); 863fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell // Check that the number of block successors matches the switch count plus 864fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell // one for the default block. 865fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell HBasicBlock* block = instruction->GetBlock(); 866fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell if (instruction->GetNumEntries() + 1u != block->GetSuccessors().size()) { 867fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell AddError(StringPrintf( 868fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell "%s instruction %d in block %d expects %u successors to the block, but found: %zu.", 869fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell instruction->DebugName(), 870fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell instruction->GetId(), 871fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell block->GetBlockId(), 872fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell instruction->GetNumEntries() + 1u, 873fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell block->GetSuccessors().size())); 874fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell } 875fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell} 876fe57faa2e0349418dda38e77ef1c0ac29db75f4dMark Mendell 877badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitIf(HIf* instruction) { 87813b4718ecd52a674b25eac106e654d8e89872750David Brazdil VisitInstruction(instruction); 87913b4718ecd52a674b25eac106e654d8e89872750David Brazdil HandleBooleanInput(instruction, 0); 88013b4718ecd52a674b25eac106e654d8e89872750David Brazdil} 88113b4718ecd52a674b25eac106e654d8e89872750David Brazdil 882badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitSelect(HSelect* instruction) { 88374eb1b264691c4eb399d0858015a7fc13c476ac6David Brazdil VisitInstruction(instruction); 88474eb1b264691c4eb399d0858015a7fc13c476ac6David Brazdil HandleBooleanInput(instruction, 2); 88574eb1b264691c4eb399d0858015a7fc13c476ac6David Brazdil} 88674eb1b264691c4eb399d0858015a7fc13c476ac6David Brazdil 887badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitBooleanNot(HBooleanNot* instruction) { 88813b4718ecd52a674b25eac106e654d8e89872750David Brazdil VisitInstruction(instruction); 88913b4718ecd52a674b25eac106e654d8e89872750David Brazdil HandleBooleanInput(instruction, 0); 89013b4718ecd52a674b25eac106e654d8e89872750David Brazdil} 89113b4718ecd52a674b25eac106e654d8e89872750David Brazdil 892badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitCondition(HCondition* op) { 8933159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray VisitInstruction(op); 8943159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (op->GetType() != Primitive::kPrimBoolean) { 8955c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 8965c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "Condition %s %d has a non-Boolean result type: %s.", 8975c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain op->DebugName(), op->GetId(), 8985c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain Primitive::PrettyDescriptor(op->GetType()))); 8993159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 9009ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray HInstruction* lhs = op->InputAt(0); 9019ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray HInstruction* rhs = op->InputAt(1); 902a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain if (Primitive::PrimitiveKind(lhs->GetType()) != Primitive::PrimitiveKind(rhs->GetType())) { 903a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle AddError(StringPrintf( 904a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain "Condition %s %d has inputs of different kinds: %s, and %s.", 905a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle op->DebugName(), op->GetId(), 906a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle Primitive::PrettyDescriptor(lhs->GetType()), 907a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle Primitive::PrettyDescriptor(rhs->GetType()))); 908a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle } 909a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle if (!op->IsEqual() && !op->IsNotEqual()) { 910a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle if ((lhs->GetType() == Primitive::kPrimNot)) { 9115c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 9125c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "Condition %s %d uses an object as left-hand side input.", 9135c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain op->DebugName(), op->GetId())); 914a4f8831d6533e4fe5aed18433099e1130d95a877Calin Juravle } else if (rhs->GetType() == Primitive::kPrimNot) { 9155c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain AddError(StringPrintf( 9165c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain "Condition %s %d uses an object as right-hand side input.", 9175c4405e8ca4a0c1ee2d7759e650530c9aff77fd0Roland Levillain op->DebugName(), op->GetId())); 918aecbd26b29c6122d1eacfd67e0bd5aa26b96eebbRoland Levillain } 9199ee66183d8e046ea661f642ba884626f16b46e06Nicolas Geoffray } 9203159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray} 9213159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 922937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillainvoid GraphChecker::VisitNeg(HNeg* instruction) { 923937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain VisitInstruction(instruction); 924937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain Primitive::Type input_type = instruction->InputAt(0)->GetType(); 925937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain Primitive::Type result_type = instruction->GetType(); 926937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain if (result_type != Primitive::PrimitiveKind(input_type)) { 927937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain AddError(StringPrintf("Binary operation %s %d has a result type different " 928937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain "from its input kind: %s vs %s.", 929937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain instruction->DebugName(), instruction->GetId(), 930937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain Primitive::PrettyDescriptor(result_type), 931937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain Primitive::PrettyDescriptor(input_type))); 932937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain } 933937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain} 934937e6cd515bbe7ff2f255c8fcd40bf1a575a9a16Roland Levillain 935badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitBinaryOperation(HBinaryOperation* op) { 9363159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray VisitInstruction(op); 937a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::Type lhs_type = op->InputAt(0)->GetType(); 938a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::Type rhs_type = op->InputAt(1)->GetType(); 939a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::Type result_type = op->GetType(); 9405b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain 9415b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain // Type consistency between inputs. 94240a04bf64e5837fa48aceaffe970c9984c94084aScott Wakeling if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) { 943a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain if (Primitive::PrimitiveKind(rhs_type) != Primitive::kPrimInt) { 9445b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain AddError(StringPrintf("Shift/rotate operation %s %d has a non-int kind second input: " 9455b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain "%s of type %s.", 946a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain op->DebugName(), op->GetId(), 947a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain op->InputAt(1)->DebugName(), 948a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::PrettyDescriptor(rhs_type))); 9493159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 9503159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } else { 951a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain if (Primitive::PrimitiveKind(lhs_type) != Primitive::PrimitiveKind(rhs_type)) { 952a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.", 953a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain op->DebugName(), op->GetId(), 954a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::PrettyDescriptor(lhs_type), 955a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::PrettyDescriptor(rhs_type))); 9563159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 9573159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 9583159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 9595b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain // Type consistency between result and input(s). 9603159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (op->IsCompare()) { 961a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain if (result_type != Primitive::kPrimInt) { 962a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain AddError(StringPrintf("Compare operation %d has a non-int result type: %s.", 963a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain op->GetId(), 964a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::PrettyDescriptor(result_type))); 9653159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 9665b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain } else if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) { 9675b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain // Only check the first input (value), as the second one (distance) 9685b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain // must invariably be of kind `int`. 9695b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain if (result_type != Primitive::PrimitiveKind(lhs_type)) { 9705b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain AddError(StringPrintf("Shift/rotate operation %s %d has a result type different " 9715b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain "from its left-hand side (value) input kind: %s vs %s.", 9725b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain op->DebugName(), op->GetId(), 9735b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain Primitive::PrettyDescriptor(result_type), 9745b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain Primitive::PrettyDescriptor(lhs_type))); 9755b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain } 9763159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } else { 977a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain if (Primitive::PrimitiveKind(result_type) != Primitive::PrimitiveKind(lhs_type)) { 978a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain AddError(StringPrintf("Binary operation %s %d has a result kind different " 9795b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain "from its left-hand side input kind: %s vs %s.", 980a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain op->DebugName(), op->GetId(), 981a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::PrettyDescriptor(result_type), 982a5c4a4060edd03eda017abebc85f24cffb083ba7Roland Levillain Primitive::PrettyDescriptor(lhs_type))); 9833159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 9845b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain if (Primitive::PrimitiveKind(result_type) != Primitive::PrimitiveKind(rhs_type)) { 9855b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain AddError(StringPrintf("Binary operation %s %d has a result kind different " 9865b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain "from its right-hand side input kind: %s vs %s.", 9875b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain op->DebugName(), op->GetId(), 9885b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain Primitive::PrettyDescriptor(result_type), 9895b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain Primitive::PrettyDescriptor(rhs_type))); 9905b5b9319ff970979ed47d41a41283e4faeffb602Roland Levillain } 9913159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 9923159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray} 9933159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 994badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitConstant(HConstant* instruction) { 9958d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil HBasicBlock* block = instruction->GetBlock(); 9968d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil if (!block->IsEntryBlock()) { 9978d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil AddError(StringPrintf( 9988d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil "%s %d should be in the entry block but is in block %d.", 9998d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil instruction->DebugName(), 10008d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil instruction->GetId(), 10018d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil block->GetBlockId())); 10028d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil } 10038d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil} 10048d5b8b295930aaa43255c4f0b74ece3ee8b43a47David Brazdil 1005badd826664896d4a9628a5a89b78016894aa414bDavid Brazdilvoid GraphChecker::VisitBoundType(HBoundType* instruction) { 1006f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil VisitInstruction(instruction); 1007f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil 1008f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil ScopedObjectAccess soa(Thread::Current()); 1009f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil if (!instruction->GetUpperBound().IsValid()) { 1010f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil AddError(StringPrintf( 1011f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil "%s %d does not have a valid upper bound RTI.", 1012f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil instruction->DebugName(), 1013f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil instruction->GetId())); 1014f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil } 1015f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil} 1016f555258861aea7df8af9c2241ab761227fd2f66aDavid Brazdil 1017f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillainvoid GraphChecker::VisitTypeConversion(HTypeConversion* instruction) { 1018f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain VisitInstruction(instruction); 1019f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain Primitive::Type result_type = instruction->GetResultType(); 1020f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain Primitive::Type input_type = instruction->GetInputType(); 1021f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain // Invariant: We should never generate a conversion to a Boolean value. 1022f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain if (result_type == Primitive::kPrimBoolean) { 1023f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain AddError(StringPrintf( 1024f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain "%s %d converts to a %s (from a %s).", 1025f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain instruction->DebugName(), 1026f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain instruction->GetId(), 1027f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain Primitive::PrettyDescriptor(result_type), 1028f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain Primitive::PrettyDescriptor(input_type))); 1029f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain } 1030f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain} 1031f355c3ff08710ac2eba3aac2aacc5e65caa06b4cRoland Levillain 1032ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} // namespace art 1033