blob: 7c3c3797954be896c5167c97914fd676a066fb11 [file] [log] [blame]
Roland Levillainccc07a92014-09-16 14:48:16 +01001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "graph_checker.h"
18
Roland Levillainccc07a92014-09-16 14:48:16 +010019#include <map>
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +000020#include <string>
Calin Juravlea4f88312015-04-16 12:57:19 +010021#include <sstream>
Roland Levillainccc07a92014-09-16 14:48:16 +010022
Roland Levillain7e53b412014-09-23 10:50:22 +010023#include "base/bit_vector-inl.h"
Roland Levillain5c4405e2015-01-21 11:39:58 +000024#include "base/stringprintf.h"
Roland Levillain7e53b412014-09-23 10:50:22 +010025
Roland Levillainccc07a92014-09-16 14:48:16 +010026namespace art {
27
28void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
29 current_block_ = block;
30
31 // Check consistency with respect to predecessors of `block`.
32 const GrowableArray<HBasicBlock*>& predecessors = block->GetPredecessors();
33 std::map<HBasicBlock*, size_t> predecessors_count;
34 for (size_t i = 0, e = predecessors.Size(); i < e; ++i) {
35 HBasicBlock* p = predecessors.Get(i);
36 ++predecessors_count[p];
37 }
38 for (auto& pc : predecessors_count) {
39 HBasicBlock* p = pc.first;
40 size_t p_count_in_block_predecessors = pc.second;
41 const GrowableArray<HBasicBlock*>& p_successors = p->GetSuccessors();
42 size_t block_count_in_p_successors = 0;
43 for (size_t j = 0, f = p_successors.Size(); j < f; ++j) {
44 if (p_successors.Get(j) == block) {
45 ++block_count_in_p_successors;
46 }
47 }
48 if (p_count_in_block_predecessors != block_count_in_p_successors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +000049 AddError(StringPrintf(
50 "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
51 "block %d lists %zu occurrences of block %d in its successors.",
52 block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(),
53 p->GetBlockId(), block_count_in_p_successors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010054 }
55 }
56
57 // Check consistency with respect to successors of `block`.
58 const GrowableArray<HBasicBlock*>& successors = block->GetSuccessors();
59 std::map<HBasicBlock*, size_t> successors_count;
60 for (size_t i = 0, e = successors.Size(); i < e; ++i) {
61 HBasicBlock* s = successors.Get(i);
62 ++successors_count[s];
63 }
64 for (auto& sc : successors_count) {
65 HBasicBlock* s = sc.first;
66 size_t s_count_in_block_successors = sc.second;
67 const GrowableArray<HBasicBlock*>& s_predecessors = s->GetPredecessors();
68 size_t block_count_in_s_predecessors = 0;
69 for (size_t j = 0, f = s_predecessors.Size(); j < f; ++j) {
70 if (s_predecessors.Get(j) == block) {
71 ++block_count_in_s_predecessors;
72 }
73 }
74 if (s_count_in_block_successors != block_count_in_s_predecessors) {
Roland Levillain5c4405e2015-01-21 11:39:58 +000075 AddError(StringPrintf(
76 "Block %d lists %zu occurrences of block %d in its successors, whereas "
77 "block %d lists %zu occurrences of block %d in its predecessors.",
78 block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(),
79 s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010080 }
81 }
82
83 // Ensure `block` ends with a branch instruction.
David Brazdil8d5b8b22015-03-24 10:51:52 +000084 if (!block->EndsWithControlFlowInstruction()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +000085 AddError(StringPrintf("Block %d does not end with a branch instruction.",
86 block->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010087 }
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 Levillain5c4405e2015-01-21 11:39:58 +000093 AddError(StringPrintf("Block %d has a non-phi in its phi list.",
94 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +010095 }
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 Levillain5c4405e2015-01-21 11:39:58 +0000104 AddError(StringPrintf("Block %d has a phi in its non-phi list.",
105 current_block_->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100106 }
107 it.Current()->Accept(this);
108 }
109}
110
111void GraphChecker::VisitInstruction(HInstruction* instruction) {
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000112 if (seen_ids_.IsBitSet(instruction->GetId())) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000113 AddError(StringPrintf("Instruction id %d is duplicate in graph.",
114 instruction->GetId()));
Nicolas Geoffray7c5367b2014-12-17 10:13:46 +0000115 } else {
116 seen_ids_.SetBit(instruction->GetId());
117 }
118
Roland Levillainccc07a92014-09-16 14:48:16 +0100119 // Ensure `instruction` is associated with `current_block_`.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000120 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 Levillainccc07a92014-09-16 14:48:16 +0100131 }
Roland Levillain6b469232014-09-25 10:10:38 +0100132
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 Levillain5c4405e2015-01-21 11:39:58 +0000141 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 Levillain6b469232014-09-25 10:10:38 +0100145 }
146 }
147
148 // Ensure the uses of `instruction` are defined in a block of the graph.
David Brazdiled596192015-01-23 10:39:45 +0000149 for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
Roland Levillain6b469232014-09-25 10:10:38 +0100150 !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 Geoffray276d9da2015-02-02 18:24:11 +0000156 AddError(StringPrintf("User %s:%d of instruction %d is not defined "
Roland Levillain5c4405e2015-01-21 11:39:58 +0000157 "in a basic block of the control-flow graph.",
Nicolas Geoffray276d9da2015-02-02 18:24:11 +0000158 use->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000159 use->GetId(),
160 instruction->GetId()));
Roland Levillain6b469232014-09-25 10:10:38 +0100161 }
162 }
David Brazdil1abb4192015-02-17 18:33:36 +0000163
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 Levillainccc07a92014-09-16 14:48:16 +0100179}
180
Roland Levillain4c0eb422015-04-24 16:43:49 +0100181void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
182 VisitInstruction(invoke);
183
184 if (invoke->IsStaticWithExplicitClinitCheck()) {
185 size_t last_input_index = invoke->InputCount() - 1;
186 HInstruction* last_input = invoke->InputAt(last_input_index);
187 if (last_input == nullptr) {
188 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
189 "has a null pointer as last input.",
190 invoke->DebugName(),
191 invoke->GetId()));
192 }
193 if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) {
194 AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
195 "has a last instruction (%s:%d) which is neither a clinit check "
196 "nor a load class instruction.",
197 invoke->DebugName(),
198 invoke->GetId(),
199 last_input->DebugName(),
200 last_input->GetId()));
201 }
202 }
203}
204
Roland Levillainccc07a92014-09-16 14:48:16 +0100205void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
206 super_type::VisitBasicBlock(block);
207
208 // Ensure there is no critical edge (i.e., an edge connecting a
209 // block with multiple successors to a block with multiple
210 // predecessors).
211 if (block->GetSuccessors().Size() > 1) {
212 for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
213 HBasicBlock* successor = block->GetSuccessors().Get(j);
214 if (successor->GetPredecessors().Size() > 1) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000215 AddError(StringPrintf("Critical edge between blocks %d and %d.",
216 block->GetBlockId(),
217 successor->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100218 }
219 }
220 }
Roland Levillain6b879dd2014-09-22 17:13:44 +0100221
Calin Juravlea4f88312015-04-16 12:57:19 +0100222 // Check Phi uniqueness (no two Phis with the same type refer to the same register).
223 for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
224 HPhi* phi = it.Current()->AsPhi();
225 if (phi->GetNextEquivalentPhiWithSameType() != nullptr) {
226 std::stringstream type_str;
227 type_str << phi->GetType();
228 AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s",
229 phi->GetId(), phi->GetRegNumber(), type_str.str().c_str()));
230 }
231 }
232
Roland Levillain6b879dd2014-09-22 17:13:44 +0100233 if (block->IsLoopHeader()) {
234 CheckLoop(block);
235 }
236}
237
238void SSAChecker::CheckLoop(HBasicBlock* loop_header) {
239 int id = loop_header->GetBlockId();
240
241 // Ensure the pre-header block is first in the list of
242 // predecessors of a loop header.
243 if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000244 AddError(StringPrintf(
245 "Loop pre-header is not the first predecessor of the loop header %d.",
246 id));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100247 }
248
249 // Ensure the loop header has only two predecessors and that only the
250 // second one is a back edge.
Roland Levillain5c4405e2015-01-21 11:39:58 +0000251 size_t num_preds = loop_header->GetPredecessors().Size();
252 if (num_preds < 2) {
253 AddError(StringPrintf(
254 "Loop header %d has less than two predecessors: %zu.",
255 id,
256 num_preds));
257 } else if (num_preds > 2) {
258 AddError(StringPrintf(
259 "Loop header %d has more than two predecessors: %zu.",
260 id,
261 num_preds));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100262 } else {
263 HLoopInformation* loop_information = loop_header->GetLoopInformation();
264 HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0);
David Brazdil46e2a392015-03-16 17:31:52 +0000265 if (loop_information->IsBackEdge(*first_predecessor)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000266 AddError(StringPrintf(
267 "First predecessor of loop header %d is a back edge.",
268 id));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100269 }
270 HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1);
David Brazdil46e2a392015-03-16 17:31:52 +0000271 if (!loop_information->IsBackEdge(*second_predecessor)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000272 AddError(StringPrintf(
273 "Second predecessor of loop header %d is not a back edge.",
274 id));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100275 }
276 }
277
278 // Ensure there is only one back edge per loop.
279 size_t num_back_edges =
280 loop_header->GetLoopInformation()->GetBackEdges().Size();
Roland Levillain5c4405e2015-01-21 11:39:58 +0000281 if (num_back_edges == 0) {
282 AddError(StringPrintf(
283 "Loop defined by header %d has no back edge.",
284 id));
285 } else if (num_back_edges > 1) {
286 AddError(StringPrintf(
287 "Loop defined by header %d has several back edges: %zu.",
288 id,
289 num_back_edges));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100290 }
Roland Levillain7e53b412014-09-23 10:50:22 +0100291
292 // Ensure all blocks in the loop are dominated by the loop header.
293 const ArenaBitVector& loop_blocks =
294 loop_header->GetLoopInformation()->GetBlocks();
295 for (uint32_t i : loop_blocks.Indexes()) {
296 HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i);
297 if (!loop_header->Dominates(loop_block)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000298 AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
299 loop_block->GetBlockId(),
300 id));
Roland Levillain7e53b412014-09-23 10:50:22 +0100301 }
302 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100303}
304
305void SSAChecker::VisitInstruction(HInstruction* instruction) {
306 super_type::VisitInstruction(instruction);
307
Roland Levillaina8069ce2014-10-01 10:48:29 +0100308 // Ensure an instruction dominates all its uses.
David Brazdiled596192015-01-23 10:39:45 +0000309 for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
Roland Levillaina8069ce2014-10-01 10:48:29 +0100310 !use_it.Done(); use_it.Advance()) {
311 HInstruction* use = use_it.Current()->GetUser();
Roland Levillain6c82d402014-10-13 16:10:27 +0100312 if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000313 AddError(StringPrintf("Instruction %d in block %d does not dominate "
314 "use %d in block %d.",
315 instruction->GetId(), current_block_->GetBlockId(),
316 use->GetId(), use->GetBlock()->GetBlockId()));
Roland Levillainccc07a92014-09-16 14:48:16 +0100317 }
318 }
Roland Levillaina8069ce2014-10-01 10:48:29 +0100319
320 // Ensure an instruction having an environment is dominated by the
321 // instructions contained in the environment.
322 HEnvironment* environment = instruction->GetEnvironment();
323 if (environment != nullptr) {
324 for (size_t i = 0, e = environment->Size(); i < e; ++i) {
325 HInstruction* env_instruction = environment->GetInstructionAt(i);
326 if (env_instruction != nullptr
Roland Levillain6c82d402014-10-13 16:10:27 +0100327 && !env_instruction->StrictlyDominates(instruction)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000328 AddError(StringPrintf("Instruction %d in environment of instruction %d "
329 "from block %d does not dominate instruction %d.",
330 env_instruction->GetId(),
331 instruction->GetId(),
332 current_block_->GetBlockId(),
333 instruction->GetId()));
Roland Levillaina8069ce2014-10-01 10:48:29 +0100334 }
335 }
336 }
Roland Levillainccc07a92014-09-16 14:48:16 +0100337}
338
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000339static Primitive::Type PrimitiveKind(Primitive::Type type) {
340 switch (type) {
341 case Primitive::kPrimBoolean:
342 case Primitive::kPrimByte:
343 case Primitive::kPrimShort:
344 case Primitive::kPrimChar:
345 case Primitive::kPrimInt:
346 return Primitive::kPrimInt;
347 default:
348 return type;
349 }
350}
351
Roland Levillain6b879dd2014-09-22 17:13:44 +0100352void SSAChecker::VisitPhi(HPhi* phi) {
353 VisitInstruction(phi);
354
355 // Ensure the first input of a phi is not itself.
356 if (phi->InputAt(0) == phi) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000357 AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
358 phi->GetId(),
359 phi->GetBlock()->GetBlockId()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100360 }
361
Roland Levillain5c4405e2015-01-21 11:39:58 +0000362 // Ensure the number of inputs of a phi is the same as the number of
Roland Levillain6b879dd2014-09-22 17:13:44 +0100363 // its predecessors.
364 const GrowableArray<HBasicBlock*>& predecessors =
365 phi->GetBlock()->GetPredecessors();
366 if (phi->InputCount() != predecessors.Size()) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000367 AddError(StringPrintf(
368 "Phi %d in block %d has %zu inputs, "
369 "but block %d has %zu predecessors.",
370 phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(),
371 phi->GetBlock()->GetBlockId(), predecessors.Size()));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100372 } else {
373 // Ensure phi input at index I either comes from the Ith
374 // predecessor or from a block that dominates this predecessor.
375 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
376 HInstruction* input = phi->InputAt(i);
377 HBasicBlock* predecessor = predecessors.Get(i);
378 if (!(input->GetBlock() == predecessor
379 || input->GetBlock()->Dominates(predecessor))) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000380 AddError(StringPrintf(
381 "Input %d at index %zu of phi %d from block %d is not defined in "
382 "predecessor number %zu nor in a block dominating it.",
383 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
384 i));
Roland Levillain6b879dd2014-09-22 17:13:44 +0100385 }
386 }
387 }
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000388 // Ensure that the inputs have the same primitive kind as the phi.
389 for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
390 HInstruction* input = phi->InputAt(i);
391 if (PrimitiveKind(input->GetType()) != PrimitiveKind(phi->GetType())) {
392 AddError(StringPrintf(
393 "Input %d at index %zu of phi %d from block %d does not have the "
394 "same type as the phi: %s versus %s",
395 input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
396 Primitive::PrettyDescriptor(input->GetType()),
397 Primitive::PrettyDescriptor(phi->GetType())));
398 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000399 }
Nicolas Geoffraye0fe7ae2015-03-09 10:02:49 +0000400 if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
401 AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
402 phi->GetId(),
403 phi->GetBlock()->GetBlockId(),
404 Primitive::PrettyDescriptor(phi->GetType())));
405 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000406}
407
David Brazdil13b47182015-04-15 16:29:32 +0100408void SSAChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
409 HInstruction* input = instruction->InputAt(input_index);
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000410 if (input->IsIntConstant()) {
David Brazdil13b47182015-04-15 16:29:32 +0100411 int32_t value = input->AsIntConstant()->GetValue();
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000412 if (value != 0 && value != 1) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000413 AddError(StringPrintf(
David Brazdil13b47182015-04-15 16:29:32 +0100414 "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
415 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000416 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100417 static_cast<int>(input_index),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000418 value));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000419 }
David Brazdil2fa194b2015-04-20 10:14:42 +0100420 } else if (input->GetType() == Primitive::kPrimInt
421 && (input->IsPhi() || input->IsAnd() || input->IsOr() || input->IsXor())) {
422 // TODO: We need a data-flow analysis to determine if the Phi or
423 // binary operation is actually Boolean. Allow for now.
David Brazdil13b47182015-04-15 16:29:32 +0100424 } else if (input->GetType() != Primitive::kPrimBoolean) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000425 AddError(StringPrintf(
David Brazdil13b47182015-04-15 16:29:32 +0100426 "%s instruction %d has a non-Boolean input %d whose type is: %s.",
427 instruction->DebugName(),
Roland Levillain5c4405e2015-01-21 11:39:58 +0000428 instruction->GetId(),
David Brazdil13b47182015-04-15 16:29:32 +0100429 static_cast<int>(input_index),
430 Primitive::PrettyDescriptor(input->GetType())));
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000431 }
432}
433
David Brazdil13b47182015-04-15 16:29:32 +0100434void SSAChecker::VisitIf(HIf* instruction) {
435 VisitInstruction(instruction);
436 HandleBooleanInput(instruction, 0);
437}
438
439void SSAChecker::VisitBooleanNot(HBooleanNot* instruction) {
440 VisitInstruction(instruction);
441 HandleBooleanInput(instruction, 0);
442}
443
Nicolas Geoffray31596742014-11-24 15:28:45 +0000444void SSAChecker::VisitCondition(HCondition* op) {
445 VisitInstruction(op);
Nicolas Geoffray31596742014-11-24 15:28:45 +0000446 if (op->GetType() != Primitive::kPrimBoolean) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000447 AddError(StringPrintf(
448 "Condition %s %d has a non-Boolean result type: %s.",
449 op->DebugName(), op->GetId(),
450 Primitive::PrettyDescriptor(op->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000451 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000452 HInstruction* lhs = op->InputAt(0);
453 HInstruction* rhs = op->InputAt(1);
Calin Juravlea4f88312015-04-16 12:57:19 +0100454 if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) {
455 AddError(StringPrintf(
456 "Condition %s %d has inputs of different types: %s, and %s.",
457 op->DebugName(), op->GetId(),
458 Primitive::PrettyDescriptor(lhs->GetType()),
459 Primitive::PrettyDescriptor(rhs->GetType())));
460 }
461 if (!op->IsEqual() && !op->IsNotEqual()) {
462 if ((lhs->GetType() == Primitive::kPrimNot)) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000463 AddError(StringPrintf(
464 "Condition %s %d uses an object as left-hand side input.",
465 op->DebugName(), op->GetId()));
Calin Juravlea4f88312015-04-16 12:57:19 +0100466 } else if (rhs->GetType() == Primitive::kPrimNot) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000467 AddError(StringPrintf(
468 "Condition %s %d uses an object as right-hand side input.",
469 op->DebugName(), op->GetId()));
Roland Levillainaecbd262015-01-19 12:44:01 +0000470 }
Nicolas Geoffray9ee66182015-01-16 12:35:40 +0000471 }
Nicolas Geoffray31596742014-11-24 15:28:45 +0000472}
473
474void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) {
475 VisitInstruction(op);
476 if (op->IsUShr() || op->IsShr() || op->IsShl()) {
477 if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000478 AddError(StringPrintf(
479 "Shift operation %s %d has a non-int kind second input: "
480 "%s of type %s.",
481 op->DebugName(), op->GetId(),
482 op->InputAt(1)->DebugName(),
483 Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000484 }
485 } else {
Roland Levillain4c0eb422015-04-24 16:43:49 +0100486 if (PrimitiveKind(op->InputAt(0)->GetType()) != PrimitiveKind(op->InputAt(1)->GetType())) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000487 AddError(StringPrintf(
488 "Binary operation %s %d has inputs of different types: "
489 "%s, and %s.",
490 op->DebugName(), op->GetId(),
491 Primitive::PrettyDescriptor(op->InputAt(0)->GetType()),
492 Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000493 }
494 }
495
496 if (op->IsCompare()) {
497 if (op->GetType() != Primitive::kPrimInt) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000498 AddError(StringPrintf(
499 "Compare operation %d has a non-int result type: %s.",
500 op->GetId(),
501 Primitive::PrettyDescriptor(op->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000502 }
503 } else {
504 // Use the first input, so that we can also make this check for shift operations.
505 if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
Roland Levillain5c4405e2015-01-21 11:39:58 +0000506 AddError(StringPrintf(
507 "Binary operation %s %d has a result type different "
508 "from its input type: %s vs %s.",
509 op->DebugName(), op->GetId(),
510 Primitive::PrettyDescriptor(op->GetType()),
Roland Levillain4c0eb422015-04-24 16:43:49 +0100511 Primitive::PrettyDescriptor(op->InputAt(0)->GetType())));
Nicolas Geoffray31596742014-11-24 15:28:45 +0000512 }
513 }
514}
515
David Brazdil8d5b8b22015-03-24 10:51:52 +0000516void SSAChecker::VisitConstant(HConstant* instruction) {
517 HBasicBlock* block = instruction->GetBlock();
518 if (!block->IsEntryBlock()) {
519 AddError(StringPrintf(
520 "%s %d should be in the entry block but is in block %d.",
521 instruction->DebugName(),
522 instruction->GetId(),
523 block->GetBlockId()));
524 }
525}
526
Roland Levillainccc07a92014-09-16 14:48:16 +0100527} // namespace art