1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "graph_checker.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include <algorithm>
20*795d594fSAndroid Build Coastguard Worker #include <sstream>
21*795d594fSAndroid Build Coastguard Worker #include <string>
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
28*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
29*795d594fSAndroid Build Coastguard Worker #include "handle.h"
30*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
31*795d594fSAndroid Build Coastguard Worker #include "mirror/class.h"
32*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
33*795d594fSAndroid Build Coastguard Worker #include "obj_ptr-inl.h"
34*795d594fSAndroid Build Coastguard Worker #include "optimizing/data_type.h"
35*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
36*795d594fSAndroid Build Coastguard Worker #include "subtype_check.h"
37*795d594fSAndroid Build Coastguard Worker
38*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
39*795d594fSAndroid Build Coastguard Worker
40*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
41*795d594fSAndroid Build Coastguard Worker
IsAllowedToJumpToExitBlock(HInstruction * instruction)42*795d594fSAndroid Build Coastguard Worker static bool IsAllowedToJumpToExitBlock(HInstruction* instruction) {
43*795d594fSAndroid Build Coastguard Worker // Anything that returns is allowed to jump into the exit block.
44*795d594fSAndroid Build Coastguard Worker if (instruction->IsReturn() || instruction->IsReturnVoid()) {
45*795d594fSAndroid Build Coastguard Worker return true;
46*795d594fSAndroid Build Coastguard Worker }
47*795d594fSAndroid Build Coastguard Worker // Anything that always throws is allowed to jump into the exit block.
48*795d594fSAndroid Build Coastguard Worker if (instruction->IsGoto() && instruction->GetPrevious() != nullptr) {
49*795d594fSAndroid Build Coastguard Worker instruction = instruction->GetPrevious();
50*795d594fSAndroid Build Coastguard Worker }
51*795d594fSAndroid Build Coastguard Worker return instruction->AlwaysThrows();
52*795d594fSAndroid Build Coastguard Worker }
53*795d594fSAndroid Build Coastguard Worker
IsExitTryBoundaryIntoExitBlock(HBasicBlock * block)54*795d594fSAndroid Build Coastguard Worker static bool IsExitTryBoundaryIntoExitBlock(HBasicBlock* block) {
55*795d594fSAndroid Build Coastguard Worker if (!block->IsSingleTryBoundary()) {
56*795d594fSAndroid Build Coastguard Worker return false;
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker
59*795d594fSAndroid Build Coastguard Worker HTryBoundary* boundary = block->GetLastInstruction()->AsTryBoundary();
60*795d594fSAndroid Build Coastguard Worker return block->GetPredecessors().size() == 1u &&
61*795d594fSAndroid Build Coastguard Worker boundary->GetNormalFlowSuccessor()->IsExitBlock() &&
62*795d594fSAndroid Build Coastguard Worker !boundary->IsEntry();
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker
65*795d594fSAndroid Build Coastguard Worker
Run(bool pass_change,size_t last_size)66*795d594fSAndroid Build Coastguard Worker size_t GraphChecker::Run(bool pass_change, size_t last_size) {
67*795d594fSAndroid Build Coastguard Worker size_t current_size = GetGraph()->GetReversePostOrder().size();
68*795d594fSAndroid Build Coastguard Worker if (!pass_change) {
69*795d594fSAndroid Build Coastguard Worker // Nothing changed for certain. Do a quick check of the validity on that assertion
70*795d594fSAndroid Build Coastguard Worker // for anything other than the first call (when last size was still 0).
71*795d594fSAndroid Build Coastguard Worker if (last_size != 0) {
72*795d594fSAndroid Build Coastguard Worker if (current_size != last_size) {
73*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Incorrect no-change assertion, "
74*795d594fSAndroid Build Coastguard Worker "last graph size %zu vs current graph size %zu",
75*795d594fSAndroid Build Coastguard Worker last_size, current_size));
76*795d594fSAndroid Build Coastguard Worker }
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker // TODO: if we would trust the "false" value of the flag completely, we
79*795d594fSAndroid Build Coastguard Worker // could skip checking the graph at this point.
80*795d594fSAndroid Build Coastguard Worker }
81*795d594fSAndroid Build Coastguard Worker
82*795d594fSAndroid Build Coastguard Worker // VisitReversePostOrder is used instead of VisitInsertionOrder,
83*795d594fSAndroid Build Coastguard Worker // as the latter might visit dead blocks removed by the dominator
84*795d594fSAndroid Build Coastguard Worker // computation.
85*795d594fSAndroid Build Coastguard Worker VisitReversePostOrder();
86*795d594fSAndroid Build Coastguard Worker CheckGraphFlags();
87*795d594fSAndroid Build Coastguard Worker return current_size;
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker
VisitReversePostOrder()90*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitReversePostOrder() {
91*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
92*795d594fSAndroid Build Coastguard Worker if (block->IsInLoop()) {
93*795d594fSAndroid Build Coastguard Worker flag_info_.seen_loop = true;
94*795d594fSAndroid Build Coastguard Worker if (block->GetLoopInformation()->IsIrreducible()) {
95*795d594fSAndroid Build Coastguard Worker flag_info_.seen_irreducible_loop = true;
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker
99*795d594fSAndroid Build Coastguard Worker VisitBasicBlock(block);
100*795d594fSAndroid Build Coastguard Worker }
101*795d594fSAndroid Build Coastguard Worker }
102*795d594fSAndroid Build Coastguard Worker
StrBool(bool val)103*795d594fSAndroid Build Coastguard Worker static const char* StrBool(bool val) {
104*795d594fSAndroid Build Coastguard Worker return val ? "true" : "false";
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker
CheckGraphFlags()107*795d594fSAndroid Build Coastguard Worker void GraphChecker::CheckGraphFlags() {
108*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasMonitorOperations() != flag_info_.seen_monitor_operation) {
109*795d594fSAndroid Build Coastguard Worker AddError(
110*795d594fSAndroid Build Coastguard Worker StringPrintf("Flag mismatch: HasMonitorOperations() (%s) should be equal to "
111*795d594fSAndroid Build Coastguard Worker "flag_info_.seen_monitor_operation (%s)",
112*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasMonitorOperations()),
113*795d594fSAndroid Build Coastguard Worker StrBool(flag_info_.seen_monitor_operation)));
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker
116*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasTryCatch() != flag_info_.seen_try_boundary) {
117*795d594fSAndroid Build Coastguard Worker AddError(
118*795d594fSAndroid Build Coastguard Worker StringPrintf("Flag mismatch: HasTryCatch() (%s) should be equal to "
119*795d594fSAndroid Build Coastguard Worker "flag_info_.seen_try_boundary (%s)",
120*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasTryCatch()),
121*795d594fSAndroid Build Coastguard Worker StrBool(flag_info_.seen_try_boundary)));
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker
124*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasLoops() != flag_info_.seen_loop) {
125*795d594fSAndroid Build Coastguard Worker AddError(
126*795d594fSAndroid Build Coastguard Worker StringPrintf("Flag mismatch: HasLoops() (%s) should be equal to "
127*795d594fSAndroid Build Coastguard Worker "flag_info_.seen_loop (%s)",
128*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasLoops()),
129*795d594fSAndroid Build Coastguard Worker StrBool(flag_info_.seen_loop)));
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasIrreducibleLoops() && !GetGraph()->HasLoops()) {
133*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Flag mismatch: HasIrreducibleLoops() (%s) implies HasLoops() (%s)",
134*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasIrreducibleLoops()),
135*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasLoops())));
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker
138*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasIrreducibleLoops() != flag_info_.seen_irreducible_loop) {
139*795d594fSAndroid Build Coastguard Worker AddError(
140*795d594fSAndroid Build Coastguard Worker StringPrintf("Flag mismatch: HasIrreducibleLoops() (%s) should be equal to "
141*795d594fSAndroid Build Coastguard Worker "flag_info_.seen_irreducible_loop (%s)",
142*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasIrreducibleLoops()),
143*795d594fSAndroid Build Coastguard Worker StrBool(flag_info_.seen_irreducible_loop)));
144*795d594fSAndroid Build Coastguard Worker }
145*795d594fSAndroid Build Coastguard Worker
146*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasSIMD() != flag_info_.seen_SIMD) {
147*795d594fSAndroid Build Coastguard Worker AddError(
148*795d594fSAndroid Build Coastguard Worker StringPrintf("Flag mismatch: HasSIMD() (%s) should be equal to "
149*795d594fSAndroid Build Coastguard Worker "flag_info_.seen_SIMD (%s)",
150*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasSIMD()),
151*795d594fSAndroid Build Coastguard Worker StrBool(flag_info_.seen_SIMD)));
152*795d594fSAndroid Build Coastguard Worker }
153*795d594fSAndroid Build Coastguard Worker
154*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasBoundsChecks() != flag_info_.seen_bounds_checks) {
155*795d594fSAndroid Build Coastguard Worker AddError(
156*795d594fSAndroid Build Coastguard Worker StringPrintf("Flag mismatch: HasBoundsChecks() (%s) should be equal to "
157*795d594fSAndroid Build Coastguard Worker "flag_info_.seen_bounds_checks (%s)",
158*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasBoundsChecks()),
159*795d594fSAndroid Build Coastguard Worker StrBool(flag_info_.seen_bounds_checks)));
160*795d594fSAndroid Build Coastguard Worker }
161*795d594fSAndroid Build Coastguard Worker
162*795d594fSAndroid Build Coastguard Worker if (GetGraph()->HasAlwaysThrowingInvokes() != flag_info_.seen_always_throwing_invokes) {
163*795d594fSAndroid Build Coastguard Worker AddError(
164*795d594fSAndroid Build Coastguard Worker StringPrintf("Flag mismatch: HasAlwaysThrowingInvokes() (%s) should be equal to "
165*795d594fSAndroid Build Coastguard Worker "flag_info_.seen_always_throwing_invokes (%s)",
166*795d594fSAndroid Build Coastguard Worker StrBool(GetGraph()->HasAlwaysThrowingInvokes()),
167*795d594fSAndroid Build Coastguard Worker StrBool(flag_info_.seen_always_throwing_invokes)));
168*795d594fSAndroid Build Coastguard Worker }
169*795d594fSAndroid Build Coastguard Worker }
170*795d594fSAndroid Build Coastguard Worker
VisitBasicBlock(HBasicBlock * block)171*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitBasicBlock(HBasicBlock* block) {
172*795d594fSAndroid Build Coastguard Worker current_block_ = block;
173*795d594fSAndroid Build Coastguard Worker
174*795d594fSAndroid Build Coastguard Worker {
175*795d594fSAndroid Build Coastguard Worker // Use local allocator for allocating memory. We use C++ scopes (i.e. `{}`) to reclaim the
176*795d594fSAndroid Build Coastguard Worker // memory as soon as possible, and to end the scope of this `ScopedArenaAllocator`.
177*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
178*795d594fSAndroid Build Coastguard Worker
179*795d594fSAndroid Build Coastguard Worker {
180*795d594fSAndroid Build Coastguard Worker // Check consistency with respect to predecessors of `block`.
181*795d594fSAndroid Build Coastguard Worker // Note: Counting duplicates with a sorted vector uses up to 6x less memory
182*795d594fSAndroid Build Coastguard Worker // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
183*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<HBasicBlock*> sorted_predecessors(
184*795d594fSAndroid Build Coastguard Worker allocator.Adapter(kArenaAllocGraphChecker));
185*795d594fSAndroid Build Coastguard Worker sorted_predecessors.assign(block->GetPredecessors().begin(), block->GetPredecessors().end());
186*795d594fSAndroid Build Coastguard Worker std::sort(sorted_predecessors.begin(), sorted_predecessors.end());
187*795d594fSAndroid Build Coastguard Worker for (auto it = sorted_predecessors.begin(), end = sorted_predecessors.end(); it != end;) {
188*795d594fSAndroid Build Coastguard Worker HBasicBlock* p = *it++;
189*795d594fSAndroid Build Coastguard Worker size_t p_count_in_block_predecessors = 1u;
190*795d594fSAndroid Build Coastguard Worker for (; it != end && *it == p; ++it) {
191*795d594fSAndroid Build Coastguard Worker ++p_count_in_block_predecessors;
192*795d594fSAndroid Build Coastguard Worker }
193*795d594fSAndroid Build Coastguard Worker size_t block_count_in_p_successors =
194*795d594fSAndroid Build Coastguard Worker std::count(p->GetSuccessors().begin(), p->GetSuccessors().end(), block);
195*795d594fSAndroid Build Coastguard Worker if (p_count_in_block_predecessors != block_count_in_p_successors) {
196*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
197*795d594fSAndroid Build Coastguard Worker "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
198*795d594fSAndroid Build Coastguard Worker "block %d lists %zu occurrences of block %d in its successors.",
199*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
200*795d594fSAndroid Build Coastguard Worker p_count_in_block_predecessors,
201*795d594fSAndroid Build Coastguard Worker p->GetBlockId(),
202*795d594fSAndroid Build Coastguard Worker p->GetBlockId(),
203*795d594fSAndroid Build Coastguard Worker block_count_in_p_successors,
204*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker }
208*795d594fSAndroid Build Coastguard Worker
209*795d594fSAndroid Build Coastguard Worker {
210*795d594fSAndroid Build Coastguard Worker // Check consistency with respect to successors of `block`.
211*795d594fSAndroid Build Coastguard Worker // Note: Counting duplicates with a sorted vector uses up to 6x less memory
212*795d594fSAndroid Build Coastguard Worker // than ArenaSafeMap<HBasicBlock*, size_t> and also allows storage reuse.
213*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<HBasicBlock*> sorted_successors(allocator.Adapter(kArenaAllocGraphChecker));
214*795d594fSAndroid Build Coastguard Worker sorted_successors.assign(block->GetSuccessors().begin(), block->GetSuccessors().end());
215*795d594fSAndroid Build Coastguard Worker std::sort(sorted_successors.begin(), sorted_successors.end());
216*795d594fSAndroid Build Coastguard Worker for (auto it = sorted_successors.begin(), end = sorted_successors.end(); it != end;) {
217*795d594fSAndroid Build Coastguard Worker HBasicBlock* s = *it++;
218*795d594fSAndroid Build Coastguard Worker size_t s_count_in_block_successors = 1u;
219*795d594fSAndroid Build Coastguard Worker for (; it != end && *it == s; ++it) {
220*795d594fSAndroid Build Coastguard Worker ++s_count_in_block_successors;
221*795d594fSAndroid Build Coastguard Worker }
222*795d594fSAndroid Build Coastguard Worker size_t block_count_in_s_predecessors =
223*795d594fSAndroid Build Coastguard Worker std::count(s->GetPredecessors().begin(), s->GetPredecessors().end(), block);
224*795d594fSAndroid Build Coastguard Worker if (s_count_in_block_successors != block_count_in_s_predecessors) {
225*795d594fSAndroid Build Coastguard Worker AddError(
226*795d594fSAndroid Build Coastguard Worker StringPrintf("Block %d lists %zu occurrences of block %d in its successors, whereas "
227*795d594fSAndroid Build Coastguard Worker "block %d lists %zu occurrences of block %d in its predecessors.",
228*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
229*795d594fSAndroid Build Coastguard Worker s_count_in_block_successors,
230*795d594fSAndroid Build Coastguard Worker s->GetBlockId(),
231*795d594fSAndroid Build Coastguard Worker s->GetBlockId(),
232*795d594fSAndroid Build Coastguard Worker block_count_in_s_predecessors,
233*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
234*795d594fSAndroid Build Coastguard Worker }
235*795d594fSAndroid Build Coastguard Worker }
236*795d594fSAndroid Build Coastguard Worker }
237*795d594fSAndroid Build Coastguard Worker }
238*795d594fSAndroid Build Coastguard Worker
239*795d594fSAndroid Build Coastguard Worker // Ensure `block` ends with a branch instruction.
240*795d594fSAndroid Build Coastguard Worker // This invariant is not enforced on non-SSA graphs. Graph built from DEX with
241*795d594fSAndroid Build Coastguard Worker // dead code that falls out of the method will not end with a control-flow
242*795d594fSAndroid Build Coastguard Worker // instruction. Such code is removed during the SSA-building DCE phase.
243*795d594fSAndroid Build Coastguard Worker if (GetGraph()->IsInSsaForm() && !block->EndsWithControlFlowInstruction()) {
244*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d does not end with a branch instruction.",
245*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
246*795d594fSAndroid Build Coastguard Worker }
247*795d594fSAndroid Build Coastguard Worker
248*795d594fSAndroid Build Coastguard Worker // Ensure that only Return(Void) and Throw jump to Exit. An exiting TryBoundary
249*795d594fSAndroid Build Coastguard Worker // may be between the instructions if the Throw/Return(Void) is in a try block.
250*795d594fSAndroid Build Coastguard Worker if (block->IsExitBlock()) {
251*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : block->GetPredecessors()) {
252*795d594fSAndroid Build Coastguard Worker HInstruction* last_instruction = IsExitTryBoundaryIntoExitBlock(predecessor) ?
253*795d594fSAndroid Build Coastguard Worker predecessor->GetSinglePredecessor()->GetLastInstruction() :
254*795d594fSAndroid Build Coastguard Worker predecessor->GetLastInstruction();
255*795d594fSAndroid Build Coastguard Worker if (!IsAllowedToJumpToExitBlock(last_instruction)) {
256*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Unexpected instruction %s:%d jumps into the exit block.",
257*795d594fSAndroid Build Coastguard Worker last_instruction->DebugName(),
258*795d594fSAndroid Build Coastguard Worker last_instruction->GetId()));
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker }
261*795d594fSAndroid Build Coastguard Worker }
262*795d594fSAndroid Build Coastguard Worker
263*795d594fSAndroid Build Coastguard Worker // Make sure the first instruction of a catch block is always a Nop that emits an environment.
264*795d594fSAndroid Build Coastguard Worker if (block->IsCatchBlock()) {
265*795d594fSAndroid Build Coastguard Worker if (!block->GetFirstInstruction()->IsNop()) {
266*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d doesn't have a Nop as its first instruction.",
267*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId()));
268*795d594fSAndroid Build Coastguard Worker } else {
269*795d594fSAndroid Build Coastguard Worker HNop* nop = block->GetFirstInstruction()->AsNop();
270*795d594fSAndroid Build Coastguard Worker if (!nop->NeedsEnvironment()) {
271*795d594fSAndroid Build Coastguard Worker AddError(
272*795d594fSAndroid Build Coastguard Worker StringPrintf("%s:%d is a Nop and the first instruction of block %d, but it doesn't "
273*795d594fSAndroid Build Coastguard Worker "need an environment.",
274*795d594fSAndroid Build Coastguard Worker nop->DebugName(),
275*795d594fSAndroid Build Coastguard Worker nop->GetId(),
276*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId()));
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker }
279*795d594fSAndroid Build Coastguard Worker }
280*795d594fSAndroid Build Coastguard Worker
281*795d594fSAndroid Build Coastguard Worker // Visit this block's list of phis.
282*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
283*795d594fSAndroid Build Coastguard Worker HInstruction* current = it.Current();
284*795d594fSAndroid Build Coastguard Worker // Ensure this block's list of phis contains only phis.
285*795d594fSAndroid Build Coastguard Worker if (!current->IsPhi()) {
286*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d has a non-phi in its phi list.",
287*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId()));
288*795d594fSAndroid Build Coastguard Worker }
289*795d594fSAndroid Build Coastguard Worker if (current->GetNext() == nullptr && current != block->GetLastPhi()) {
290*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("The recorded last phi of block %d does not match "
291*795d594fSAndroid Build Coastguard Worker "the actual last phi %d.",
292*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId(),
293*795d594fSAndroid Build Coastguard Worker current->GetId()));
294*795d594fSAndroid Build Coastguard Worker }
295*795d594fSAndroid Build Coastguard Worker current->Accept(this);
296*795d594fSAndroid Build Coastguard Worker }
297*795d594fSAndroid Build Coastguard Worker
298*795d594fSAndroid Build Coastguard Worker // Visit this block's list of instructions.
299*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
300*795d594fSAndroid Build Coastguard Worker HInstruction* current = it.Current();
301*795d594fSAndroid Build Coastguard Worker // Ensure this block's list of instructions does not contains phis.
302*795d594fSAndroid Build Coastguard Worker if (current->IsPhi()) {
303*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d has a phi in its non-phi list.",
304*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId()));
305*795d594fSAndroid Build Coastguard Worker }
306*795d594fSAndroid Build Coastguard Worker if (current->GetNext() == nullptr && current != block->GetLastInstruction()) {
307*795d594fSAndroid Build Coastguard Worker AddError(
308*795d594fSAndroid Build Coastguard Worker StringPrintf("The recorded last instruction of block %d does not match "
309*795d594fSAndroid Build Coastguard Worker "the actual last instruction %d.",
310*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId(),
311*795d594fSAndroid Build Coastguard Worker current->GetId()));
312*795d594fSAndroid Build Coastguard Worker }
313*795d594fSAndroid Build Coastguard Worker current->Accept(this);
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker
316*795d594fSAndroid Build Coastguard Worker // Ensure that catch blocks are not normal successors, and normal blocks are
317*795d594fSAndroid Build Coastguard Worker // never exceptional successors.
318*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : block->GetNormalSuccessors()) {
319*795d594fSAndroid Build Coastguard Worker if (successor->IsCatchBlock()) {
320*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
321*795d594fSAndroid Build Coastguard Worker successor->GetBlockId(),
322*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
323*795d594fSAndroid Build Coastguard Worker }
324*795d594fSAndroid Build Coastguard Worker }
325*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : block->GetExceptionalSuccessors()) {
326*795d594fSAndroid Build Coastguard Worker if (!successor->IsCatchBlock()) {
327*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
328*795d594fSAndroid Build Coastguard Worker successor->GetBlockId(),
329*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
330*795d594fSAndroid Build Coastguard Worker }
331*795d594fSAndroid Build Coastguard Worker }
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker // Ensure dominated blocks have `block` as the dominator.
334*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* dominated : block->GetDominatedBlocks()) {
335*795d594fSAndroid Build Coastguard Worker if (dominated->GetDominator() != block) {
336*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d should be the dominator of %d.",
337*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
338*795d594fSAndroid Build Coastguard Worker dominated->GetBlockId()));
339*795d594fSAndroid Build Coastguard Worker }
340*795d594fSAndroid Build Coastguard Worker }
341*795d594fSAndroid Build Coastguard Worker
342*795d594fSAndroid Build Coastguard Worker // Ensure all blocks have at least one successor, except the Exit block.
343*795d594fSAndroid Build Coastguard Worker if (block->GetSuccessors().empty() && !block->IsExitBlock()) {
344*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d has no successor and it is not the Exit block.",
345*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
346*795d594fSAndroid Build Coastguard Worker }
347*795d594fSAndroid Build Coastguard Worker
348*795d594fSAndroid Build Coastguard Worker // Ensure there is no critical edge (i.e., an edge connecting a
349*795d594fSAndroid Build Coastguard Worker // block with multiple successors to a block with multiple
350*795d594fSAndroid Build Coastguard Worker // predecessors). Exceptional edges are synthesized and hence
351*795d594fSAndroid Build Coastguard Worker // not accounted for.
352*795d594fSAndroid Build Coastguard Worker if (block->GetSuccessors().size() > 1) {
353*795d594fSAndroid Build Coastguard Worker if (IsExitTryBoundaryIntoExitBlock(block)) {
354*795d594fSAndroid Build Coastguard Worker // Allowed critical edge (Throw/Return/ReturnVoid)->TryBoundary->Exit.
355*795d594fSAndroid Build Coastguard Worker } else {
356*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : block->GetNormalSuccessors()) {
357*795d594fSAndroid Build Coastguard Worker if (successor->GetPredecessors().size() > 1) {
358*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Critical edge between blocks %d and %d.",
359*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
360*795d594fSAndroid Build Coastguard Worker successor->GetBlockId()));
361*795d594fSAndroid Build Coastguard Worker }
362*795d594fSAndroid Build Coastguard Worker }
363*795d594fSAndroid Build Coastguard Worker }
364*795d594fSAndroid Build Coastguard Worker }
365*795d594fSAndroid Build Coastguard Worker
366*795d594fSAndroid Build Coastguard Worker // Ensure try membership information is consistent.
367*795d594fSAndroid Build Coastguard Worker if (block->IsCatchBlock()) {
368*795d594fSAndroid Build Coastguard Worker if (block->IsTryBlock()) {
369*795d594fSAndroid Build Coastguard Worker const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry();
370*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
371*795d594fSAndroid Build Coastguard Worker "has try entry %s:%d.",
372*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
373*795d594fSAndroid Build Coastguard Worker try_entry.DebugName(),
374*795d594fSAndroid Build Coastguard Worker try_entry.GetId()));
375*795d594fSAndroid Build Coastguard Worker }
376*795d594fSAndroid Build Coastguard Worker
377*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
378*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
379*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
380*795d594fSAndroid Build Coastguard Worker }
381*795d594fSAndroid Build Coastguard Worker } else {
382*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : block->GetPredecessors()) {
383*795d594fSAndroid Build Coastguard Worker const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
384*795d594fSAndroid Build Coastguard Worker if (block->IsTryBlock()) {
385*795d594fSAndroid Build Coastguard Worker const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry();
386*795d594fSAndroid Build Coastguard Worker if (incoming_try_entry == nullptr) {
387*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
388*795d594fSAndroid Build Coastguard Worker "from predecessor %d.",
389*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
390*795d594fSAndroid Build Coastguard Worker stored_try_entry.DebugName(),
391*795d594fSAndroid Build Coastguard Worker stored_try_entry.GetId(),
392*795d594fSAndroid Build Coastguard Worker predecessor->GetBlockId()));
393*795d594fSAndroid Build Coastguard Worker } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) {
394*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
395*795d594fSAndroid Build Coastguard Worker "with %s:%d that follows from predecessor %d.",
396*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
397*795d594fSAndroid Build Coastguard Worker stored_try_entry.DebugName(),
398*795d594fSAndroid Build Coastguard Worker stored_try_entry.GetId(),
399*795d594fSAndroid Build Coastguard Worker incoming_try_entry->DebugName(),
400*795d594fSAndroid Build Coastguard Worker incoming_try_entry->GetId(),
401*795d594fSAndroid Build Coastguard Worker predecessor->GetBlockId()));
402*795d594fSAndroid Build Coastguard Worker }
403*795d594fSAndroid Build Coastguard Worker } else if (incoming_try_entry != nullptr) {
404*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows "
405*795d594fSAndroid Build Coastguard Worker "from predecessor %d.",
406*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
407*795d594fSAndroid Build Coastguard Worker incoming_try_entry->DebugName(),
408*795d594fSAndroid Build Coastguard Worker incoming_try_entry->GetId(),
409*795d594fSAndroid Build Coastguard Worker predecessor->GetBlockId()));
410*795d594fSAndroid Build Coastguard Worker }
411*795d594fSAndroid Build Coastguard Worker }
412*795d594fSAndroid Build Coastguard Worker }
413*795d594fSAndroid Build Coastguard Worker
414*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
415*795d594fSAndroid Build Coastguard Worker HandleLoop(block);
416*795d594fSAndroid Build Coastguard Worker }
417*795d594fSAndroid Build Coastguard Worker }
418*795d594fSAndroid Build Coastguard Worker
VisitBoundsCheck(HBoundsCheck * check)419*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) {
420*795d594fSAndroid Build Coastguard Worker VisitInstruction(check);
421*795d594fSAndroid Build Coastguard Worker
422*795d594fSAndroid Build Coastguard Worker if (!GetGraph()->HasBoundsChecks()) {
423*795d594fSAndroid Build Coastguard Worker AddError(
424*795d594fSAndroid Build Coastguard Worker StringPrintf("The graph doesn't have the HasBoundsChecks flag set but we saw "
425*795d594fSAndroid Build Coastguard Worker "%s:%d in block %d.",
426*795d594fSAndroid Build Coastguard Worker check->DebugName(),
427*795d594fSAndroid Build Coastguard Worker check->GetId(),
428*795d594fSAndroid Build Coastguard Worker check->GetBlock()->GetBlockId()));
429*795d594fSAndroid Build Coastguard Worker }
430*795d594fSAndroid Build Coastguard Worker
431*795d594fSAndroid Build Coastguard Worker flag_info_.seen_bounds_checks = true;
432*795d594fSAndroid Build Coastguard Worker }
433*795d594fSAndroid Build Coastguard Worker
VisitDeoptimize(HDeoptimize * deopt)434*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitDeoptimize(HDeoptimize* deopt) {
435*795d594fSAndroid Build Coastguard Worker VisitInstruction(deopt);
436*795d594fSAndroid Build Coastguard Worker if (GetGraph()->IsCompilingOsr()) {
437*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("A graph compiled OSR cannot have a HDeoptimize instruction"));
438*795d594fSAndroid Build Coastguard Worker }
439*795d594fSAndroid Build Coastguard Worker }
440*795d594fSAndroid Build Coastguard Worker
VisitTryBoundary(HTryBoundary * try_boundary)441*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitTryBoundary(HTryBoundary* try_boundary) {
442*795d594fSAndroid Build Coastguard Worker VisitInstruction(try_boundary);
443*795d594fSAndroid Build Coastguard Worker
444*795d594fSAndroid Build Coastguard Worker ArrayRef<HBasicBlock* const> handlers = try_boundary->GetExceptionHandlers();
445*795d594fSAndroid Build Coastguard Worker
446*795d594fSAndroid Build Coastguard Worker // Ensure that all exception handlers are catch blocks.
447*795d594fSAndroid Build Coastguard Worker // Note that a normal-flow successor may be a catch block before CFG
448*795d594fSAndroid Build Coastguard Worker // simplification. We only test normal-flow successors in GraphChecker.
449*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* handler : handlers) {
450*795d594fSAndroid Build Coastguard Worker if (!handler->IsCatchBlock()) {
451*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which "
452*795d594fSAndroid Build Coastguard Worker "is not a catch block.",
453*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId(),
454*795d594fSAndroid Build Coastguard Worker try_boundary->DebugName(),
455*795d594fSAndroid Build Coastguard Worker try_boundary->GetId(),
456*795d594fSAndroid Build Coastguard Worker handler->GetBlockId()));
457*795d594fSAndroid Build Coastguard Worker }
458*795d594fSAndroid Build Coastguard Worker }
459*795d594fSAndroid Build Coastguard Worker
460*795d594fSAndroid Build Coastguard Worker // Ensure that handlers are not listed multiple times.
461*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = handlers.size(); i < e; ++i) {
462*795d594fSAndroid Build Coastguard Worker if (ContainsElement(handlers, handlers[i], i + 1)) {
463*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Exception handler block %d of %s:%d is listed multiple times.",
464*795d594fSAndroid Build Coastguard Worker handlers[i]->GetBlockId(),
465*795d594fSAndroid Build Coastguard Worker try_boundary->DebugName(),
466*795d594fSAndroid Build Coastguard Worker try_boundary->GetId()));
467*795d594fSAndroid Build Coastguard Worker }
468*795d594fSAndroid Build Coastguard Worker }
469*795d594fSAndroid Build Coastguard Worker
470*795d594fSAndroid Build Coastguard Worker if (!GetGraph()->HasTryCatch()) {
471*795d594fSAndroid Build Coastguard Worker AddError(
472*795d594fSAndroid Build Coastguard Worker StringPrintf("The graph doesn't have the HasTryCatch flag set but we saw "
473*795d594fSAndroid Build Coastguard Worker "%s:%d in block %d.",
474*795d594fSAndroid Build Coastguard Worker try_boundary->DebugName(),
475*795d594fSAndroid Build Coastguard Worker try_boundary->GetId(),
476*795d594fSAndroid Build Coastguard Worker try_boundary->GetBlock()->GetBlockId()));
477*795d594fSAndroid Build Coastguard Worker }
478*795d594fSAndroid Build Coastguard Worker
479*795d594fSAndroid Build Coastguard Worker flag_info_.seen_try_boundary = true;
480*795d594fSAndroid Build Coastguard Worker }
481*795d594fSAndroid Build Coastguard Worker
VisitLoadClass(HLoadClass * load)482*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitLoadClass(HLoadClass* load) {
483*795d594fSAndroid Build Coastguard Worker VisitInstruction(load);
484*795d594fSAndroid Build Coastguard Worker
485*795d594fSAndroid Build Coastguard Worker if (load->GetLoadedClassRTI().IsValid() && !load->GetLoadedClassRTI().IsExact()) {
486*795d594fSAndroid Build Coastguard Worker std::stringstream ssRTI;
487*795d594fSAndroid Build Coastguard Worker ssRTI << load->GetLoadedClassRTI();
488*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d in block %d with RTI %s has valid but inexact RTI.",
489*795d594fSAndroid Build Coastguard Worker load->DebugName(),
490*795d594fSAndroid Build Coastguard Worker load->GetId(),
491*795d594fSAndroid Build Coastguard Worker load->GetBlock()->GetBlockId(),
492*795d594fSAndroid Build Coastguard Worker ssRTI.str().c_str()));
493*795d594fSAndroid Build Coastguard Worker }
494*795d594fSAndroid Build Coastguard Worker }
495*795d594fSAndroid Build Coastguard Worker
VisitLoadException(HLoadException * load)496*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitLoadException(HLoadException* load) {
497*795d594fSAndroid Build Coastguard Worker VisitInstruction(load);
498*795d594fSAndroid Build Coastguard Worker
499*795d594fSAndroid Build Coastguard Worker // Ensure that LoadException is the second instruction in a catch block. The first one should be a
500*795d594fSAndroid Build Coastguard Worker // Nop (checked separately).
501*795d594fSAndroid Build Coastguard Worker if (!load->GetBlock()->IsCatchBlock()) {
502*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d is in a non-catch block %d.",
503*795d594fSAndroid Build Coastguard Worker load->DebugName(),
504*795d594fSAndroid Build Coastguard Worker load->GetId(),
505*795d594fSAndroid Build Coastguard Worker load->GetBlock()->GetBlockId()));
506*795d594fSAndroid Build Coastguard Worker } else if (load->GetBlock()->GetFirstInstruction()->GetNext() != load) {
507*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d is not the second instruction in catch block %d.",
508*795d594fSAndroid Build Coastguard Worker load->DebugName(),
509*795d594fSAndroid Build Coastguard Worker load->GetId(),
510*795d594fSAndroid Build Coastguard Worker load->GetBlock()->GetBlockId()));
511*795d594fSAndroid Build Coastguard Worker }
512*795d594fSAndroid Build Coastguard Worker }
513*795d594fSAndroid Build Coastguard Worker
VisitMonitorOperation(HMonitorOperation * monitor_op)514*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitMonitorOperation(HMonitorOperation* monitor_op) {
515*795d594fSAndroid Build Coastguard Worker VisitInstruction(monitor_op);
516*795d594fSAndroid Build Coastguard Worker
517*795d594fSAndroid Build Coastguard Worker if (!GetGraph()->HasMonitorOperations()) {
518*795d594fSAndroid Build Coastguard Worker AddError(
519*795d594fSAndroid Build Coastguard Worker StringPrintf("The graph doesn't have the HasMonitorOperations flag set but we saw "
520*795d594fSAndroid Build Coastguard Worker "%s:%d in block %d.",
521*795d594fSAndroid Build Coastguard Worker monitor_op->DebugName(),
522*795d594fSAndroid Build Coastguard Worker monitor_op->GetId(),
523*795d594fSAndroid Build Coastguard Worker monitor_op->GetBlock()->GetBlockId()));
524*795d594fSAndroid Build Coastguard Worker }
525*795d594fSAndroid Build Coastguard Worker
526*795d594fSAndroid Build Coastguard Worker flag_info_.seen_monitor_operation = true;
527*795d594fSAndroid Build Coastguard Worker }
528*795d594fSAndroid Build Coastguard Worker
ContainedInItsBlockList(HInstruction * instruction)529*795d594fSAndroid Build Coastguard Worker bool GraphChecker::ContainedInItsBlockList(HInstruction* instruction) {
530*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
531*795d594fSAndroid Build Coastguard Worker ScopedArenaSafeMap<HBasicBlock*, ScopedArenaHashSet<HInstruction*>>& instruction_set =
532*795d594fSAndroid Build Coastguard Worker instruction->IsPhi() ? phis_per_block_ : instructions_per_block_;
533*795d594fSAndroid Build Coastguard Worker auto map_it = instruction_set.find(block);
534*795d594fSAndroid Build Coastguard Worker if (map_it == instruction_set.end()) {
535*795d594fSAndroid Build Coastguard Worker // Populate extra bookkeeping.
536*795d594fSAndroid Build Coastguard Worker map_it = instruction_set.insert(
537*795d594fSAndroid Build Coastguard Worker {block, ScopedArenaHashSet<HInstruction*>(allocator_.Adapter(kArenaAllocGraphChecker))})
538*795d594fSAndroid Build Coastguard Worker .first;
539*795d594fSAndroid Build Coastguard Worker const HInstructionList& instruction_list = instruction->IsPhi() ?
540*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->GetPhis() :
541*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->GetInstructions();
542*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator list_it(instruction_list); !list_it.Done(); list_it.Advance()) {
543*795d594fSAndroid Build Coastguard Worker map_it->second.insert(list_it.Current());
544*795d594fSAndroid Build Coastguard Worker }
545*795d594fSAndroid Build Coastguard Worker }
546*795d594fSAndroid Build Coastguard Worker return map_it->second.find(instruction) != map_it->second.end();
547*795d594fSAndroid Build Coastguard Worker }
548*795d594fSAndroid Build Coastguard Worker
VisitInstruction(HInstruction * instruction)549*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitInstruction(HInstruction* instruction) {
550*795d594fSAndroid Build Coastguard Worker if (seen_ids_.IsBitSet(instruction->GetId())) {
551*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Instruction id %d is duplicate in graph.",
552*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
553*795d594fSAndroid Build Coastguard Worker } else {
554*795d594fSAndroid Build Coastguard Worker seen_ids_.SetBit(instruction->GetId());
555*795d594fSAndroid Build Coastguard Worker }
556*795d594fSAndroid Build Coastguard Worker
557*795d594fSAndroid Build Coastguard Worker // Ensure `instruction` is associated with `current_block_`.
558*795d594fSAndroid Build Coastguard Worker if (instruction->GetBlock() == nullptr) {
559*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s %d in block %d not associated with any block.",
560*795d594fSAndroid Build Coastguard Worker instruction->IsPhi() ? "Phi" : "Instruction",
561*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
562*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId()));
563*795d594fSAndroid Build Coastguard Worker } else if (instruction->GetBlock() != current_block_) {
564*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s %d in block %d associated with block %d.",
565*795d594fSAndroid Build Coastguard Worker instruction->IsPhi() ? "Phi" : "Instruction",
566*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
567*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId(),
568*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->GetBlockId()));
569*795d594fSAndroid Build Coastguard Worker }
570*795d594fSAndroid Build Coastguard Worker
571*795d594fSAndroid Build Coastguard Worker // Ensure the inputs of `instruction` are defined in a block of the graph, and the entry in the
572*795d594fSAndroid Build Coastguard Worker // use list is consistent.
573*795d594fSAndroid Build Coastguard Worker for (HInstruction* input : instruction->GetInputs()) {
574*795d594fSAndroid Build Coastguard Worker if (input->GetBlock() == nullptr) {
575*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Input %d of instruction %d is not in any "
576*795d594fSAndroid Build Coastguard Worker "basic block of the control-flow graph.",
577*795d594fSAndroid Build Coastguard Worker input->GetId(),
578*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
579*795d594fSAndroid Build Coastguard Worker } else if (!ContainedInItsBlockList(input)) {
580*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Input %d of instruction %d is not defined "
581*795d594fSAndroid Build Coastguard Worker "in a basic block of the control-flow graph.",
582*795d594fSAndroid Build Coastguard Worker input->GetId(),
583*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
584*795d594fSAndroid Build Coastguard Worker }
585*795d594fSAndroid Build Coastguard Worker }
586*795d594fSAndroid Build Coastguard Worker
587*795d594fSAndroid Build Coastguard Worker // Ensure the uses of `instruction` are defined in a block of the graph,
588*795d594fSAndroid Build Coastguard Worker // and the entry in the use list is consistent.
589*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
590*795d594fSAndroid Build Coastguard Worker HInstruction* user = use.GetUser();
591*795d594fSAndroid Build Coastguard Worker if (!ContainedInItsBlockList(user)) {
592*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("User %s:%d of instruction %d is not defined "
593*795d594fSAndroid Build Coastguard Worker "in a basic block of the control-flow graph.",
594*795d594fSAndroid Build Coastguard Worker user->DebugName(),
595*795d594fSAndroid Build Coastguard Worker user->GetId(),
596*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
597*795d594fSAndroid Build Coastguard Worker }
598*795d594fSAndroid Build Coastguard Worker size_t use_index = use.GetIndex();
599*795d594fSAndroid Build Coastguard Worker HConstInputsRef user_inputs = user->GetInputs();
600*795d594fSAndroid Build Coastguard Worker if ((use_index >= user_inputs.size()) || (user_inputs[use_index] != instruction)) {
601*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("User %s:%d of instruction %s:%d has a wrong "
602*795d594fSAndroid Build Coastguard Worker "UseListNode index.",
603*795d594fSAndroid Build Coastguard Worker user->DebugName(),
604*795d594fSAndroid Build Coastguard Worker user->GetId(),
605*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
606*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
607*795d594fSAndroid Build Coastguard Worker }
608*795d594fSAndroid Build Coastguard Worker }
609*795d594fSAndroid Build Coastguard Worker
610*795d594fSAndroid Build Coastguard Worker // Ensure the environment uses entries are consistent.
611*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
612*795d594fSAndroid Build Coastguard Worker HEnvironment* user = use.GetUser();
613*795d594fSAndroid Build Coastguard Worker size_t use_index = use.GetIndex();
614*795d594fSAndroid Build Coastguard Worker if ((use_index >= user->Size()) || (user->GetInstructionAt(use_index) != instruction)) {
615*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Environment user of %s:%d has a wrong "
616*795d594fSAndroid Build Coastguard Worker "UseListNode index.",
617*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
618*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
619*795d594fSAndroid Build Coastguard Worker }
620*795d594fSAndroid Build Coastguard Worker }
621*795d594fSAndroid Build Coastguard Worker
622*795d594fSAndroid Build Coastguard Worker // Ensure 'instruction' has pointers to its inputs' use entries.
623*795d594fSAndroid Build Coastguard Worker {
624*795d594fSAndroid Build Coastguard Worker auto&& input_records = instruction->GetInputRecords();
625*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < input_records.size(); ++i) {
626*795d594fSAndroid Build Coastguard Worker const HUserRecord<HInstruction*>& input_record = input_records[i];
627*795d594fSAndroid Build Coastguard Worker HInstruction* input = input_record.GetInstruction();
628*795d594fSAndroid Build Coastguard Worker
629*795d594fSAndroid Build Coastguard Worker // Populate bookkeeping, if needed. See comment in graph_checker.h for uses_per_instruction_.
630*795d594fSAndroid Build Coastguard Worker auto it = uses_per_instruction_.find(input->GetId());
631*795d594fSAndroid Build Coastguard Worker if (it == uses_per_instruction_.end()) {
632*795d594fSAndroid Build Coastguard Worker it = uses_per_instruction_
633*795d594fSAndroid Build Coastguard Worker .insert({input->GetId(),
634*795d594fSAndroid Build Coastguard Worker ScopedArenaSet<const art::HUseListNode<art::HInstruction*>*>(
635*795d594fSAndroid Build Coastguard Worker allocator_.Adapter(kArenaAllocGraphChecker))})
636*795d594fSAndroid Build Coastguard Worker .first;
637*795d594fSAndroid Build Coastguard Worker for (auto&& use : input->GetUses()) {
638*795d594fSAndroid Build Coastguard Worker it->second.insert(std::addressof(use));
639*795d594fSAndroid Build Coastguard Worker }
640*795d594fSAndroid Build Coastguard Worker }
641*795d594fSAndroid Build Coastguard Worker
642*795d594fSAndroid Build Coastguard Worker if ((input_record.GetBeforeUseNode() == input->GetUses().end()) ||
643*795d594fSAndroid Build Coastguard Worker (input_record.GetUseNode() == input->GetUses().end()) ||
644*795d594fSAndroid Build Coastguard Worker (it->second.find(std::addressof(*input_record.GetUseNode())) == it->second.end()) ||
645*795d594fSAndroid Build Coastguard Worker (input_record.GetUseNode()->GetIndex() != i)) {
646*795d594fSAndroid Build Coastguard Worker AddError(
647*795d594fSAndroid Build Coastguard Worker StringPrintf("Instruction %s:%d has an invalid iterator before use entry "
648*795d594fSAndroid Build Coastguard Worker "at input %u (%s:%d).",
649*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
650*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
651*795d594fSAndroid Build Coastguard Worker static_cast<unsigned>(i),
652*795d594fSAndroid Build Coastguard Worker input->DebugName(),
653*795d594fSAndroid Build Coastguard Worker input->GetId()));
654*795d594fSAndroid Build Coastguard Worker }
655*795d594fSAndroid Build Coastguard Worker }
656*795d594fSAndroid Build Coastguard Worker }
657*795d594fSAndroid Build Coastguard Worker
658*795d594fSAndroid Build Coastguard Worker // Ensure an instruction dominates all its uses.
659*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
660*795d594fSAndroid Build Coastguard Worker HInstruction* user = use.GetUser();
661*795d594fSAndroid Build Coastguard Worker if (!user->IsPhi() && (instruction->GetBlock() == user->GetBlock()
662*795d594fSAndroid Build Coastguard Worker ? seen_ids_.IsBitSet(user->GetId())
663*795d594fSAndroid Build Coastguard Worker : !instruction->GetBlock()->Dominates(user->GetBlock()))) {
664*795d594fSAndroid Build Coastguard Worker AddError(
665*795d594fSAndroid Build Coastguard Worker StringPrintf("Instruction %s:%d in block %d does not dominate "
666*795d594fSAndroid Build Coastguard Worker "use %s:%d in block %d.",
667*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
668*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
669*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId(),
670*795d594fSAndroid Build Coastguard Worker user->DebugName(),
671*795d594fSAndroid Build Coastguard Worker user->GetId(),
672*795d594fSAndroid Build Coastguard Worker user->GetBlock()->GetBlockId()));
673*795d594fSAndroid Build Coastguard Worker }
674*795d594fSAndroid Build Coastguard Worker }
675*795d594fSAndroid Build Coastguard Worker
676*795d594fSAndroid Build Coastguard Worker if (instruction->NeedsEnvironment() != instruction->HasEnvironment()) {
677*795d594fSAndroid Build Coastguard Worker const char* str;
678*795d594fSAndroid Build Coastguard Worker if (instruction->NeedsEnvironment()) {
679*795d594fSAndroid Build Coastguard Worker str = "Instruction %s:%d in block %d requires an environment but does not have one.";
680*795d594fSAndroid Build Coastguard Worker } else {
681*795d594fSAndroid Build Coastguard Worker str = "Instruction %s:%d in block %d doesn't require an environment but it has one.";
682*795d594fSAndroid Build Coastguard Worker }
683*795d594fSAndroid Build Coastguard Worker
684*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(str,
685*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
686*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
687*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId()));
688*795d594fSAndroid Build Coastguard Worker }
689*795d594fSAndroid Build Coastguard Worker
690*795d594fSAndroid Build Coastguard Worker // Ensure an instruction dominates all its environment uses.
691*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
692*795d594fSAndroid Build Coastguard Worker HInstruction* user = use.GetUser()->GetHolder();
693*795d594fSAndroid Build Coastguard Worker if (user->IsPhi()) {
694*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Phi %d shouldn't have an environment", instruction->GetId()));
695*795d594fSAndroid Build Coastguard Worker }
696*795d594fSAndroid Build Coastguard Worker if (instruction->GetBlock() == user->GetBlock()
697*795d594fSAndroid Build Coastguard Worker ? seen_ids_.IsBitSet(user->GetId())
698*795d594fSAndroid Build Coastguard Worker : !instruction->GetBlock()->Dominates(user->GetBlock())) {
699*795d594fSAndroid Build Coastguard Worker AddError(
700*795d594fSAndroid Build Coastguard Worker StringPrintf("Instruction %s:%d in block %d does not dominate "
701*795d594fSAndroid Build Coastguard Worker "environment use %s:%d in block %d.",
702*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
703*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
704*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId(),
705*795d594fSAndroid Build Coastguard Worker user->DebugName(),
706*795d594fSAndroid Build Coastguard Worker user->GetId(),
707*795d594fSAndroid Build Coastguard Worker user->GetBlock()->GetBlockId()));
708*795d594fSAndroid Build Coastguard Worker }
709*795d594fSAndroid Build Coastguard Worker }
710*795d594fSAndroid Build Coastguard Worker
711*795d594fSAndroid Build Coastguard Worker if (instruction->CanThrow() && !instruction->HasEnvironment()) {
712*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Throwing instruction %s:%d in block %d does not have an environment.",
713*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
714*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
715*795d594fSAndroid Build Coastguard Worker current_block_->GetBlockId()));
716*795d594fSAndroid Build Coastguard Worker } else if (instruction->CanThrowIntoCatchBlock()) {
717*795d594fSAndroid Build Coastguard Worker // Find all catch blocks and test that `instruction` has an environment value for each one.
718*795d594fSAndroid Build Coastguard Worker const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
719*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) {
720*795d594fSAndroid Build Coastguard Worker const HEnvironment* environment = catch_block->GetFirstInstruction()->GetEnvironment();
721*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
722*795d594fSAndroid Build Coastguard Worker HPhi* catch_phi = phi_it.Current()->AsPhi();
723*795d594fSAndroid Build Coastguard Worker if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) {
724*795d594fSAndroid Build Coastguard Worker AddError(
725*795d594fSAndroid Build Coastguard Worker StringPrintf("Instruction %s:%d throws into catch block %d "
726*795d594fSAndroid Build Coastguard Worker "with catch phi %d for vreg %d but its "
727*795d594fSAndroid Build Coastguard Worker "corresponding environment slot is empty.",
728*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
729*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
730*795d594fSAndroid Build Coastguard Worker catch_block->GetBlockId(),
731*795d594fSAndroid Build Coastguard Worker catch_phi->GetId(),
732*795d594fSAndroid Build Coastguard Worker catch_phi->GetRegNumber()));
733*795d594fSAndroid Build Coastguard Worker }
734*795d594fSAndroid Build Coastguard Worker }
735*795d594fSAndroid Build Coastguard Worker }
736*795d594fSAndroid Build Coastguard Worker }
737*795d594fSAndroid Build Coastguard Worker }
738*795d594fSAndroid Build Coastguard Worker
VisitInvoke(HInvoke * invoke)739*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitInvoke(HInvoke* invoke) {
740*795d594fSAndroid Build Coastguard Worker VisitInstruction(invoke);
741*795d594fSAndroid Build Coastguard Worker
742*795d594fSAndroid Build Coastguard Worker if (invoke->AlwaysThrows()) {
743*795d594fSAndroid Build Coastguard Worker if (!GetGraph()->HasAlwaysThrowingInvokes()) {
744*795d594fSAndroid Build Coastguard Worker AddError(
745*795d594fSAndroid Build Coastguard Worker StringPrintf("The graph doesn't have the HasAlwaysThrowingInvokes flag set but we saw "
746*795d594fSAndroid Build Coastguard Worker "%s:%d in block %d and it always throws.",
747*795d594fSAndroid Build Coastguard Worker invoke->DebugName(),
748*795d594fSAndroid Build Coastguard Worker invoke->GetId(),
749*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->GetBlockId()));
750*795d594fSAndroid Build Coastguard Worker }
751*795d594fSAndroid Build Coastguard Worker flag_info_.seen_always_throwing_invokes = true;
752*795d594fSAndroid Build Coastguard Worker }
753*795d594fSAndroid Build Coastguard Worker
754*795d594fSAndroid Build Coastguard Worker // Check for intrinsics which should have been replaced by intermediate representation in the
755*795d594fSAndroid Build Coastguard Worker // instruction builder.
756*795d594fSAndroid Build Coastguard Worker if (!IsValidIntrinsicAfterBuilder(invoke->GetIntrinsic())) {
757*795d594fSAndroid Build Coastguard Worker std::stringstream ss;
758*795d594fSAndroid Build Coastguard Worker ss << invoke->GetIntrinsic();
759*795d594fSAndroid Build Coastguard Worker AddError(
760*795d594fSAndroid Build Coastguard Worker StringPrintf("The graph contains the intrinsic %s which should have been replaced in the "
761*795d594fSAndroid Build Coastguard Worker "instruction builder: %s:%d in block %d.",
762*795d594fSAndroid Build Coastguard Worker ss.str().c_str(),
763*795d594fSAndroid Build Coastguard Worker invoke->DebugName(),
764*795d594fSAndroid Build Coastguard Worker invoke->GetId(),
765*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->GetBlockId()));
766*795d594fSAndroid Build Coastguard Worker }
767*795d594fSAndroid Build Coastguard Worker }
768*795d594fSAndroid Build Coastguard Worker
VisitInvokeStaticOrDirect(HInvokeStaticOrDirect * invoke)769*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
770*795d594fSAndroid Build Coastguard Worker // We call VisitInvoke and not VisitInstruction to de-duplicate the common code: always throwing
771*795d594fSAndroid Build Coastguard Worker // and intrinsic checks.
772*795d594fSAndroid Build Coastguard Worker VisitInvoke(invoke);
773*795d594fSAndroid Build Coastguard Worker
774*795d594fSAndroid Build Coastguard Worker if (invoke->IsStaticWithExplicitClinitCheck()) {
775*795d594fSAndroid Build Coastguard Worker const HInstruction* last_input = invoke->GetInputs().back();
776*795d594fSAndroid Build Coastguard Worker if (last_input == nullptr) {
777*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
778*795d594fSAndroid Build Coastguard Worker "has a null pointer as last input.",
779*795d594fSAndroid Build Coastguard Worker invoke->DebugName(),
780*795d594fSAndroid Build Coastguard Worker invoke->GetId()));
781*795d594fSAndroid Build Coastguard Worker } else if (!last_input->IsClinitCheck() && !last_input->IsLoadClass()) {
782*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Static invoke %s:%d marked as having an explicit clinit check "
783*795d594fSAndroid Build Coastguard Worker "has a last instruction (%s:%d) which is neither a clinit check "
784*795d594fSAndroid Build Coastguard Worker "nor a load class instruction.",
785*795d594fSAndroid Build Coastguard Worker invoke->DebugName(),
786*795d594fSAndroid Build Coastguard Worker invoke->GetId(),
787*795d594fSAndroid Build Coastguard Worker last_input->DebugName(),
788*795d594fSAndroid Build Coastguard Worker last_input->GetId()));
789*795d594fSAndroid Build Coastguard Worker }
790*795d594fSAndroid Build Coastguard Worker }
791*795d594fSAndroid Build Coastguard Worker }
792*795d594fSAndroid Build Coastguard Worker
VisitReturn(HReturn * ret)793*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitReturn(HReturn* ret) {
794*795d594fSAndroid Build Coastguard Worker VisitInstruction(ret);
795*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
796*795d594fSAndroid Build Coastguard Worker if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
797*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d does not jump to the exit block.",
798*795d594fSAndroid Build Coastguard Worker ret->DebugName(),
799*795d594fSAndroid Build Coastguard Worker ret->GetId()));
800*795d594fSAndroid Build Coastguard Worker }
801*795d594fSAndroid Build Coastguard Worker }
802*795d594fSAndroid Build Coastguard Worker
VisitReturnVoid(HReturnVoid * ret)803*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitReturnVoid(HReturnVoid* ret) {
804*795d594fSAndroid Build Coastguard Worker VisitInstruction(ret);
805*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = ret->GetBlock()->GetSingleSuccessor();
806*795d594fSAndroid Build Coastguard Worker if (!successor->IsExitBlock() && !IsExitTryBoundaryIntoExitBlock(successor)) {
807*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d does not jump to the exit block.",
808*795d594fSAndroid Build Coastguard Worker ret->DebugName(),
809*795d594fSAndroid Build Coastguard Worker ret->GetId()));
810*795d594fSAndroid Build Coastguard Worker }
811*795d594fSAndroid Build Coastguard Worker }
812*795d594fSAndroid Build Coastguard Worker
CheckTypeCheckBitstringInput(HTypeCheckInstruction * check,size_t input_pos,bool check_value,uint32_t expected_value,const char * name)813*795d594fSAndroid Build Coastguard Worker void GraphChecker::CheckTypeCheckBitstringInput(HTypeCheckInstruction* check,
814*795d594fSAndroid Build Coastguard Worker size_t input_pos,
815*795d594fSAndroid Build Coastguard Worker bool check_value,
816*795d594fSAndroid Build Coastguard Worker uint32_t expected_value,
817*795d594fSAndroid Build Coastguard Worker const char* name) {
818*795d594fSAndroid Build Coastguard Worker if (!check->InputAt(input_pos)->IsIntConstant()) {
819*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d (bitstring) expects a HIntConstant input %zu (%s), not %s:%d.",
820*795d594fSAndroid Build Coastguard Worker check->DebugName(),
821*795d594fSAndroid Build Coastguard Worker check->GetId(),
822*795d594fSAndroid Build Coastguard Worker input_pos,
823*795d594fSAndroid Build Coastguard Worker name,
824*795d594fSAndroid Build Coastguard Worker check->InputAt(2)->DebugName(),
825*795d594fSAndroid Build Coastguard Worker check->InputAt(2)->GetId()));
826*795d594fSAndroid Build Coastguard Worker } else if (check_value) {
827*795d594fSAndroid Build Coastguard Worker uint32_t actual_value =
828*795d594fSAndroid Build Coastguard Worker static_cast<uint32_t>(check->InputAt(input_pos)->AsIntConstant()->GetValue());
829*795d594fSAndroid Build Coastguard Worker if (actual_value != expected_value) {
830*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d (bitstring) has %s 0x%x, not 0x%x as expected.",
831*795d594fSAndroid Build Coastguard Worker check->DebugName(),
832*795d594fSAndroid Build Coastguard Worker check->GetId(),
833*795d594fSAndroid Build Coastguard Worker name,
834*795d594fSAndroid Build Coastguard Worker actual_value,
835*795d594fSAndroid Build Coastguard Worker expected_value));
836*795d594fSAndroid Build Coastguard Worker }
837*795d594fSAndroid Build Coastguard Worker }
838*795d594fSAndroid Build Coastguard Worker }
839*795d594fSAndroid Build Coastguard Worker
HandleTypeCheckInstruction(HTypeCheckInstruction * check)840*795d594fSAndroid Build Coastguard Worker void GraphChecker::HandleTypeCheckInstruction(HTypeCheckInstruction* check) {
841*795d594fSAndroid Build Coastguard Worker VisitInstruction(check);
842*795d594fSAndroid Build Coastguard Worker
843*795d594fSAndroid Build Coastguard Worker if (check->GetTargetClassRTI().IsValid() && !check->GetTargetClassRTI().IsExact()) {
844*795d594fSAndroid Build Coastguard Worker std::stringstream ssRTI;
845*795d594fSAndroid Build Coastguard Worker ssRTI << check->GetTargetClassRTI();
846*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d in block %d with RTI %s has valid but inexact RTI.",
847*795d594fSAndroid Build Coastguard Worker check->DebugName(),
848*795d594fSAndroid Build Coastguard Worker check->GetId(),
849*795d594fSAndroid Build Coastguard Worker check->GetBlock()->GetBlockId(),
850*795d594fSAndroid Build Coastguard Worker ssRTI.str().c_str()));
851*795d594fSAndroid Build Coastguard Worker }
852*795d594fSAndroid Build Coastguard Worker
853*795d594fSAndroid Build Coastguard Worker HInstruction* input = check->InputAt(1);
854*795d594fSAndroid Build Coastguard Worker if (check->GetTypeCheckKind() == TypeCheckKind::kBitstringCheck) {
855*795d594fSAndroid Build Coastguard Worker if (!input->IsNullConstant()) {
856*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d (bitstring) expects a HNullConstant as second input, not %s:%d.",
857*795d594fSAndroid Build Coastguard Worker check->DebugName(),
858*795d594fSAndroid Build Coastguard Worker check->GetId(),
859*795d594fSAndroid Build Coastguard Worker input->DebugName(),
860*795d594fSAndroid Build Coastguard Worker input->GetId()));
861*795d594fSAndroid Build Coastguard Worker }
862*795d594fSAndroid Build Coastguard Worker bool check_values = false;
863*795d594fSAndroid Build Coastguard Worker BitString::StorageType expected_path_to_root = 0u;
864*795d594fSAndroid Build Coastguard Worker BitString::StorageType expected_mask = 0u;
865*795d594fSAndroid Build Coastguard Worker {
866*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
867*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Class> klass = check->GetClass().Get();
868*795d594fSAndroid Build Coastguard Worker MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
869*795d594fSAndroid Build Coastguard Worker SubtypeCheckInfo::State state = SubtypeCheck<ObjPtr<mirror::Class>>::GetState(klass);
870*795d594fSAndroid Build Coastguard Worker if (state == SubtypeCheckInfo::kAssigned) {
871*795d594fSAndroid Build Coastguard Worker expected_path_to_root =
872*795d594fSAndroid Build Coastguard Worker SubtypeCheck<ObjPtr<mirror::Class>>::GetEncodedPathToRootForTarget(klass);
873*795d594fSAndroid Build Coastguard Worker expected_mask = SubtypeCheck<ObjPtr<mirror::Class>>::GetEncodedPathToRootMask(klass);
874*795d594fSAndroid Build Coastguard Worker check_values = true;
875*795d594fSAndroid Build Coastguard Worker } else {
876*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d (bitstring) references a class with unassigned bitstring.",
877*795d594fSAndroid Build Coastguard Worker check->DebugName(),
878*795d594fSAndroid Build Coastguard Worker check->GetId()));
879*795d594fSAndroid Build Coastguard Worker }
880*795d594fSAndroid Build Coastguard Worker }
881*795d594fSAndroid Build Coastguard Worker CheckTypeCheckBitstringInput(
882*795d594fSAndroid Build Coastguard Worker check, /* input_pos= */ 2, check_values, expected_path_to_root, "path_to_root");
883*795d594fSAndroid Build Coastguard Worker CheckTypeCheckBitstringInput(check, /* input_pos= */ 3, check_values, expected_mask, "mask");
884*795d594fSAndroid Build Coastguard Worker } else {
885*795d594fSAndroid Build Coastguard Worker if (!input->IsLoadClass()) {
886*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s:%d (classic) expects a HLoadClass as second input, not %s:%d.",
887*795d594fSAndroid Build Coastguard Worker check->DebugName(),
888*795d594fSAndroid Build Coastguard Worker check->GetId(),
889*795d594fSAndroid Build Coastguard Worker input->DebugName(),
890*795d594fSAndroid Build Coastguard Worker input->GetId()));
891*795d594fSAndroid Build Coastguard Worker }
892*795d594fSAndroid Build Coastguard Worker }
893*795d594fSAndroid Build Coastguard Worker }
894*795d594fSAndroid Build Coastguard Worker
VisitCheckCast(HCheckCast * check)895*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitCheckCast(HCheckCast* check) {
896*795d594fSAndroid Build Coastguard Worker HandleTypeCheckInstruction(check);
897*795d594fSAndroid Build Coastguard Worker }
898*795d594fSAndroid Build Coastguard Worker
VisitInstanceOf(HInstanceOf * instruction)899*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitInstanceOf(HInstanceOf* instruction) {
900*795d594fSAndroid Build Coastguard Worker HandleTypeCheckInstruction(instruction);
901*795d594fSAndroid Build Coastguard Worker }
902*795d594fSAndroid Build Coastguard Worker
HandleLoop(HBasicBlock * loop_header)903*795d594fSAndroid Build Coastguard Worker void GraphChecker::HandleLoop(HBasicBlock* loop_header) {
904*795d594fSAndroid Build Coastguard Worker int id = loop_header->GetBlockId();
905*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_information = loop_header->GetLoopInformation();
906*795d594fSAndroid Build Coastguard Worker
907*795d594fSAndroid Build Coastguard Worker if (loop_information->GetPreHeader()->GetSuccessors().size() != 1) {
908*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
909*795d594fSAndroid Build Coastguard Worker "Loop pre-header %d of loop defined by header %d has %zu successors.",
910*795d594fSAndroid Build Coastguard Worker loop_information->GetPreHeader()->GetBlockId(),
911*795d594fSAndroid Build Coastguard Worker id,
912*795d594fSAndroid Build Coastguard Worker loop_information->GetPreHeader()->GetSuccessors().size()));
913*795d594fSAndroid Build Coastguard Worker }
914*795d594fSAndroid Build Coastguard Worker
915*795d594fSAndroid Build Coastguard Worker if (!GetGraph()->SuspendChecksAreAllowedToNoOp() &&
916*795d594fSAndroid Build Coastguard Worker loop_information->GetSuspendCheck() == nullptr) {
917*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Loop with header %d does not have a suspend check.",
918*795d594fSAndroid Build Coastguard Worker loop_header->GetBlockId()));
919*795d594fSAndroid Build Coastguard Worker }
920*795d594fSAndroid Build Coastguard Worker
921*795d594fSAndroid Build Coastguard Worker if (!GetGraph()->SuspendChecksAreAllowedToNoOp() &&
922*795d594fSAndroid Build Coastguard Worker loop_information->GetSuspendCheck() != loop_header->GetFirstInstructionDisregardMoves()) {
923*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
924*795d594fSAndroid Build Coastguard Worker "Loop header %d does not have the loop suspend check as the first instruction.",
925*795d594fSAndroid Build Coastguard Worker loop_header->GetBlockId()));
926*795d594fSAndroid Build Coastguard Worker }
927*795d594fSAndroid Build Coastguard Worker
928*795d594fSAndroid Build Coastguard Worker // Ensure the loop header has only one incoming branch and the remaining
929*795d594fSAndroid Build Coastguard Worker // predecessors are back edges.
930*795d594fSAndroid Build Coastguard Worker size_t num_preds = loop_header->GetPredecessors().size();
931*795d594fSAndroid Build Coastguard Worker if (num_preds < 2) {
932*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
933*795d594fSAndroid Build Coastguard Worker "Loop header %d has less than two predecessors: %zu.",
934*795d594fSAndroid Build Coastguard Worker id,
935*795d594fSAndroid Build Coastguard Worker num_preds));
936*795d594fSAndroid Build Coastguard Worker } else {
937*795d594fSAndroid Build Coastguard Worker HBasicBlock* first_predecessor = loop_header->GetPredecessors()[0];
938*795d594fSAndroid Build Coastguard Worker if (loop_information->IsBackEdge(*first_predecessor)) {
939*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
940*795d594fSAndroid Build Coastguard Worker "First predecessor of loop header %d is a back edge.",
941*795d594fSAndroid Build Coastguard Worker id));
942*795d594fSAndroid Build Coastguard Worker }
943*795d594fSAndroid Build Coastguard Worker for (size_t i = 1, e = loop_header->GetPredecessors().size(); i < e; ++i) {
944*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = loop_header->GetPredecessors()[i];
945*795d594fSAndroid Build Coastguard Worker if (!loop_information->IsBackEdge(*predecessor)) {
946*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
947*795d594fSAndroid Build Coastguard Worker "Loop header %d has multiple incoming (non back edge) blocks: %d.",
948*795d594fSAndroid Build Coastguard Worker id,
949*795d594fSAndroid Build Coastguard Worker predecessor->GetBlockId()));
950*795d594fSAndroid Build Coastguard Worker }
951*795d594fSAndroid Build Coastguard Worker }
952*795d594fSAndroid Build Coastguard Worker }
953*795d594fSAndroid Build Coastguard Worker
954*795d594fSAndroid Build Coastguard Worker const ArenaBitVector& loop_blocks = loop_information->GetBlocks();
955*795d594fSAndroid Build Coastguard Worker
956*795d594fSAndroid Build Coastguard Worker // Ensure back edges belong to the loop.
957*795d594fSAndroid Build Coastguard Worker if (loop_information->NumberOfBackEdges() == 0) {
958*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
959*795d594fSAndroid Build Coastguard Worker "Loop defined by header %d has no back edge.",
960*795d594fSAndroid Build Coastguard Worker id));
961*795d594fSAndroid Build Coastguard Worker } else {
962*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge : loop_information->GetBackEdges()) {
963*795d594fSAndroid Build Coastguard Worker int back_edge_id = back_edge->GetBlockId();
964*795d594fSAndroid Build Coastguard Worker if (!loop_blocks.IsBitSet(back_edge_id)) {
965*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
966*795d594fSAndroid Build Coastguard Worker "Loop defined by header %d has an invalid back edge %d.",
967*795d594fSAndroid Build Coastguard Worker id,
968*795d594fSAndroid Build Coastguard Worker back_edge_id));
969*795d594fSAndroid Build Coastguard Worker } else if (back_edge->GetLoopInformation() != loop_information) {
970*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
971*795d594fSAndroid Build Coastguard Worker "Back edge %d of loop defined by header %d belongs to nested loop "
972*795d594fSAndroid Build Coastguard Worker "with header %d.",
973*795d594fSAndroid Build Coastguard Worker back_edge_id,
974*795d594fSAndroid Build Coastguard Worker id,
975*795d594fSAndroid Build Coastguard Worker back_edge->GetLoopInformation()->GetHeader()->GetBlockId()));
976*795d594fSAndroid Build Coastguard Worker }
977*795d594fSAndroid Build Coastguard Worker }
978*795d594fSAndroid Build Coastguard Worker }
979*795d594fSAndroid Build Coastguard Worker
980*795d594fSAndroid Build Coastguard Worker // If this is a nested loop, ensure the outer loops contain a superset of the blocks.
981*795d594fSAndroid Build Coastguard Worker for (HLoopInformationOutwardIterator it(*loop_header); !it.Done(); it.Advance()) {
982*795d594fSAndroid Build Coastguard Worker HLoopInformation* outer_info = it.Current();
983*795d594fSAndroid Build Coastguard Worker if (!loop_blocks.IsSubsetOf(&outer_info->GetBlocks())) {
984*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Blocks of loop defined by header %d are not a subset of blocks of "
985*795d594fSAndroid Build Coastguard Worker "an outer loop defined by header %d.",
986*795d594fSAndroid Build Coastguard Worker id,
987*795d594fSAndroid Build Coastguard Worker outer_info->GetHeader()->GetBlockId()));
988*795d594fSAndroid Build Coastguard Worker }
989*795d594fSAndroid Build Coastguard Worker }
990*795d594fSAndroid Build Coastguard Worker
991*795d594fSAndroid Build Coastguard Worker // Ensure the pre-header block is first in the list of predecessors of a loop
992*795d594fSAndroid Build Coastguard Worker // header and that the header block is its only successor.
993*795d594fSAndroid Build Coastguard Worker if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
994*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
995*795d594fSAndroid Build Coastguard Worker "Loop pre-header is not the first predecessor of the loop header %d.",
996*795d594fSAndroid Build Coastguard Worker id));
997*795d594fSAndroid Build Coastguard Worker }
998*795d594fSAndroid Build Coastguard Worker
999*795d594fSAndroid Build Coastguard Worker // Ensure all blocks in the loop are live and dominated by the loop header in
1000*795d594fSAndroid Build Coastguard Worker // the case of natural loops.
1001*795d594fSAndroid Build Coastguard Worker for (uint32_t i : loop_blocks.Indexes()) {
1002*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_block = GetGraph()->GetBlocks()[i];
1003*795d594fSAndroid Build Coastguard Worker if (loop_block == nullptr) {
1004*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Loop defined by header %d contains a previously removed block %d.",
1005*795d594fSAndroid Build Coastguard Worker id,
1006*795d594fSAndroid Build Coastguard Worker i));
1007*795d594fSAndroid Build Coastguard Worker } else if (!loop_information->IsIrreducible() && !loop_header->Dominates(loop_block)) {
1008*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
1009*795d594fSAndroid Build Coastguard Worker i,
1010*795d594fSAndroid Build Coastguard Worker id));
1011*795d594fSAndroid Build Coastguard Worker }
1012*795d594fSAndroid Build Coastguard Worker }
1013*795d594fSAndroid Build Coastguard Worker }
1014*795d594fSAndroid Build Coastguard Worker
IsSameSizeConstant(const HInstruction * insn1,const HInstruction * insn2)1015*795d594fSAndroid Build Coastguard Worker static bool IsSameSizeConstant(const HInstruction* insn1, const HInstruction* insn2) {
1016*795d594fSAndroid Build Coastguard Worker return insn1->IsConstant()
1017*795d594fSAndroid Build Coastguard Worker && insn2->IsConstant()
1018*795d594fSAndroid Build Coastguard Worker && DataType::Is64BitType(insn1->GetType()) == DataType::Is64BitType(insn2->GetType());
1019*795d594fSAndroid Build Coastguard Worker }
1020*795d594fSAndroid Build Coastguard Worker
IsConstantEquivalent(const HInstruction * insn1,const HInstruction * insn2,BitVector * visited)1021*795d594fSAndroid Build Coastguard Worker static bool IsConstantEquivalent(const HInstruction* insn1,
1022*795d594fSAndroid Build Coastguard Worker const HInstruction* insn2,
1023*795d594fSAndroid Build Coastguard Worker BitVector* visited) {
1024*795d594fSAndroid Build Coastguard Worker if (insn1->IsPhi() && insn1->AsPhi()->IsVRegEquivalentOf(insn2)) {
1025*795d594fSAndroid Build Coastguard Worker HConstInputsRef insn1_inputs = insn1->GetInputs();
1026*795d594fSAndroid Build Coastguard Worker HConstInputsRef insn2_inputs = insn2->GetInputs();
1027*795d594fSAndroid Build Coastguard Worker if (insn1_inputs.size() != insn2_inputs.size()) {
1028*795d594fSAndroid Build Coastguard Worker return false;
1029*795d594fSAndroid Build Coastguard Worker }
1030*795d594fSAndroid Build Coastguard Worker
1031*795d594fSAndroid Build Coastguard Worker // Testing only one of the two inputs for recursion is sufficient.
1032*795d594fSAndroid Build Coastguard Worker if (visited->IsBitSet(insn1->GetId())) {
1033*795d594fSAndroid Build Coastguard Worker return true;
1034*795d594fSAndroid Build Coastguard Worker }
1035*795d594fSAndroid Build Coastguard Worker visited->SetBit(insn1->GetId());
1036*795d594fSAndroid Build Coastguard Worker
1037*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < insn1_inputs.size(); ++i) {
1038*795d594fSAndroid Build Coastguard Worker if (!IsConstantEquivalent(insn1_inputs[i], insn2_inputs[i], visited)) {
1039*795d594fSAndroid Build Coastguard Worker return false;
1040*795d594fSAndroid Build Coastguard Worker }
1041*795d594fSAndroid Build Coastguard Worker }
1042*795d594fSAndroid Build Coastguard Worker return true;
1043*795d594fSAndroid Build Coastguard Worker } else if (IsSameSizeConstant(insn1, insn2)) {
1044*795d594fSAndroid Build Coastguard Worker return insn1->AsConstant()->GetValueAsUint64() == insn2->AsConstant()->GetValueAsUint64();
1045*795d594fSAndroid Build Coastguard Worker } else {
1046*795d594fSAndroid Build Coastguard Worker return false;
1047*795d594fSAndroid Build Coastguard Worker }
1048*795d594fSAndroid Build Coastguard Worker }
1049*795d594fSAndroid Build Coastguard Worker
VisitPhi(HPhi * phi)1050*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitPhi(HPhi* phi) {
1051*795d594fSAndroid Build Coastguard Worker VisitInstruction(phi);
1052*795d594fSAndroid Build Coastguard Worker
1053*795d594fSAndroid Build Coastguard Worker // Ensure the first input of a phi is not itself.
1054*795d594fSAndroid Build Coastguard Worker ArrayRef<HUserRecord<HInstruction*>> input_records = phi->GetInputRecords();
1055*795d594fSAndroid Build Coastguard Worker if (input_records[0].GetInstruction() == phi) {
1056*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
1057*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1058*795d594fSAndroid Build Coastguard Worker phi->GetBlock()->GetBlockId()));
1059*795d594fSAndroid Build Coastguard Worker }
1060*795d594fSAndroid Build Coastguard Worker
1061*795d594fSAndroid Build Coastguard Worker // Ensure that the inputs have the same primitive kind as the phi.
1062*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < input_records.size(); ++i) {
1063*795d594fSAndroid Build Coastguard Worker HInstruction* input = input_records[i].GetInstruction();
1064*795d594fSAndroid Build Coastguard Worker if (DataType::Kind(input->GetType()) != DataType::Kind(phi->GetType())) {
1065*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1066*795d594fSAndroid Build Coastguard Worker "Input %d at index %zu of phi %d from block %d does not have the "
1067*795d594fSAndroid Build Coastguard Worker "same kind as the phi: %s versus %s",
1068*795d594fSAndroid Build Coastguard Worker input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
1069*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(input->GetType()),
1070*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(phi->GetType())));
1071*795d594fSAndroid Build Coastguard Worker }
1072*795d594fSAndroid Build Coastguard Worker }
1073*795d594fSAndroid Build Coastguard Worker if (phi->GetType() != HPhi::ToPhiType(phi->GetType())) {
1074*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Phi %d in block %d does not have an expected phi type: %s",
1075*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1076*795d594fSAndroid Build Coastguard Worker phi->GetBlock()->GetBlockId(),
1077*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(phi->GetType())));
1078*795d594fSAndroid Build Coastguard Worker }
1079*795d594fSAndroid Build Coastguard Worker
1080*795d594fSAndroid Build Coastguard Worker if (phi->IsCatchPhi()) {
1081*795d594fSAndroid Build Coastguard Worker // The number of inputs of a catch phi should be the total number of throwing
1082*795d594fSAndroid Build Coastguard Worker // instructions caught by this catch block. We do not enforce this, however,
1083*795d594fSAndroid Build Coastguard Worker // because we do not remove the corresponding inputs when we prove that an
1084*795d594fSAndroid Build Coastguard Worker // instruction cannot throw. Instead, we at least test that all phis have the
1085*795d594fSAndroid Build Coastguard Worker // same, non-zero number of inputs (b/24054676).
1086*795d594fSAndroid Build Coastguard Worker if (input_records.empty()) {
1087*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Phi %d in catch block %d has zero inputs.",
1088*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1089*795d594fSAndroid Build Coastguard Worker phi->GetBlock()->GetBlockId()));
1090*795d594fSAndroid Build Coastguard Worker } else {
1091*795d594fSAndroid Build Coastguard Worker HInstruction* next_phi = phi->GetNext();
1092*795d594fSAndroid Build Coastguard Worker if (next_phi != nullptr) {
1093*795d594fSAndroid Build Coastguard Worker size_t input_count_next = next_phi->InputCount();
1094*795d594fSAndroid Build Coastguard Worker if (input_records.size() != input_count_next) {
1095*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Phi %d in catch block %d has %zu inputs, "
1096*795d594fSAndroid Build Coastguard Worker "but phi %d has %zu inputs.",
1097*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1098*795d594fSAndroid Build Coastguard Worker phi->GetBlock()->GetBlockId(),
1099*795d594fSAndroid Build Coastguard Worker input_records.size(),
1100*795d594fSAndroid Build Coastguard Worker next_phi->GetId(),
1101*795d594fSAndroid Build Coastguard Worker input_count_next));
1102*795d594fSAndroid Build Coastguard Worker }
1103*795d594fSAndroid Build Coastguard Worker }
1104*795d594fSAndroid Build Coastguard Worker }
1105*795d594fSAndroid Build Coastguard Worker } else {
1106*795d594fSAndroid Build Coastguard Worker // Ensure the number of inputs of a non-catch phi is the same as the number
1107*795d594fSAndroid Build Coastguard Worker // of its predecessors.
1108*795d594fSAndroid Build Coastguard Worker const ArenaVector<HBasicBlock*>& predecessors = phi->GetBlock()->GetPredecessors();
1109*795d594fSAndroid Build Coastguard Worker if (input_records.size() != predecessors.size()) {
1110*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1111*795d594fSAndroid Build Coastguard Worker "Phi %d in block %d has %zu inputs, "
1112*795d594fSAndroid Build Coastguard Worker "but block %d has %zu predecessors.",
1113*795d594fSAndroid Build Coastguard Worker phi->GetId(), phi->GetBlock()->GetBlockId(), input_records.size(),
1114*795d594fSAndroid Build Coastguard Worker phi->GetBlock()->GetBlockId(), predecessors.size()));
1115*795d594fSAndroid Build Coastguard Worker } else {
1116*795d594fSAndroid Build Coastguard Worker // Ensure phi input at index I either comes from the Ith
1117*795d594fSAndroid Build Coastguard Worker // predecessor or from a block that dominates this predecessor.
1118*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < input_records.size(); ++i) {
1119*795d594fSAndroid Build Coastguard Worker HInstruction* input = input_records[i].GetInstruction();
1120*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = predecessors[i];
1121*795d594fSAndroid Build Coastguard Worker if (!(input->GetBlock() == predecessor
1122*795d594fSAndroid Build Coastguard Worker || input->GetBlock()->Dominates(predecessor))) {
1123*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1124*795d594fSAndroid Build Coastguard Worker "Input %d at index %zu of phi %d from block %d is not defined in "
1125*795d594fSAndroid Build Coastguard Worker "predecessor number %zu nor in a block dominating it.",
1126*795d594fSAndroid Build Coastguard Worker input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
1127*795d594fSAndroid Build Coastguard Worker i));
1128*795d594fSAndroid Build Coastguard Worker }
1129*795d594fSAndroid Build Coastguard Worker }
1130*795d594fSAndroid Build Coastguard Worker }
1131*795d594fSAndroid Build Coastguard Worker }
1132*795d594fSAndroid Build Coastguard Worker
1133*795d594fSAndroid Build Coastguard Worker // Ensure that catch phis are sorted by their vreg number, as required by
1134*795d594fSAndroid Build Coastguard Worker // the register allocator and code generator. This does not apply to normal
1135*795d594fSAndroid Build Coastguard Worker // phis which can be constructed artifically.
1136*795d594fSAndroid Build Coastguard Worker if (phi->IsCatchPhi()) {
1137*795d594fSAndroid Build Coastguard Worker HInstruction* next_phi = phi->GetNext();
1138*795d594fSAndroid Build Coastguard Worker if (next_phi != nullptr && phi->GetRegNumber() > next_phi->AsPhi()->GetRegNumber()) {
1139*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Catch phis %d and %d in block %d are not sorted by their "
1140*795d594fSAndroid Build Coastguard Worker "vreg numbers.",
1141*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1142*795d594fSAndroid Build Coastguard Worker next_phi->GetId(),
1143*795d594fSAndroid Build Coastguard Worker phi->GetBlock()->GetBlockId()));
1144*795d594fSAndroid Build Coastguard Worker }
1145*795d594fSAndroid Build Coastguard Worker }
1146*795d594fSAndroid Build Coastguard Worker
1147*795d594fSAndroid Build Coastguard Worker // Test phi equivalents. There should not be two of the same type and they should only be
1148*795d594fSAndroid Build Coastguard Worker // created for constants which were untyped in DEX. Note that this test can be skipped for
1149*795d594fSAndroid Build Coastguard Worker // a synthetic phi (indicated by lack of a virtual register).
1150*795d594fSAndroid Build Coastguard Worker if (phi->GetRegNumber() != kNoRegNumber) {
1151*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator phi_it(phi->GetBlock()->GetPhis());
1152*795d594fSAndroid Build Coastguard Worker !phi_it.Done();
1153*795d594fSAndroid Build Coastguard Worker phi_it.Advance()) {
1154*795d594fSAndroid Build Coastguard Worker HPhi* other_phi = phi_it.Current()->AsPhi();
1155*795d594fSAndroid Build Coastguard Worker if (phi != other_phi && phi->GetRegNumber() == other_phi->GetRegNumber()) {
1156*795d594fSAndroid Build Coastguard Worker if (phi->GetType() == other_phi->GetType()) {
1157*795d594fSAndroid Build Coastguard Worker std::stringstream type_str;
1158*795d594fSAndroid Build Coastguard Worker type_str << phi->GetType();
1159*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Equivalent phi (%d) found for VReg %d with type: %s.",
1160*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1161*795d594fSAndroid Build Coastguard Worker phi->GetRegNumber(),
1162*795d594fSAndroid Build Coastguard Worker type_str.str().c_str()));
1163*795d594fSAndroid Build Coastguard Worker } else if (phi->GetType() == DataType::Type::kReference) {
1164*795d594fSAndroid Build Coastguard Worker std::stringstream type_str;
1165*795d594fSAndroid Build Coastguard Worker type_str << other_phi->GetType();
1166*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1167*795d594fSAndroid Build Coastguard Worker "Equivalent non-reference phi (%d) found for VReg %d with type: %s.",
1168*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1169*795d594fSAndroid Build Coastguard Worker phi->GetRegNumber(),
1170*795d594fSAndroid Build Coastguard Worker type_str.str().c_str()));
1171*795d594fSAndroid Build Coastguard Worker } else {
1172*795d594fSAndroid Build Coastguard Worker // Use local allocator for allocating memory.
1173*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(GetGraph()->GetArenaStack());
1174*795d594fSAndroid Build Coastguard Worker // If we get here, make sure we allocate all the necessary storage at once
1175*795d594fSAndroid Build Coastguard Worker // because the BitVector reallocation strategy has very bad worst-case behavior.
1176*795d594fSAndroid Build Coastguard Worker ArenaBitVector visited(&allocator,
1177*795d594fSAndroid Build Coastguard Worker GetGraph()->GetCurrentInstructionId(),
1178*795d594fSAndroid Build Coastguard Worker /* expandable= */ false,
1179*795d594fSAndroid Build Coastguard Worker kArenaAllocGraphChecker);
1180*795d594fSAndroid Build Coastguard Worker if (!IsConstantEquivalent(phi, other_phi, &visited)) {
1181*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Two phis (%d and %d) found for VReg %d but they "
1182*795d594fSAndroid Build Coastguard Worker "are not equivalents of constants.",
1183*795d594fSAndroid Build Coastguard Worker phi->GetId(),
1184*795d594fSAndroid Build Coastguard Worker other_phi->GetId(),
1185*795d594fSAndroid Build Coastguard Worker phi->GetRegNumber()));
1186*795d594fSAndroid Build Coastguard Worker }
1187*795d594fSAndroid Build Coastguard Worker }
1188*795d594fSAndroid Build Coastguard Worker }
1189*795d594fSAndroid Build Coastguard Worker }
1190*795d594fSAndroid Build Coastguard Worker }
1191*795d594fSAndroid Build Coastguard Worker }
1192*795d594fSAndroid Build Coastguard Worker
HandleBooleanInput(HInstruction * instruction,size_t input_index)1193*795d594fSAndroid Build Coastguard Worker void GraphChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
1194*795d594fSAndroid Build Coastguard Worker HInstruction* input = instruction->InputAt(input_index);
1195*795d594fSAndroid Build Coastguard Worker if (input->IsIntConstant()) {
1196*795d594fSAndroid Build Coastguard Worker int32_t value = input->AsIntConstant()->GetValue();
1197*795d594fSAndroid Build Coastguard Worker if (value != 0 && value != 1) {
1198*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1199*795d594fSAndroid Build Coastguard Worker "%s instruction %d has a non-Boolean constant input %d whose value is: %d.",
1200*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1201*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1202*795d594fSAndroid Build Coastguard Worker static_cast<int>(input_index),
1203*795d594fSAndroid Build Coastguard Worker value));
1204*795d594fSAndroid Build Coastguard Worker }
1205*795d594fSAndroid Build Coastguard Worker } else if (DataType::Kind(input->GetType()) != DataType::Type::kInt32) {
1206*795d594fSAndroid Build Coastguard Worker // TODO: We need a data-flow analysis to determine if an input like Phi,
1207*795d594fSAndroid Build Coastguard Worker // Select or a binary operation is actually Boolean. Allow for now.
1208*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1209*795d594fSAndroid Build Coastguard Worker "%s instruction %d has a non-integer input %d whose type is: %s.",
1210*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1211*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1212*795d594fSAndroid Build Coastguard Worker static_cast<int>(input_index),
1213*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(input->GetType())));
1214*795d594fSAndroid Build Coastguard Worker }
1215*795d594fSAndroid Build Coastguard Worker }
1216*795d594fSAndroid Build Coastguard Worker
VisitPackedSwitch(HPackedSwitch * instruction)1217*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitPackedSwitch(HPackedSwitch* instruction) {
1218*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1219*795d594fSAndroid Build Coastguard Worker // Check that the number of block successors matches the switch count plus
1220*795d594fSAndroid Build Coastguard Worker // one for the default block.
1221*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
1222*795d594fSAndroid Build Coastguard Worker if (instruction->GetNumEntries() + 1u != block->GetSuccessors().size()) {
1223*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1224*795d594fSAndroid Build Coastguard Worker "%s instruction %d in block %d expects %u successors to the block, but found: %zu.",
1225*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1226*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1227*795d594fSAndroid Build Coastguard Worker block->GetBlockId(),
1228*795d594fSAndroid Build Coastguard Worker instruction->GetNumEntries() + 1u,
1229*795d594fSAndroid Build Coastguard Worker block->GetSuccessors().size()));
1230*795d594fSAndroid Build Coastguard Worker }
1231*795d594fSAndroid Build Coastguard Worker }
1232*795d594fSAndroid Build Coastguard Worker
VisitIf(HIf * instruction)1233*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitIf(HIf* instruction) {
1234*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1235*795d594fSAndroid Build Coastguard Worker HandleBooleanInput(instruction, 0);
1236*795d594fSAndroid Build Coastguard Worker }
1237*795d594fSAndroid Build Coastguard Worker
VisitSelect(HSelect * instruction)1238*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitSelect(HSelect* instruction) {
1239*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1240*795d594fSAndroid Build Coastguard Worker HandleBooleanInput(instruction, 2);
1241*795d594fSAndroid Build Coastguard Worker }
1242*795d594fSAndroid Build Coastguard Worker
VisitBooleanNot(HBooleanNot * instruction)1243*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitBooleanNot(HBooleanNot* instruction) {
1244*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1245*795d594fSAndroid Build Coastguard Worker HandleBooleanInput(instruction, 0);
1246*795d594fSAndroid Build Coastguard Worker }
1247*795d594fSAndroid Build Coastguard Worker
VisitCondition(HCondition * op)1248*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitCondition(HCondition* op) {
1249*795d594fSAndroid Build Coastguard Worker VisitInstruction(op);
1250*795d594fSAndroid Build Coastguard Worker if (op->GetType() != DataType::Type::kBool) {
1251*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1252*795d594fSAndroid Build Coastguard Worker "Condition %s %d has a non-Boolean result type: %s.",
1253*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId(),
1254*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(op->GetType())));
1255*795d594fSAndroid Build Coastguard Worker }
1256*795d594fSAndroid Build Coastguard Worker HInstruction* lhs = op->InputAt(0);
1257*795d594fSAndroid Build Coastguard Worker HInstruction* rhs = op->InputAt(1);
1258*795d594fSAndroid Build Coastguard Worker if (DataType::Kind(lhs->GetType()) != DataType::Kind(rhs->GetType())) {
1259*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1260*795d594fSAndroid Build Coastguard Worker "Condition %s %d has inputs of different kinds: %s, and %s.",
1261*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId(),
1262*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(lhs->GetType()),
1263*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(rhs->GetType())));
1264*795d594fSAndroid Build Coastguard Worker }
1265*795d594fSAndroid Build Coastguard Worker if (!op->IsEqual() && !op->IsNotEqual()) {
1266*795d594fSAndroid Build Coastguard Worker if ((lhs->GetType() == DataType::Type::kReference)) {
1267*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1268*795d594fSAndroid Build Coastguard Worker "Condition %s %d uses an object as left-hand side input.",
1269*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId()));
1270*795d594fSAndroid Build Coastguard Worker } else if (rhs->GetType() == DataType::Type::kReference) {
1271*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1272*795d594fSAndroid Build Coastguard Worker "Condition %s %d uses an object as right-hand side input.",
1273*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId()));
1274*795d594fSAndroid Build Coastguard Worker }
1275*795d594fSAndroid Build Coastguard Worker }
1276*795d594fSAndroid Build Coastguard Worker }
1277*795d594fSAndroid Build Coastguard Worker
VisitNeg(HNeg * instruction)1278*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitNeg(HNeg* instruction) {
1279*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1280*795d594fSAndroid Build Coastguard Worker DataType::Type input_type = instruction->InputAt(0)->GetType();
1281*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = instruction->GetType();
1282*795d594fSAndroid Build Coastguard Worker if (result_type != DataType::Kind(input_type)) {
1283*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Binary operation %s %d has a result type different "
1284*795d594fSAndroid Build Coastguard Worker "from its input kind: %s vs %s.",
1285*795d594fSAndroid Build Coastguard Worker instruction->DebugName(), instruction->GetId(),
1286*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(result_type),
1287*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(input_type)));
1288*795d594fSAndroid Build Coastguard Worker }
1289*795d594fSAndroid Build Coastguard Worker }
1290*795d594fSAndroid Build Coastguard Worker
HuntForOriginalReference(HInstruction * ref)1291*795d594fSAndroid Build Coastguard Worker HInstruction* HuntForOriginalReference(HInstruction* ref) {
1292*795d594fSAndroid Build Coastguard Worker // An original reference can be transformed by instructions like:
1293*795d594fSAndroid Build Coastguard Worker // i0 NewArray
1294*795d594fSAndroid Build Coastguard Worker // i1 HInstruction(i0) <-- NullCheck, BoundType, IntermediateAddress.
1295*795d594fSAndroid Build Coastguard Worker // i2 ArraySet(i1, index, value)
1296*795d594fSAndroid Build Coastguard Worker DCHECK(ref != nullptr);
1297*795d594fSAndroid Build Coastguard Worker while (ref->IsNullCheck() || ref->IsBoundType() || ref->IsIntermediateAddress()) {
1298*795d594fSAndroid Build Coastguard Worker ref = ref->InputAt(0);
1299*795d594fSAndroid Build Coastguard Worker }
1300*795d594fSAndroid Build Coastguard Worker return ref;
1301*795d594fSAndroid Build Coastguard Worker }
1302*795d594fSAndroid Build Coastguard Worker
IsRemovedWriteBarrier(DataType::Type type,WriteBarrierKind write_barrier_kind,HInstruction * value)1303*795d594fSAndroid Build Coastguard Worker bool IsRemovedWriteBarrier(DataType::Type type,
1304*795d594fSAndroid Build Coastguard Worker WriteBarrierKind write_barrier_kind,
1305*795d594fSAndroid Build Coastguard Worker HInstruction* value) {
1306*795d594fSAndroid Build Coastguard Worker return write_barrier_kind == WriteBarrierKind::kDontEmit &&
1307*795d594fSAndroid Build Coastguard Worker type == DataType::Type::kReference &&
1308*795d594fSAndroid Build Coastguard Worker !HuntForOriginalReference(value)->IsNullConstant();
1309*795d594fSAndroid Build Coastguard Worker }
1310*795d594fSAndroid Build Coastguard Worker
VisitArraySet(HArraySet * instruction)1311*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitArraySet(HArraySet* instruction) {
1312*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1313*795d594fSAndroid Build Coastguard Worker
1314*795d594fSAndroid Build Coastguard Worker if (instruction->NeedsTypeCheck() !=
1315*795d594fSAndroid Build Coastguard Worker instruction->GetSideEffects().Includes(SideEffects::CanTriggerGC())) {
1316*795d594fSAndroid Build Coastguard Worker AddError(
1317*795d594fSAndroid Build Coastguard Worker StringPrintf("%s %d has a flag mismatch. An ArraySet instruction can trigger a GC iff it "
1318*795d594fSAndroid Build Coastguard Worker "needs a type check. Needs type check: %s, Can trigger GC: %s",
1319*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1320*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1321*795d594fSAndroid Build Coastguard Worker StrBool(instruction->NeedsTypeCheck()),
1322*795d594fSAndroid Build Coastguard Worker StrBool(instruction->GetSideEffects().Includes(SideEffects::CanTriggerGC()))));
1323*795d594fSAndroid Build Coastguard Worker }
1324*795d594fSAndroid Build Coastguard Worker
1325*795d594fSAndroid Build Coastguard Worker if (IsRemovedWriteBarrier(instruction->GetComponentType(),
1326*795d594fSAndroid Build Coastguard Worker instruction->GetWriteBarrierKind(),
1327*795d594fSAndroid Build Coastguard Worker instruction->GetValue())) {
1328*795d594fSAndroid Build Coastguard Worker CheckWriteBarrier(instruction, [](HInstruction* it_instr) {
1329*795d594fSAndroid Build Coastguard Worker return it_instr->AsArraySet()->GetWriteBarrierKind();
1330*795d594fSAndroid Build Coastguard Worker });
1331*795d594fSAndroid Build Coastguard Worker }
1332*795d594fSAndroid Build Coastguard Worker }
1333*795d594fSAndroid Build Coastguard Worker
VisitInstanceFieldSet(HInstanceFieldSet * instruction)1334*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1335*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1336*795d594fSAndroid Build Coastguard Worker if (IsRemovedWriteBarrier(instruction->GetFieldType(),
1337*795d594fSAndroid Build Coastguard Worker instruction->GetWriteBarrierKind(),
1338*795d594fSAndroid Build Coastguard Worker instruction->GetValue())) {
1339*795d594fSAndroid Build Coastguard Worker CheckWriteBarrier(instruction, [](HInstruction* it_instr) {
1340*795d594fSAndroid Build Coastguard Worker return it_instr->AsInstanceFieldSet()->GetWriteBarrierKind();
1341*795d594fSAndroid Build Coastguard Worker });
1342*795d594fSAndroid Build Coastguard Worker }
1343*795d594fSAndroid Build Coastguard Worker }
1344*795d594fSAndroid Build Coastguard Worker
VisitStaticFieldSet(HStaticFieldSet * instruction)1345*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitStaticFieldSet(HStaticFieldSet* instruction) {
1346*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1347*795d594fSAndroid Build Coastguard Worker if (IsRemovedWriteBarrier(instruction->GetFieldType(),
1348*795d594fSAndroid Build Coastguard Worker instruction->GetWriteBarrierKind(),
1349*795d594fSAndroid Build Coastguard Worker instruction->GetValue())) {
1350*795d594fSAndroid Build Coastguard Worker CheckWriteBarrier(instruction, [](HInstruction* it_instr) {
1351*795d594fSAndroid Build Coastguard Worker return it_instr->AsStaticFieldSet()->GetWriteBarrierKind();
1352*795d594fSAndroid Build Coastguard Worker });
1353*795d594fSAndroid Build Coastguard Worker }
1354*795d594fSAndroid Build Coastguard Worker }
1355*795d594fSAndroid Build Coastguard Worker
1356*795d594fSAndroid Build Coastguard Worker template <typename GetWriteBarrierKind>
CheckWriteBarrier(HInstruction * instruction,GetWriteBarrierKind && get_write_barrier_kind)1357*795d594fSAndroid Build Coastguard Worker void GraphChecker::CheckWriteBarrier(HInstruction* instruction,
1358*795d594fSAndroid Build Coastguard Worker GetWriteBarrierKind&& get_write_barrier_kind) {
1359*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->IsStaticFieldSet() ||
1360*795d594fSAndroid Build Coastguard Worker instruction->IsInstanceFieldSet() ||
1361*795d594fSAndroid Build Coastguard Worker instruction->IsArraySet());
1362*795d594fSAndroid Build Coastguard Worker
1363*795d594fSAndroid Build Coastguard Worker // For removed write barriers, we expect that the write barrier they are relying on is:
1364*795d594fSAndroid Build Coastguard Worker // A) In the same block, and
1365*795d594fSAndroid Build Coastguard Worker // B) There's no instruction between them that can trigger a GC.
1366*795d594fSAndroid Build Coastguard Worker HInstruction* object = HuntForOriginalReference(instruction->InputAt(0));
1367*795d594fSAndroid Build Coastguard Worker bool found = false;
1368*795d594fSAndroid Build Coastguard Worker for (HBackwardInstructionIterator it(instruction); !it.Done(); it.Advance()) {
1369*795d594fSAndroid Build Coastguard Worker if (instruction->GetKind() == it.Current()->GetKind() &&
1370*795d594fSAndroid Build Coastguard Worker object == HuntForOriginalReference(it.Current()->InputAt(0)) &&
1371*795d594fSAndroid Build Coastguard Worker get_write_barrier_kind(it.Current()) == WriteBarrierKind::kEmitBeingReliedOn) {
1372*795d594fSAndroid Build Coastguard Worker // Found the write barrier we are relying on.
1373*795d594fSAndroid Build Coastguard Worker found = true;
1374*795d594fSAndroid Build Coastguard Worker break;
1375*795d594fSAndroid Build Coastguard Worker }
1376*795d594fSAndroid Build Coastguard Worker
1377*795d594fSAndroid Build Coastguard Worker // We check the `SideEffects::CanTriggerGC` after failing to find the write barrier since having
1378*795d594fSAndroid Build Coastguard Worker // a write barrier that's relying on an ArraySet that can trigger GC is fine because the card
1379*795d594fSAndroid Build Coastguard Worker // table is marked after the GC happens.
1380*795d594fSAndroid Build Coastguard Worker if (it.Current()->GetSideEffects().Includes(SideEffects::CanTriggerGC())) {
1381*795d594fSAndroid Build Coastguard Worker AddError(
1382*795d594fSAndroid Build Coastguard Worker StringPrintf("%s %d from block %d was expecting a write barrier and it didn't find "
1383*795d594fSAndroid Build Coastguard Worker "any. %s %d can trigger GC",
1384*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1385*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1386*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->GetBlockId(),
1387*795d594fSAndroid Build Coastguard Worker it.Current()->DebugName(),
1388*795d594fSAndroid Build Coastguard Worker it.Current()->GetId()));
1389*795d594fSAndroid Build Coastguard Worker }
1390*795d594fSAndroid Build Coastguard Worker }
1391*795d594fSAndroid Build Coastguard Worker
1392*795d594fSAndroid Build Coastguard Worker if (!found) {
1393*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("%s %d in block %d didn't find a write barrier to latch onto",
1394*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1395*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1396*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->GetBlockId()));
1397*795d594fSAndroid Build Coastguard Worker }
1398*795d594fSAndroid Build Coastguard Worker }
1399*795d594fSAndroid Build Coastguard Worker
VisitBinaryOperation(HBinaryOperation * op)1400*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
1401*795d594fSAndroid Build Coastguard Worker VisitInstruction(op);
1402*795d594fSAndroid Build Coastguard Worker DataType::Type lhs_type = op->InputAt(0)->GetType();
1403*795d594fSAndroid Build Coastguard Worker DataType::Type rhs_type = op->InputAt(1)->GetType();
1404*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = op->GetType();
1405*795d594fSAndroid Build Coastguard Worker
1406*795d594fSAndroid Build Coastguard Worker // Type consistency between inputs.
1407*795d594fSAndroid Build Coastguard Worker if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRol() || op->IsRor()) {
1408*795d594fSAndroid Build Coastguard Worker if (DataType::Kind(rhs_type) != DataType::Type::kInt32) {
1409*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Shift/rotate operation %s %d has a non-int kind second input: "
1410*795d594fSAndroid Build Coastguard Worker "%s of type %s.",
1411*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId(),
1412*795d594fSAndroid Build Coastguard Worker op->InputAt(1)->DebugName(),
1413*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(rhs_type)));
1414*795d594fSAndroid Build Coastguard Worker }
1415*795d594fSAndroid Build Coastguard Worker } else {
1416*795d594fSAndroid Build Coastguard Worker if (DataType::Kind(lhs_type) != DataType::Kind(rhs_type)) {
1417*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Binary operation %s %d has inputs of different kinds: %s, and %s.",
1418*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId(),
1419*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(lhs_type),
1420*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(rhs_type)));
1421*795d594fSAndroid Build Coastguard Worker }
1422*795d594fSAndroid Build Coastguard Worker }
1423*795d594fSAndroid Build Coastguard Worker
1424*795d594fSAndroid Build Coastguard Worker // Type consistency between result and input(s).
1425*795d594fSAndroid Build Coastguard Worker if (op->IsCompare()) {
1426*795d594fSAndroid Build Coastguard Worker if (result_type != DataType::Type::kInt32) {
1427*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Compare operation %d has a non-int result type: %s.",
1428*795d594fSAndroid Build Coastguard Worker op->GetId(),
1429*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(result_type)));
1430*795d594fSAndroid Build Coastguard Worker }
1431*795d594fSAndroid Build Coastguard Worker } else if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRol() || op->IsRor()) {
1432*795d594fSAndroid Build Coastguard Worker // Only check the first input (value), as the second one (distance)
1433*795d594fSAndroid Build Coastguard Worker // must invariably be of kind `int`.
1434*795d594fSAndroid Build Coastguard Worker if (result_type != DataType::Kind(lhs_type)) {
1435*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Shift/rotate operation %s %d has a result type different "
1436*795d594fSAndroid Build Coastguard Worker "from its left-hand side (value) input kind: %s vs %s.",
1437*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId(),
1438*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(result_type),
1439*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(lhs_type)));
1440*795d594fSAndroid Build Coastguard Worker }
1441*795d594fSAndroid Build Coastguard Worker } else {
1442*795d594fSAndroid Build Coastguard Worker if (DataType::Kind(result_type) != DataType::Kind(lhs_type)) {
1443*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Binary operation %s %d has a result kind different "
1444*795d594fSAndroid Build Coastguard Worker "from its left-hand side input kind: %s vs %s.",
1445*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId(),
1446*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(result_type),
1447*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(lhs_type)));
1448*795d594fSAndroid Build Coastguard Worker }
1449*795d594fSAndroid Build Coastguard Worker if (DataType::Kind(result_type) != DataType::Kind(rhs_type)) {
1450*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf("Binary operation %s %d has a result kind different "
1451*795d594fSAndroid Build Coastguard Worker "from its right-hand side input kind: %s vs %s.",
1452*795d594fSAndroid Build Coastguard Worker op->DebugName(), op->GetId(),
1453*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(result_type),
1454*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(rhs_type)));
1455*795d594fSAndroid Build Coastguard Worker }
1456*795d594fSAndroid Build Coastguard Worker }
1457*795d594fSAndroid Build Coastguard Worker }
1458*795d594fSAndroid Build Coastguard Worker
VisitConstant(HConstant * instruction)1459*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitConstant(HConstant* instruction) {
1460*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1461*795d594fSAndroid Build Coastguard Worker
1462*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instruction->GetBlock();
1463*795d594fSAndroid Build Coastguard Worker if (!block->IsEntryBlock()) {
1464*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1465*795d594fSAndroid Build Coastguard Worker "%s %d should be in the entry block but is in block %d.",
1466*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1467*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1468*795d594fSAndroid Build Coastguard Worker block->GetBlockId()));
1469*795d594fSAndroid Build Coastguard Worker }
1470*795d594fSAndroid Build Coastguard Worker }
1471*795d594fSAndroid Build Coastguard Worker
VisitBoundType(HBoundType * instruction)1472*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitBoundType(HBoundType* instruction) {
1473*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1474*795d594fSAndroid Build Coastguard Worker
1475*795d594fSAndroid Build Coastguard Worker if (!instruction->GetUpperBound().IsValid()) {
1476*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1477*795d594fSAndroid Build Coastguard Worker "%s %d does not have a valid upper bound RTI.",
1478*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1479*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
1480*795d594fSAndroid Build Coastguard Worker }
1481*795d594fSAndroid Build Coastguard Worker }
1482*795d594fSAndroid Build Coastguard Worker
VisitTypeConversion(HTypeConversion * instruction)1483*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitTypeConversion(HTypeConversion* instruction) {
1484*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1485*795d594fSAndroid Build Coastguard Worker DataType::Type result_type = instruction->GetResultType();
1486*795d594fSAndroid Build Coastguard Worker DataType::Type input_type = instruction->GetInputType();
1487*795d594fSAndroid Build Coastguard Worker // Invariant: We should never generate a conversion to a Boolean value.
1488*795d594fSAndroid Build Coastguard Worker if (result_type == DataType::Type::kBool) {
1489*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1490*795d594fSAndroid Build Coastguard Worker "%s %d converts to a %s (from a %s).",
1491*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1492*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1493*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(result_type),
1494*795d594fSAndroid Build Coastguard Worker DataType::PrettyDescriptor(input_type)));
1495*795d594fSAndroid Build Coastguard Worker }
1496*795d594fSAndroid Build Coastguard Worker }
1497*795d594fSAndroid Build Coastguard Worker
VisitVecOperation(HVecOperation * instruction)1498*795d594fSAndroid Build Coastguard Worker void GraphChecker::VisitVecOperation(HVecOperation* instruction) {
1499*795d594fSAndroid Build Coastguard Worker VisitInstruction(instruction);
1500*795d594fSAndroid Build Coastguard Worker
1501*795d594fSAndroid Build Coastguard Worker if (!GetGraph()->HasSIMD()) {
1502*795d594fSAndroid Build Coastguard Worker AddError(
1503*795d594fSAndroid Build Coastguard Worker StringPrintf("The graph doesn't have the HasSIMD flag set but we saw "
1504*795d594fSAndroid Build Coastguard Worker "%s:%d in block %d.",
1505*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1506*795d594fSAndroid Build Coastguard Worker instruction->GetId(),
1507*795d594fSAndroid Build Coastguard Worker instruction->GetBlock()->GetBlockId()));
1508*795d594fSAndroid Build Coastguard Worker }
1509*795d594fSAndroid Build Coastguard Worker
1510*795d594fSAndroid Build Coastguard Worker flag_info_.seen_SIMD = true;
1511*795d594fSAndroid Build Coastguard Worker
1512*795d594fSAndroid Build Coastguard Worker if (codegen_ == nullptr) {
1513*795d594fSAndroid Build Coastguard Worker return;
1514*795d594fSAndroid Build Coastguard Worker }
1515*795d594fSAndroid Build Coastguard Worker
1516*795d594fSAndroid Build Coastguard Worker if (!codegen_->SupportsPredicatedSIMD() && instruction->IsPredicated()) {
1517*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1518*795d594fSAndroid Build Coastguard Worker "%s %d must not be predicated.",
1519*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1520*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
1521*795d594fSAndroid Build Coastguard Worker }
1522*795d594fSAndroid Build Coastguard Worker
1523*795d594fSAndroid Build Coastguard Worker if (codegen_->SupportsPredicatedSIMD() &&
1524*795d594fSAndroid Build Coastguard Worker (instruction->MustBePredicatedInPredicatedSIMDMode() != instruction->IsPredicated())) {
1525*795d594fSAndroid Build Coastguard Worker AddError(StringPrintf(
1526*795d594fSAndroid Build Coastguard Worker "%s %d predication mode is incorrect; see HVecOperation::MustBePredicated.",
1527*795d594fSAndroid Build Coastguard Worker instruction->DebugName(),
1528*795d594fSAndroid Build Coastguard Worker instruction->GetId()));
1529*795d594fSAndroid Build Coastguard Worker }
1530*795d594fSAndroid Build Coastguard Worker }
1531*795d594fSAndroid Build Coastguard Worker
1532*795d594fSAndroid Build Coastguard Worker } // namespace art
1533