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 
19 #include <map>
20 #include <string>
21 #include <sstream>
22 
23 #include "base/bit_vector-inl.h"
24 #include "base/stringprintf.h"
25 
26 namespace art {
27 
VisitBasicBlock(HBasicBlock * block)28 void 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) {
49       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()));
54     }
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) {
75       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()));
80     }
81   }
82 
83   // Ensure `block` ends with a branch instruction.
84   if (!block->EndsWithControlFlowInstruction()) {
85     AddError(StringPrintf("Block %d does not end with a branch instruction.",
86                           block->GetBlockId()));
87   }
88 
89   // Visit this block's list of phis.
90   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
91     HInstruction* current = it.Current();
92     // Ensure this block's list of phis contains only phis.
93     if (!current->IsPhi()) {
94       AddError(StringPrintf("Block %d has a non-phi in its phi list.",
95                             current_block_->GetBlockId()));
96     }
97     if (current->GetNext() == nullptr && current != block->GetLastPhi()) {
98       AddError(StringPrintf("The recorded last phi of block %d does not match "
99                             "the actual last phi %d.",
100                             current_block_->GetBlockId(),
101                             current->GetId()));
102     }
103     current->Accept(this);
104   }
105 
106   // Visit this block's list of instructions.
107   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
108     HInstruction* current = it.Current();
109     // Ensure this block's list of instructions does not contains phis.
110     if (current->IsPhi()) {
111       AddError(StringPrintf("Block %d has a phi in its non-phi list.",
112                             current_block_->GetBlockId()));
113     }
114     if (current->GetNext() == nullptr && current != block->GetLastInstruction()) {
115       AddError(StringPrintf("The recorded last instruction of block %d does not match "
116                             "the actual last instruction %d.",
117                             current_block_->GetBlockId(),
118                             current->GetId()));
119     }
120     current->Accept(this);
121   }
122 }
123 
VisitBoundsCheck(HBoundsCheck * check)124 void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) {
125   if (!GetGraph()->HasBoundsChecks()) {
126     AddError(StringPrintf("Instruction %s:%d is a HBoundsCheck, "
127                           "but HasBoundsChecks() returns false",
128                           check->DebugName(),
129                           check->GetId()));
130   }
131 
132   // Perform the instruction base checks too.
133   VisitInstruction(check);
134 }
135 
VisitInstruction(HInstruction * instruction)136 void GraphChecker::VisitInstruction(HInstruction* instruction) {
137   if (seen_ids_.IsBitSet(instruction->GetId())) {
138     AddError(StringPrintf("Instruction id %d is duplicate in graph.",
139                           instruction->GetId()));
140   } else {
141     seen_ids_.SetBit(instruction->GetId());
142   }
143 
144   // Ensure `instruction` is associated with `current_block_`.
145   if (instruction->GetBlock() == nullptr) {
146     AddError(StringPrintf("%s %d in block %d not associated with any block.",
147                           instruction->IsPhi() ? "Phi" : "Instruction",
148                           instruction->GetId(),
149                           current_block_->GetBlockId()));
150   } else if (instruction->GetBlock() != current_block_) {
151     AddError(StringPrintf("%s %d in block %d associated with block %d.",
152                           instruction->IsPhi() ? "Phi" : "Instruction",
153                           instruction->GetId(),
154                           current_block_->GetBlockId(),
155                           instruction->GetBlock()->GetBlockId()));
156   }
157 
158   // Ensure the inputs of `instruction` are defined in a block of the graph.
159   for (HInputIterator input_it(instruction); !input_it.Done();
160        input_it.Advance()) {
161     HInstruction* input = input_it.Current();
162     const HInstructionList& list = input->IsPhi()
163         ? input->GetBlock()->GetPhis()
164         : input->GetBlock()->GetInstructions();
165     if (!list.Contains(input)) {
166       AddError(StringPrintf("Input %d of instruction %d is not defined "
167                             "in a basic block of the control-flow graph.",
168                             input->GetId(),
169                             instruction->GetId()));
170     }
171   }
172 
173   // Ensure the uses of `instruction` are defined in a block of the graph,
174   // and the entry in the use list is consistent.
175   for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
176        !use_it.Done(); use_it.Advance()) {
177     HInstruction* use = use_it.Current()->GetUser();
178     const HInstructionList& list = use->IsPhi()
179         ? use->GetBlock()->GetPhis()
180         : use->GetBlock()->GetInstructions();
181     if (!list.Contains(use)) {
182       AddError(StringPrintf("User %s:%d of instruction %d is not defined "
183                             "in a basic block of the control-flow graph.",
184                             use->DebugName(),
185                             use->GetId(),
186                             instruction->GetId()));
187     }
188     size_t use_index = use_it.Current()->GetIndex();
189     if ((use_index >= use->InputCount()) || (use->InputAt(use_index) != instruction)) {
190       AddError(StringPrintf("User %s:%d of instruction %d has a wrong "
191                             "UseListNode index.",
192                             use->DebugName(),
193                             use->GetId(),
194                             instruction->GetId()));
195     }
196   }
197 
198   // Ensure the environment uses entries are consistent.
199   for (HUseIterator<HEnvironment*> use_it(instruction->GetEnvUses());
200        !use_it.Done(); use_it.Advance()) {
201     HEnvironment* use = use_it.Current()->GetUser();
202     size_t use_index = use_it.Current()->GetIndex();
203     if ((use_index >= use->Size()) || (use->GetInstructionAt(use_index) != instruction)) {
204       AddError(StringPrintf("Environment user of %s:%d has a wrong "
205                             "UseListNode index.",
206                             instruction->DebugName(),
207                             instruction->GetId()));
208     }
209   }
210 
211   // Ensure 'instruction' has pointers to its inputs' use entries.
212   for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
213     HUserRecord<HInstruction*> input_record = instruction->InputRecordAt(i);
214     HInstruction* input = input_record.GetInstruction();
215     HUseListNode<HInstruction*>* use_node = input_record.GetUseNode();
216     size_t use_index = use_node->GetIndex();
217     if ((use_node == nullptr)
218         || !input->GetUses().Contains(use_node)
219         || (use_index >= e)
220         || (use_index != i)) {
221       AddError(StringPrintf("Instruction %s:%d has an invalid pointer to use entry "
222                             "at input %u (%s:%d).",
223                             instruction->DebugName(),
224                             instruction->GetId(),
225                             static_cast<unsigned>(i),
226                             input->DebugName(),
227                             input->GetId()));
228     }
229   }
230 }
231 
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)232 void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
233   VisitInstruction(invoke);
234 
235   if (invoke->IsStaticWithExplicitClinitCheck()) {
236     size_t last_input_index = invoke->InputCount() - 1;
237     HInstruction* last_input = invoke->InputAt(last_input_index);
238     if (last_input == nullptr) {
239       AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
240                             "has a null pointer as last input.",
241                             invoke->DebugName(),
242                             invoke->GetId()));
243     }
244     if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) {
245       AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
246                             "has a last instruction (%s:%d) which is neither a clinit check "
247                             "nor a load class instruction.",
248                             invoke->DebugName(),
249                             invoke->GetId(),
250                             last_input->DebugName(),
251                             last_input->GetId()));
252     }
253   }
254 }
255 
VisitCheckCast(HCheckCast * check)256 void GraphChecker::VisitCheckCast(HCheckCast* check) {
257   VisitInstruction(check);
258   HInstruction* input = check->InputAt(1);
259   if (!input->IsLoadClass()) {
260     AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
261                           check->DebugName(),
262                           check->GetId(),
263                           input->DebugName(),
264                           input->GetId()));
265   }
266 }
267 
VisitInstanceOf(HInstanceOf * instruction)268 void GraphChecker::VisitInstanceOf(HInstanceOf* instruction) {
269   VisitInstruction(instruction);
270   HInstruction* input = instruction->InputAt(1);
271   if (!input->IsLoadClass()) {
272     AddError(StringPrintf("%s:%d expects a HLoadClass as second input, not %s:%d.",
273                           instruction->DebugName(),
274                           instruction->GetId(),
275                           input->DebugName(),
276                           input->GetId()));
277   }
278 }
279 
VisitBasicBlock(HBasicBlock * block)280 void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
281   super_type::VisitBasicBlock(block);
282 
283   // Ensure there is no critical edge (i.e., an edge connecting a
284   // block with multiple successors to a block with multiple
285   // predecessors).
286   if (block->GetSuccessors().Size() > 1) {
287     for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
288       HBasicBlock* successor = block->GetSuccessors().Get(j);
289       if (successor->GetPredecessors().Size() > 1) {
290         AddError(StringPrintf("Critical edge between blocks %d and %d.",
291                               block->GetBlockId(),
292                               successor->GetBlockId()));
293       }
294     }
295   }
296 
297   // Check Phi uniqueness (no two Phis with the same type refer to the same register).
298   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
299     HPhi* phi = it.Current()->AsPhi();
300     if (phi->GetNextEquivalentPhiWithSameType() != nullptr) {
301       std::stringstream type_str;
302       type_str << phi->GetType();
303       AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s",
304           phi->GetId(), phi->GetRegNumber(), type_str.str().c_str()));
305     }
306   }
307 
308   if (block->IsLoopHeader()) {
309     CheckLoop(block);
310   }
311 }
312 
CheckLoop(HBasicBlock * loop_header)313 void SSAChecker::CheckLoop(HBasicBlock* loop_header) {
314   int id = loop_header->GetBlockId();
315   HLoopInformation* loop_information = loop_header->GetLoopInformation();
316 
317   // Ensure the pre-header block is first in the list of
318   // predecessors of a loop header.
319   if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
320     AddError(StringPrintf(
321         "Loop pre-header is not the first predecessor of the loop header %d.",
322         id));
323   }
324 
325   // Ensure the loop header has only one incoming branch and the remaining
326   // predecessors are back edges.
327   size_t num_preds = loop_header->GetPredecessors().Size();
328   if (num_preds < 2) {
329     AddError(StringPrintf(
330         "Loop header %d has less than two predecessors: %zu.",
331         id,
332         num_preds));
333   } else {
334     HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0);
335     if (loop_information->IsBackEdge(*first_predecessor)) {
336       AddError(StringPrintf(
337           "First predecessor of loop header %d is a back edge.",
338           id));
339     }
340     for (size_t i = 1, e = loop_header->GetPredecessors().Size(); i < e; ++i) {
341       HBasicBlock* predecessor = loop_header->GetPredecessors().Get(i);
342       if (!loop_information->IsBackEdge(*predecessor)) {
343         AddError(StringPrintf(
344             "Loop header %d has multiple incoming (non back edge) blocks.",
345             id));
346       }
347     }
348   }
349 
350   const ArenaBitVector& loop_blocks = loop_information->GetBlocks();
351 
352   // Ensure back edges belong to the loop.
353   size_t num_back_edges = loop_information->GetBackEdges().Size();
354   if (num_back_edges == 0) {
355     AddError(StringPrintf(
356         "Loop defined by header %d has no back edge.",
357         id));
358   } else {
359     for (size_t i = 0; i < num_back_edges; ++i) {
360       int back_edge_id = loop_information->GetBackEdges().Get(i)->GetBlockId();
361       if (!loop_blocks.IsBitSet(back_edge_id)) {
362         AddError(StringPrintf(
363             "Loop defined by header %d has an invalid back edge %d.",
364             id,
365             back_edge_id));
366       }
367     }
368   }
369 
370   // Ensure all blocks in the loop are live and dominated by the loop header.
371   for (uint32_t i : loop_blocks.Indexes()) {
372     HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i);
373     if (loop_block == nullptr) {
374       AddError(StringPrintf("Loop defined by header %d contains a previously removed block %d.",
375                             id,
376                             i));
377     } else if (!loop_header->Dominates(loop_block)) {
378       AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
379                             i,
380                             id));
381     }
382   }
383 
384   // If this is a nested loop, ensure the outer loops contain a superset of the blocks.
385   for (HLoopInformationOutwardIterator it(*loop_header); !it.Done(); it.Advance()) {
386     HLoopInformation* outer_info = it.Current();
387     if (!loop_blocks.IsSubsetOf(&outer_info->GetBlocks())) {
388       AddError(StringPrintf("Blocks of loop defined by header %d are not a subset of blocks of "
389                             "an outer loop defined by header %d.",
390                             id,
391                             outer_info->GetHeader()->GetBlockId()));
392     }
393   }
394 }
395 
VisitInstruction(HInstruction * instruction)396 void SSAChecker::VisitInstruction(HInstruction* instruction) {
397   super_type::VisitInstruction(instruction);
398 
399   // Ensure an instruction dominates all its uses.
400   for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
401        !use_it.Done(); use_it.Advance()) {
402     HInstruction* use = use_it.Current()->GetUser();
403     if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
404       AddError(StringPrintf("Instruction %d in block %d does not dominate "
405                             "use %d in block %d.",
406                             instruction->GetId(), current_block_->GetBlockId(),
407                             use->GetId(), use->GetBlock()->GetBlockId()));
408     }
409   }
410 
411   // Ensure an instruction having an environment is dominated by the
412   // instructions contained in the environment.
413   for (HEnvironment* environment = instruction->GetEnvironment();
414        environment != nullptr;
415        environment = environment->GetParent()) {
416     for (size_t i = 0, e = environment->Size(); i < e; ++i) {
417       HInstruction* env_instruction = environment->GetInstructionAt(i);
418       if (env_instruction != nullptr
419           && !env_instruction->StrictlyDominates(instruction)) {
420         AddError(StringPrintf("Instruction %d in environment of instruction %d "
421                               "from block %d does not dominate instruction %d.",
422                               env_instruction->GetId(),
423                               instruction->GetId(),
424                               current_block_->GetBlockId(),
425                               instruction->GetId()));
426       }
427     }
428   }
429 }
430 
PrimitiveKind(Primitive::Type type)431 static Primitive::Type PrimitiveKind(Primitive::Type type) {
432   switch (type) {
433     case Primitive::kPrimBoolean:
434     case Primitive::kPrimByte:
435     case Primitive::kPrimShort:
436     case Primitive::kPrimChar:
437     case Primitive::kPrimInt:
438       return Primitive::kPrimInt;
439     default:
440       return type;
441   }
442 }
443 
VisitPhi(HPhi * phi)444 void SSAChecker::VisitPhi(HPhi* phi) {
445   VisitInstruction(phi);
446 
447   // Ensure the first input of a phi is not itself.
448   if (phi->InputAt(0) == phi) {
449     AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
450                           phi->GetId(),
451                           phi->GetBlock()->GetBlockId()));
452   }
453 
454   // Ensure the number of inputs of a phi is the same as the number of
455   // its predecessors.
456   const GrowableArray<HBasicBlock*>& predecessors =
457     phi->GetBlock()->GetPredecessors();
458   if (phi->InputCount() != predecessors.Size()) {
459     AddError(StringPrintf(
460         "Phi %d in block %d has %zu inputs, "
461         "but block %d has %zu predecessors.",
462         phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(),
463         phi->GetBlock()->GetBlockId(), predecessors.Size()));
464   } else {
465     // Ensure phi input at index I either comes from the Ith
466     // predecessor or from a block that dominates this predecessor.
467     for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
468       HInstruction* input = phi->InputAt(i);
469       HBasicBlock* predecessor = predecessors.Get(i);
470       if (!(input->GetBlock() == predecessor
471             || input->GetBlock()->Dominates(predecessor))) {
472         AddError(StringPrintf(
473             "Input %d at index %zu of phi %d from block %d is not defined in "
474             "predecessor number %zu nor in a block dominating it.",
475             input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
476             i));
477       }
478     }
479   }
480   // Ensure that the inputs have the same primitive kind as the phi.
481   for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
482     HInstruction* input = phi->InputAt(i);
483     if (PrimitiveKind(input->GetType()) != PrimitiveKind(phi->GetType())) {
484         AddError(StringPrintf(
485             "Input %d at index %zu of phi %d from block %d does not have the "
486             "same type as the phi: %s versus %s",
487             input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
488             Primitive::PrettyDescriptor(input->GetType()),
489             Primitive::PrettyDescriptor(phi->GetType())));
490     }
491   }
492   if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
493     AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
494                           phi->GetId(),
495                           phi->GetBlock()->GetBlockId(),
496                           Primitive::PrettyDescriptor(phi->GetType())));
497   }
498 }
499 
HandleBooleanInput(HInstruction * instruction,size_t input_index)500 void SSAChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
501   HInstruction* input = instruction->InputAt(input_index);
502   if (input->IsIntConstant()) {
503     int32_t value = input->AsIntConstant()->GetValue();
504     if (value != 0 && value != 1) {
505       AddError(StringPrintf(
506           "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
507           instruction->DebugName(),
508           instruction->GetId(),
509           static_cast<int>(input_index),
510           value));
511     }
512   } else if (input->GetType() == Primitive::kPrimInt
513              && (input->IsPhi() || input->IsAnd() || input->IsOr() || input->IsXor())) {
514     // TODO: We need a data-flow analysis to determine if the Phi or
515     //       binary operation is actually Boolean. Allow for now.
516   } else if (input->GetType() != Primitive::kPrimBoolean) {
517     AddError(StringPrintf(
518         "%s instruction %d has a non-Boolean input %d whose type is: %s.",
519         instruction->DebugName(),
520         instruction->GetId(),
521         static_cast<int>(input_index),
522         Primitive::PrettyDescriptor(input->GetType())));
523   }
524 }
525 
VisitIf(HIf * instruction)526 void SSAChecker::VisitIf(HIf* instruction) {
527   VisitInstruction(instruction);
528   HandleBooleanInput(instruction, 0);
529 }
530 
VisitBooleanNot(HBooleanNot * instruction)531 void SSAChecker::VisitBooleanNot(HBooleanNot* instruction) {
532   VisitInstruction(instruction);
533   HandleBooleanInput(instruction, 0);
534 }
535 
VisitCondition(HCondition * op)536 void SSAChecker::VisitCondition(HCondition* op) {
537   VisitInstruction(op);
538   if (op->GetType() != Primitive::kPrimBoolean) {
539     AddError(StringPrintf(
540         "Condition %s %d has a non-Boolean result type: %s.",
541         op->DebugName(), op->GetId(),
542         Primitive::PrettyDescriptor(op->GetType())));
543   }
544   HInstruction* lhs = op->InputAt(0);
545   HInstruction* rhs = op->InputAt(1);
546   if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) {
547     AddError(StringPrintf(
548         "Condition %s %d has inputs of different types: %s, and %s.",
549         op->DebugName(), op->GetId(),
550         Primitive::PrettyDescriptor(lhs->GetType()),
551         Primitive::PrettyDescriptor(rhs->GetType())));
552   }
553   if (!op->IsEqual() && !op->IsNotEqual()) {
554     if ((lhs->GetType() == Primitive::kPrimNot)) {
555       AddError(StringPrintf(
556           "Condition %s %d uses an object as left-hand side input.",
557           op->DebugName(), op->GetId()));
558     } else if (rhs->GetType() == Primitive::kPrimNot) {
559       AddError(StringPrintf(
560           "Condition %s %d uses an object as right-hand side input.",
561           op->DebugName(), op->GetId()));
562     }
563   }
564 }
565 
VisitBinaryOperation(HBinaryOperation * op)566 void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) {
567   VisitInstruction(op);
568   if (op->IsUShr() || op->IsShr() || op->IsShl()) {
569     if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
570       AddError(StringPrintf(
571           "Shift operation %s %d has a non-int kind second input: "
572           "%s of type %s.",
573           op->DebugName(), op->GetId(),
574           op->InputAt(1)->DebugName(),
575           Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
576     }
577   } else {
578     if (PrimitiveKind(op->InputAt(0)->GetType()) != PrimitiveKind(op->InputAt(1)->GetType())) {
579       AddError(StringPrintf(
580           "Binary operation %s %d has inputs of different types: "
581           "%s, and %s.",
582           op->DebugName(), op->GetId(),
583           Primitive::PrettyDescriptor(op->InputAt(0)->GetType()),
584           Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
585     }
586   }
587 
588   if (op->IsCompare()) {
589     if (op->GetType() != Primitive::kPrimInt) {
590       AddError(StringPrintf(
591           "Compare operation %d has a non-int result type: %s.",
592           op->GetId(),
593           Primitive::PrettyDescriptor(op->GetType())));
594     }
595   } else {
596     // Use the first input, so that we can also make this check for shift operations.
597     if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
598       AddError(StringPrintf(
599           "Binary operation %s %d has a result type different "
600           "from its input type: %s vs %s.",
601           op->DebugName(), op->GetId(),
602           Primitive::PrettyDescriptor(op->GetType()),
603           Primitive::PrettyDescriptor(op->InputAt(0)->GetType())));
604     }
605   }
606 }
607 
VisitConstant(HConstant * instruction)608 void SSAChecker::VisitConstant(HConstant* instruction) {
609   HBasicBlock* block = instruction->GetBlock();
610   if (!block->IsEntryBlock()) {
611     AddError(StringPrintf(
612         "%s %d should be in the entry block but is in block %d.",
613         instruction->DebugName(),
614         instruction->GetId(),
615         block->GetBlockId()));
616   }
617 }
618 
619 }  // namespace art
620