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