graph_checker.cc revision 7c5367badfe61b96c5836d495d286cee64861579
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 19ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain#include <map> 20ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain#include <sstream> 217c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray#include <string> 22ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 237e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain#include "base/bit_vector-inl.h" 247e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain 25ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainnamespace art { 26ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 27ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainvoid GraphChecker::VisitBasicBlock(HBasicBlock* block) { 28ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain current_block_ = block; 29ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 30ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Check consistency with respect to predecessors of `block`. 31ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain const GrowableArray<HBasicBlock*>& predecessors = block->GetPredecessors(); 32ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::map<HBasicBlock*, size_t> predecessors_count; 33ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (size_t i = 0, e = predecessors.Size(); i < e; ++i) { 34ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain HBasicBlock* p = predecessors.Get(i); 35ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain ++predecessors_count[p]; 36ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 37ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (auto& pc : predecessors_count) { 38ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain HBasicBlock* p = pc.first; 39ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain size_t p_count_in_block_predecessors = pc.second; 40ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain const GrowableArray<HBasicBlock*>& p_successors = p->GetSuccessors(); 41ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain size_t block_count_in_p_successors = 0; 42ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (size_t j = 0, f = p_successors.Size(); j < f; ++j) { 43ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (p_successors.Get(j) == block) { 44ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain ++block_count_in_p_successors; 45ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 46ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 47ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (p_count_in_block_predecessors != block_count_in_p_successors) { 48ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 49ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Block " << block->GetBlockId() 50ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " lists " << p_count_in_block_predecessors 51ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " occurrences of block " << p->GetBlockId() 52ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " in its predecessors, whereas block " << p->GetBlockId() 53ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " lists " << block_count_in_p_successors 54ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " occurrences of block " << block->GetBlockId() 55ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " in its successors."; 5691356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 57ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 58ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 59ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 60ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Check consistency with respect to successors of `block`. 61ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain const GrowableArray<HBasicBlock*>& successors = block->GetSuccessors(); 62ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::map<HBasicBlock*, size_t> successors_count; 63ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (size_t i = 0, e = successors.Size(); i < e; ++i) { 64ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain HBasicBlock* s = successors.Get(i); 65ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain ++successors_count[s]; 66ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 67ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (auto& sc : successors_count) { 68ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain HBasicBlock* s = sc.first; 69ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain size_t s_count_in_block_successors = sc.second; 70ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain const GrowableArray<HBasicBlock*>& s_predecessors = s->GetPredecessors(); 71ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain size_t block_count_in_s_predecessors = 0; 72ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (size_t j = 0, f = s_predecessors.Size(); j < f; ++j) { 73ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (s_predecessors.Get(j) == block) { 74ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain ++block_count_in_s_predecessors; 75ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 76ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 77ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (s_count_in_block_successors != block_count_in_s_predecessors) { 78ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 79ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Block " << block->GetBlockId() 80ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " lists " << s_count_in_block_successors 81ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " occurrences of block " << s->GetBlockId() 82ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " in its successors, whereas block " << s->GetBlockId() 83ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " lists " << block_count_in_s_predecessors 84ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " occurrences of block " << block->GetBlockId() 85ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " in its predecessors."; 8691356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 87ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 88ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 89ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 90ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure `block` ends with a branch instruction. 91ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain HInstruction* last_inst = block->GetLastInstruction(); 92ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (last_inst == nullptr || !last_inst->IsControlFlow()) { 93ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 94ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Block " << block->GetBlockId() 95ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " does not end with a branch instruction."; 9691356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 97ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 98ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 99ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Visit this block's list of phis. 100ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { 101ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure this block's list of phis contains only phis. 102ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (!it.Current()->IsPhi()) { 103ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 104ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Block " << current_block_->GetBlockId() 105ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " has a non-phi in its phi list."; 10691356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 107ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 108ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain it.Current()->Accept(this); 109ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 110ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 111ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Visit this block's list of instructions. 112ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (HInstructionIterator it(block->GetInstructions()); !it.Done(); 113ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain it.Advance()) { 114ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure this block's list of instructions does not contains phis. 115ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (it.Current()->IsPhi()) { 116ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 117ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Block " << current_block_->GetBlockId() 118ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " has a phi in its non-phi list."; 11991356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 120ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 121ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain it.Current()->Accept(this); 122ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 123ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} 124ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 125ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainvoid GraphChecker::VisitInstruction(HInstruction* instruction) { 1267c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray if (seen_ids_.IsBitSet(instruction->GetId())) { 1277c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray std::stringstream error; 1287c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray error << "Duplicate id in graph " << instruction->GetId() << "."; 1297c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray errors_.push_back(error.str()); 1307c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray } else { 1317c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray seen_ids_.SetBit(instruction->GetId()); 1327c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray } 1337c5367badfe61b96c5836d495d286cee64861579Nicolas Geoffray 134ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure `instruction` is associated with `current_block_`. 135ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (instruction->GetBlock() != current_block_) { 136ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 137ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (instruction->IsPhi()) { 138ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Phi "; 139ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } else { 140ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Instruction "; 141ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 142ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << instruction->GetId() << " in block " 143ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << current_block_->GetBlockId(); 144ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (instruction->GetBlock() != nullptr) { 145ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << " associated with block " 146ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << instruction->GetBlock()->GetBlockId() << "."; 147ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } else { 148ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << " not associated with any block."; 149ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 15091356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 151ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 1526b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain 1536b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain // Ensure the inputs of `instruction` are defined in a block of the graph. 1546b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain for (HInputIterator input_it(instruction); !input_it.Done(); 1556b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain input_it.Advance()) { 1566b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain HInstruction* input = input_it.Current(); 1576b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain const HInstructionList& list = input->IsPhi() 1586b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain ? input->GetBlock()->GetPhis() 1596b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain : input->GetBlock()->GetInstructions(); 1606b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain if (!list.Contains(input)) { 1616b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain std::stringstream error; 1626b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain error << "Input " << input->GetId() 1636b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain << " of instruction " << instruction->GetId() 1646b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain << " is not defined in a basic block of the control-flow graph."; 16591356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 1666b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 1676b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 1686b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain 1696b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain // Ensure the uses of `instruction` are defined in a block of the graph. 1706b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain for (HUseIterator<HInstruction> use_it(instruction->GetUses()); 1716b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain !use_it.Done(); use_it.Advance()) { 1726b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain HInstruction* use = use_it.Current()->GetUser(); 1736b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain const HInstructionList& list = use->IsPhi() 1746b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain ? use->GetBlock()->GetPhis() 1756b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain : use->GetBlock()->GetInstructions(); 1766b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain if (!list.Contains(use)) { 1776b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain std::stringstream error; 1786b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain error << "User " << use->GetId() 1796b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain << " of instruction " << instruction->GetId() 1806b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain << " is not defined in a basic block of the control-flow graph."; 18191356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 1826b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 1836b46923ff0197c95f1e7ea0bc730961df6725cc9Roland Levillain } 184ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} 185ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 186ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainvoid SSAChecker::VisitBasicBlock(HBasicBlock* block) { 187ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain super_type::VisitBasicBlock(block); 188ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 189ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // Ensure there is no critical edge (i.e., an edge connecting a 190ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // block with multiple successors to a block with multiple 191ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain // predecessors). 192ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (block->GetSuccessors().Size() > 1) { 193ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) { 194ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain HBasicBlock* successor = block->GetSuccessors().Get(j); 195ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain if (successor->GetPredecessors().Size() > 1) { 196ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 197ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain error << "Critical edge between blocks " << block->GetBlockId() 198ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain << " and " << successor->GetBlockId() << "."; 19991356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 200ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 201ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 202ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 2036b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 2046b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (block->IsLoopHeader()) { 2056b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain CheckLoop(block); 2066b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 2076b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain} 2086b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 2096b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillainvoid SSAChecker::CheckLoop(HBasicBlock* loop_header) { 2106b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain int id = loop_header->GetBlockId(); 2116b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 2126b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // Ensure the pre-header block is first in the list of 2136b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // predecessors of a loop header. 2146b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (!loop_header->IsLoopPreHeaderFirstPredecessor()) { 2156b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 2166b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Loop pre-header is not the first predecessor of the loop header " 2176b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << id << "."; 21891356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 2196b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 2206b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 2216b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // Ensure the loop header has only two predecessors and that only the 2226b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // second one is a back edge. 2236b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (loop_header->GetPredecessors().Size() < 2) { 2246b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 2256b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Loop header " << id << " has less than two predecessors."; 22691356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 2276b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } else if (loop_header->GetPredecessors().Size() > 2) { 2286b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 2296b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Loop header " << id << " has more than two predecessors."; 23091356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 2316b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } else { 2326b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain HLoopInformation* loop_information = loop_header->GetLoopInformation(); 2336b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0); 2346b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (loop_information->IsBackEdge(first_predecessor)) { 2356b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 2366b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "First predecessor of loop header " << id << " is a back edge."; 23791356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 2386b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 2396b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1); 2406b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (!loop_information->IsBackEdge(second_predecessor)) { 2416b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 2426b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Second predecessor of loop header " << id 2436b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " is not a back edge."; 24491356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 2456b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 2466b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 2476b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 2486b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // Ensure there is only one back edge per loop. 2496b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain size_t num_back_edges = 2506b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain loop_header->GetLoopInformation()->GetBackEdges().Size(); 2516b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (num_back_edges != 1) { 2526b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 2536b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Loop defined by header " << id << " has " 2546b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << num_back_edges << " back edge(s)."; 25591356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 2566b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 2577e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain 2587e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain // Ensure all blocks in the loop are dominated by the loop header. 2597e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain const ArenaBitVector& loop_blocks = 2607e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain loop_header->GetLoopInformation()->GetBlocks(); 2617e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain for (uint32_t i : loop_blocks.Indexes()) { 2627e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i); 2637e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain if (!loop_header->Dominates(loop_block)) { 2647e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain std::stringstream error; 2657e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain error << "Loop block " << loop_block->GetBlockId() 2667e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain << " not dominated by loop header " << id; 26791356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 2687e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain } 2697e53b415e5e587cd7961978f6da7347248f40b29Roland Levillain } 270ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} 271ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 272ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillainvoid SSAChecker::VisitInstruction(HInstruction* instruction) { 273ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain super_type::VisitInstruction(instruction); 274ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 275a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain // Ensure an instruction dominates all its uses. 276a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain for (HUseIterator<HInstruction> use_it(instruction->GetUses()); 277a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain !use_it.Done(); use_it.Advance()) { 278a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain HInstruction* use = use_it.Current()->GetUser(); 2796c82d40eb142771086f5531998de2273ba5cc08cRoland Levillain if (!use->IsPhi() && !instruction->StrictlyDominates(use)) { 280ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain std::stringstream error; 281a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain error << "Instruction " << instruction->GetId() 282a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain << " in block " << current_block_->GetBlockId() 283a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain << " does not dominate use " << use->GetId() 284a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain << " in block " << use->GetBlock()->GetBlockId() << "."; 28591356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 286ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 287ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain } 288a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain 289a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain // Ensure an instruction having an environment is dominated by the 290a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain // instructions contained in the environment. 291a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain HEnvironment* environment = instruction->GetEnvironment(); 292a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain if (environment != nullptr) { 293a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain for (size_t i = 0, e = environment->Size(); i < e; ++i) { 294a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain HInstruction* env_instruction = environment->GetInstructionAt(i); 295a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain if (env_instruction != nullptr 2966c82d40eb142771086f5531998de2273ba5cc08cRoland Levillain && !env_instruction->StrictlyDominates(instruction)) { 297a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain std::stringstream error; 298a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain error << "Instruction " << env_instruction->GetId() 299a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain << " in environment of instruction " << instruction->GetId() 300a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain << " from block " << current_block_->GetBlockId() 301a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain << " does not dominate instruction " << instruction->GetId() 302a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain << "."; 30391356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 304a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain } 305a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain } 306a8069ce1c3caa4f9b1651988986f3732152c186dRoland Levillain } 307ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} 308ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain 3096b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillainvoid SSAChecker::VisitPhi(HPhi* phi) { 3106b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain VisitInstruction(phi); 3116b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 3126b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // Ensure the first input of a phi is not itself. 3136b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (phi->InputAt(0) == phi) { 3146b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 3156b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Loop phi " << phi->GetId() 3166b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " in block " << phi->GetBlock()->GetBlockId() 3176b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " is its own first input."; 31891356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 3196b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 3206b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 3216b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // Ensure the number of phi inputs is the same as the number of 3226b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // its predecessors. 3236b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain const GrowableArray<HBasicBlock*>& predecessors = 3246b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain phi->GetBlock()->GetPredecessors(); 3256b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (phi->InputCount() != predecessors.Size()) { 3266b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 3276b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Phi " << phi->GetId() 3286b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " in block " << phi->GetBlock()->GetBlockId() 3296b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " has " << phi->InputCount() << " inputs, but block " 3306b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << phi->GetBlock()->GetBlockId() << " has " 3316b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << predecessors.Size() << " predecessors."; 33291356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 3336b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } else { 3346b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // Ensure phi input at index I either comes from the Ith 3356b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain // predecessor or from a block that dominates this predecessor. 3366b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { 3376b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain HInstruction* input = phi->InputAt(i); 3386b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain HBasicBlock* predecessor = predecessors.Get(i); 3396b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain if (!(input->GetBlock() == predecessor 3406b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain || input->GetBlock()->Dominates(predecessor))) { 3416b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain std::stringstream error; 3426b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain error << "Input " << input->GetId() << " at index " << i 3436b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " of phi " << phi->GetId() 3446b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " from block " << phi->GetBlock()->GetBlockId() 3456b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " is not defined in predecessor number " << i 3466b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain << " nor in a block dominating it."; 34791356c028022180dfbe54ed7f5f465041c8b23ffAndreas Gampe errors_.push_back(error.str()); 3486b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 3496b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 3506b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain } 3516b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain} 3526b879ddc0959df1cec871f0d41f11cce35a11716Roland Levillain 3533159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffraystatic Primitive::Type PrimitiveKind(Primitive::Type type) { 3543159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray switch (type) { 3553159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray case Primitive::kPrimBoolean: 3563159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray case Primitive::kPrimByte: 3573159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray case Primitive::kPrimShort: 3583159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray case Primitive::kPrimChar: 3593159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray case Primitive::kPrimInt: 3603159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray return Primitive::kPrimInt; 3613159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray default: 3623159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray return type; 3633159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 3643159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray} 3653159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 3663159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffrayvoid SSAChecker::VisitCondition(HCondition* op) { 3673159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray VisitInstruction(op); 3683159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray // TODO: check inputs types, and special case the `null` check. 3693159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (op->GetType() != Primitive::kPrimBoolean) { 3703159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray std::stringstream error; 3713159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray error << "Condition " << op->DebugName() << " " << op->GetId() 3723159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << " has a non-boolean result type: " 3733159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << op->GetType() << "."; 3743159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray errors_.push_back(error.str()); 3753159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 3763159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray} 3773159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 3783159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffrayvoid SSAChecker::VisitBinaryOperation(HBinaryOperation* op) { 3793159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray VisitInstruction(op); 3803159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (op->IsUShr() || op->IsShr() || op->IsShl()) { 3813159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) { 3823159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray std::stringstream error; 3833159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray error << "Shift operation " << op->DebugName() << " " << op->GetId() 3843159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << " has a non-int kind second input: " 3853159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << op->InputAt(1)->DebugName() << " of type " << op->InputAt(1)->GetType() 3863159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << "."; 3873159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray errors_.push_back(error.str()); 3883159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 3893159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } else { 3903159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (PrimitiveKind(op->InputAt(1)->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) { 3913159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray std::stringstream error; 3923159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray error << "Binary operation " << op->DebugName() << " " << op->GetId() 3933159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << " has inputs of different type: " 3943159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << op->InputAt(0)->GetType() << ", and " << op->InputAt(1)->GetType() 3953159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << "."; 3963159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray errors_.push_back(error.str()); 3973159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 3983159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 3993159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 4003159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (op->IsCompare()) { 4013159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (op->GetType() != Primitive::kPrimInt) { 4023159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray std::stringstream error; 4033159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray error << "Compare operation " << op->GetId() 4043159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << " has a non-int result type: " 4053159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << op->GetType() << "."; 4063159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray errors_.push_back(error.str()); 4073159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 4083159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } else { 4093159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray // Use the first input, so that we can also make this check for shift operations. 4103159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) { 4113159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray std::stringstream error; 4123159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray error << "Binary operation " << op->DebugName() << " " << op->GetId() 4133159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << " has a result type different than its input type: " 4143159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << op->GetType() << ", and " << op->InputAt(1)->GetType() 4153159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray << "."; 4163159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray errors_.push_back(error.str()); 4173159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 4183159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray } 4193159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray} 4203159674c0863f53cfbc1913d493550221ac47f02Nicolas Geoffray 421ccc07a9579c554443cd03a306ca9b4f943fd2a93Roland Levillain} // namespace art 422