| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2014 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
 | 17 | #include "graph_checker.h" | 
 | 18 |  | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 19 | #include <map> | 
| Nicolas Geoffray | 7c5367b | 2014-12-17 10:13:46 +0000 | [diff] [blame] | 20 | #include <string> | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 21 |  | 
| Roland Levillain | 7e53b41 | 2014-09-23 10:50:22 +0100 | [diff] [blame] | 22 | #include "base/bit_vector-inl.h" | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 23 | #include "base/stringprintf.h" | 
| Roland Levillain | 7e53b41 | 2014-09-23 10:50:22 +0100 | [diff] [blame] | 24 |  | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 25 | namespace art { | 
 | 26 |  | 
 | 27 | void GraphChecker::VisitBasicBlock(HBasicBlock* block) { | 
 | 28 |   current_block_ = block; | 
 | 29 |  | 
 | 30 |   // Check consistency with respect to predecessors of `block`. | 
 | 31 |   const GrowableArray<HBasicBlock*>& predecessors = block->GetPredecessors(); | 
 | 32 |   std::map<HBasicBlock*, size_t> predecessors_count; | 
 | 33 |   for (size_t i = 0, e = predecessors.Size(); i < e; ++i) { | 
 | 34 |     HBasicBlock* p = predecessors.Get(i); | 
 | 35 |     ++predecessors_count[p]; | 
 | 36 |   } | 
 | 37 |   for (auto& pc : predecessors_count) { | 
 | 38 |     HBasicBlock* p = pc.first; | 
 | 39 |     size_t p_count_in_block_predecessors = pc.second; | 
 | 40 |     const GrowableArray<HBasicBlock*>& p_successors = p->GetSuccessors(); | 
 | 41 |     size_t block_count_in_p_successors = 0; | 
 | 42 |     for (size_t j = 0, f = p_successors.Size(); j < f; ++j) { | 
 | 43 |       if (p_successors.Get(j) == block) { | 
 | 44 |         ++block_count_in_p_successors; | 
 | 45 |       } | 
 | 46 |     } | 
 | 47 |     if (p_count_in_block_predecessors != block_count_in_p_successors) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 48 |       AddError(StringPrintf( | 
 | 49 |           "Block %d lists %zu occurrences of block %d in its predecessors, whereas " | 
 | 50 |           "block %d lists %zu occurrences of block %d in its successors.", | 
 | 51 |           block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(), | 
 | 52 |           p->GetBlockId(), block_count_in_p_successors, block->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 53 |     } | 
 | 54 |   } | 
 | 55 |  | 
 | 56 |   // Check consistency with respect to successors of `block`. | 
 | 57 |   const GrowableArray<HBasicBlock*>& successors = block->GetSuccessors(); | 
 | 58 |   std::map<HBasicBlock*, size_t> successors_count; | 
 | 59 |   for (size_t i = 0, e = successors.Size(); i < e; ++i) { | 
 | 60 |     HBasicBlock* s = successors.Get(i); | 
 | 61 |     ++successors_count[s]; | 
 | 62 |   } | 
 | 63 |   for (auto& sc : successors_count) { | 
 | 64 |     HBasicBlock* s = sc.first; | 
 | 65 |     size_t s_count_in_block_successors = sc.second; | 
 | 66 |     const GrowableArray<HBasicBlock*>& s_predecessors = s->GetPredecessors(); | 
 | 67 |     size_t block_count_in_s_predecessors = 0; | 
 | 68 |     for (size_t j = 0, f = s_predecessors.Size(); j < f; ++j) { | 
 | 69 |       if (s_predecessors.Get(j) == block) { | 
 | 70 |         ++block_count_in_s_predecessors; | 
 | 71 |       } | 
 | 72 |     } | 
 | 73 |     if (s_count_in_block_successors != block_count_in_s_predecessors) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 74 |       AddError(StringPrintf( | 
 | 75 |           "Block %d lists %zu occurrences of block %d in its successors, whereas " | 
 | 76 |           "block %d lists %zu occurrences of block %d in its predecessors.", | 
 | 77 |           block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(), | 
 | 78 |           s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 79 |     } | 
 | 80 |   } | 
 | 81 |  | 
 | 82 |   // Ensure `block` ends with a branch instruction. | 
 | 83 |   HInstruction* last_inst = block->GetLastInstruction(); | 
 | 84 |   if (last_inst == nullptr || !last_inst->IsControlFlow()) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 85 |     AddError(StringPrintf("Block %d does not end with a branch instruction.", | 
 | 86 |                           block->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 87 |   } | 
 | 88 |  | 
 | 89 |   // Visit this block's list of phis. | 
 | 90 |   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) { | 
 | 91 |     // Ensure this block's list of phis contains only phis. | 
 | 92 |     if (!it.Current()->IsPhi()) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 93 |       AddError(StringPrintf("Block %d has a non-phi in its phi list.", | 
 | 94 |                             current_block_->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 95 |     } | 
 | 96 |     it.Current()->Accept(this); | 
 | 97 |   } | 
 | 98 |  | 
 | 99 |   // Visit this block's list of instructions. | 
 | 100 |   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); | 
 | 101 |        it.Advance()) { | 
 | 102 |     // Ensure this block's list of instructions does not contains phis. | 
 | 103 |     if (it.Current()->IsPhi()) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 104 |       AddError(StringPrintf("Block %d has a phi in its non-phi list.", | 
 | 105 |                             current_block_->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 106 |     } | 
 | 107 |     it.Current()->Accept(this); | 
 | 108 |   } | 
 | 109 | } | 
 | 110 |  | 
 | 111 | void GraphChecker::VisitInstruction(HInstruction* instruction) { | 
| Nicolas Geoffray | 7c5367b | 2014-12-17 10:13:46 +0000 | [diff] [blame] | 112 |   if (seen_ids_.IsBitSet(instruction->GetId())) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 113 |     AddError(StringPrintf("Instruction id %d is duplicate in graph.", | 
 | 114 |                           instruction->GetId())); | 
| Nicolas Geoffray | 7c5367b | 2014-12-17 10:13:46 +0000 | [diff] [blame] | 115 |   } else { | 
 | 116 |     seen_ids_.SetBit(instruction->GetId()); | 
 | 117 |   } | 
 | 118 |  | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 119 |   // Ensure `instruction` is associated with `current_block_`. | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 120 |   if (instruction->GetBlock() == nullptr) { | 
 | 121 |     AddError(StringPrintf("%s %d in block %d not associated with any block.", | 
 | 122 |                           instruction->IsPhi() ? "Phi" : "Instruction", | 
 | 123 |                           instruction->GetId(), | 
 | 124 |                           current_block_->GetBlockId())); | 
 | 125 |   } else if (instruction->GetBlock() != current_block_) { | 
 | 126 |     AddError(StringPrintf("%s %d in block %d associated with block %d.", | 
 | 127 |                           instruction->IsPhi() ? "Phi" : "Instruction", | 
 | 128 |                           instruction->GetId(), | 
 | 129 |                           current_block_->GetBlockId(), | 
 | 130 |                           instruction->GetBlock()->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 131 |   } | 
| Roland Levillain | 6b46923 | 2014-09-25 10:10:38 +0100 | [diff] [blame] | 132 |  | 
 | 133 |   // Ensure the inputs of `instruction` are defined in a block of the graph. | 
 | 134 |   for (HInputIterator input_it(instruction); !input_it.Done(); | 
 | 135 |        input_it.Advance()) { | 
 | 136 |     HInstruction* input = input_it.Current(); | 
 | 137 |     const HInstructionList& list = input->IsPhi() | 
 | 138 |         ? input->GetBlock()->GetPhis() | 
 | 139 |         : input->GetBlock()->GetInstructions(); | 
 | 140 |     if (!list.Contains(input)) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 141 |       AddError(StringPrintf("Input %d of instruction %d is not defined " | 
 | 142 |                             "in a basic block of the control-flow graph.", | 
 | 143 |                             input->GetId(), | 
 | 144 |                             instruction->GetId())); | 
| Roland Levillain | 6b46923 | 2014-09-25 10:10:38 +0100 | [diff] [blame] | 145 |     } | 
 | 146 |   } | 
 | 147 |  | 
 | 148 |   // Ensure the uses of `instruction` are defined in a block of the graph. | 
| David Brazdil | ed59619 | 2015-01-23 10:39:45 +0000 | [diff] [blame] | 149 |   for (HUseIterator<HInstruction*> use_it(instruction->GetUses()); | 
| Roland Levillain | 6b46923 | 2014-09-25 10:10:38 +0100 | [diff] [blame] | 150 |        !use_it.Done(); use_it.Advance()) { | 
 | 151 |     HInstruction* use = use_it.Current()->GetUser(); | 
 | 152 |     const HInstructionList& list = use->IsPhi() | 
 | 153 |         ? use->GetBlock()->GetPhis() | 
 | 154 |         : use->GetBlock()->GetInstructions(); | 
 | 155 |     if (!list.Contains(use)) { | 
| Nicolas Geoffray | 276d9da | 2015-02-02 18:24:11 +0000 | [diff] [blame] | 156 |       AddError(StringPrintf("User %s:%d of instruction %d is not defined " | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 157 |                             "in a basic block of the control-flow graph.", | 
| Nicolas Geoffray | 276d9da | 2015-02-02 18:24:11 +0000 | [diff] [blame] | 158 |                             use->DebugName(), | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 159 |                             use->GetId(), | 
 | 160 |                             instruction->GetId())); | 
| Roland Levillain | 6b46923 | 2014-09-25 10:10:38 +0100 | [diff] [blame] | 161 |     } | 
 | 162 |   } | 
| David Brazdil | 1abb419 | 2015-02-17 18:33:36 +0000 | [diff] [blame] | 163 |  | 
 | 164 |   // Ensure 'instruction' has pointers to its inputs' use entries. | 
 | 165 |   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { | 
 | 166 |     HUserRecord<HInstruction*> input_record = instruction->InputRecordAt(i); | 
 | 167 |     HInstruction* input = input_record.GetInstruction(); | 
 | 168 |     HUseListNode<HInstruction*>* use_node = input_record.GetUseNode(); | 
 | 169 |     if (use_node == nullptr || !input->GetUses().Contains(use_node)) { | 
 | 170 |       AddError(StringPrintf("Instruction %s:%d has an invalid pointer to use entry " | 
 | 171 |                             "at input %u (%s:%d).", | 
 | 172 |                             instruction->DebugName(), | 
 | 173 |                             instruction->GetId(), | 
 | 174 |                             static_cast<unsigned>(i), | 
 | 175 |                             input->DebugName(), | 
 | 176 |                             input->GetId())); | 
 | 177 |     } | 
 | 178 |   } | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 179 | } | 
 | 180 |  | 
 | 181 | void SSAChecker::VisitBasicBlock(HBasicBlock* block) { | 
 | 182 |   super_type::VisitBasicBlock(block); | 
 | 183 |  | 
 | 184 |   // Ensure there is no critical edge (i.e., an edge connecting a | 
 | 185 |   // block with multiple successors to a block with multiple | 
 | 186 |   // predecessors). | 
 | 187 |   if (block->GetSuccessors().Size() > 1) { | 
 | 188 |     for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) { | 
 | 189 |       HBasicBlock* successor = block->GetSuccessors().Get(j); | 
 | 190 |       if (successor->GetPredecessors().Size() > 1) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 191 |         AddError(StringPrintf("Critical edge between blocks %d and %d.", | 
 | 192 |                               block->GetBlockId(), | 
 | 193 |                               successor->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 194 |       } | 
 | 195 |     } | 
 | 196 |   } | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 197 |  | 
 | 198 |   if (block->IsLoopHeader()) { | 
 | 199 |     CheckLoop(block); | 
 | 200 |   } | 
 | 201 | } | 
 | 202 |  | 
 | 203 | void SSAChecker::CheckLoop(HBasicBlock* loop_header) { | 
 | 204 |   int id = loop_header->GetBlockId(); | 
 | 205 |  | 
 | 206 |   // Ensure the pre-header block is first in the list of | 
 | 207 |   // predecessors of a loop header. | 
 | 208 |   if (!loop_header->IsLoopPreHeaderFirstPredecessor()) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 209 |     AddError(StringPrintf( | 
 | 210 |         "Loop pre-header is not the first predecessor of the loop header %d.", | 
 | 211 |         id)); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 212 |   } | 
 | 213 |  | 
 | 214 |   // Ensure the loop header has only two predecessors and that only the | 
 | 215 |   // second one is a back edge. | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 216 |   size_t num_preds = loop_header->GetPredecessors().Size(); | 
 | 217 |   if (num_preds < 2) { | 
 | 218 |     AddError(StringPrintf( | 
 | 219 |         "Loop header %d has less than two predecessors: %zu.", | 
 | 220 |         id, | 
 | 221 |         num_preds)); | 
 | 222 |   } else if (num_preds > 2) { | 
 | 223 |     AddError(StringPrintf( | 
 | 224 |         "Loop header %d has more than two predecessors: %zu.", | 
 | 225 |         id, | 
 | 226 |         num_preds)); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 227 |   } else { | 
 | 228 |     HLoopInformation* loop_information = loop_header->GetLoopInformation(); | 
 | 229 |     HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0); | 
 | 230 |     if (loop_information->IsBackEdge(first_predecessor)) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 231 |       AddError(StringPrintf( | 
 | 232 |           "First predecessor of loop header %d is a back edge.", | 
 | 233 |           id)); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 234 |     } | 
 | 235 |     HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1); | 
 | 236 |     if (!loop_information->IsBackEdge(second_predecessor)) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 237 |       AddError(StringPrintf( | 
 | 238 |           "Second predecessor of loop header %d is not a back edge.", | 
 | 239 |           id)); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 240 |     } | 
 | 241 |   } | 
 | 242 |  | 
 | 243 |   // Ensure there is only one back edge per loop. | 
 | 244 |   size_t num_back_edges = | 
 | 245 |     loop_header->GetLoopInformation()->GetBackEdges().Size(); | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 246 |   if (num_back_edges == 0) { | 
 | 247 |     AddError(StringPrintf( | 
 | 248 |         "Loop defined by header %d has no back edge.", | 
 | 249 |         id)); | 
 | 250 |   } else if (num_back_edges > 1) { | 
 | 251 |     AddError(StringPrintf( | 
 | 252 |         "Loop defined by header %d has several back edges: %zu.", | 
 | 253 |         id, | 
 | 254 |         num_back_edges)); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 255 |   } | 
| Roland Levillain | 7e53b41 | 2014-09-23 10:50:22 +0100 | [diff] [blame] | 256 |  | 
 | 257 |   // Ensure all blocks in the loop are dominated by the loop header. | 
 | 258 |   const ArenaBitVector& loop_blocks = | 
 | 259 |     loop_header->GetLoopInformation()->GetBlocks(); | 
 | 260 |   for (uint32_t i : loop_blocks.Indexes()) { | 
 | 261 |     HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i); | 
 | 262 |     if (!loop_header->Dominates(loop_block)) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 263 |       AddError(StringPrintf("Loop block %d not dominated by loop header %d.", | 
 | 264 |                             loop_block->GetBlockId(), | 
 | 265 |                             id)); | 
| Roland Levillain | 7e53b41 | 2014-09-23 10:50:22 +0100 | [diff] [blame] | 266 |     } | 
 | 267 |   } | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 268 | } | 
 | 269 |  | 
 | 270 | void SSAChecker::VisitInstruction(HInstruction* instruction) { | 
 | 271 |   super_type::VisitInstruction(instruction); | 
 | 272 |  | 
| Roland Levillain | a8069ce | 2014-10-01 10:48:29 +0100 | [diff] [blame] | 273 |   // Ensure an instruction dominates all its uses. | 
| David Brazdil | ed59619 | 2015-01-23 10:39:45 +0000 | [diff] [blame] | 274 |   for (HUseIterator<HInstruction*> use_it(instruction->GetUses()); | 
| Roland Levillain | a8069ce | 2014-10-01 10:48:29 +0100 | [diff] [blame] | 275 |        !use_it.Done(); use_it.Advance()) { | 
 | 276 |     HInstruction* use = use_it.Current()->GetUser(); | 
| Roland Levillain | 6c82d40 | 2014-10-13 16:10:27 +0100 | [diff] [blame] | 277 |     if (!use->IsPhi() && !instruction->StrictlyDominates(use)) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 278 |       AddError(StringPrintf("Instruction %d in block %d does not dominate " | 
 | 279 |                             "use %d in block %d.", | 
 | 280 |                             instruction->GetId(), current_block_->GetBlockId(), | 
 | 281 |                             use->GetId(), use->GetBlock()->GetBlockId())); | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 282 |     } | 
 | 283 |   } | 
| Roland Levillain | a8069ce | 2014-10-01 10:48:29 +0100 | [diff] [blame] | 284 |  | 
 | 285 |   // Ensure an instruction having an environment is dominated by the | 
 | 286 |   // instructions contained in the environment. | 
 | 287 |   HEnvironment* environment = instruction->GetEnvironment(); | 
 | 288 |   if (environment != nullptr) { | 
 | 289 |     for (size_t i = 0, e = environment->Size(); i < e; ++i) { | 
 | 290 |       HInstruction* env_instruction = environment->GetInstructionAt(i); | 
 | 291 |       if (env_instruction != nullptr | 
| Roland Levillain | 6c82d40 | 2014-10-13 16:10:27 +0100 | [diff] [blame] | 292 |           && !env_instruction->StrictlyDominates(instruction)) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 293 |         AddError(StringPrintf("Instruction %d in environment of instruction %d " | 
 | 294 |                               "from block %d does not dominate instruction %d.", | 
 | 295 |                               env_instruction->GetId(), | 
 | 296 |                               instruction->GetId(), | 
 | 297 |                               current_block_->GetBlockId(), | 
 | 298 |                               instruction->GetId())); | 
| Roland Levillain | a8069ce | 2014-10-01 10:48:29 +0100 | [diff] [blame] | 299 |       } | 
 | 300 |     } | 
 | 301 |   } | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 302 | } | 
 | 303 |  | 
| Nicolas Geoffray | d6138ef | 2015-02-18 14:48:53 +0000 | [diff] [blame] | 304 | static Primitive::Type PrimitiveKind(Primitive::Type type) { | 
 | 305 |   switch (type) { | 
 | 306 |     case Primitive::kPrimBoolean: | 
 | 307 |     case Primitive::kPrimByte: | 
 | 308 |     case Primitive::kPrimShort: | 
 | 309 |     case Primitive::kPrimChar: | 
 | 310 |     case Primitive::kPrimInt: | 
 | 311 |       return Primitive::kPrimInt; | 
 | 312 |     default: | 
 | 313 |       return type; | 
 | 314 |   } | 
 | 315 | } | 
 | 316 |  | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 317 | void SSAChecker::VisitPhi(HPhi* phi) { | 
 | 318 |   VisitInstruction(phi); | 
 | 319 |  | 
 | 320 |   // Ensure the first input of a phi is not itself. | 
 | 321 |   if (phi->InputAt(0) == phi) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 322 |     AddError(StringPrintf("Loop phi %d in block %d is its own first input.", | 
 | 323 |                           phi->GetId(), | 
 | 324 |                           phi->GetBlock()->GetBlockId())); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 325 |   } | 
 | 326 |  | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 327 |   // Ensure the number of inputs of a phi is the same as the number of | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 328 |   // its predecessors. | 
 | 329 |   const GrowableArray<HBasicBlock*>& predecessors = | 
 | 330 |     phi->GetBlock()->GetPredecessors(); | 
 | 331 |   if (phi->InputCount() != predecessors.Size()) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 332 |     AddError(StringPrintf( | 
 | 333 |         "Phi %d in block %d has %zu inputs, " | 
 | 334 |         "but block %d has %zu predecessors.", | 
 | 335 |         phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(), | 
 | 336 |         phi->GetBlock()->GetBlockId(), predecessors.Size())); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 337 |   } else { | 
 | 338 |     // Ensure phi input at index I either comes from the Ith | 
 | 339 |     // predecessor or from a block that dominates this predecessor. | 
 | 340 |     for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { | 
 | 341 |       HInstruction* input = phi->InputAt(i); | 
 | 342 |       HBasicBlock* predecessor = predecessors.Get(i); | 
 | 343 |       if (!(input->GetBlock() == predecessor | 
 | 344 |             || input->GetBlock()->Dominates(predecessor))) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 345 |         AddError(StringPrintf( | 
 | 346 |             "Input %d at index %zu of phi %d from block %d is not defined in " | 
 | 347 |             "predecessor number %zu nor in a block dominating it.", | 
 | 348 |             input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(), | 
 | 349 |             i)); | 
| Roland Levillain | 6b879dd | 2014-09-22 17:13:44 +0100 | [diff] [blame] | 350 |       } | 
 | 351 |     } | 
 | 352 |   } | 
| Nicolas Geoffray | d6138ef | 2015-02-18 14:48:53 +0000 | [diff] [blame] | 353 |   // Ensure that the inputs have the same primitive kind as the phi. | 
 | 354 |   for (size_t i = 0, e = phi->InputCount(); i < e; ++i) { | 
 | 355 |     HInstruction* input = phi->InputAt(i); | 
 | 356 |     if (PrimitiveKind(input->GetType()) != PrimitiveKind(phi->GetType())) { | 
 | 357 |         AddError(StringPrintf( | 
 | 358 |             "Input %d at index %zu of phi %d from block %d does not have the " | 
 | 359 |             "same type as the phi: %s versus %s", | 
 | 360 |             input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(), | 
 | 361 |             Primitive::PrettyDescriptor(input->GetType()), | 
 | 362 |             Primitive::PrettyDescriptor(phi->GetType()))); | 
 | 363 |     } | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 364 |   } | 
| Nicolas Geoffray | e0fe7ae | 2015-03-09 10:02:49 +0000 | [diff] [blame] | 365 |   if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) { | 
 | 366 |     AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s", | 
 | 367 |                           phi->GetId(), | 
 | 368 |                           phi->GetBlock()->GetBlockId(), | 
 | 369 |                           Primitive::PrettyDescriptor(phi->GetType()))); | 
 | 370 |   } | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 371 | } | 
 | 372 |  | 
| Nicolas Geoffray | 9ee6618 | 2015-01-16 12:35:40 +0000 | [diff] [blame] | 373 | void SSAChecker::VisitIf(HIf* instruction) { | 
 | 374 |   VisitInstruction(instruction); | 
 | 375 |   HInstruction* input = instruction->InputAt(0); | 
 | 376 |   if (input->IsIntConstant()) { | 
 | 377 |     int value = input->AsIntConstant()->GetValue(); | 
 | 378 |     if (value != 0 && value != 1) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 379 |       AddError(StringPrintf( | 
 | 380 |           "If instruction %d has a non-Boolean constant input " | 
 | 381 |           "whose value is: %d.", | 
 | 382 |           instruction->GetId(), | 
 | 383 |           value)); | 
| Nicolas Geoffray | 9ee6618 | 2015-01-16 12:35:40 +0000 | [diff] [blame] | 384 |     } | 
 | 385 |   } else if (instruction->InputAt(0)->GetType() != Primitive::kPrimBoolean) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 386 |     AddError(StringPrintf( | 
 | 387 |         "If instruction %d has a non-Boolean input type: %s.", | 
 | 388 |         instruction->GetId(), | 
 | 389 |         Primitive::PrettyDescriptor(instruction->InputAt(0)->GetType()))); | 
| Nicolas Geoffray | 9ee6618 | 2015-01-16 12:35:40 +0000 | [diff] [blame] | 390 |   } | 
 | 391 | } | 
 | 392 |  | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 393 | void SSAChecker::VisitCondition(HCondition* op) { | 
 | 394 |   VisitInstruction(op); | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 395 |   if (op->GetType() != Primitive::kPrimBoolean) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 396 |     AddError(StringPrintf( | 
 | 397 |         "Condition %s %d has a non-Boolean result type: %s.", | 
 | 398 |         op->DebugName(), op->GetId(), | 
 | 399 |         Primitive::PrettyDescriptor(op->GetType()))); | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 400 |   } | 
| Nicolas Geoffray | 9ee6618 | 2015-01-16 12:35:40 +0000 | [diff] [blame] | 401 |   HInstruction* lhs = op->InputAt(0); | 
 | 402 |   HInstruction* rhs = op->InputAt(1); | 
| Roland Levillain | aecbd26 | 2015-01-19 12:44:01 +0000 | [diff] [blame] | 403 |   if (lhs->GetType() == Primitive::kPrimNot) { | 
 | 404 |     if (!op->IsEqual() && !op->IsNotEqual()) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 405 |       AddError(StringPrintf( | 
 | 406 |           "Condition %s %d uses an object as left-hand side input.", | 
 | 407 |           op->DebugName(), op->GetId())); | 
| Roland Levillain | aecbd26 | 2015-01-19 12:44:01 +0000 | [diff] [blame] | 408 |     } | 
 | 409 |     if (rhs->IsIntConstant() && rhs->AsIntConstant()->GetValue() != 0) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 410 |       AddError(StringPrintf( | 
 | 411 |           "Condition %s %d compares an object with a non-zero integer: %d.", | 
 | 412 |           op->DebugName(), op->GetId(), | 
 | 413 |           rhs->AsIntConstant()->GetValue())); | 
| Nicolas Geoffray | 9ee6618 | 2015-01-16 12:35:40 +0000 | [diff] [blame] | 414 |     } | 
| Roland Levillain | aecbd26 | 2015-01-19 12:44:01 +0000 | [diff] [blame] | 415 |   } else if (rhs->GetType() == Primitive::kPrimNot) { | 
 | 416 |     if (!op->IsEqual() && !op->IsNotEqual()) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 417 |       AddError(StringPrintf( | 
 | 418 |           "Condition %s %d uses an object as right-hand side input.", | 
 | 419 |           op->DebugName(), op->GetId())); | 
| Roland Levillain | aecbd26 | 2015-01-19 12:44:01 +0000 | [diff] [blame] | 420 |     } | 
 | 421 |     if (lhs->IsIntConstant() && lhs->AsIntConstant()->GetValue() != 0) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 422 |       AddError(StringPrintf( | 
 | 423 |           "Condition %s %d compares a non-zero integer with an object: %d.", | 
 | 424 |           op->DebugName(), op->GetId(), | 
 | 425 |           lhs->AsIntConstant()->GetValue())); | 
| Nicolas Geoffray | 9ee6618 | 2015-01-16 12:35:40 +0000 | [diff] [blame] | 426 |     } | 
 | 427 |   } else if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 428 |       AddError(StringPrintf( | 
 | 429 |           "Condition %s %d has inputs of different types: " | 
 | 430 |           "%s, and %s.", | 
 | 431 |           op->DebugName(), op->GetId(), | 
 | 432 |           Primitive::PrettyDescriptor(lhs->GetType()), | 
 | 433 |           Primitive::PrettyDescriptor(rhs->GetType()))); | 
| Nicolas Geoffray | 9ee6618 | 2015-01-16 12:35:40 +0000 | [diff] [blame] | 434 |   } | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 435 | } | 
 | 436 |  | 
 | 437 | void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) { | 
 | 438 |   VisitInstruction(op); | 
 | 439 |   if (op->IsUShr() || op->IsShr() || op->IsShl()) { | 
 | 440 |     if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 441 |       AddError(StringPrintf( | 
 | 442 |           "Shift operation %s %d has a non-int kind second input: " | 
 | 443 |           "%s of type %s.", | 
 | 444 |           op->DebugName(), op->GetId(), | 
 | 445 |           op->InputAt(1)->DebugName(), | 
 | 446 |           Primitive::PrettyDescriptor(op->InputAt(1)->GetType()))); | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 447 |     } | 
 | 448 |   } else { | 
 | 449 |     if (PrimitiveKind(op->InputAt(1)->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 450 |       AddError(StringPrintf( | 
 | 451 |           "Binary operation %s %d has inputs of different types: " | 
 | 452 |           "%s, and %s.", | 
 | 453 |           op->DebugName(), op->GetId(), | 
 | 454 |           Primitive::PrettyDescriptor(op->InputAt(0)->GetType()), | 
 | 455 |           Primitive::PrettyDescriptor(op->InputAt(1)->GetType()))); | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 456 |     } | 
 | 457 |   } | 
 | 458 |  | 
 | 459 |   if (op->IsCompare()) { | 
 | 460 |     if (op->GetType() != Primitive::kPrimInt) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 461 |       AddError(StringPrintf( | 
 | 462 |           "Compare operation %d has a non-int result type: %s.", | 
 | 463 |           op->GetId(), | 
 | 464 |           Primitive::PrettyDescriptor(op->GetType()))); | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 465 |     } | 
 | 466 |   } else { | 
 | 467 |     // Use the first input, so that we can also make this check for shift operations. | 
 | 468 |     if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) { | 
| Roland Levillain | 5c4405e | 2015-01-21 11:39:58 +0000 | [diff] [blame] | 469 |       AddError(StringPrintf( | 
 | 470 |           "Binary operation %s %d has a result type different " | 
 | 471 |           "from its input type: %s vs %s.", | 
 | 472 |           op->DebugName(), op->GetId(), | 
 | 473 |           Primitive::PrettyDescriptor(op->GetType()), | 
 | 474 |           Primitive::PrettyDescriptor(op->InputAt(1)->GetType()))); | 
| Nicolas Geoffray | 3159674 | 2014-11-24 15:28:45 +0000 | [diff] [blame] | 475 |     } | 
 | 476 |   } | 
 | 477 | } | 
 | 478 |  | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 479 | }  // namespace art |