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 #include "nodes.h"
17*795d594fSAndroid Build Coastguard Worker
18*795d594fSAndroid Build Coastguard Worker #include <algorithm>
19*795d594fSAndroid Build Coastguard Worker #include <cfloat>
20*795d594fSAndroid Build Coastguard Worker #include <functional>
21*795d594fSAndroid Build Coastguard Worker #include <optional>
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/arena_allocator.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/arena_bit_vector.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/bit_utils.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector.h"
29*795d594fSAndroid Build Coastguard Worker #include "base/iteration_range.h"
30*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
31*795d594fSAndroid Build Coastguard Worker #include "base/malloc_arena_pool.h"
32*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
33*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
34*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
35*795d594fSAndroid Build Coastguard Worker #include "class_linker-inl.h"
36*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
37*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
38*795d594fSAndroid Build Coastguard Worker #include "common_dominator.h"
39*795d594fSAndroid Build Coastguard Worker #include "intrinsic_objects.h"
40*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
41*795d594fSAndroid Build Coastguard Worker #include "intrinsics_list.h"
42*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
43*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
44*795d594fSAndroid Build Coastguard Worker #include "ssa_builder.h"
45*795d594fSAndroid Build Coastguard Worker
46*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
47*795d594fSAndroid Build Coastguard Worker
48*795d594fSAndroid Build Coastguard Worker // Enable floating-point static evaluation during constant folding
49*795d594fSAndroid Build Coastguard Worker // only if all floating-point operations and constants evaluate in the
50*795d594fSAndroid Build Coastguard Worker // range and precision of the type used (i.e., 32-bit float, 64-bit
51*795d594fSAndroid Build Coastguard Worker // double).
52*795d594fSAndroid Build Coastguard Worker static constexpr bool kEnableFloatingPointStaticEvaluation = (FLT_EVAL_METHOD == 0);
53*795d594fSAndroid Build Coastguard Worker
AddBlock(HBasicBlock * block)54*795d594fSAndroid Build Coastguard Worker void HGraph::AddBlock(HBasicBlock* block) {
55*795d594fSAndroid Build Coastguard Worker block->SetBlockId(blocks_.size());
56*795d594fSAndroid Build Coastguard Worker blocks_.push_back(block);
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker
FindBackEdges(ArenaBitVector * visited)59*795d594fSAndroid Build Coastguard Worker void HGraph::FindBackEdges(ArenaBitVector* visited) {
60*795d594fSAndroid Build Coastguard Worker // "visited" must be empty on entry, it's an output argument for all visited (i.e. live) blocks.
61*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(visited->GetHighestBitSet(), -1);
62*795d594fSAndroid Build Coastguard Worker
63*795d594fSAndroid Build Coastguard Worker // Allocate memory from local ScopedArenaAllocator.
64*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(GetArenaStack());
65*795d594fSAndroid Build Coastguard Worker // Nodes that we're currently visiting, indexed by block id.
66*795d594fSAndroid Build Coastguard Worker ArenaBitVector visiting(
67*795d594fSAndroid Build Coastguard Worker &allocator, blocks_.size(), /* expandable= */ false, kArenaAllocGraphBuilder);
68*795d594fSAndroid Build Coastguard Worker // Number of successors visited from a given node, indexed by block id.
69*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<size_t> successors_visited(blocks_.size(),
70*795d594fSAndroid Build Coastguard Worker 0u,
71*795d594fSAndroid Build Coastguard Worker allocator.Adapter(kArenaAllocGraphBuilder));
72*795d594fSAndroid Build Coastguard Worker // Stack of nodes that we're currently visiting (same as marked in "visiting" above).
73*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder));
74*795d594fSAndroid Build Coastguard Worker constexpr size_t kDefaultWorklistSize = 8;
75*795d594fSAndroid Build Coastguard Worker worklist.reserve(kDefaultWorklistSize);
76*795d594fSAndroid Build Coastguard Worker visited->SetBit(entry_block_->GetBlockId());
77*795d594fSAndroid Build Coastguard Worker visiting.SetBit(entry_block_->GetBlockId());
78*795d594fSAndroid Build Coastguard Worker worklist.push_back(entry_block_);
79*795d594fSAndroid Build Coastguard Worker
80*795d594fSAndroid Build Coastguard Worker while (!worklist.empty()) {
81*795d594fSAndroid Build Coastguard Worker HBasicBlock* current = worklist.back();
82*795d594fSAndroid Build Coastguard Worker uint32_t current_id = current->GetBlockId();
83*795d594fSAndroid Build Coastguard Worker if (successors_visited[current_id] == current->GetSuccessors().size()) {
84*795d594fSAndroid Build Coastguard Worker visiting.ClearBit(current_id);
85*795d594fSAndroid Build Coastguard Worker worklist.pop_back();
86*795d594fSAndroid Build Coastguard Worker } else {
87*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
88*795d594fSAndroid Build Coastguard Worker uint32_t successor_id = successor->GetBlockId();
89*795d594fSAndroid Build Coastguard Worker if (visiting.IsBitSet(successor_id)) {
90*795d594fSAndroid Build Coastguard Worker DCHECK(ContainsElement(worklist, successor));
91*795d594fSAndroid Build Coastguard Worker successor->AddBackEdge(current);
92*795d594fSAndroid Build Coastguard Worker } else if (!visited->IsBitSet(successor_id)) {
93*795d594fSAndroid Build Coastguard Worker visited->SetBit(successor_id);
94*795d594fSAndroid Build Coastguard Worker visiting.SetBit(successor_id);
95*795d594fSAndroid Build Coastguard Worker worklist.push_back(successor);
96*795d594fSAndroid Build Coastguard Worker }
97*795d594fSAndroid Build Coastguard Worker }
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker
101*795d594fSAndroid Build Coastguard Worker // Remove the environment use records of the instruction for users.
RemoveEnvironmentUses(HInstruction * instruction)102*795d594fSAndroid Build Coastguard Worker void RemoveEnvironmentUses(HInstruction* instruction) {
103*795d594fSAndroid Build Coastguard Worker for (HEnvironment* environment = instruction->GetEnvironment();
104*795d594fSAndroid Build Coastguard Worker environment != nullptr;
105*795d594fSAndroid Build Coastguard Worker environment = environment->GetParent()) {
106*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = environment->Size(); i < e; ++i) {
107*795d594fSAndroid Build Coastguard Worker if (environment->GetInstructionAt(i) != nullptr) {
108*795d594fSAndroid Build Coastguard Worker environment->RemoveAsUserOfInput(i);
109*795d594fSAndroid Build Coastguard Worker }
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker }
112*795d594fSAndroid Build Coastguard Worker }
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker // Return whether the instruction has an environment and it's used by others.
HasEnvironmentUsedByOthers(HInstruction * instruction)115*795d594fSAndroid Build Coastguard Worker bool HasEnvironmentUsedByOthers(HInstruction* instruction) {
116*795d594fSAndroid Build Coastguard Worker for (HEnvironment* environment = instruction->GetEnvironment();
117*795d594fSAndroid Build Coastguard Worker environment != nullptr;
118*795d594fSAndroid Build Coastguard Worker environment = environment->GetParent()) {
119*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = environment->Size(); i < e; ++i) {
120*795d594fSAndroid Build Coastguard Worker HInstruction* user = environment->GetInstructionAt(i);
121*795d594fSAndroid Build Coastguard Worker if (user != nullptr) {
122*795d594fSAndroid Build Coastguard Worker return true;
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker }
125*795d594fSAndroid Build Coastguard Worker }
126*795d594fSAndroid Build Coastguard Worker return false;
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker
129*795d594fSAndroid Build Coastguard Worker // Reset environment records of the instruction itself.
ResetEnvironmentInputRecords(HInstruction * instruction)130*795d594fSAndroid Build Coastguard Worker void ResetEnvironmentInputRecords(HInstruction* instruction) {
131*795d594fSAndroid Build Coastguard Worker for (HEnvironment* environment = instruction->GetEnvironment();
132*795d594fSAndroid Build Coastguard Worker environment != nullptr;
133*795d594fSAndroid Build Coastguard Worker environment = environment->GetParent()) {
134*795d594fSAndroid Build Coastguard Worker for (size_t i = 0, e = environment->Size(); i < e; ++i) {
135*795d594fSAndroid Build Coastguard Worker DCHECK(environment->GetHolder() == instruction);
136*795d594fSAndroid Build Coastguard Worker if (environment->GetInstructionAt(i) != nullptr) {
137*795d594fSAndroid Build Coastguard Worker environment->SetRawEnvAt(i, nullptr);
138*795d594fSAndroid Build Coastguard Worker }
139*795d594fSAndroid Build Coastguard Worker }
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker }
142*795d594fSAndroid Build Coastguard Worker
RemoveAsUser(HInstruction * instruction)143*795d594fSAndroid Build Coastguard Worker static void RemoveAsUser(HInstruction* instruction) {
144*795d594fSAndroid Build Coastguard Worker instruction->RemoveAsUserOfAllInputs();
145*795d594fSAndroid Build Coastguard Worker RemoveEnvironmentUses(instruction);
146*795d594fSAndroid Build Coastguard Worker }
147*795d594fSAndroid Build Coastguard Worker
RemoveDeadBlocksInstructionsAsUsersAndDisconnect(const ArenaBitVector & visited) const148*795d594fSAndroid Build Coastguard Worker void HGraph::RemoveDeadBlocksInstructionsAsUsersAndDisconnect(const ArenaBitVector& visited) const {
149*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < blocks_.size(); ++i) {
150*795d594fSAndroid Build Coastguard Worker if (!visited.IsBitSet(i)) {
151*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = blocks_[i];
152*795d594fSAndroid Build Coastguard Worker if (block == nullptr) continue;
153*795d594fSAndroid Build Coastguard Worker
154*795d594fSAndroid Build Coastguard Worker // Remove as user.
155*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
156*795d594fSAndroid Build Coastguard Worker RemoveAsUser(it.Current());
157*795d594fSAndroid Build Coastguard Worker }
158*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
159*795d594fSAndroid Build Coastguard Worker RemoveAsUser(it.Current());
160*795d594fSAndroid Build Coastguard Worker }
161*795d594fSAndroid Build Coastguard Worker
162*795d594fSAndroid Build Coastguard Worker // Remove non-catch phi uses, and disconnect the block.
163*795d594fSAndroid Build Coastguard Worker block->DisconnectFromSuccessors(&visited);
164*795d594fSAndroid Build Coastguard Worker }
165*795d594fSAndroid Build Coastguard Worker }
166*795d594fSAndroid Build Coastguard Worker }
167*795d594fSAndroid Build Coastguard Worker
168*795d594fSAndroid Build Coastguard Worker // This method assumes `insn` has been removed from all users with the exception of catch
169*795d594fSAndroid Build Coastguard Worker // phis because of missing exceptional edges in the graph. It removes the
170*795d594fSAndroid Build Coastguard Worker // instruction from catch phi uses, together with inputs of other catch phis in
171*795d594fSAndroid Build Coastguard Worker // the catch block at the same index, as these must be dead too.
RemoveCatchPhiUsesOfDeadInstruction(HInstruction * insn)172*795d594fSAndroid Build Coastguard Worker static void RemoveCatchPhiUsesOfDeadInstruction(HInstruction* insn) {
173*795d594fSAndroid Build Coastguard Worker DCHECK(!insn->HasEnvironmentUses());
174*795d594fSAndroid Build Coastguard Worker while (insn->HasNonEnvironmentUses()) {
175*795d594fSAndroid Build Coastguard Worker const HUseListNode<HInstruction*>& use = insn->GetUses().front();
176*795d594fSAndroid Build Coastguard Worker size_t use_index = use.GetIndex();
177*795d594fSAndroid Build Coastguard Worker HBasicBlock* user_block = use.GetUser()->GetBlock();
178*795d594fSAndroid Build Coastguard Worker DCHECK(use.GetUser()->IsPhi());
179*795d594fSAndroid Build Coastguard Worker DCHECK(user_block->IsCatchBlock());
180*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator phi_it(user_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
181*795d594fSAndroid Build Coastguard Worker phi_it.Current()->AsPhi()->RemoveInputAt(use_index);
182*795d594fSAndroid Build Coastguard Worker }
183*795d594fSAndroid Build Coastguard Worker }
184*795d594fSAndroid Build Coastguard Worker }
185*795d594fSAndroid Build Coastguard Worker
RemoveDeadBlocks(const ArenaBitVector & visited)186*795d594fSAndroid Build Coastguard Worker void HGraph::RemoveDeadBlocks(const ArenaBitVector& visited) {
187*795d594fSAndroid Build Coastguard Worker DCHECK(reverse_post_order_.empty()) << "We shouldn't have dominance information.";
188*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < blocks_.size(); ++i) {
189*795d594fSAndroid Build Coastguard Worker if (!visited.IsBitSet(i)) {
190*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = blocks_[i];
191*795d594fSAndroid Build Coastguard Worker if (block == nullptr) continue;
192*795d594fSAndroid Build Coastguard Worker
193*795d594fSAndroid Build Coastguard Worker // Remove all remaining uses (which should be only catch phi uses), and the instructions.
194*795d594fSAndroid Build Coastguard Worker block->RemoveCatchPhiUsesAndInstruction(/* building_dominator_tree = */ true);
195*795d594fSAndroid Build Coastguard Worker
196*795d594fSAndroid Build Coastguard Worker // Remove the block from the list of blocks, so that further analyses
197*795d594fSAndroid Build Coastguard Worker // never see it.
198*795d594fSAndroid Build Coastguard Worker blocks_[i] = nullptr;
199*795d594fSAndroid Build Coastguard Worker if (block->IsExitBlock()) {
200*795d594fSAndroid Build Coastguard Worker SetExitBlock(nullptr);
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker // Mark the block as removed. This is used by the HGraphBuilder to discard
203*795d594fSAndroid Build Coastguard Worker // the block as a branch target.
204*795d594fSAndroid Build Coastguard Worker block->SetGraph(nullptr);
205*795d594fSAndroid Build Coastguard Worker }
206*795d594fSAndroid Build Coastguard Worker }
207*795d594fSAndroid Build Coastguard Worker }
208*795d594fSAndroid Build Coastguard Worker
BuildDominatorTree()209*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult HGraph::BuildDominatorTree() {
210*795d594fSAndroid Build Coastguard Worker // Allocate memory from local ScopedArenaAllocator.
211*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(GetArenaStack());
212*795d594fSAndroid Build Coastguard Worker
213*795d594fSAndroid Build Coastguard Worker ArenaBitVector visited(&allocator, blocks_.size(), false, kArenaAllocGraphBuilder);
214*795d594fSAndroid Build Coastguard Worker
215*795d594fSAndroid Build Coastguard Worker // (1) Find the back edges in the graph doing a DFS traversal.
216*795d594fSAndroid Build Coastguard Worker FindBackEdges(&visited);
217*795d594fSAndroid Build Coastguard Worker
218*795d594fSAndroid Build Coastguard Worker // (2) Remove instructions and phis from blocks not visited during
219*795d594fSAndroid Build Coastguard Worker // the initial DFS as users from other instructions, so that
220*795d594fSAndroid Build Coastguard Worker // users can be safely removed before uses later.
221*795d594fSAndroid Build Coastguard Worker // Also disconnect the block from its successors, updating the successor's phis if needed.
222*795d594fSAndroid Build Coastguard Worker RemoveDeadBlocksInstructionsAsUsersAndDisconnect(visited);
223*795d594fSAndroid Build Coastguard Worker
224*795d594fSAndroid Build Coastguard Worker // (3) Remove blocks not visited during the initial DFS.
225*795d594fSAndroid Build Coastguard Worker // Step (5) requires dead blocks to be removed from the
226*795d594fSAndroid Build Coastguard Worker // predecessors list of live blocks.
227*795d594fSAndroid Build Coastguard Worker RemoveDeadBlocks(visited);
228*795d594fSAndroid Build Coastguard Worker
229*795d594fSAndroid Build Coastguard Worker // (4) Simplify the CFG now, so that we don't need to recompute
230*795d594fSAndroid Build Coastguard Worker // dominators and the reverse post order.
231*795d594fSAndroid Build Coastguard Worker SimplifyCFG();
232*795d594fSAndroid Build Coastguard Worker
233*795d594fSAndroid Build Coastguard Worker // (5) Compute the dominance information and the reverse post order.
234*795d594fSAndroid Build Coastguard Worker ComputeDominanceInformation();
235*795d594fSAndroid Build Coastguard Worker
236*795d594fSAndroid Build Coastguard Worker // (6) Analyze loops discovered through back edge analysis, and
237*795d594fSAndroid Build Coastguard Worker // set the loop information on each block.
238*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult result = AnalyzeLoops();
239*795d594fSAndroid Build Coastguard Worker if (result != kAnalysisSuccess) {
240*795d594fSAndroid Build Coastguard Worker return result;
241*795d594fSAndroid Build Coastguard Worker }
242*795d594fSAndroid Build Coastguard Worker
243*795d594fSAndroid Build Coastguard Worker // (7) Precompute per-block try membership before entering the SSA builder,
244*795d594fSAndroid Build Coastguard Worker // which needs the information to build catch block phis from values of
245*795d594fSAndroid Build Coastguard Worker // locals at throwing instructions inside try blocks.
246*795d594fSAndroid Build Coastguard Worker ComputeTryBlockInformation();
247*795d594fSAndroid Build Coastguard Worker
248*795d594fSAndroid Build Coastguard Worker return kAnalysisSuccess;
249*795d594fSAndroid Build Coastguard Worker }
250*795d594fSAndroid Build Coastguard Worker
RecomputeDominatorTree()251*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult HGraph::RecomputeDominatorTree() {
252*795d594fSAndroid Build Coastguard Worker DCHECK(!HasIrreducibleLoops()) << "Recomputing loop information in graphs with irreducible loops "
253*795d594fSAndroid Build Coastguard Worker << "is unsupported, as it could lead to loop header changes";
254*795d594fSAndroid Build Coastguard Worker ClearLoopInformation();
255*795d594fSAndroid Build Coastguard Worker ClearDominanceInformation();
256*795d594fSAndroid Build Coastguard Worker return BuildDominatorTree();
257*795d594fSAndroid Build Coastguard Worker }
258*795d594fSAndroid Build Coastguard Worker
ClearDominanceInformation()259*795d594fSAndroid Build Coastguard Worker void HGraph::ClearDominanceInformation() {
260*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetActiveBlocks()) {
261*795d594fSAndroid Build Coastguard Worker block->ClearDominanceInformation();
262*795d594fSAndroid Build Coastguard Worker }
263*795d594fSAndroid Build Coastguard Worker reverse_post_order_.clear();
264*795d594fSAndroid Build Coastguard Worker }
265*795d594fSAndroid Build Coastguard Worker
ClearLoopInformation()266*795d594fSAndroid Build Coastguard Worker void HGraph::ClearLoopInformation() {
267*795d594fSAndroid Build Coastguard Worker SetHasLoops(false);
268*795d594fSAndroid Build Coastguard Worker SetHasIrreducibleLoops(false);
269*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetActiveBlocks()) {
270*795d594fSAndroid Build Coastguard Worker block->SetLoopInformation(nullptr);
271*795d594fSAndroid Build Coastguard Worker }
272*795d594fSAndroid Build Coastguard Worker }
273*795d594fSAndroid Build Coastguard Worker
ClearDominanceInformation()274*795d594fSAndroid Build Coastguard Worker void HBasicBlock::ClearDominanceInformation() {
275*795d594fSAndroid Build Coastguard Worker dominated_blocks_.clear();
276*795d594fSAndroid Build Coastguard Worker dominator_ = nullptr;
277*795d594fSAndroid Build Coastguard Worker }
278*795d594fSAndroid Build Coastguard Worker
GetFirstInstructionDisregardMoves() const279*795d594fSAndroid Build Coastguard Worker HInstruction* HBasicBlock::GetFirstInstructionDisregardMoves() const {
280*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = GetFirstInstruction();
281*795d594fSAndroid Build Coastguard Worker while (instruction->IsParallelMove()) {
282*795d594fSAndroid Build Coastguard Worker instruction = instruction->GetNext();
283*795d594fSAndroid Build Coastguard Worker }
284*795d594fSAndroid Build Coastguard Worker return instruction;
285*795d594fSAndroid Build Coastguard Worker }
286*795d594fSAndroid Build Coastguard Worker
UpdateDominatorOfSuccessor(HBasicBlock * block,HBasicBlock * successor)287*795d594fSAndroid Build Coastguard Worker static bool UpdateDominatorOfSuccessor(HBasicBlock* block, HBasicBlock* successor) {
288*795d594fSAndroid Build Coastguard Worker DCHECK(ContainsElement(block->GetSuccessors(), successor));
289*795d594fSAndroid Build Coastguard Worker
290*795d594fSAndroid Build Coastguard Worker HBasicBlock* old_dominator = successor->GetDominator();
291*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_dominator =
292*795d594fSAndroid Build Coastguard Worker (old_dominator == nullptr) ? block
293*795d594fSAndroid Build Coastguard Worker : CommonDominator::ForPair(old_dominator, block);
294*795d594fSAndroid Build Coastguard Worker
295*795d594fSAndroid Build Coastguard Worker if (old_dominator == new_dominator) {
296*795d594fSAndroid Build Coastguard Worker return false;
297*795d594fSAndroid Build Coastguard Worker } else {
298*795d594fSAndroid Build Coastguard Worker successor->SetDominator(new_dominator);
299*795d594fSAndroid Build Coastguard Worker return true;
300*795d594fSAndroid Build Coastguard Worker }
301*795d594fSAndroid Build Coastguard Worker }
302*795d594fSAndroid Build Coastguard Worker
ComputeDominanceInformation()303*795d594fSAndroid Build Coastguard Worker void HGraph::ComputeDominanceInformation() {
304*795d594fSAndroid Build Coastguard Worker DCHECK(reverse_post_order_.empty());
305*795d594fSAndroid Build Coastguard Worker reverse_post_order_.reserve(blocks_.size());
306*795d594fSAndroid Build Coastguard Worker reverse_post_order_.push_back(entry_block_);
307*795d594fSAndroid Build Coastguard Worker
308*795d594fSAndroid Build Coastguard Worker // Allocate memory from local ScopedArenaAllocator.
309*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(GetArenaStack());
310*795d594fSAndroid Build Coastguard Worker // Number of visits of a given node, indexed by block id.
311*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<size_t> visits(blocks_.size(), 0u, allocator.Adapter(kArenaAllocGraphBuilder));
312*795d594fSAndroid Build Coastguard Worker // Number of successors visited from a given node, indexed by block id.
313*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<size_t> successors_visited(blocks_.size(),
314*795d594fSAndroid Build Coastguard Worker 0u,
315*795d594fSAndroid Build Coastguard Worker allocator.Adapter(kArenaAllocGraphBuilder));
316*795d594fSAndroid Build Coastguard Worker // Nodes for which we need to visit successors.
317*795d594fSAndroid Build Coastguard Worker ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocGraphBuilder));
318*795d594fSAndroid Build Coastguard Worker constexpr size_t kDefaultWorklistSize = 8;
319*795d594fSAndroid Build Coastguard Worker worklist.reserve(kDefaultWorklistSize);
320*795d594fSAndroid Build Coastguard Worker worklist.push_back(entry_block_);
321*795d594fSAndroid Build Coastguard Worker
322*795d594fSAndroid Build Coastguard Worker while (!worklist.empty()) {
323*795d594fSAndroid Build Coastguard Worker HBasicBlock* current = worklist.back();
324*795d594fSAndroid Build Coastguard Worker uint32_t current_id = current->GetBlockId();
325*795d594fSAndroid Build Coastguard Worker if (successors_visited[current_id] == current->GetSuccessors().size()) {
326*795d594fSAndroid Build Coastguard Worker worklist.pop_back();
327*795d594fSAndroid Build Coastguard Worker } else {
328*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
329*795d594fSAndroid Build Coastguard Worker UpdateDominatorOfSuccessor(current, successor);
330*795d594fSAndroid Build Coastguard Worker
331*795d594fSAndroid Build Coastguard Worker // Once all the forward edges have been visited, we know the immediate
332*795d594fSAndroid Build Coastguard Worker // dominator of the block. We can then start visiting its successors.
333*795d594fSAndroid Build Coastguard Worker if (++visits[successor->GetBlockId()] ==
334*795d594fSAndroid Build Coastguard Worker successor->GetPredecessors().size() - successor->NumberOfBackEdges()) {
335*795d594fSAndroid Build Coastguard Worker reverse_post_order_.push_back(successor);
336*795d594fSAndroid Build Coastguard Worker worklist.push_back(successor);
337*795d594fSAndroid Build Coastguard Worker }
338*795d594fSAndroid Build Coastguard Worker }
339*795d594fSAndroid Build Coastguard Worker }
340*795d594fSAndroid Build Coastguard Worker
341*795d594fSAndroid Build Coastguard Worker // Check if the graph has back edges not dominated by their respective headers.
342*795d594fSAndroid Build Coastguard Worker // If so, we need to update the dominators of those headers and recursively of
343*795d594fSAndroid Build Coastguard Worker // their successors. We do that with a fix-point iteration over all blocks.
344*795d594fSAndroid Build Coastguard Worker // The algorithm is guaranteed to terminate because it loops only if the sum
345*795d594fSAndroid Build Coastguard Worker // of all dominator chains has decreased in the current iteration.
346*795d594fSAndroid Build Coastguard Worker bool must_run_fix_point = false;
347*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : blocks_) {
348*795d594fSAndroid Build Coastguard Worker if (block != nullptr &&
349*795d594fSAndroid Build Coastguard Worker block->IsLoopHeader() &&
350*795d594fSAndroid Build Coastguard Worker block->GetLoopInformation()->HasBackEdgeNotDominatedByHeader()) {
351*795d594fSAndroid Build Coastguard Worker must_run_fix_point = true;
352*795d594fSAndroid Build Coastguard Worker break;
353*795d594fSAndroid Build Coastguard Worker }
354*795d594fSAndroid Build Coastguard Worker }
355*795d594fSAndroid Build Coastguard Worker if (must_run_fix_point) {
356*795d594fSAndroid Build Coastguard Worker bool update_occurred = true;
357*795d594fSAndroid Build Coastguard Worker while (update_occurred) {
358*795d594fSAndroid Build Coastguard Worker update_occurred = false;
359*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetReversePostOrder()) {
360*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : block->GetSuccessors()) {
361*795d594fSAndroid Build Coastguard Worker update_occurred |= UpdateDominatorOfSuccessor(block, successor);
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
367*795d594fSAndroid Build Coastguard Worker // Make sure that there are no remaining blocks whose dominator information
368*795d594fSAndroid Build Coastguard Worker // needs to be updated.
369*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
370*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetReversePostOrder()) {
371*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : block->GetSuccessors()) {
372*795d594fSAndroid Build Coastguard Worker DCHECK(!UpdateDominatorOfSuccessor(block, successor));
373*795d594fSAndroid Build Coastguard Worker }
374*795d594fSAndroid Build Coastguard Worker }
375*795d594fSAndroid Build Coastguard Worker }
376*795d594fSAndroid Build Coastguard Worker
377*795d594fSAndroid Build Coastguard Worker // Populate `dominated_blocks_` information after computing all dominators.
378*795d594fSAndroid Build Coastguard Worker // The potential presence of irreducible loops requires to do it after.
379*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetReversePostOrder()) {
380*795d594fSAndroid Build Coastguard Worker if (!block->IsEntryBlock()) {
381*795d594fSAndroid Build Coastguard Worker block->GetDominator()->AddDominatedBlock(block);
382*795d594fSAndroid Build Coastguard Worker }
383*795d594fSAndroid Build Coastguard Worker }
384*795d594fSAndroid Build Coastguard Worker }
385*795d594fSAndroid Build Coastguard Worker
SplitEdge(HBasicBlock * block,HBasicBlock * successor)386*795d594fSAndroid Build Coastguard Worker HBasicBlock* HGraph::SplitEdge(HBasicBlock* block, HBasicBlock* successor) {
387*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block = new (allocator_) HBasicBlock(this, successor->GetDexPc());
388*795d594fSAndroid Build Coastguard Worker AddBlock(new_block);
389*795d594fSAndroid Build Coastguard Worker // Use `InsertBetween` to ensure the predecessor index and successor index of
390*795d594fSAndroid Build Coastguard Worker // `block` and `successor` are preserved.
391*795d594fSAndroid Build Coastguard Worker new_block->InsertBetween(block, successor);
392*795d594fSAndroid Build Coastguard Worker return new_block;
393*795d594fSAndroid Build Coastguard Worker }
394*795d594fSAndroid Build Coastguard Worker
SplitCriticalEdge(HBasicBlock * block,HBasicBlock * successor)395*795d594fSAndroid Build Coastguard Worker void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
396*795d594fSAndroid Build Coastguard Worker // Insert a new node between `block` and `successor` to split the
397*795d594fSAndroid Build Coastguard Worker // critical edge.
398*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block = SplitEdge(block, successor);
399*795d594fSAndroid Build Coastguard Worker new_block->AddInstruction(new (allocator_) HGoto(successor->GetDexPc()));
400*795d594fSAndroid Build Coastguard Worker if (successor->IsLoopHeader()) {
401*795d594fSAndroid Build Coastguard Worker // If we split at a back edge boundary, make the new block the back edge.
402*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = successor->GetLoopInformation();
403*795d594fSAndroid Build Coastguard Worker if (info->IsBackEdge(*block)) {
404*795d594fSAndroid Build Coastguard Worker info->RemoveBackEdge(block);
405*795d594fSAndroid Build Coastguard Worker info->AddBackEdge(new_block);
406*795d594fSAndroid Build Coastguard Worker }
407*795d594fSAndroid Build Coastguard Worker }
408*795d594fSAndroid Build Coastguard Worker }
409*795d594fSAndroid Build Coastguard Worker
SplitEdgeAndUpdateRPO(HBasicBlock * block,HBasicBlock * successor)410*795d594fSAndroid Build Coastguard Worker HBasicBlock* HGraph::SplitEdgeAndUpdateRPO(HBasicBlock* block, HBasicBlock* successor) {
411*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block = SplitEdge(block, successor);
412*795d594fSAndroid Build Coastguard Worker // In the RPO we have {... , block, ... , successor}. We want to insert `new_block` right after
413*795d594fSAndroid Build Coastguard Worker // `block` to have a consistent RPO without recomputing the whole graph's RPO.
414*795d594fSAndroid Build Coastguard Worker reverse_post_order_.insert(
415*795d594fSAndroid Build Coastguard Worker reverse_post_order_.begin() + IndexOfElement(reverse_post_order_, block) + 1, new_block);
416*795d594fSAndroid Build Coastguard Worker return new_block;
417*795d594fSAndroid Build Coastguard Worker }
418*795d594fSAndroid Build Coastguard Worker
419*795d594fSAndroid Build Coastguard Worker // Reorder phi inputs to match reordering of the block's predecessors.
FixPhisAfterPredecessorsReodering(HBasicBlock * block,size_t first,size_t second)420*795d594fSAndroid Build Coastguard Worker static void FixPhisAfterPredecessorsReodering(HBasicBlock* block, size_t first, size_t second) {
421*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
422*795d594fSAndroid Build Coastguard Worker HPhi* phi = it.Current()->AsPhi();
423*795d594fSAndroid Build Coastguard Worker HInstruction* first_instr = phi->InputAt(first);
424*795d594fSAndroid Build Coastguard Worker HInstruction* second_instr = phi->InputAt(second);
425*795d594fSAndroid Build Coastguard Worker phi->ReplaceInput(first_instr, second);
426*795d594fSAndroid Build Coastguard Worker phi->ReplaceInput(second_instr, first);
427*795d594fSAndroid Build Coastguard Worker }
428*795d594fSAndroid Build Coastguard Worker }
429*795d594fSAndroid Build Coastguard Worker
430*795d594fSAndroid Build Coastguard Worker // Make sure that the first predecessor of a loop header is the incoming block.
OrderLoopHeaderPredecessors(HBasicBlock * header)431*795d594fSAndroid Build Coastguard Worker void HGraph::OrderLoopHeaderPredecessors(HBasicBlock* header) {
432*795d594fSAndroid Build Coastguard Worker DCHECK(header->IsLoopHeader());
433*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = header->GetLoopInformation();
434*795d594fSAndroid Build Coastguard Worker if (info->IsBackEdge(*header->GetPredecessors()[0])) {
435*795d594fSAndroid Build Coastguard Worker HBasicBlock* to_swap = header->GetPredecessors()[0];
436*795d594fSAndroid Build Coastguard Worker for (size_t pred = 1, e = header->GetPredecessors().size(); pred < e; ++pred) {
437*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = header->GetPredecessors()[pred];
438*795d594fSAndroid Build Coastguard Worker if (!info->IsBackEdge(*predecessor)) {
439*795d594fSAndroid Build Coastguard Worker header->predecessors_[pred] = to_swap;
440*795d594fSAndroid Build Coastguard Worker header->predecessors_[0] = predecessor;
441*795d594fSAndroid Build Coastguard Worker FixPhisAfterPredecessorsReodering(header, 0, pred);
442*795d594fSAndroid Build Coastguard Worker break;
443*795d594fSAndroid Build Coastguard Worker }
444*795d594fSAndroid Build Coastguard Worker }
445*795d594fSAndroid Build Coastguard Worker }
446*795d594fSAndroid Build Coastguard Worker }
447*795d594fSAndroid Build Coastguard Worker
448*795d594fSAndroid Build Coastguard Worker // Transform control flow of the loop to a single preheader format (don't touch the data flow).
449*795d594fSAndroid Build Coastguard Worker // New_preheader can be already among the header predecessors - this situation will be correctly
450*795d594fSAndroid Build Coastguard Worker // processed.
FixControlForNewSinglePreheader(HBasicBlock * header,HBasicBlock * new_preheader)451*795d594fSAndroid Build Coastguard Worker static void FixControlForNewSinglePreheader(HBasicBlock* header, HBasicBlock* new_preheader) {
452*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info = header->GetLoopInformation();
453*795d594fSAndroid Build Coastguard Worker for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
454*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = header->GetPredecessors()[pred];
455*795d594fSAndroid Build Coastguard Worker if (!loop_info->IsBackEdge(*predecessor) && predecessor != new_preheader) {
456*795d594fSAndroid Build Coastguard Worker predecessor->ReplaceSuccessor(header, new_preheader);
457*795d594fSAndroid Build Coastguard Worker pred--;
458*795d594fSAndroid Build Coastguard Worker }
459*795d594fSAndroid Build Coastguard Worker }
460*795d594fSAndroid Build Coastguard Worker }
461*795d594fSAndroid Build Coastguard Worker
462*795d594fSAndroid Build Coastguard Worker // == Before == == After ==
463*795d594fSAndroid Build Coastguard Worker // _________ _________ _________ _________
464*795d594fSAndroid Build Coastguard Worker // | B0 | | B1 | (old preheaders) | B0 | | B1 |
465*795d594fSAndroid Build Coastguard Worker // |=========| |=========| |=========| |=========|
466*795d594fSAndroid Build Coastguard Worker // | i0 = .. | | i1 = .. | | i0 = .. | | i1 = .. |
467*795d594fSAndroid Build Coastguard Worker // |_________| |_________| |_________| |_________|
468*795d594fSAndroid Build Coastguard Worker // \ / \ /
469*795d594fSAndroid Build Coastguard Worker // \ / ___v____________v___
470*795d594fSAndroid Build Coastguard Worker // \ / (new preheader) | B20 <- B0, B1 |
471*795d594fSAndroid Build Coastguard Worker // | | |====================|
472*795d594fSAndroid Build Coastguard Worker // | | | i20 = phi(i0, i1) |
473*795d594fSAndroid Build Coastguard Worker // | | |____________________|
474*795d594fSAndroid Build Coastguard Worker // | | |
475*795d594fSAndroid Build Coastguard Worker // /\ | | /\ /\ | /\
476*795d594fSAndroid Build Coastguard Worker // / v_______v_________v_______v \ / v___________v_____________v \
477*795d594fSAndroid Build Coastguard Worker // | | B10 <- B0, B1, B2, B3 | | | | B10 <- B20, B2, B3 | |
478*795d594fSAndroid Build Coastguard Worker // | |===========================| | (header) | |===========================| |
479*795d594fSAndroid Build Coastguard Worker // | | i10 = phi(i0, i1, i2, i3) | | | | i10 = phi(i20, i2, i3) | |
480*795d594fSAndroid Build Coastguard Worker // | |___________________________| | | |___________________________| |
481*795d594fSAndroid Build Coastguard Worker // | / \ | | / \ |
482*795d594fSAndroid Build Coastguard Worker // | ... ... | | ... ... |
483*795d594fSAndroid Build Coastguard Worker // | _________ _________ | | _________ _________ |
484*795d594fSAndroid Build Coastguard Worker // | | B2 | | B3 | | | | B2 | | B3 | |
485*795d594fSAndroid Build Coastguard Worker // | |=========| |=========| | (back edges) | |=========| |=========| |
486*795d594fSAndroid Build Coastguard Worker // | | i2 = .. | | i3 = .. | | | | i2 = .. | | i3 = .. | |
487*795d594fSAndroid Build Coastguard Worker // | |_________| |_________| | | |_________| |_________| |
488*795d594fSAndroid Build Coastguard Worker // \ / \ / \ / \ /
489*795d594fSAndroid Build Coastguard Worker // \___/ \___/ \___/ \___/
490*795d594fSAndroid Build Coastguard Worker //
TransformLoopToSinglePreheaderFormat(HBasicBlock * header)491*795d594fSAndroid Build Coastguard Worker void HGraph::TransformLoopToSinglePreheaderFormat(HBasicBlock* header) {
492*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info = header->GetLoopInformation();
493*795d594fSAndroid Build Coastguard Worker
494*795d594fSAndroid Build Coastguard Worker HBasicBlock* preheader = new (allocator_) HBasicBlock(this, header->GetDexPc());
495*795d594fSAndroid Build Coastguard Worker AddBlock(preheader);
496*795d594fSAndroid Build Coastguard Worker preheader->AddInstruction(new (allocator_) HGoto(header->GetDexPc()));
497*795d594fSAndroid Build Coastguard Worker
498*795d594fSAndroid Build Coastguard Worker // If the old header has no Phis then we only need to fix the control flow.
499*795d594fSAndroid Build Coastguard Worker if (header->GetPhis().IsEmpty()) {
500*795d594fSAndroid Build Coastguard Worker FixControlForNewSinglePreheader(header, preheader);
501*795d594fSAndroid Build Coastguard Worker preheader->AddSuccessor(header);
502*795d594fSAndroid Build Coastguard Worker return;
503*795d594fSAndroid Build Coastguard Worker }
504*795d594fSAndroid Build Coastguard Worker
505*795d594fSAndroid Build Coastguard Worker // Find the first non-back edge block in the header's predecessors list.
506*795d594fSAndroid Build Coastguard Worker size_t first_nonbackedge_pred_pos = 0;
507*795d594fSAndroid Build Coastguard Worker bool found = false;
508*795d594fSAndroid Build Coastguard Worker for (size_t pred = 0; pred < header->GetPredecessors().size(); ++pred) {
509*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = header->GetPredecessors()[pred];
510*795d594fSAndroid Build Coastguard Worker if (!loop_info->IsBackEdge(*predecessor)) {
511*795d594fSAndroid Build Coastguard Worker first_nonbackedge_pred_pos = pred;
512*795d594fSAndroid Build Coastguard Worker found = true;
513*795d594fSAndroid Build Coastguard Worker break;
514*795d594fSAndroid Build Coastguard Worker }
515*795d594fSAndroid Build Coastguard Worker }
516*795d594fSAndroid Build Coastguard Worker
517*795d594fSAndroid Build Coastguard Worker DCHECK(found);
518*795d594fSAndroid Build Coastguard Worker
519*795d594fSAndroid Build Coastguard Worker // Fix the data-flow.
520*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(header->GetPhis()); !it.Done(); it.Advance()) {
521*795d594fSAndroid Build Coastguard Worker HPhi* header_phi = it.Current()->AsPhi();
522*795d594fSAndroid Build Coastguard Worker
523*795d594fSAndroid Build Coastguard Worker HPhi* preheader_phi = new (GetAllocator()) HPhi(GetAllocator(),
524*795d594fSAndroid Build Coastguard Worker header_phi->GetRegNumber(),
525*795d594fSAndroid Build Coastguard Worker 0,
526*795d594fSAndroid Build Coastguard Worker header_phi->GetType());
527*795d594fSAndroid Build Coastguard Worker if (header_phi->GetType() == DataType::Type::kReference) {
528*795d594fSAndroid Build Coastguard Worker preheader_phi->SetReferenceTypeInfoIfValid(header_phi->GetReferenceTypeInfo());
529*795d594fSAndroid Build Coastguard Worker }
530*795d594fSAndroid Build Coastguard Worker preheader->AddPhi(preheader_phi);
531*795d594fSAndroid Build Coastguard Worker
532*795d594fSAndroid Build Coastguard Worker HInstruction* orig_input = header_phi->InputAt(first_nonbackedge_pred_pos);
533*795d594fSAndroid Build Coastguard Worker header_phi->ReplaceInput(preheader_phi, first_nonbackedge_pred_pos);
534*795d594fSAndroid Build Coastguard Worker preheader_phi->AddInput(orig_input);
535*795d594fSAndroid Build Coastguard Worker
536*795d594fSAndroid Build Coastguard Worker for (size_t input_pos = first_nonbackedge_pred_pos + 1;
537*795d594fSAndroid Build Coastguard Worker input_pos < header_phi->InputCount();
538*795d594fSAndroid Build Coastguard Worker input_pos++) {
539*795d594fSAndroid Build Coastguard Worker HInstruction* input = header_phi->InputAt(input_pos);
540*795d594fSAndroid Build Coastguard Worker HBasicBlock* pred_block = header->GetPredecessors()[input_pos];
541*795d594fSAndroid Build Coastguard Worker
542*795d594fSAndroid Build Coastguard Worker if (loop_info->Contains(*pred_block)) {
543*795d594fSAndroid Build Coastguard Worker DCHECK(loop_info->IsBackEdge(*pred_block));
544*795d594fSAndroid Build Coastguard Worker } else {
545*795d594fSAndroid Build Coastguard Worker preheader_phi->AddInput(input);
546*795d594fSAndroid Build Coastguard Worker header_phi->RemoveInputAt(input_pos);
547*795d594fSAndroid Build Coastguard Worker input_pos--;
548*795d594fSAndroid Build Coastguard Worker }
549*795d594fSAndroid Build Coastguard Worker }
550*795d594fSAndroid Build Coastguard Worker }
551*795d594fSAndroid Build Coastguard Worker
552*795d594fSAndroid Build Coastguard Worker // Fix the control-flow.
553*795d594fSAndroid Build Coastguard Worker HBasicBlock* first_pred = header->GetPredecessors()[first_nonbackedge_pred_pos];
554*795d594fSAndroid Build Coastguard Worker preheader->InsertBetween(first_pred, header);
555*795d594fSAndroid Build Coastguard Worker
556*795d594fSAndroid Build Coastguard Worker FixControlForNewSinglePreheader(header, preheader);
557*795d594fSAndroid Build Coastguard Worker }
558*795d594fSAndroid Build Coastguard Worker
SimplifyLoop(HBasicBlock * header)559*795d594fSAndroid Build Coastguard Worker void HGraph::SimplifyLoop(HBasicBlock* header) {
560*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = header->GetLoopInformation();
561*795d594fSAndroid Build Coastguard Worker
562*795d594fSAndroid Build Coastguard Worker // Make sure the loop has only one pre header. This simplifies SSA building by having
563*795d594fSAndroid Build Coastguard Worker // to just look at the pre header to know which locals are initialized at entry of the
564*795d594fSAndroid Build Coastguard Worker // loop. Also, don't allow the entry block to be a pre header: this simplifies inlining
565*795d594fSAndroid Build Coastguard Worker // this graph.
566*795d594fSAndroid Build Coastguard Worker size_t number_of_incomings = header->GetPredecessors().size() - info->NumberOfBackEdges();
567*795d594fSAndroid Build Coastguard Worker if (number_of_incomings != 1 || (GetEntryBlock()->GetSingleSuccessor() == header)) {
568*795d594fSAndroid Build Coastguard Worker TransformLoopToSinglePreheaderFormat(header);
569*795d594fSAndroid Build Coastguard Worker }
570*795d594fSAndroid Build Coastguard Worker
571*795d594fSAndroid Build Coastguard Worker OrderLoopHeaderPredecessors(header);
572*795d594fSAndroid Build Coastguard Worker
573*795d594fSAndroid Build Coastguard Worker HInstruction* first_instruction = header->GetFirstInstruction();
574*795d594fSAndroid Build Coastguard Worker if (first_instruction != nullptr && first_instruction->IsSuspendCheck()) {
575*795d594fSAndroid Build Coastguard Worker // Called from DeadBlockElimination. Update SuspendCheck pointer.
576*795d594fSAndroid Build Coastguard Worker info->SetSuspendCheck(first_instruction->AsSuspendCheck());
577*795d594fSAndroid Build Coastguard Worker }
578*795d594fSAndroid Build Coastguard Worker }
579*795d594fSAndroid Build Coastguard Worker
ComputeTryBlockInformation()580*795d594fSAndroid Build Coastguard Worker void HGraph::ComputeTryBlockInformation() {
581*795d594fSAndroid Build Coastguard Worker // Iterate in reverse post order to propagate try membership information from
582*795d594fSAndroid Build Coastguard Worker // predecessors to their successors.
583*795d594fSAndroid Build Coastguard Worker bool graph_has_try_catch = false;
584*795d594fSAndroid Build Coastguard Worker
585*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetReversePostOrder()) {
586*795d594fSAndroid Build Coastguard Worker if (block->IsEntryBlock() || block->IsCatchBlock()) {
587*795d594fSAndroid Build Coastguard Worker // Catch blocks after simplification have only exceptional predecessors
588*795d594fSAndroid Build Coastguard Worker // and hence are never in tries.
589*795d594fSAndroid Build Coastguard Worker continue;
590*795d594fSAndroid Build Coastguard Worker }
591*795d594fSAndroid Build Coastguard Worker
592*795d594fSAndroid Build Coastguard Worker // Infer try membership from the first predecessor. Having simplified loops,
593*795d594fSAndroid Build Coastguard Worker // the first predecessor can never be a back edge and therefore it must have
594*795d594fSAndroid Build Coastguard Worker // been visited already and had its try membership set.
595*795d594fSAndroid Build Coastguard Worker HBasicBlock* first_predecessor = block->GetPredecessors()[0];
596*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(block->IsLoopHeader(),
597*795d594fSAndroid Build Coastguard Worker !block->GetLoopInformation()->IsBackEdge(*first_predecessor));
598*795d594fSAndroid Build Coastguard Worker const HTryBoundary* try_entry = first_predecessor->ComputeTryEntryOfSuccessors();
599*795d594fSAndroid Build Coastguard Worker graph_has_try_catch |= try_entry != nullptr;
600*795d594fSAndroid Build Coastguard Worker if (try_entry != nullptr &&
601*795d594fSAndroid Build Coastguard Worker (block->GetTryCatchInformation() == nullptr ||
602*795d594fSAndroid Build Coastguard Worker try_entry != &block->GetTryCatchInformation()->GetTryEntry())) {
603*795d594fSAndroid Build Coastguard Worker // We are either setting try block membership for the first time or it
604*795d594fSAndroid Build Coastguard Worker // has changed.
605*795d594fSAndroid Build Coastguard Worker block->SetTryCatchInformation(new (allocator_) TryCatchInformation(*try_entry));
606*795d594fSAndroid Build Coastguard Worker }
607*795d594fSAndroid Build Coastguard Worker }
608*795d594fSAndroid Build Coastguard Worker
609*795d594fSAndroid Build Coastguard Worker SetHasTryCatch(graph_has_try_catch);
610*795d594fSAndroid Build Coastguard Worker }
611*795d594fSAndroid Build Coastguard Worker
SimplifyCFG()612*795d594fSAndroid Build Coastguard Worker void HGraph::SimplifyCFG() {
613*795d594fSAndroid Build Coastguard Worker // Simplify the CFG for future analysis, and code generation:
614*795d594fSAndroid Build Coastguard Worker // (1): Split critical edges.
615*795d594fSAndroid Build Coastguard Worker // (2): Simplify loops by having only one preheader.
616*795d594fSAndroid Build Coastguard Worker // NOTE: We're appending new blocks inside the loop, so we need to use index because iterators
617*795d594fSAndroid Build Coastguard Worker // can be invalidated. We remember the initial size to avoid iterating over the new blocks.
618*795d594fSAndroid Build Coastguard Worker for (size_t block_id = 0u, end = blocks_.size(); block_id != end; ++block_id) {
619*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = blocks_[block_id];
620*795d594fSAndroid Build Coastguard Worker if (block == nullptr) continue;
621*795d594fSAndroid Build Coastguard Worker if (block->GetSuccessors().size() > 1) {
622*795d594fSAndroid Build Coastguard Worker // Only split normal-flow edges. We cannot split exceptional edges as they
623*795d594fSAndroid Build Coastguard Worker // are synthesized (approximate real control flow), and we do not need to
624*795d594fSAndroid Build Coastguard Worker // anyway. Moves that would be inserted there are performed by the runtime.
625*795d594fSAndroid Build Coastguard Worker ArrayRef<HBasicBlock* const> normal_successors = block->GetNormalSuccessors();
626*795d594fSAndroid Build Coastguard Worker for (size_t j = 0, e = normal_successors.size(); j < e; ++j) {
627*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = normal_successors[j];
628*795d594fSAndroid Build Coastguard Worker DCHECK(!successor->IsCatchBlock());
629*795d594fSAndroid Build Coastguard Worker if (successor == exit_block_) {
630*795d594fSAndroid Build Coastguard Worker // (Throw/Return/ReturnVoid)->TryBoundary->Exit. Special case which we
631*795d594fSAndroid Build Coastguard Worker // do not want to split because Goto->Exit is not allowed.
632*795d594fSAndroid Build Coastguard Worker DCHECK(block->IsSingleTryBoundary());
633*795d594fSAndroid Build Coastguard Worker } else if (successor->GetPredecessors().size() > 1) {
634*795d594fSAndroid Build Coastguard Worker SplitCriticalEdge(block, successor);
635*795d594fSAndroid Build Coastguard Worker // SplitCriticalEdge could have invalidated the `normal_successors`
636*795d594fSAndroid Build Coastguard Worker // ArrayRef. We must re-acquire it.
637*795d594fSAndroid Build Coastguard Worker normal_successors = block->GetNormalSuccessors();
638*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(normal_successors[j]->GetSingleSuccessor(), successor);
639*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(e, normal_successors.size());
640*795d594fSAndroid Build Coastguard Worker }
641*795d594fSAndroid Build Coastguard Worker }
642*795d594fSAndroid Build Coastguard Worker }
643*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
644*795d594fSAndroid Build Coastguard Worker SimplifyLoop(block);
645*795d594fSAndroid Build Coastguard Worker } else if (!block->IsEntryBlock() &&
646*795d594fSAndroid Build Coastguard Worker block->GetFirstInstruction() != nullptr &&
647*795d594fSAndroid Build Coastguard Worker block->GetFirstInstruction()->IsSuspendCheck()) {
648*795d594fSAndroid Build Coastguard Worker // We are being called by the dead code elimiation pass, and what used to be
649*795d594fSAndroid Build Coastguard Worker // a loop got dismantled. Just remove the suspend check.
650*795d594fSAndroid Build Coastguard Worker block->RemoveInstruction(block->GetFirstInstruction());
651*795d594fSAndroid Build Coastguard Worker }
652*795d594fSAndroid Build Coastguard Worker }
653*795d594fSAndroid Build Coastguard Worker }
654*795d594fSAndroid Build Coastguard Worker
AnalyzeLoops() const655*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult HGraph::AnalyzeLoops() const {
656*795d594fSAndroid Build Coastguard Worker // We iterate post order to ensure we visit inner loops before outer loops.
657*795d594fSAndroid Build Coastguard Worker // `PopulateRecursive` needs this guarantee to know whether a natural loop
658*795d594fSAndroid Build Coastguard Worker // contains an irreducible loop.
659*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetPostOrder()) {
660*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
661*795d594fSAndroid Build Coastguard Worker if (block->IsCatchBlock()) {
662*795d594fSAndroid Build Coastguard Worker // TODO: Dealing with exceptional back edges could be tricky because
663*795d594fSAndroid Build Coastguard Worker // they only approximate the real control flow. Bail out for now.
664*795d594fSAndroid Build Coastguard Worker VLOG(compiler) << "Not compiled: Exceptional back edges";
665*795d594fSAndroid Build Coastguard Worker return kAnalysisFailThrowCatchLoop;
666*795d594fSAndroid Build Coastguard Worker }
667*795d594fSAndroid Build Coastguard Worker block->GetLoopInformation()->Populate();
668*795d594fSAndroid Build Coastguard Worker }
669*795d594fSAndroid Build Coastguard Worker }
670*795d594fSAndroid Build Coastguard Worker return kAnalysisSuccess;
671*795d594fSAndroid Build Coastguard Worker }
672*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os)673*795d594fSAndroid Build Coastguard Worker void HLoopInformation::Dump(std::ostream& os) {
674*795d594fSAndroid Build Coastguard Worker os << "header: " << header_->GetBlockId() << std::endl;
675*795d594fSAndroid Build Coastguard Worker os << "pre header: " << GetPreHeader()->GetBlockId() << std::endl;
676*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : back_edges_) {
677*795d594fSAndroid Build Coastguard Worker os << "back edge: " << block->GetBlockId() << std::endl;
678*795d594fSAndroid Build Coastguard Worker }
679*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : header_->GetPredecessors()) {
680*795d594fSAndroid Build Coastguard Worker os << "predecessor: " << block->GetBlockId() << std::endl;
681*795d594fSAndroid Build Coastguard Worker }
682*795d594fSAndroid Build Coastguard Worker for (uint32_t idx : blocks_.Indexes()) {
683*795d594fSAndroid Build Coastguard Worker os << " in loop: " << idx << std::endl;
684*795d594fSAndroid Build Coastguard Worker }
685*795d594fSAndroid Build Coastguard Worker }
686*795d594fSAndroid Build Coastguard Worker
687*795d594fSAndroid Build Coastguard Worker template <class InstructionType, typename ValueType>
CreateConstant(ValueType value,ArenaSafeMap<ValueType,InstructionType * > * cache)688*795d594fSAndroid Build Coastguard Worker InstructionType* HGraph::CreateConstant(ValueType value,
689*795d594fSAndroid Build Coastguard Worker ArenaSafeMap<ValueType, InstructionType*>* cache) {
690*795d594fSAndroid Build Coastguard Worker // Try to find an existing constant of the given value.
691*795d594fSAndroid Build Coastguard Worker InstructionType* constant = nullptr;
692*795d594fSAndroid Build Coastguard Worker auto cached_constant = cache->find(value);
693*795d594fSAndroid Build Coastguard Worker if (cached_constant != cache->end()) {
694*795d594fSAndroid Build Coastguard Worker constant = cached_constant->second;
695*795d594fSAndroid Build Coastguard Worker }
696*795d594fSAndroid Build Coastguard Worker
697*795d594fSAndroid Build Coastguard Worker // If not found or previously deleted, create and cache a new instruction.
698*795d594fSAndroid Build Coastguard Worker // Don't bother reviving a previously deleted instruction, for simplicity.
699*795d594fSAndroid Build Coastguard Worker if (constant == nullptr || constant->GetBlock() == nullptr) {
700*795d594fSAndroid Build Coastguard Worker constant = new (allocator_) InstructionType(value);
701*795d594fSAndroid Build Coastguard Worker cache->Overwrite(value, constant);
702*795d594fSAndroid Build Coastguard Worker InsertConstant(constant);
703*795d594fSAndroid Build Coastguard Worker }
704*795d594fSAndroid Build Coastguard Worker return constant;
705*795d594fSAndroid Build Coastguard Worker }
706*795d594fSAndroid Build Coastguard Worker
InsertConstant(HConstant * constant)707*795d594fSAndroid Build Coastguard Worker void HGraph::InsertConstant(HConstant* constant) {
708*795d594fSAndroid Build Coastguard Worker // New constants are inserted before the SuspendCheck at the bottom of the
709*795d594fSAndroid Build Coastguard Worker // entry block. Note that this method can be called from the graph builder and
710*795d594fSAndroid Build Coastguard Worker // the entry block therefore may not end with SuspendCheck->Goto yet.
711*795d594fSAndroid Build Coastguard Worker HInstruction* insert_before = nullptr;
712*795d594fSAndroid Build Coastguard Worker
713*795d594fSAndroid Build Coastguard Worker HInstruction* gota = entry_block_->GetLastInstruction();
714*795d594fSAndroid Build Coastguard Worker if (gota != nullptr && gota->IsGoto()) {
715*795d594fSAndroid Build Coastguard Worker HInstruction* suspend_check = gota->GetPrevious();
716*795d594fSAndroid Build Coastguard Worker if (suspend_check != nullptr && suspend_check->IsSuspendCheck()) {
717*795d594fSAndroid Build Coastguard Worker insert_before = suspend_check;
718*795d594fSAndroid Build Coastguard Worker } else {
719*795d594fSAndroid Build Coastguard Worker insert_before = gota;
720*795d594fSAndroid Build Coastguard Worker }
721*795d594fSAndroid Build Coastguard Worker }
722*795d594fSAndroid Build Coastguard Worker
723*795d594fSAndroid Build Coastguard Worker if (insert_before == nullptr) {
724*795d594fSAndroid Build Coastguard Worker entry_block_->AddInstruction(constant);
725*795d594fSAndroid Build Coastguard Worker } else {
726*795d594fSAndroid Build Coastguard Worker entry_block_->InsertInstructionBefore(constant, insert_before);
727*795d594fSAndroid Build Coastguard Worker }
728*795d594fSAndroid Build Coastguard Worker }
729*795d594fSAndroid Build Coastguard Worker
GetNullConstant()730*795d594fSAndroid Build Coastguard Worker HNullConstant* HGraph::GetNullConstant() {
731*795d594fSAndroid Build Coastguard Worker // For simplicity, don't bother reviving the cached null constant if it is
732*795d594fSAndroid Build Coastguard Worker // not null and not in a block. Otherwise, we need to clear the instruction
733*795d594fSAndroid Build Coastguard Worker // id and/or any invariants the graph is assuming when adding new instructions.
734*795d594fSAndroid Build Coastguard Worker if ((cached_null_constant_ == nullptr) || (cached_null_constant_->GetBlock() == nullptr)) {
735*795d594fSAndroid Build Coastguard Worker cached_null_constant_ = new (allocator_) HNullConstant();
736*795d594fSAndroid Build Coastguard Worker cached_null_constant_->SetReferenceTypeInfo(GetInexactObjectRti());
737*795d594fSAndroid Build Coastguard Worker InsertConstant(cached_null_constant_);
738*795d594fSAndroid Build Coastguard Worker }
739*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
740*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
741*795d594fSAndroid Build Coastguard Worker DCHECK(cached_null_constant_->GetReferenceTypeInfo().IsValid());
742*795d594fSAndroid Build Coastguard Worker }
743*795d594fSAndroid Build Coastguard Worker return cached_null_constant_;
744*795d594fSAndroid Build Coastguard Worker }
745*795d594fSAndroid Build Coastguard Worker
GetIntConstant(int32_t value)746*795d594fSAndroid Build Coastguard Worker HIntConstant* HGraph::GetIntConstant(int32_t value) {
747*795d594fSAndroid Build Coastguard Worker return CreateConstant(value, &cached_int_constants_);
748*795d594fSAndroid Build Coastguard Worker }
749*795d594fSAndroid Build Coastguard Worker
GetLongConstant(int64_t value)750*795d594fSAndroid Build Coastguard Worker HLongConstant* HGraph::GetLongConstant(int64_t value) {
751*795d594fSAndroid Build Coastguard Worker return CreateConstant(value, &cached_long_constants_);
752*795d594fSAndroid Build Coastguard Worker }
753*795d594fSAndroid Build Coastguard Worker
GetFloatConstant(float value)754*795d594fSAndroid Build Coastguard Worker HFloatConstant* HGraph::GetFloatConstant(float value) {
755*795d594fSAndroid Build Coastguard Worker return CreateConstant(bit_cast<int32_t, float>(value), &cached_float_constants_);
756*795d594fSAndroid Build Coastguard Worker }
757*795d594fSAndroid Build Coastguard Worker
GetDoubleConstant(double value)758*795d594fSAndroid Build Coastguard Worker HDoubleConstant* HGraph::GetDoubleConstant(double value) {
759*795d594fSAndroid Build Coastguard Worker return CreateConstant(bit_cast<int64_t, double>(value), &cached_double_constants_);
760*795d594fSAndroid Build Coastguard Worker }
761*795d594fSAndroid Build Coastguard Worker
GetCurrentMethod()762*795d594fSAndroid Build Coastguard Worker HCurrentMethod* HGraph::GetCurrentMethod() {
763*795d594fSAndroid Build Coastguard Worker // For simplicity, don't bother reviving the cached current method if it is
764*795d594fSAndroid Build Coastguard Worker // not null and not in a block. Otherwise, we need to clear the instruction
765*795d594fSAndroid Build Coastguard Worker // id and/or any invariants the graph is assuming when adding new instructions.
766*795d594fSAndroid Build Coastguard Worker if ((cached_current_method_ == nullptr) || (cached_current_method_->GetBlock() == nullptr)) {
767*795d594fSAndroid Build Coastguard Worker cached_current_method_ = new (allocator_) HCurrentMethod(
768*795d594fSAndroid Build Coastguard Worker Is64BitInstructionSet(instruction_set_) ? DataType::Type::kInt64 : DataType::Type::kInt32,
769*795d594fSAndroid Build Coastguard Worker entry_block_->GetDexPc());
770*795d594fSAndroid Build Coastguard Worker if (entry_block_->GetFirstInstruction() == nullptr) {
771*795d594fSAndroid Build Coastguard Worker entry_block_->AddInstruction(cached_current_method_);
772*795d594fSAndroid Build Coastguard Worker } else {
773*795d594fSAndroid Build Coastguard Worker entry_block_->InsertInstructionBefore(
774*795d594fSAndroid Build Coastguard Worker cached_current_method_, entry_block_->GetFirstInstruction());
775*795d594fSAndroid Build Coastguard Worker }
776*795d594fSAndroid Build Coastguard Worker }
777*795d594fSAndroid Build Coastguard Worker return cached_current_method_;
778*795d594fSAndroid Build Coastguard Worker }
779*795d594fSAndroid Build Coastguard Worker
GetMethodName() const780*795d594fSAndroid Build Coastguard Worker const char* HGraph::GetMethodName() const {
781*795d594fSAndroid Build Coastguard Worker const dex::MethodId& method_id = dex_file_.GetMethodId(method_idx_);
782*795d594fSAndroid Build Coastguard Worker return dex_file_.GetMethodName(method_id);
783*795d594fSAndroid Build Coastguard Worker }
784*795d594fSAndroid Build Coastguard Worker
PrettyMethod(bool with_signature) const785*795d594fSAndroid Build Coastguard Worker std::string HGraph::PrettyMethod(bool with_signature) const {
786*795d594fSAndroid Build Coastguard Worker return dex_file_.PrettyMethod(method_idx_, with_signature);
787*795d594fSAndroid Build Coastguard Worker }
788*795d594fSAndroid Build Coastguard Worker
GetConstant(DataType::Type type,int64_t value)789*795d594fSAndroid Build Coastguard Worker HConstant* HGraph::GetConstant(DataType::Type type, int64_t value) {
790*795d594fSAndroid Build Coastguard Worker switch (type) {
791*795d594fSAndroid Build Coastguard Worker case DataType::Type::kBool:
792*795d594fSAndroid Build Coastguard Worker DCHECK(IsUint<1>(value));
793*795d594fSAndroid Build Coastguard Worker FALLTHROUGH_INTENDED;
794*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
795*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
796*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
797*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
798*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
799*795d594fSAndroid Build Coastguard Worker DCHECK(IsInt(DataType::Size(type) * kBitsPerByte, value));
800*795d594fSAndroid Build Coastguard Worker return GetIntConstant(static_cast<int32_t>(value));
801*795d594fSAndroid Build Coastguard Worker
802*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
803*795d594fSAndroid Build Coastguard Worker return GetLongConstant(value);
804*795d594fSAndroid Build Coastguard Worker
805*795d594fSAndroid Build Coastguard Worker default:
806*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unsupported constant type";
807*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
808*795d594fSAndroid Build Coastguard Worker }
809*795d594fSAndroid Build Coastguard Worker }
810*795d594fSAndroid Build Coastguard Worker
CacheFloatConstant(HFloatConstant * constant)811*795d594fSAndroid Build Coastguard Worker void HGraph::CacheFloatConstant(HFloatConstant* constant) {
812*795d594fSAndroid Build Coastguard Worker int32_t value = bit_cast<int32_t, float>(constant->GetValue());
813*795d594fSAndroid Build Coastguard Worker DCHECK(cached_float_constants_.find(value) == cached_float_constants_.end());
814*795d594fSAndroid Build Coastguard Worker cached_float_constants_.Overwrite(value, constant);
815*795d594fSAndroid Build Coastguard Worker }
816*795d594fSAndroid Build Coastguard Worker
CacheDoubleConstant(HDoubleConstant * constant)817*795d594fSAndroid Build Coastguard Worker void HGraph::CacheDoubleConstant(HDoubleConstant* constant) {
818*795d594fSAndroid Build Coastguard Worker int64_t value = bit_cast<int64_t, double>(constant->GetValue());
819*795d594fSAndroid Build Coastguard Worker DCHECK(cached_double_constants_.find(value) == cached_double_constants_.end());
820*795d594fSAndroid Build Coastguard Worker cached_double_constants_.Overwrite(value, constant);
821*795d594fSAndroid Build Coastguard Worker }
822*795d594fSAndroid Build Coastguard Worker
Add(HBasicBlock * block)823*795d594fSAndroid Build Coastguard Worker void HLoopInformation::Add(HBasicBlock* block) {
824*795d594fSAndroid Build Coastguard Worker blocks_.SetBit(block->GetBlockId());
825*795d594fSAndroid Build Coastguard Worker }
826*795d594fSAndroid Build Coastguard Worker
Remove(HBasicBlock * block)827*795d594fSAndroid Build Coastguard Worker void HLoopInformation::Remove(HBasicBlock* block) {
828*795d594fSAndroid Build Coastguard Worker blocks_.ClearBit(block->GetBlockId());
829*795d594fSAndroid Build Coastguard Worker }
830*795d594fSAndroid Build Coastguard Worker
PopulateRecursive(HBasicBlock * block)831*795d594fSAndroid Build Coastguard Worker void HLoopInformation::PopulateRecursive(HBasicBlock* block) {
832*795d594fSAndroid Build Coastguard Worker if (blocks_.IsBitSet(block->GetBlockId())) {
833*795d594fSAndroid Build Coastguard Worker return;
834*795d594fSAndroid Build Coastguard Worker }
835*795d594fSAndroid Build Coastguard Worker
836*795d594fSAndroid Build Coastguard Worker blocks_.SetBit(block->GetBlockId());
837*795d594fSAndroid Build Coastguard Worker block->SetInLoop(this);
838*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
839*795d594fSAndroid Build Coastguard Worker // We're visiting loops in post-order, so inner loops must have been
840*795d594fSAndroid Build Coastguard Worker // populated already.
841*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetLoopInformation()->IsPopulated());
842*795d594fSAndroid Build Coastguard Worker if (block->GetLoopInformation()->IsIrreducible()) {
843*795d594fSAndroid Build Coastguard Worker contains_irreducible_loop_ = true;
844*795d594fSAndroid Build Coastguard Worker }
845*795d594fSAndroid Build Coastguard Worker }
846*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : block->GetPredecessors()) {
847*795d594fSAndroid Build Coastguard Worker PopulateRecursive(predecessor);
848*795d594fSAndroid Build Coastguard Worker }
849*795d594fSAndroid Build Coastguard Worker }
850*795d594fSAndroid Build Coastguard Worker
PopulateIrreducibleRecursive(HBasicBlock * block,ArenaBitVector * finalized)851*795d594fSAndroid Build Coastguard Worker void HLoopInformation::PopulateIrreducibleRecursive(HBasicBlock* block, ArenaBitVector* finalized) {
852*795d594fSAndroid Build Coastguard Worker size_t block_id = block->GetBlockId();
853*795d594fSAndroid Build Coastguard Worker
854*795d594fSAndroid Build Coastguard Worker // If `block` is in `finalized`, we know its membership in the loop has been
855*795d594fSAndroid Build Coastguard Worker // decided and it does not need to be revisited.
856*795d594fSAndroid Build Coastguard Worker if (finalized->IsBitSet(block_id)) {
857*795d594fSAndroid Build Coastguard Worker return;
858*795d594fSAndroid Build Coastguard Worker }
859*795d594fSAndroid Build Coastguard Worker
860*795d594fSAndroid Build Coastguard Worker bool is_finalized = false;
861*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
862*795d594fSAndroid Build Coastguard Worker // If we hit a loop header in an irreducible loop, we first check if the
863*795d594fSAndroid Build Coastguard Worker // pre header of that loop belongs to the currently analyzed loop. If it does,
864*795d594fSAndroid Build Coastguard Worker // then we visit the back edges.
865*795d594fSAndroid Build Coastguard Worker // Note that we cannot use GetPreHeader, as the loop may have not been populated
866*795d594fSAndroid Build Coastguard Worker // yet.
867*795d594fSAndroid Build Coastguard Worker HBasicBlock* pre_header = block->GetPredecessors()[0];
868*795d594fSAndroid Build Coastguard Worker PopulateIrreducibleRecursive(pre_header, finalized);
869*795d594fSAndroid Build Coastguard Worker if (blocks_.IsBitSet(pre_header->GetBlockId())) {
870*795d594fSAndroid Build Coastguard Worker block->SetInLoop(this);
871*795d594fSAndroid Build Coastguard Worker blocks_.SetBit(block_id);
872*795d594fSAndroid Build Coastguard Worker finalized->SetBit(block_id);
873*795d594fSAndroid Build Coastguard Worker is_finalized = true;
874*795d594fSAndroid Build Coastguard Worker
875*795d594fSAndroid Build Coastguard Worker HLoopInformation* info = block->GetLoopInformation();
876*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge : info->GetBackEdges()) {
877*795d594fSAndroid Build Coastguard Worker PopulateIrreducibleRecursive(back_edge, finalized);
878*795d594fSAndroid Build Coastguard Worker }
879*795d594fSAndroid Build Coastguard Worker }
880*795d594fSAndroid Build Coastguard Worker } else {
881*795d594fSAndroid Build Coastguard Worker // Visit all predecessors. If one predecessor is part of the loop, this
882*795d594fSAndroid Build Coastguard Worker // block is also part of this loop.
883*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : block->GetPredecessors()) {
884*795d594fSAndroid Build Coastguard Worker PopulateIrreducibleRecursive(predecessor, finalized);
885*795d594fSAndroid Build Coastguard Worker if (!is_finalized && blocks_.IsBitSet(predecessor->GetBlockId())) {
886*795d594fSAndroid Build Coastguard Worker block->SetInLoop(this);
887*795d594fSAndroid Build Coastguard Worker blocks_.SetBit(block_id);
888*795d594fSAndroid Build Coastguard Worker finalized->SetBit(block_id);
889*795d594fSAndroid Build Coastguard Worker is_finalized = true;
890*795d594fSAndroid Build Coastguard Worker }
891*795d594fSAndroid Build Coastguard Worker }
892*795d594fSAndroid Build Coastguard Worker }
893*795d594fSAndroid Build Coastguard Worker
894*795d594fSAndroid Build Coastguard Worker // All predecessors have been recursively visited. Mark finalized if not marked yet.
895*795d594fSAndroid Build Coastguard Worker if (!is_finalized) {
896*795d594fSAndroid Build Coastguard Worker finalized->SetBit(block_id);
897*795d594fSAndroid Build Coastguard Worker }
898*795d594fSAndroid Build Coastguard Worker }
899*795d594fSAndroid Build Coastguard Worker
Populate()900*795d594fSAndroid Build Coastguard Worker void HLoopInformation::Populate() {
901*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(blocks_.NumSetBits(), 0u) << "Loop information has already been populated";
902*795d594fSAndroid Build Coastguard Worker // Populate this loop: starting with the back edge, recursively add predecessors
903*795d594fSAndroid Build Coastguard Worker // that are not already part of that loop. Set the header as part of the loop
904*795d594fSAndroid Build Coastguard Worker // to end the recursion.
905*795d594fSAndroid Build Coastguard Worker // This is a recursive implementation of the algorithm described in
906*795d594fSAndroid Build Coastguard Worker // "Advanced Compiler Design & Implementation" (Muchnick) p192.
907*795d594fSAndroid Build Coastguard Worker HGraph* graph = header_->GetGraph();
908*795d594fSAndroid Build Coastguard Worker blocks_.SetBit(header_->GetBlockId());
909*795d594fSAndroid Build Coastguard Worker header_->SetInLoop(this);
910*795d594fSAndroid Build Coastguard Worker
911*795d594fSAndroid Build Coastguard Worker bool is_irreducible_loop = HasBackEdgeNotDominatedByHeader();
912*795d594fSAndroid Build Coastguard Worker
913*795d594fSAndroid Build Coastguard Worker if (is_irreducible_loop) {
914*795d594fSAndroid Build Coastguard Worker // Allocate memory from local ScopedArenaAllocator.
915*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(graph->GetArenaStack());
916*795d594fSAndroid Build Coastguard Worker ArenaBitVector visited(&allocator,
917*795d594fSAndroid Build Coastguard Worker graph->GetBlocks().size(),
918*795d594fSAndroid Build Coastguard Worker /* expandable= */ false,
919*795d594fSAndroid Build Coastguard Worker kArenaAllocGraphBuilder);
920*795d594fSAndroid Build Coastguard Worker // Stop marking blocks at the loop header.
921*795d594fSAndroid Build Coastguard Worker visited.SetBit(header_->GetBlockId());
922*795d594fSAndroid Build Coastguard Worker
923*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge : GetBackEdges()) {
924*795d594fSAndroid Build Coastguard Worker PopulateIrreducibleRecursive(back_edge, &visited);
925*795d594fSAndroid Build Coastguard Worker }
926*795d594fSAndroid Build Coastguard Worker } else {
927*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge : GetBackEdges()) {
928*795d594fSAndroid Build Coastguard Worker PopulateRecursive(back_edge);
929*795d594fSAndroid Build Coastguard Worker }
930*795d594fSAndroid Build Coastguard Worker }
931*795d594fSAndroid Build Coastguard Worker
932*795d594fSAndroid Build Coastguard Worker if (!is_irreducible_loop && graph->IsCompilingOsr()) {
933*795d594fSAndroid Build Coastguard Worker // When compiling in OSR mode, all loops in the compiled method may be entered
934*795d594fSAndroid Build Coastguard Worker // from the interpreter. We treat this OSR entry point just like an extra entry
935*795d594fSAndroid Build Coastguard Worker // to an irreducible loop, so we need to mark the method's loops as irreducible.
936*795d594fSAndroid Build Coastguard Worker // This does not apply to inlined loops which do not act as OSR entry points.
937*795d594fSAndroid Build Coastguard Worker if (suspend_check_ == nullptr) {
938*795d594fSAndroid Build Coastguard Worker // Just building the graph in OSR mode, this loop is not inlined. We never build an
939*795d594fSAndroid Build Coastguard Worker // inner graph in OSR mode as we can do OSR transition only from the outer method.
940*795d594fSAndroid Build Coastguard Worker is_irreducible_loop = true;
941*795d594fSAndroid Build Coastguard Worker } else {
942*795d594fSAndroid Build Coastguard Worker // Look at the suspend check's environment to determine if the loop was inlined.
943*795d594fSAndroid Build Coastguard Worker DCHECK(suspend_check_->HasEnvironment());
944*795d594fSAndroid Build Coastguard Worker if (!suspend_check_->GetEnvironment()->IsFromInlinedInvoke()) {
945*795d594fSAndroid Build Coastguard Worker is_irreducible_loop = true;
946*795d594fSAndroid Build Coastguard Worker }
947*795d594fSAndroid Build Coastguard Worker }
948*795d594fSAndroid Build Coastguard Worker }
949*795d594fSAndroid Build Coastguard Worker if (is_irreducible_loop) {
950*795d594fSAndroid Build Coastguard Worker irreducible_ = true;
951*795d594fSAndroid Build Coastguard Worker contains_irreducible_loop_ = true;
952*795d594fSAndroid Build Coastguard Worker graph->SetHasIrreducibleLoops(true);
953*795d594fSAndroid Build Coastguard Worker }
954*795d594fSAndroid Build Coastguard Worker graph->SetHasLoops(true);
955*795d594fSAndroid Build Coastguard Worker }
956*795d594fSAndroid Build Coastguard Worker
PopulateInnerLoopUpwards(HLoopInformation * inner_loop)957*795d594fSAndroid Build Coastguard Worker void HLoopInformation::PopulateInnerLoopUpwards(HLoopInformation* inner_loop) {
958*795d594fSAndroid Build Coastguard Worker DCHECK(inner_loop->GetPreHeader()->GetLoopInformation() == this);
959*795d594fSAndroid Build Coastguard Worker blocks_.Union(&inner_loop->blocks_);
960*795d594fSAndroid Build Coastguard Worker HLoopInformation* outer_loop = GetPreHeader()->GetLoopInformation();
961*795d594fSAndroid Build Coastguard Worker if (outer_loop != nullptr) {
962*795d594fSAndroid Build Coastguard Worker outer_loop->PopulateInnerLoopUpwards(this);
963*795d594fSAndroid Build Coastguard Worker }
964*795d594fSAndroid Build Coastguard Worker }
965*795d594fSAndroid Build Coastguard Worker
GetPreHeader() const966*795d594fSAndroid Build Coastguard Worker HBasicBlock* HLoopInformation::GetPreHeader() const {
967*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = header_->GetPredecessors()[0];
968*795d594fSAndroid Build Coastguard Worker DCHECK(irreducible_ || (block == header_->GetDominator()));
969*795d594fSAndroid Build Coastguard Worker return block;
970*795d594fSAndroid Build Coastguard Worker }
971*795d594fSAndroid Build Coastguard Worker
Contains(const HBasicBlock & block) const972*795d594fSAndroid Build Coastguard Worker bool HLoopInformation::Contains(const HBasicBlock& block) const {
973*795d594fSAndroid Build Coastguard Worker return blocks_.IsBitSet(block.GetBlockId());
974*795d594fSAndroid Build Coastguard Worker }
975*795d594fSAndroid Build Coastguard Worker
IsIn(const HLoopInformation & other) const976*795d594fSAndroid Build Coastguard Worker bool HLoopInformation::IsIn(const HLoopInformation& other) const {
977*795d594fSAndroid Build Coastguard Worker return other.blocks_.IsBitSet(header_->GetBlockId());
978*795d594fSAndroid Build Coastguard Worker }
979*795d594fSAndroid Build Coastguard Worker
IsDefinedOutOfTheLoop(HInstruction * instruction) const980*795d594fSAndroid Build Coastguard Worker bool HLoopInformation::IsDefinedOutOfTheLoop(HInstruction* instruction) const {
981*795d594fSAndroid Build Coastguard Worker return !blocks_.IsBitSet(instruction->GetBlock()->GetBlockId());
982*795d594fSAndroid Build Coastguard Worker }
983*795d594fSAndroid Build Coastguard Worker
GetLifetimeEnd() const984*795d594fSAndroid Build Coastguard Worker size_t HLoopInformation::GetLifetimeEnd() const {
985*795d594fSAndroid Build Coastguard Worker size_t last_position = 0;
986*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge : GetBackEdges()) {
987*795d594fSAndroid Build Coastguard Worker last_position = std::max(back_edge->GetLifetimeEnd(), last_position);
988*795d594fSAndroid Build Coastguard Worker }
989*795d594fSAndroid Build Coastguard Worker return last_position;
990*795d594fSAndroid Build Coastguard Worker }
991*795d594fSAndroid Build Coastguard Worker
HasBackEdgeNotDominatedByHeader() const992*795d594fSAndroid Build Coastguard Worker bool HLoopInformation::HasBackEdgeNotDominatedByHeader() const {
993*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge : GetBackEdges()) {
994*795d594fSAndroid Build Coastguard Worker DCHECK(back_edge->GetDominator() != nullptr);
995*795d594fSAndroid Build Coastguard Worker if (!header_->Dominates(back_edge)) {
996*795d594fSAndroid Build Coastguard Worker return true;
997*795d594fSAndroid Build Coastguard Worker }
998*795d594fSAndroid Build Coastguard Worker }
999*795d594fSAndroid Build Coastguard Worker return false;
1000*795d594fSAndroid Build Coastguard Worker }
1001*795d594fSAndroid Build Coastguard Worker
DominatesAllBackEdges(HBasicBlock * block)1002*795d594fSAndroid Build Coastguard Worker bool HLoopInformation::DominatesAllBackEdges(HBasicBlock* block) {
1003*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* back_edge : GetBackEdges()) {
1004*795d594fSAndroid Build Coastguard Worker if (!block->Dominates(back_edge)) {
1005*795d594fSAndroid Build Coastguard Worker return false;
1006*795d594fSAndroid Build Coastguard Worker }
1007*795d594fSAndroid Build Coastguard Worker }
1008*795d594fSAndroid Build Coastguard Worker return true;
1009*795d594fSAndroid Build Coastguard Worker }
1010*795d594fSAndroid Build Coastguard Worker
1011*795d594fSAndroid Build Coastguard Worker
HasExitEdge() const1012*795d594fSAndroid Build Coastguard Worker bool HLoopInformation::HasExitEdge() const {
1013*795d594fSAndroid Build Coastguard Worker // Determine if this loop has at least one exit edge.
1014*795d594fSAndroid Build Coastguard Worker HBlocksInLoopReversePostOrderIterator it_loop(*this);
1015*795d594fSAndroid Build Coastguard Worker for (; !it_loop.Done(); it_loop.Advance()) {
1016*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : it_loop.Current()->GetSuccessors()) {
1017*795d594fSAndroid Build Coastguard Worker if (!Contains(*successor)) {
1018*795d594fSAndroid Build Coastguard Worker return true;
1019*795d594fSAndroid Build Coastguard Worker }
1020*795d594fSAndroid Build Coastguard Worker }
1021*795d594fSAndroid Build Coastguard Worker }
1022*795d594fSAndroid Build Coastguard Worker return false;
1023*795d594fSAndroid Build Coastguard Worker }
1024*795d594fSAndroid Build Coastguard Worker
Dominates(const HBasicBlock * other) const1025*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::Dominates(const HBasicBlock* other) const {
1026*795d594fSAndroid Build Coastguard Worker // Walk up the dominator tree from `other`, to find out if `this`
1027*795d594fSAndroid Build Coastguard Worker // is an ancestor.
1028*795d594fSAndroid Build Coastguard Worker const HBasicBlock* current = other;
1029*795d594fSAndroid Build Coastguard Worker while (current != nullptr) {
1030*795d594fSAndroid Build Coastguard Worker if (current == this) {
1031*795d594fSAndroid Build Coastguard Worker return true;
1032*795d594fSAndroid Build Coastguard Worker }
1033*795d594fSAndroid Build Coastguard Worker current = current->GetDominator();
1034*795d594fSAndroid Build Coastguard Worker }
1035*795d594fSAndroid Build Coastguard Worker return false;
1036*795d594fSAndroid Build Coastguard Worker }
1037*795d594fSAndroid Build Coastguard Worker
UpdateInputsUsers(HInstruction * instruction)1038*795d594fSAndroid Build Coastguard Worker static void UpdateInputsUsers(HInstruction* instruction) {
1039*795d594fSAndroid Build Coastguard Worker HInputsRef inputs = instruction->GetInputs();
1040*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < inputs.size(); ++i) {
1041*795d594fSAndroid Build Coastguard Worker inputs[i]->AddUseAt(instruction, i);
1042*795d594fSAndroid Build Coastguard Worker }
1043*795d594fSAndroid Build Coastguard Worker // Environment should be created later.
1044*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->HasEnvironment());
1045*795d594fSAndroid Build Coastguard Worker }
1046*795d594fSAndroid Build Coastguard Worker
ReplaceAndRemovePhiWith(HPhi * initial,HPhi * replacement)1047*795d594fSAndroid Build Coastguard Worker void HBasicBlock::ReplaceAndRemovePhiWith(HPhi* initial, HPhi* replacement) {
1048*795d594fSAndroid Build Coastguard Worker DCHECK(initial->GetBlock() == this);
1049*795d594fSAndroid Build Coastguard Worker InsertPhiAfter(replacement, initial);
1050*795d594fSAndroid Build Coastguard Worker initial->ReplaceWith(replacement);
1051*795d594fSAndroid Build Coastguard Worker RemovePhi(initial);
1052*795d594fSAndroid Build Coastguard Worker }
1053*795d594fSAndroid Build Coastguard Worker
ReplaceAndRemoveInstructionWith(HInstruction * initial,HInstruction * replacement)1054*795d594fSAndroid Build Coastguard Worker void HBasicBlock::ReplaceAndRemoveInstructionWith(HInstruction* initial,
1055*795d594fSAndroid Build Coastguard Worker HInstruction* replacement) {
1056*795d594fSAndroid Build Coastguard Worker DCHECK(initial->GetBlock() == this);
1057*795d594fSAndroid Build Coastguard Worker if (initial->IsControlFlow()) {
1058*795d594fSAndroid Build Coastguard Worker // We can only replace a control flow instruction with another control flow instruction.
1059*795d594fSAndroid Build Coastguard Worker DCHECK(replacement->IsControlFlow());
1060*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(replacement->GetId(), -1);
1061*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(replacement->GetType(), DataType::Type::kVoid);
1062*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(initial->GetBlock(), this);
1063*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(initial->GetType(), DataType::Type::kVoid);
1064*795d594fSAndroid Build Coastguard Worker DCHECK(initial->GetUses().empty());
1065*795d594fSAndroid Build Coastguard Worker DCHECK(initial->GetEnvUses().empty());
1066*795d594fSAndroid Build Coastguard Worker replacement->SetBlock(this);
1067*795d594fSAndroid Build Coastguard Worker replacement->SetId(GetGraph()->GetNextInstructionId());
1068*795d594fSAndroid Build Coastguard Worker instructions_.InsertInstructionBefore(replacement, initial);
1069*795d594fSAndroid Build Coastguard Worker UpdateInputsUsers(replacement);
1070*795d594fSAndroid Build Coastguard Worker } else {
1071*795d594fSAndroid Build Coastguard Worker InsertInstructionBefore(replacement, initial);
1072*795d594fSAndroid Build Coastguard Worker initial->ReplaceWith(replacement);
1073*795d594fSAndroid Build Coastguard Worker }
1074*795d594fSAndroid Build Coastguard Worker RemoveInstruction(initial);
1075*795d594fSAndroid Build Coastguard Worker }
1076*795d594fSAndroid Build Coastguard Worker
Add(HInstructionList * instruction_list,HBasicBlock * block,HInstruction * instruction)1077*795d594fSAndroid Build Coastguard Worker static void Add(HInstructionList* instruction_list,
1078*795d594fSAndroid Build Coastguard Worker HBasicBlock* block,
1079*795d594fSAndroid Build Coastguard Worker HInstruction* instruction) {
1080*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetBlock() == nullptr);
1081*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction->GetId(), -1);
1082*795d594fSAndroid Build Coastguard Worker instruction->SetBlock(block);
1083*795d594fSAndroid Build Coastguard Worker instruction->SetId(block->GetGraph()->GetNextInstructionId());
1084*795d594fSAndroid Build Coastguard Worker UpdateInputsUsers(instruction);
1085*795d594fSAndroid Build Coastguard Worker instruction_list->AddInstruction(instruction);
1086*795d594fSAndroid Build Coastguard Worker }
1087*795d594fSAndroid Build Coastguard Worker
AddInstruction(HInstruction * instruction)1088*795d594fSAndroid Build Coastguard Worker void HBasicBlock::AddInstruction(HInstruction* instruction) {
1089*795d594fSAndroid Build Coastguard Worker Add(&instructions_, this, instruction);
1090*795d594fSAndroid Build Coastguard Worker }
1091*795d594fSAndroid Build Coastguard Worker
AddPhi(HPhi * phi)1092*795d594fSAndroid Build Coastguard Worker void HBasicBlock::AddPhi(HPhi* phi) {
1093*795d594fSAndroid Build Coastguard Worker Add(&phis_, this, phi);
1094*795d594fSAndroid Build Coastguard Worker }
1095*795d594fSAndroid Build Coastguard Worker
InsertInstructionBefore(HInstruction * instruction,HInstruction * cursor)1096*795d594fSAndroid Build Coastguard Worker void HBasicBlock::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
1097*795d594fSAndroid Build Coastguard Worker DCHECK(!cursor->IsPhi());
1098*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->IsPhi());
1099*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction->GetId(), -1);
1100*795d594fSAndroid Build Coastguard Worker DCHECK_NE(cursor->GetId(), -1);
1101*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cursor->GetBlock(), this);
1102*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->IsControlFlow());
1103*795d594fSAndroid Build Coastguard Worker instruction->SetBlock(this);
1104*795d594fSAndroid Build Coastguard Worker instruction->SetId(GetGraph()->GetNextInstructionId());
1105*795d594fSAndroid Build Coastguard Worker UpdateInputsUsers(instruction);
1106*795d594fSAndroid Build Coastguard Worker instructions_.InsertInstructionBefore(instruction, cursor);
1107*795d594fSAndroid Build Coastguard Worker }
1108*795d594fSAndroid Build Coastguard Worker
InsertInstructionAfter(HInstruction * instruction,HInstruction * cursor)1109*795d594fSAndroid Build Coastguard Worker void HBasicBlock::InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor) {
1110*795d594fSAndroid Build Coastguard Worker DCHECK(!cursor->IsPhi());
1111*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->IsPhi());
1112*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction->GetId(), -1);
1113*795d594fSAndroid Build Coastguard Worker DCHECK_NE(cursor->GetId(), -1);
1114*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cursor->GetBlock(), this);
1115*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->IsControlFlow());
1116*795d594fSAndroid Build Coastguard Worker DCHECK(!cursor->IsControlFlow());
1117*795d594fSAndroid Build Coastguard Worker instruction->SetBlock(this);
1118*795d594fSAndroid Build Coastguard Worker instruction->SetId(GetGraph()->GetNextInstructionId());
1119*795d594fSAndroid Build Coastguard Worker UpdateInputsUsers(instruction);
1120*795d594fSAndroid Build Coastguard Worker instructions_.InsertInstructionAfter(instruction, cursor);
1121*795d594fSAndroid Build Coastguard Worker }
1122*795d594fSAndroid Build Coastguard Worker
InsertPhiAfter(HPhi * phi,HPhi * cursor)1123*795d594fSAndroid Build Coastguard Worker void HBasicBlock::InsertPhiAfter(HPhi* phi, HPhi* cursor) {
1124*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(phi->GetId(), -1);
1125*795d594fSAndroid Build Coastguard Worker DCHECK_NE(cursor->GetId(), -1);
1126*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cursor->GetBlock(), this);
1127*795d594fSAndroid Build Coastguard Worker phi->SetBlock(this);
1128*795d594fSAndroid Build Coastguard Worker phi->SetId(GetGraph()->GetNextInstructionId());
1129*795d594fSAndroid Build Coastguard Worker UpdateInputsUsers(phi);
1130*795d594fSAndroid Build Coastguard Worker phis_.InsertInstructionAfter(phi, cursor);
1131*795d594fSAndroid Build Coastguard Worker }
1132*795d594fSAndroid Build Coastguard Worker
Remove(HInstructionList * instruction_list,HBasicBlock * block,HInstruction * instruction,bool ensure_safety)1133*795d594fSAndroid Build Coastguard Worker static void Remove(HInstructionList* instruction_list,
1134*795d594fSAndroid Build Coastguard Worker HBasicBlock* block,
1135*795d594fSAndroid Build Coastguard Worker HInstruction* instruction,
1136*795d594fSAndroid Build Coastguard Worker bool ensure_safety) {
1137*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(block, instruction->GetBlock());
1138*795d594fSAndroid Build Coastguard Worker instruction->SetBlock(nullptr);
1139*795d594fSAndroid Build Coastguard Worker instruction_list->RemoveInstruction(instruction);
1140*795d594fSAndroid Build Coastguard Worker if (ensure_safety) {
1141*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetUses().empty());
1142*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetEnvUses().empty());
1143*795d594fSAndroid Build Coastguard Worker RemoveAsUser(instruction);
1144*795d594fSAndroid Build Coastguard Worker }
1145*795d594fSAndroid Build Coastguard Worker }
1146*795d594fSAndroid Build Coastguard Worker
RemoveInstruction(HInstruction * instruction,bool ensure_safety)1147*795d594fSAndroid Build Coastguard Worker void HBasicBlock::RemoveInstruction(HInstruction* instruction, bool ensure_safety) {
1148*795d594fSAndroid Build Coastguard Worker DCHECK(!instruction->IsPhi());
1149*795d594fSAndroid Build Coastguard Worker Remove(&instructions_, this, instruction, ensure_safety);
1150*795d594fSAndroid Build Coastguard Worker }
1151*795d594fSAndroid Build Coastguard Worker
RemovePhi(HPhi * phi,bool ensure_safety)1152*795d594fSAndroid Build Coastguard Worker void HBasicBlock::RemovePhi(HPhi* phi, bool ensure_safety) {
1153*795d594fSAndroid Build Coastguard Worker Remove(&phis_, this, phi, ensure_safety);
1154*795d594fSAndroid Build Coastguard Worker }
1155*795d594fSAndroid Build Coastguard Worker
RemoveInstructionOrPhi(HInstruction * instruction,bool ensure_safety)1156*795d594fSAndroid Build Coastguard Worker void HBasicBlock::RemoveInstructionOrPhi(HInstruction* instruction, bool ensure_safety) {
1157*795d594fSAndroid Build Coastguard Worker if (instruction->IsPhi()) {
1158*795d594fSAndroid Build Coastguard Worker RemovePhi(instruction->AsPhi(), ensure_safety);
1159*795d594fSAndroid Build Coastguard Worker } else {
1160*795d594fSAndroid Build Coastguard Worker RemoveInstruction(instruction, ensure_safety);
1161*795d594fSAndroid Build Coastguard Worker }
1162*795d594fSAndroid Build Coastguard Worker }
1163*795d594fSAndroid Build Coastguard Worker
CopyFrom(ArrayRef<HInstruction * const> locals)1164*795d594fSAndroid Build Coastguard Worker void HEnvironment::CopyFrom(ArrayRef<HInstruction* const> locals) {
1165*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < locals.size(); i++) {
1166*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = locals[i];
1167*795d594fSAndroid Build Coastguard Worker SetRawEnvAt(i, instruction);
1168*795d594fSAndroid Build Coastguard Worker if (instruction != nullptr) {
1169*795d594fSAndroid Build Coastguard Worker instruction->AddEnvUseAt(this, i);
1170*795d594fSAndroid Build Coastguard Worker }
1171*795d594fSAndroid Build Coastguard Worker }
1172*795d594fSAndroid Build Coastguard Worker }
1173*795d594fSAndroid Build Coastguard Worker
CopyFrom(const HEnvironment * env)1174*795d594fSAndroid Build Coastguard Worker void HEnvironment::CopyFrom(const HEnvironment* env) {
1175*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < env->Size(); i++) {
1176*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = env->GetInstructionAt(i);
1177*795d594fSAndroid Build Coastguard Worker SetRawEnvAt(i, instruction);
1178*795d594fSAndroid Build Coastguard Worker if (instruction != nullptr) {
1179*795d594fSAndroid Build Coastguard Worker instruction->AddEnvUseAt(this, i);
1180*795d594fSAndroid Build Coastguard Worker }
1181*795d594fSAndroid Build Coastguard Worker }
1182*795d594fSAndroid Build Coastguard Worker }
1183*795d594fSAndroid Build Coastguard Worker
CopyFromWithLoopPhiAdjustment(HEnvironment * env,HBasicBlock * loop_header)1184*795d594fSAndroid Build Coastguard Worker void HEnvironment::CopyFromWithLoopPhiAdjustment(HEnvironment* env,
1185*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_header) {
1186*795d594fSAndroid Build Coastguard Worker DCHECK(loop_header->IsLoopHeader());
1187*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < env->Size(); i++) {
1188*795d594fSAndroid Build Coastguard Worker HInstruction* instruction = env->GetInstructionAt(i);
1189*795d594fSAndroid Build Coastguard Worker SetRawEnvAt(i, instruction);
1190*795d594fSAndroid Build Coastguard Worker if (instruction == nullptr) {
1191*795d594fSAndroid Build Coastguard Worker continue;
1192*795d594fSAndroid Build Coastguard Worker }
1193*795d594fSAndroid Build Coastguard Worker if (instruction->IsLoopHeaderPhi() && (instruction->GetBlock() == loop_header)) {
1194*795d594fSAndroid Build Coastguard Worker // At the end of the loop pre-header, the corresponding value for instruction
1195*795d594fSAndroid Build Coastguard Worker // is the first input of the phi.
1196*795d594fSAndroid Build Coastguard Worker HInstruction* initial = instruction->AsPhi()->InputAt(0);
1197*795d594fSAndroid Build Coastguard Worker SetRawEnvAt(i, initial);
1198*795d594fSAndroid Build Coastguard Worker initial->AddEnvUseAt(this, i);
1199*795d594fSAndroid Build Coastguard Worker } else {
1200*795d594fSAndroid Build Coastguard Worker instruction->AddEnvUseAt(this, i);
1201*795d594fSAndroid Build Coastguard Worker }
1202*795d594fSAndroid Build Coastguard Worker }
1203*795d594fSAndroid Build Coastguard Worker }
1204*795d594fSAndroid Build Coastguard Worker
RemoveAsUserOfInput(size_t index) const1205*795d594fSAndroid Build Coastguard Worker void HEnvironment::RemoveAsUserOfInput(size_t index) const {
1206*795d594fSAndroid Build Coastguard Worker const HUserRecord<HEnvironment*>& env_use = GetVRegs()[index];
1207*795d594fSAndroid Build Coastguard Worker HInstruction* user = env_use.GetInstruction();
1208*795d594fSAndroid Build Coastguard Worker auto before_env_use_node = env_use.GetBeforeUseNode();
1209*795d594fSAndroid Build Coastguard Worker user->env_uses_.erase_after(before_env_use_node);
1210*795d594fSAndroid Build Coastguard Worker user->FixUpUserRecordsAfterEnvUseRemoval(before_env_use_node);
1211*795d594fSAndroid Build Coastguard Worker }
1212*795d594fSAndroid Build Coastguard Worker
ReplaceInput(HInstruction * replacement,size_t index)1213*795d594fSAndroid Build Coastguard Worker void HEnvironment::ReplaceInput(HInstruction* replacement, size_t index) {
1214*795d594fSAndroid Build Coastguard Worker const HUserRecord<HEnvironment*>& env_use_record = GetVRegs()[index];
1215*795d594fSAndroid Build Coastguard Worker HInstruction* orig_instr = env_use_record.GetInstruction();
1216*795d594fSAndroid Build Coastguard Worker
1217*795d594fSAndroid Build Coastguard Worker DCHECK(orig_instr != replacement);
1218*795d594fSAndroid Build Coastguard Worker
1219*795d594fSAndroid Build Coastguard Worker HUseList<HEnvironment*>::iterator before_use_node = env_use_record.GetBeforeUseNode();
1220*795d594fSAndroid Build Coastguard Worker // Note: fixup_end remains valid across splice_after().
1221*795d594fSAndroid Build Coastguard Worker auto fixup_end = replacement->env_uses_.empty() ? replacement->env_uses_.begin()
1222*795d594fSAndroid Build Coastguard Worker : ++replacement->env_uses_.begin();
1223*795d594fSAndroid Build Coastguard Worker replacement->env_uses_.splice_after(replacement->env_uses_.before_begin(),
1224*795d594fSAndroid Build Coastguard Worker env_use_record.GetInstruction()->env_uses_,
1225*795d594fSAndroid Build Coastguard Worker before_use_node);
1226*795d594fSAndroid Build Coastguard Worker replacement->FixUpUserRecordsAfterEnvUseInsertion(fixup_end);
1227*795d594fSAndroid Build Coastguard Worker orig_instr->FixUpUserRecordsAfterEnvUseRemoval(before_use_node);
1228*795d594fSAndroid Build Coastguard Worker }
1229*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os,bool dump_args)1230*795d594fSAndroid Build Coastguard Worker std::ostream& HInstruction::Dump(std::ostream& os, bool dump_args) {
1231*795d594fSAndroid Build Coastguard Worker // Note: Handle the case where the instruction has been removed from
1232*795d594fSAndroid Build Coastguard Worker // the graph to support debugging output for failed gtests.
1233*795d594fSAndroid Build Coastguard Worker HGraph* graph = (GetBlock() != nullptr) ? GetBlock()->GetGraph() : nullptr;
1234*795d594fSAndroid Build Coastguard Worker HGraphVisualizer::DumpInstruction(&os, graph, this);
1235*795d594fSAndroid Build Coastguard Worker if (dump_args) {
1236*795d594fSAndroid Build Coastguard Worker // Allocate memory from local ScopedArenaAllocator.
1237*795d594fSAndroid Build Coastguard Worker std::optional<MallocArenaPool> local_arena_pool;
1238*795d594fSAndroid Build Coastguard Worker std::optional<ArenaStack> local_arena_stack;
1239*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(graph == nullptr)) {
1240*795d594fSAndroid Build Coastguard Worker local_arena_pool.emplace();
1241*795d594fSAndroid Build Coastguard Worker local_arena_stack.emplace(&local_arena_pool.value());
1242*795d594fSAndroid Build Coastguard Worker }
1243*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(
1244*795d594fSAndroid Build Coastguard Worker graph != nullptr ? graph->GetArenaStack() : &local_arena_stack.value());
1245*795d594fSAndroid Build Coastguard Worker // Instructions that we already visited. We print each instruction only once.
1246*795d594fSAndroid Build Coastguard Worker ArenaBitVector visited(&allocator,
1247*795d594fSAndroid Build Coastguard Worker (graph != nullptr) ? graph->GetCurrentInstructionId() : 0u,
1248*795d594fSAndroid Build Coastguard Worker /* expandable= */ (graph == nullptr),
1249*795d594fSAndroid Build Coastguard Worker kArenaAllocMisc);
1250*795d594fSAndroid Build Coastguard Worker visited.SetBit(GetId());
1251*795d594fSAndroid Build Coastguard Worker // Keep a queue of instructions with their indentations.
1252*795d594fSAndroid Build Coastguard Worker ScopedArenaDeque<std::pair<HInstruction*, size_t>> queue(allocator.Adapter(kArenaAllocMisc));
1253*795d594fSAndroid Build Coastguard Worker auto add_args = [&queue](HInstruction* instruction, size_t indentation) {
1254*795d594fSAndroid Build Coastguard Worker for (HInstruction* arg : ReverseRange(instruction->GetInputs())) {
1255*795d594fSAndroid Build Coastguard Worker queue.emplace_front(arg, indentation);
1256*795d594fSAndroid Build Coastguard Worker }
1257*795d594fSAndroid Build Coastguard Worker };
1258*795d594fSAndroid Build Coastguard Worker add_args(this, /*indentation=*/ 1u);
1259*795d594fSAndroid Build Coastguard Worker while (!queue.empty()) {
1260*795d594fSAndroid Build Coastguard Worker HInstruction* instruction;
1261*795d594fSAndroid Build Coastguard Worker size_t indentation;
1262*795d594fSAndroid Build Coastguard Worker std::tie(instruction, indentation) = queue.front();
1263*795d594fSAndroid Build Coastguard Worker queue.pop_front();
1264*795d594fSAndroid Build Coastguard Worker if (!visited.IsBitSet(instruction->GetId())) {
1265*795d594fSAndroid Build Coastguard Worker visited.SetBit(instruction->GetId());
1266*795d594fSAndroid Build Coastguard Worker os << '\n';
1267*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != indentation; ++i) {
1268*795d594fSAndroid Build Coastguard Worker os << " ";
1269*795d594fSAndroid Build Coastguard Worker }
1270*795d594fSAndroid Build Coastguard Worker HGraphVisualizer::DumpInstruction(&os, graph, instruction);
1271*795d594fSAndroid Build Coastguard Worker add_args(instruction, indentation + 1u);
1272*795d594fSAndroid Build Coastguard Worker }
1273*795d594fSAndroid Build Coastguard Worker }
1274*795d594fSAndroid Build Coastguard Worker }
1275*795d594fSAndroid Build Coastguard Worker return os;
1276*795d594fSAndroid Build Coastguard Worker }
1277*795d594fSAndroid Build Coastguard Worker
GetNextDisregardingMoves() const1278*795d594fSAndroid Build Coastguard Worker HInstruction* HInstruction::GetNextDisregardingMoves() const {
1279*795d594fSAndroid Build Coastguard Worker HInstruction* next = GetNext();
1280*795d594fSAndroid Build Coastguard Worker while (next != nullptr && next->IsParallelMove()) {
1281*795d594fSAndroid Build Coastguard Worker next = next->GetNext();
1282*795d594fSAndroid Build Coastguard Worker }
1283*795d594fSAndroid Build Coastguard Worker return next;
1284*795d594fSAndroid Build Coastguard Worker }
1285*795d594fSAndroid Build Coastguard Worker
GetPreviousDisregardingMoves() const1286*795d594fSAndroid Build Coastguard Worker HInstruction* HInstruction::GetPreviousDisregardingMoves() const {
1287*795d594fSAndroid Build Coastguard Worker HInstruction* previous = GetPrevious();
1288*795d594fSAndroid Build Coastguard Worker while (previous != nullptr && previous->IsParallelMove()) {
1289*795d594fSAndroid Build Coastguard Worker previous = previous->GetPrevious();
1290*795d594fSAndroid Build Coastguard Worker }
1291*795d594fSAndroid Build Coastguard Worker return previous;
1292*795d594fSAndroid Build Coastguard Worker }
1293*795d594fSAndroid Build Coastguard Worker
AddInstruction(HInstruction * instruction)1294*795d594fSAndroid Build Coastguard Worker void HInstructionList::AddInstruction(HInstruction* instruction) {
1295*795d594fSAndroid Build Coastguard Worker if (first_instruction_ == nullptr) {
1296*795d594fSAndroid Build Coastguard Worker DCHECK(last_instruction_ == nullptr);
1297*795d594fSAndroid Build Coastguard Worker first_instruction_ = last_instruction_ = instruction;
1298*795d594fSAndroid Build Coastguard Worker } else {
1299*795d594fSAndroid Build Coastguard Worker DCHECK(last_instruction_ != nullptr);
1300*795d594fSAndroid Build Coastguard Worker last_instruction_->next_ = instruction;
1301*795d594fSAndroid Build Coastguard Worker instruction->previous_ = last_instruction_;
1302*795d594fSAndroid Build Coastguard Worker last_instruction_ = instruction;
1303*795d594fSAndroid Build Coastguard Worker }
1304*795d594fSAndroid Build Coastguard Worker }
1305*795d594fSAndroid Build Coastguard Worker
InsertInstructionBefore(HInstruction * instruction,HInstruction * cursor)1306*795d594fSAndroid Build Coastguard Worker void HInstructionList::InsertInstructionBefore(HInstruction* instruction, HInstruction* cursor) {
1307*795d594fSAndroid Build Coastguard Worker DCHECK(Contains(cursor));
1308*795d594fSAndroid Build Coastguard Worker if (cursor == first_instruction_) {
1309*795d594fSAndroid Build Coastguard Worker cursor->previous_ = instruction;
1310*795d594fSAndroid Build Coastguard Worker instruction->next_ = cursor;
1311*795d594fSAndroid Build Coastguard Worker first_instruction_ = instruction;
1312*795d594fSAndroid Build Coastguard Worker } else {
1313*795d594fSAndroid Build Coastguard Worker instruction->previous_ = cursor->previous_;
1314*795d594fSAndroid Build Coastguard Worker instruction->next_ = cursor;
1315*795d594fSAndroid Build Coastguard Worker cursor->previous_ = instruction;
1316*795d594fSAndroid Build Coastguard Worker instruction->previous_->next_ = instruction;
1317*795d594fSAndroid Build Coastguard Worker }
1318*795d594fSAndroid Build Coastguard Worker }
1319*795d594fSAndroid Build Coastguard Worker
InsertInstructionAfter(HInstruction * instruction,HInstruction * cursor)1320*795d594fSAndroid Build Coastguard Worker void HInstructionList::InsertInstructionAfter(HInstruction* instruction, HInstruction* cursor) {
1321*795d594fSAndroid Build Coastguard Worker DCHECK(Contains(cursor));
1322*795d594fSAndroid Build Coastguard Worker if (cursor == last_instruction_) {
1323*795d594fSAndroid Build Coastguard Worker cursor->next_ = instruction;
1324*795d594fSAndroid Build Coastguard Worker instruction->previous_ = cursor;
1325*795d594fSAndroid Build Coastguard Worker last_instruction_ = instruction;
1326*795d594fSAndroid Build Coastguard Worker } else {
1327*795d594fSAndroid Build Coastguard Worker instruction->next_ = cursor->next_;
1328*795d594fSAndroid Build Coastguard Worker instruction->previous_ = cursor;
1329*795d594fSAndroid Build Coastguard Worker cursor->next_ = instruction;
1330*795d594fSAndroid Build Coastguard Worker instruction->next_->previous_ = instruction;
1331*795d594fSAndroid Build Coastguard Worker }
1332*795d594fSAndroid Build Coastguard Worker }
1333*795d594fSAndroid Build Coastguard Worker
RemoveInstruction(HInstruction * instruction)1334*795d594fSAndroid Build Coastguard Worker void HInstructionList::RemoveInstruction(HInstruction* instruction) {
1335*795d594fSAndroid Build Coastguard Worker if (instruction->previous_ != nullptr) {
1336*795d594fSAndroid Build Coastguard Worker instruction->previous_->next_ = instruction->next_;
1337*795d594fSAndroid Build Coastguard Worker }
1338*795d594fSAndroid Build Coastguard Worker if (instruction->next_ != nullptr) {
1339*795d594fSAndroid Build Coastguard Worker instruction->next_->previous_ = instruction->previous_;
1340*795d594fSAndroid Build Coastguard Worker }
1341*795d594fSAndroid Build Coastguard Worker if (instruction == first_instruction_) {
1342*795d594fSAndroid Build Coastguard Worker first_instruction_ = instruction->next_;
1343*795d594fSAndroid Build Coastguard Worker }
1344*795d594fSAndroid Build Coastguard Worker if (instruction == last_instruction_) {
1345*795d594fSAndroid Build Coastguard Worker last_instruction_ = instruction->previous_;
1346*795d594fSAndroid Build Coastguard Worker }
1347*795d594fSAndroid Build Coastguard Worker }
1348*795d594fSAndroid Build Coastguard Worker
Contains(HInstruction * instruction) const1349*795d594fSAndroid Build Coastguard Worker bool HInstructionList::Contains(HInstruction* instruction) const {
1350*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
1351*795d594fSAndroid Build Coastguard Worker if (it.Current() == instruction) {
1352*795d594fSAndroid Build Coastguard Worker return true;
1353*795d594fSAndroid Build Coastguard Worker }
1354*795d594fSAndroid Build Coastguard Worker }
1355*795d594fSAndroid Build Coastguard Worker return false;
1356*795d594fSAndroid Build Coastguard Worker }
1357*795d594fSAndroid Build Coastguard Worker
FoundBefore(const HInstruction * instruction1,const HInstruction * instruction2) const1358*795d594fSAndroid Build Coastguard Worker bool HInstructionList::FoundBefore(const HInstruction* instruction1,
1359*795d594fSAndroid Build Coastguard Worker const HInstruction* instruction2) const {
1360*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction1->GetBlock(), instruction2->GetBlock());
1361*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(*this); !it.Done(); it.Advance()) {
1362*795d594fSAndroid Build Coastguard Worker if (it.Current() == instruction2) {
1363*795d594fSAndroid Build Coastguard Worker return false;
1364*795d594fSAndroid Build Coastguard Worker }
1365*795d594fSAndroid Build Coastguard Worker if (it.Current() == instruction1) {
1366*795d594fSAndroid Build Coastguard Worker return true;
1367*795d594fSAndroid Build Coastguard Worker }
1368*795d594fSAndroid Build Coastguard Worker }
1369*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Did not find an order between two instructions of the same block.";
1370*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1371*795d594fSAndroid Build Coastguard Worker }
1372*795d594fSAndroid Build Coastguard Worker
Dominates(HInstruction * other_instruction) const1373*795d594fSAndroid Build Coastguard Worker bool HInstruction::Dominates(HInstruction* other_instruction) const {
1374*795d594fSAndroid Build Coastguard Worker return other_instruction == this || StrictlyDominates(other_instruction);
1375*795d594fSAndroid Build Coastguard Worker }
1376*795d594fSAndroid Build Coastguard Worker
StrictlyDominates(HInstruction * other_instruction) const1377*795d594fSAndroid Build Coastguard Worker bool HInstruction::StrictlyDominates(HInstruction* other_instruction) const {
1378*795d594fSAndroid Build Coastguard Worker if (other_instruction == this) {
1379*795d594fSAndroid Build Coastguard Worker // An instruction does not strictly dominate itself.
1380*795d594fSAndroid Build Coastguard Worker return false;
1381*795d594fSAndroid Build Coastguard Worker }
1382*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = GetBlock();
1383*795d594fSAndroid Build Coastguard Worker HBasicBlock* other_block = other_instruction->GetBlock();
1384*795d594fSAndroid Build Coastguard Worker if (block != other_block) {
1385*795d594fSAndroid Build Coastguard Worker return GetBlock()->Dominates(other_instruction->GetBlock());
1386*795d594fSAndroid Build Coastguard Worker } else {
1387*795d594fSAndroid Build Coastguard Worker // If both instructions are in the same block, ensure this
1388*795d594fSAndroid Build Coastguard Worker // instruction comes before `other_instruction`.
1389*795d594fSAndroid Build Coastguard Worker if (IsPhi()) {
1390*795d594fSAndroid Build Coastguard Worker if (!other_instruction->IsPhi()) {
1391*795d594fSAndroid Build Coastguard Worker // Phis appear before non phi-instructions so this instruction
1392*795d594fSAndroid Build Coastguard Worker // dominates `other_instruction`.
1393*795d594fSAndroid Build Coastguard Worker return true;
1394*795d594fSAndroid Build Coastguard Worker } else {
1395*795d594fSAndroid Build Coastguard Worker // There is no order among phis.
1396*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "There is no dominance between phis of a same block.";
1397*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1398*795d594fSAndroid Build Coastguard Worker }
1399*795d594fSAndroid Build Coastguard Worker } else {
1400*795d594fSAndroid Build Coastguard Worker // `this` is not a phi.
1401*795d594fSAndroid Build Coastguard Worker if (other_instruction->IsPhi()) {
1402*795d594fSAndroid Build Coastguard Worker // Phis appear before non phi-instructions so this instruction
1403*795d594fSAndroid Build Coastguard Worker // does not dominate `other_instruction`.
1404*795d594fSAndroid Build Coastguard Worker return false;
1405*795d594fSAndroid Build Coastguard Worker } else {
1406*795d594fSAndroid Build Coastguard Worker // Check whether this instruction comes before
1407*795d594fSAndroid Build Coastguard Worker // `other_instruction` in the instruction list.
1408*795d594fSAndroid Build Coastguard Worker return block->GetInstructions().FoundBefore(this, other_instruction);
1409*795d594fSAndroid Build Coastguard Worker }
1410*795d594fSAndroid Build Coastguard Worker }
1411*795d594fSAndroid Build Coastguard Worker }
1412*795d594fSAndroid Build Coastguard Worker }
1413*795d594fSAndroid Build Coastguard Worker
RemoveEnvironment()1414*795d594fSAndroid Build Coastguard Worker void HInstruction::RemoveEnvironment() {
1415*795d594fSAndroid Build Coastguard Worker RemoveEnvironmentUses(this);
1416*795d594fSAndroid Build Coastguard Worker environment_ = nullptr;
1417*795d594fSAndroid Build Coastguard Worker }
1418*795d594fSAndroid Build Coastguard Worker
ReplaceWith(HInstruction * other)1419*795d594fSAndroid Build Coastguard Worker void HInstruction::ReplaceWith(HInstruction* other) {
1420*795d594fSAndroid Build Coastguard Worker DCHECK(other != nullptr);
1421*795d594fSAndroid Build Coastguard Worker // Note: fixup_end remains valid across splice_after().
1422*795d594fSAndroid Build Coastguard Worker auto fixup_end = other->uses_.empty() ? other->uses_.begin() : ++other->uses_.begin();
1423*795d594fSAndroid Build Coastguard Worker other->uses_.splice_after(other->uses_.before_begin(), uses_);
1424*795d594fSAndroid Build Coastguard Worker other->FixUpUserRecordsAfterUseInsertion(fixup_end);
1425*795d594fSAndroid Build Coastguard Worker
1426*795d594fSAndroid Build Coastguard Worker // Note: env_fixup_end remains valid across splice_after().
1427*795d594fSAndroid Build Coastguard Worker auto env_fixup_end =
1428*795d594fSAndroid Build Coastguard Worker other->env_uses_.empty() ? other->env_uses_.begin() : ++other->env_uses_.begin();
1429*795d594fSAndroid Build Coastguard Worker other->env_uses_.splice_after(other->env_uses_.before_begin(), env_uses_);
1430*795d594fSAndroid Build Coastguard Worker other->FixUpUserRecordsAfterEnvUseInsertion(env_fixup_end);
1431*795d594fSAndroid Build Coastguard Worker
1432*795d594fSAndroid Build Coastguard Worker DCHECK(uses_.empty());
1433*795d594fSAndroid Build Coastguard Worker DCHECK(env_uses_.empty());
1434*795d594fSAndroid Build Coastguard Worker }
1435*795d594fSAndroid Build Coastguard Worker
ReplaceUsesDominatedBy(HInstruction * dominator,HInstruction * replacement,bool strictly_dominated)1436*795d594fSAndroid Build Coastguard Worker void HInstruction::ReplaceUsesDominatedBy(HInstruction* dominator,
1437*795d594fSAndroid Build Coastguard Worker HInstruction* replacement,
1438*795d594fSAndroid Build Coastguard Worker bool strictly_dominated) {
1439*795d594fSAndroid Build Coastguard Worker HBasicBlock* dominator_block = dominator->GetBlock();
1440*795d594fSAndroid Build Coastguard Worker std::optional<ArenaBitVector> visited_blocks;
1441*795d594fSAndroid Build Coastguard Worker
1442*795d594fSAndroid Build Coastguard Worker // Lazily compute the dominated blocks to faster calculation of domination afterwards.
1443*795d594fSAndroid Build Coastguard Worker auto maybe_generate_visited_blocks = [&visited_blocks, this, dominator_block]() {
1444*795d594fSAndroid Build Coastguard Worker if (visited_blocks.has_value()) {
1445*795d594fSAndroid Build Coastguard Worker return;
1446*795d594fSAndroid Build Coastguard Worker }
1447*795d594fSAndroid Build Coastguard Worker HGraph* graph = GetBlock()->GetGraph();
1448*795d594fSAndroid Build Coastguard Worker visited_blocks.emplace(graph->GetAllocator(),
1449*795d594fSAndroid Build Coastguard Worker graph->GetBlocks().size(),
1450*795d594fSAndroid Build Coastguard Worker /* expandable= */ false,
1451*795d594fSAndroid Build Coastguard Worker kArenaAllocMisc);
1452*795d594fSAndroid Build Coastguard Worker ScopedArenaAllocator allocator(graph->GetArenaStack());
1453*795d594fSAndroid Build Coastguard Worker ScopedArenaQueue<const HBasicBlock*> worklist(allocator.Adapter(kArenaAllocMisc));
1454*795d594fSAndroid Build Coastguard Worker worklist.push(dominator_block);
1455*795d594fSAndroid Build Coastguard Worker
1456*795d594fSAndroid Build Coastguard Worker while (!worklist.empty()) {
1457*795d594fSAndroid Build Coastguard Worker const HBasicBlock* current = worklist.front();
1458*795d594fSAndroid Build Coastguard Worker worklist.pop();
1459*795d594fSAndroid Build Coastguard Worker visited_blocks->SetBit(current->GetBlockId());
1460*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* dominated : current->GetDominatedBlocks()) {
1461*795d594fSAndroid Build Coastguard Worker if (visited_blocks->IsBitSet(dominated->GetBlockId())) {
1462*795d594fSAndroid Build Coastguard Worker continue;
1463*795d594fSAndroid Build Coastguard Worker }
1464*795d594fSAndroid Build Coastguard Worker worklist.push(dominated);
1465*795d594fSAndroid Build Coastguard Worker }
1466*795d594fSAndroid Build Coastguard Worker }
1467*795d594fSAndroid Build Coastguard Worker };
1468*795d594fSAndroid Build Coastguard Worker
1469*795d594fSAndroid Build Coastguard Worker const HUseList<HInstruction*>& uses = GetUses();
1470*795d594fSAndroid Build Coastguard Worker for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
1471*795d594fSAndroid Build Coastguard Worker HInstruction* user = it->GetUser();
1472*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = user->GetBlock();
1473*795d594fSAndroid Build Coastguard Worker size_t index = it->GetIndex();
1474*795d594fSAndroid Build Coastguard Worker // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
1475*795d594fSAndroid Build Coastguard Worker ++it;
1476*795d594fSAndroid Build Coastguard Worker bool dominated = false;
1477*795d594fSAndroid Build Coastguard Worker if (dominator_block == block) {
1478*795d594fSAndroid Build Coastguard Worker // Trickier case, call the other methods.
1479*795d594fSAndroid Build Coastguard Worker dominated =
1480*795d594fSAndroid Build Coastguard Worker strictly_dominated ? dominator->StrictlyDominates(user) : dominator->Dominates(user);
1481*795d594fSAndroid Build Coastguard Worker } else {
1482*795d594fSAndroid Build Coastguard Worker // Block domination.
1483*795d594fSAndroid Build Coastguard Worker maybe_generate_visited_blocks();
1484*795d594fSAndroid Build Coastguard Worker dominated = visited_blocks->IsBitSet(block->GetBlockId());
1485*795d594fSAndroid Build Coastguard Worker }
1486*795d594fSAndroid Build Coastguard Worker
1487*795d594fSAndroid Build Coastguard Worker if (dominated) {
1488*795d594fSAndroid Build Coastguard Worker user->ReplaceInput(replacement, index);
1489*795d594fSAndroid Build Coastguard Worker } else if (user->IsPhi() && !user->AsPhi()->IsCatchPhi()) {
1490*795d594fSAndroid Build Coastguard Worker // If the input flows from a block dominated by `dominator`, we can replace it.
1491*795d594fSAndroid Build Coastguard Worker // We do not perform this for catch phis as we don't have control flow support
1492*795d594fSAndroid Build Coastguard Worker // for their inputs.
1493*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = block->GetPredecessors()[index];
1494*795d594fSAndroid Build Coastguard Worker maybe_generate_visited_blocks();
1495*795d594fSAndroid Build Coastguard Worker if (visited_blocks->IsBitSet(predecessor->GetBlockId())) {
1496*795d594fSAndroid Build Coastguard Worker user->ReplaceInput(replacement, index);
1497*795d594fSAndroid Build Coastguard Worker }
1498*795d594fSAndroid Build Coastguard Worker }
1499*795d594fSAndroid Build Coastguard Worker }
1500*795d594fSAndroid Build Coastguard Worker }
1501*795d594fSAndroid Build Coastguard Worker
ReplaceEnvUsesDominatedBy(HInstruction * dominator,HInstruction * replacement)1502*795d594fSAndroid Build Coastguard Worker void HInstruction::ReplaceEnvUsesDominatedBy(HInstruction* dominator, HInstruction* replacement) {
1503*795d594fSAndroid Build Coastguard Worker const HUseList<HEnvironment*>& uses = GetEnvUses();
1504*795d594fSAndroid Build Coastguard Worker for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
1505*795d594fSAndroid Build Coastguard Worker HEnvironment* user = it->GetUser();
1506*795d594fSAndroid Build Coastguard Worker size_t index = it->GetIndex();
1507*795d594fSAndroid Build Coastguard Worker // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
1508*795d594fSAndroid Build Coastguard Worker ++it;
1509*795d594fSAndroid Build Coastguard Worker if (dominator->StrictlyDominates(user->GetHolder())) {
1510*795d594fSAndroid Build Coastguard Worker user->ReplaceInput(replacement, index);
1511*795d594fSAndroid Build Coastguard Worker }
1512*795d594fSAndroid Build Coastguard Worker }
1513*795d594fSAndroid Build Coastguard Worker }
1514*795d594fSAndroid Build Coastguard Worker
ReplaceInput(HInstruction * replacement,size_t index)1515*795d594fSAndroid Build Coastguard Worker void HInstruction::ReplaceInput(HInstruction* replacement, size_t index) {
1516*795d594fSAndroid Build Coastguard Worker HUserRecord<HInstruction*> input_use = InputRecordAt(index);
1517*795d594fSAndroid Build Coastguard Worker if (input_use.GetInstruction() == replacement) {
1518*795d594fSAndroid Build Coastguard Worker // Nothing to do.
1519*795d594fSAndroid Build Coastguard Worker return;
1520*795d594fSAndroid Build Coastguard Worker }
1521*795d594fSAndroid Build Coastguard Worker HUseList<HInstruction*>::iterator before_use_node = input_use.GetBeforeUseNode();
1522*795d594fSAndroid Build Coastguard Worker // Note: fixup_end remains valid across splice_after().
1523*795d594fSAndroid Build Coastguard Worker auto fixup_end =
1524*795d594fSAndroid Build Coastguard Worker replacement->uses_.empty() ? replacement->uses_.begin() : ++replacement->uses_.begin();
1525*795d594fSAndroid Build Coastguard Worker replacement->uses_.splice_after(replacement->uses_.before_begin(),
1526*795d594fSAndroid Build Coastguard Worker input_use.GetInstruction()->uses_,
1527*795d594fSAndroid Build Coastguard Worker before_use_node);
1528*795d594fSAndroid Build Coastguard Worker replacement->FixUpUserRecordsAfterUseInsertion(fixup_end);
1529*795d594fSAndroid Build Coastguard Worker input_use.GetInstruction()->FixUpUserRecordsAfterUseRemoval(before_use_node);
1530*795d594fSAndroid Build Coastguard Worker }
1531*795d594fSAndroid Build Coastguard Worker
EnvironmentSize() const1532*795d594fSAndroid Build Coastguard Worker size_t HInstruction::EnvironmentSize() const {
1533*795d594fSAndroid Build Coastguard Worker return HasEnvironment() ? environment_->Size() : 0;
1534*795d594fSAndroid Build Coastguard Worker }
1535*795d594fSAndroid Build Coastguard Worker
AddInput(HInstruction * input)1536*795d594fSAndroid Build Coastguard Worker void HVariableInputSizeInstruction::AddInput(HInstruction* input) {
1537*795d594fSAndroid Build Coastguard Worker DCHECK(input->GetBlock() != nullptr);
1538*795d594fSAndroid Build Coastguard Worker inputs_.push_back(HUserRecord<HInstruction*>(input));
1539*795d594fSAndroid Build Coastguard Worker input->AddUseAt(this, inputs_.size() - 1);
1540*795d594fSAndroid Build Coastguard Worker }
1541*795d594fSAndroid Build Coastguard Worker
InsertInputAt(size_t index,HInstruction * input)1542*795d594fSAndroid Build Coastguard Worker void HVariableInputSizeInstruction::InsertInputAt(size_t index, HInstruction* input) {
1543*795d594fSAndroid Build Coastguard Worker inputs_.insert(inputs_.begin() + index, HUserRecord<HInstruction*>(input));
1544*795d594fSAndroid Build Coastguard Worker input->AddUseAt(this, index);
1545*795d594fSAndroid Build Coastguard Worker // Update indexes in use nodes of inputs that have been pushed further back by the insert().
1546*795d594fSAndroid Build Coastguard Worker for (size_t i = index + 1u, e = inputs_.size(); i < e; ++i) {
1547*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i - 1u);
1548*795d594fSAndroid Build Coastguard Worker inputs_[i].GetUseNode()->SetIndex(i);
1549*795d594fSAndroid Build Coastguard Worker }
1550*795d594fSAndroid Build Coastguard Worker }
1551*795d594fSAndroid Build Coastguard Worker
RemoveInputAt(size_t index)1552*795d594fSAndroid Build Coastguard Worker void HVariableInputSizeInstruction::RemoveInputAt(size_t index) {
1553*795d594fSAndroid Build Coastguard Worker RemoveAsUserOfInput(index);
1554*795d594fSAndroid Build Coastguard Worker inputs_.erase(inputs_.begin() + index);
1555*795d594fSAndroid Build Coastguard Worker // Update indexes in use nodes of inputs that have been pulled forward by the erase().
1556*795d594fSAndroid Build Coastguard Worker for (size_t i = index, e = inputs_.size(); i < e; ++i) {
1557*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(inputs_[i].GetUseNode()->GetIndex(), i + 1u);
1558*795d594fSAndroid Build Coastguard Worker inputs_[i].GetUseNode()->SetIndex(i);
1559*795d594fSAndroid Build Coastguard Worker }
1560*795d594fSAndroid Build Coastguard Worker }
1561*795d594fSAndroid Build Coastguard Worker
RemoveAllInputs()1562*795d594fSAndroid Build Coastguard Worker void HVariableInputSizeInstruction::RemoveAllInputs() {
1563*795d594fSAndroid Build Coastguard Worker RemoveAsUserOfAllInputs();
1564*795d594fSAndroid Build Coastguard Worker DCHECK(!HasNonEnvironmentUses());
1565*795d594fSAndroid Build Coastguard Worker
1566*795d594fSAndroid Build Coastguard Worker inputs_.clear();
1567*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(0u, InputCount());
1568*795d594fSAndroid Build Coastguard Worker }
1569*795d594fSAndroid Build Coastguard Worker
RemoveConstructorFences(HInstruction * instruction)1570*795d594fSAndroid Build Coastguard Worker size_t HConstructorFence::RemoveConstructorFences(HInstruction* instruction) {
1571*795d594fSAndroid Build Coastguard Worker DCHECK(instruction->GetBlock() != nullptr);
1572*795d594fSAndroid Build Coastguard Worker // Removing constructor fences only makes sense for instructions with an object return type.
1573*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(DataType::Type::kReference, instruction->GetType());
1574*795d594fSAndroid Build Coastguard Worker
1575*795d594fSAndroid Build Coastguard Worker // Return how many instructions were removed for statistic purposes.
1576*795d594fSAndroid Build Coastguard Worker size_t remove_count = 0;
1577*795d594fSAndroid Build Coastguard Worker
1578*795d594fSAndroid Build Coastguard Worker // Efficient implementation that simultaneously (in one pass):
1579*795d594fSAndroid Build Coastguard Worker // * Scans the uses list for all constructor fences.
1580*795d594fSAndroid Build Coastguard Worker // * Deletes that constructor fence from the uses list of `instruction`.
1581*795d594fSAndroid Build Coastguard Worker // * Deletes `instruction` from the constructor fence's inputs.
1582*795d594fSAndroid Build Coastguard Worker // * Deletes the constructor fence if it now has 0 inputs.
1583*795d594fSAndroid Build Coastguard Worker
1584*795d594fSAndroid Build Coastguard Worker const HUseList<HInstruction*>& uses = instruction->GetUses();
1585*795d594fSAndroid Build Coastguard Worker // Warning: Although this is "const", we might mutate the list when calling RemoveInputAt.
1586*795d594fSAndroid Build Coastguard Worker for (auto it = uses.begin(), end = uses.end(); it != end; ) {
1587*795d594fSAndroid Build Coastguard Worker const HUseListNode<HInstruction*>& use_node = *it;
1588*795d594fSAndroid Build Coastguard Worker HInstruction* const use_instruction = use_node.GetUser();
1589*795d594fSAndroid Build Coastguard Worker
1590*795d594fSAndroid Build Coastguard Worker // Advance the iterator immediately once we fetch the use_node.
1591*795d594fSAndroid Build Coastguard Worker // Warning: If the input is removed, the current iterator becomes invalid.
1592*795d594fSAndroid Build Coastguard Worker ++it;
1593*795d594fSAndroid Build Coastguard Worker
1594*795d594fSAndroid Build Coastguard Worker if (use_instruction->IsConstructorFence()) {
1595*795d594fSAndroid Build Coastguard Worker HConstructorFence* ctor_fence = use_instruction->AsConstructorFence();
1596*795d594fSAndroid Build Coastguard Worker size_t input_index = use_node.GetIndex();
1597*795d594fSAndroid Build Coastguard Worker
1598*795d594fSAndroid Build Coastguard Worker // Process the candidate instruction for removal
1599*795d594fSAndroid Build Coastguard Worker // from the graph.
1600*795d594fSAndroid Build Coastguard Worker
1601*795d594fSAndroid Build Coastguard Worker // Constructor fence instructions are never
1602*795d594fSAndroid Build Coastguard Worker // used by other instructions.
1603*795d594fSAndroid Build Coastguard Worker //
1604*795d594fSAndroid Build Coastguard Worker // If we wanted to make this more generic, it
1605*795d594fSAndroid Build Coastguard Worker // could be a runtime if statement.
1606*795d594fSAndroid Build Coastguard Worker DCHECK(!ctor_fence->HasUses());
1607*795d594fSAndroid Build Coastguard Worker
1608*795d594fSAndroid Build Coastguard Worker // A constructor fence's return type is "kPrimVoid"
1609*795d594fSAndroid Build Coastguard Worker // and therefore it can't have any environment uses.
1610*795d594fSAndroid Build Coastguard Worker DCHECK(!ctor_fence->HasEnvironmentUses());
1611*795d594fSAndroid Build Coastguard Worker
1612*795d594fSAndroid Build Coastguard Worker // Remove the inputs first, otherwise removing the instruction
1613*795d594fSAndroid Build Coastguard Worker // will try to remove its uses while we are already removing uses
1614*795d594fSAndroid Build Coastguard Worker // and this operation will fail.
1615*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(instruction, ctor_fence->InputAt(input_index));
1616*795d594fSAndroid Build Coastguard Worker
1617*795d594fSAndroid Build Coastguard Worker // Removing the input will also remove the `use_node`.
1618*795d594fSAndroid Build Coastguard Worker // (Do not look at `use_node` after this, it will be a dangling reference).
1619*795d594fSAndroid Build Coastguard Worker ctor_fence->RemoveInputAt(input_index);
1620*795d594fSAndroid Build Coastguard Worker
1621*795d594fSAndroid Build Coastguard Worker // Once all inputs are removed, the fence is considered dead and
1622*795d594fSAndroid Build Coastguard Worker // is removed.
1623*795d594fSAndroid Build Coastguard Worker if (ctor_fence->InputCount() == 0u) {
1624*795d594fSAndroid Build Coastguard Worker ctor_fence->GetBlock()->RemoveInstruction(ctor_fence);
1625*795d594fSAndroid Build Coastguard Worker ++remove_count;
1626*795d594fSAndroid Build Coastguard Worker }
1627*795d594fSAndroid Build Coastguard Worker }
1628*795d594fSAndroid Build Coastguard Worker }
1629*795d594fSAndroid Build Coastguard Worker
1630*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
1631*795d594fSAndroid Build Coastguard Worker // Post-condition checks:
1632*795d594fSAndroid Build Coastguard Worker // * None of the uses of `instruction` are a constructor fence.
1633*795d594fSAndroid Build Coastguard Worker // * The `instruction` itself did not get removed from a block.
1634*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use_node : instruction->GetUses()) {
1635*795d594fSAndroid Build Coastguard Worker CHECK(!use_node.GetUser()->IsConstructorFence());
1636*795d594fSAndroid Build Coastguard Worker }
1637*795d594fSAndroid Build Coastguard Worker CHECK(instruction->GetBlock() != nullptr);
1638*795d594fSAndroid Build Coastguard Worker }
1639*795d594fSAndroid Build Coastguard Worker
1640*795d594fSAndroid Build Coastguard Worker return remove_count;
1641*795d594fSAndroid Build Coastguard Worker }
1642*795d594fSAndroid Build Coastguard Worker
Merge(HConstructorFence * other)1643*795d594fSAndroid Build Coastguard Worker void HConstructorFence::Merge(HConstructorFence* other) {
1644*795d594fSAndroid Build Coastguard Worker // Do not delete yourself from the graph.
1645*795d594fSAndroid Build Coastguard Worker DCHECK(this != other);
1646*795d594fSAndroid Build Coastguard Worker // Don't try to merge with an instruction not associated with a block.
1647*795d594fSAndroid Build Coastguard Worker DCHECK(other->GetBlock() != nullptr);
1648*795d594fSAndroid Build Coastguard Worker // A constructor fence's return type is "kPrimVoid"
1649*795d594fSAndroid Build Coastguard Worker // and therefore it cannot have any environment uses.
1650*795d594fSAndroid Build Coastguard Worker DCHECK(!other->HasEnvironmentUses());
1651*795d594fSAndroid Build Coastguard Worker
1652*795d594fSAndroid Build Coastguard Worker auto has_input = [](HInstruction* haystack, HInstruction* needle) {
1653*795d594fSAndroid Build Coastguard Worker // Check if `haystack` has `needle` as any of its inputs.
1654*795d594fSAndroid Build Coastguard Worker for (size_t input_count = 0; input_count < haystack->InputCount(); ++input_count) {
1655*795d594fSAndroid Build Coastguard Worker if (haystack->InputAt(input_count) == needle) {
1656*795d594fSAndroid Build Coastguard Worker return true;
1657*795d594fSAndroid Build Coastguard Worker }
1658*795d594fSAndroid Build Coastguard Worker }
1659*795d594fSAndroid Build Coastguard Worker return false;
1660*795d594fSAndroid Build Coastguard Worker };
1661*795d594fSAndroid Build Coastguard Worker
1662*795d594fSAndroid Build Coastguard Worker // Add any inputs from `other` into `this` if it wasn't already an input.
1663*795d594fSAndroid Build Coastguard Worker for (size_t input_count = 0; input_count < other->InputCount(); ++input_count) {
1664*795d594fSAndroid Build Coastguard Worker HInstruction* other_input = other->InputAt(input_count);
1665*795d594fSAndroid Build Coastguard Worker if (!has_input(this, other_input)) {
1666*795d594fSAndroid Build Coastguard Worker AddInput(other_input);
1667*795d594fSAndroid Build Coastguard Worker }
1668*795d594fSAndroid Build Coastguard Worker }
1669*795d594fSAndroid Build Coastguard Worker
1670*795d594fSAndroid Build Coastguard Worker other->GetBlock()->RemoveInstruction(other);
1671*795d594fSAndroid Build Coastguard Worker }
1672*795d594fSAndroid Build Coastguard Worker
GetAssociatedAllocation(bool ignore_inputs)1673*795d594fSAndroid Build Coastguard Worker HInstruction* HConstructorFence::GetAssociatedAllocation(bool ignore_inputs) {
1674*795d594fSAndroid Build Coastguard Worker HInstruction* new_instance_inst = GetPrevious();
1675*795d594fSAndroid Build Coastguard Worker // Check if the immediately preceding instruction is a new-instance/new-array.
1676*795d594fSAndroid Build Coastguard Worker // Otherwise this fence is for protecting final fields.
1677*795d594fSAndroid Build Coastguard Worker if (new_instance_inst != nullptr &&
1678*795d594fSAndroid Build Coastguard Worker (new_instance_inst->IsNewInstance() || new_instance_inst->IsNewArray())) {
1679*795d594fSAndroid Build Coastguard Worker if (ignore_inputs) {
1680*795d594fSAndroid Build Coastguard Worker // If inputs are ignored, simply check if the predecessor is
1681*795d594fSAndroid Build Coastguard Worker // *any* HNewInstance/HNewArray.
1682*795d594fSAndroid Build Coastguard Worker //
1683*795d594fSAndroid Build Coastguard Worker // Inputs are normally only ignored for prepare_for_register_allocation,
1684*795d594fSAndroid Build Coastguard Worker // at which point *any* prior HNewInstance/Array can be considered
1685*795d594fSAndroid Build Coastguard Worker // associated.
1686*795d594fSAndroid Build Coastguard Worker return new_instance_inst;
1687*795d594fSAndroid Build Coastguard Worker } else {
1688*795d594fSAndroid Build Coastguard Worker // Normal case: There must be exactly 1 input and the previous instruction
1689*795d594fSAndroid Build Coastguard Worker // must be that input.
1690*795d594fSAndroid Build Coastguard Worker if (InputCount() == 1u && InputAt(0) == new_instance_inst) {
1691*795d594fSAndroid Build Coastguard Worker return new_instance_inst;
1692*795d594fSAndroid Build Coastguard Worker }
1693*795d594fSAndroid Build Coastguard Worker }
1694*795d594fSAndroid Build Coastguard Worker }
1695*795d594fSAndroid Build Coastguard Worker return nullptr;
1696*795d594fSAndroid Build Coastguard Worker }
1697*795d594fSAndroid Build Coastguard Worker
1698*795d594fSAndroid Build Coastguard Worker #define DEFINE_ACCEPT(name, super) \
1699*795d594fSAndroid Build Coastguard Worker void H##name::Accept(HGraphVisitor* visitor) { \
1700*795d594fSAndroid Build Coastguard Worker visitor->Visit##name(this); \
1701*795d594fSAndroid Build Coastguard Worker }
1702*795d594fSAndroid Build Coastguard Worker
FOR_EACH_CONCRETE_INSTRUCTION(DEFINE_ACCEPT)1703*795d594fSAndroid Build Coastguard Worker FOR_EACH_CONCRETE_INSTRUCTION(DEFINE_ACCEPT)
1704*795d594fSAndroid Build Coastguard Worker
1705*795d594fSAndroid Build Coastguard Worker #undef DEFINE_ACCEPT
1706*795d594fSAndroid Build Coastguard Worker
1707*795d594fSAndroid Build Coastguard Worker void HGraphVisitor::VisitInsertionOrder() {
1708*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph_->GetActiveBlocks()) {
1709*795d594fSAndroid Build Coastguard Worker VisitBasicBlock(block);
1710*795d594fSAndroid Build Coastguard Worker }
1711*795d594fSAndroid Build Coastguard Worker }
1712*795d594fSAndroid Build Coastguard Worker
VisitReversePostOrder()1713*795d594fSAndroid Build Coastguard Worker void HGraphVisitor::VisitReversePostOrder() {
1714*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : graph_->GetReversePostOrder()) {
1715*795d594fSAndroid Build Coastguard Worker VisitBasicBlock(block);
1716*795d594fSAndroid Build Coastguard Worker }
1717*795d594fSAndroid Build Coastguard Worker }
1718*795d594fSAndroid Build Coastguard Worker
VisitBasicBlock(HBasicBlock * block)1719*795d594fSAndroid Build Coastguard Worker void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
1720*795d594fSAndroid Build Coastguard Worker VisitPhis(block);
1721*795d594fSAndroid Build Coastguard Worker VisitNonPhiInstructions(block);
1722*795d594fSAndroid Build Coastguard Worker }
1723*795d594fSAndroid Build Coastguard Worker
VisitPhis(HBasicBlock * block)1724*795d594fSAndroid Build Coastguard Worker void HGraphVisitor::VisitPhis(HBasicBlock* block) {
1725*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
1726*795d594fSAndroid Build Coastguard Worker DCHECK(it.Current()->IsPhi());
1727*795d594fSAndroid Build Coastguard Worker VisitPhi(it.Current()->AsPhi());
1728*795d594fSAndroid Build Coastguard Worker }
1729*795d594fSAndroid Build Coastguard Worker }
1730*795d594fSAndroid Build Coastguard Worker
VisitNonPhiInstructions(HBasicBlock * block)1731*795d594fSAndroid Build Coastguard Worker void HGraphVisitor::VisitNonPhiInstructions(HBasicBlock* block) {
1732*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
1733*795d594fSAndroid Build Coastguard Worker DCHECK(!it.Current()->IsPhi());
1734*795d594fSAndroid Build Coastguard Worker it.Current()->Accept(this);
1735*795d594fSAndroid Build Coastguard Worker }
1736*795d594fSAndroid Build Coastguard Worker }
1737*795d594fSAndroid Build Coastguard Worker
TryStaticEvaluation() const1738*795d594fSAndroid Build Coastguard Worker HConstant* HTypeConversion::TryStaticEvaluation() const { return TryStaticEvaluation(GetInput()); }
1739*795d594fSAndroid Build Coastguard Worker
TryStaticEvaluation(HInstruction * input) const1740*795d594fSAndroid Build Coastguard Worker HConstant* HTypeConversion::TryStaticEvaluation(HInstruction* input) const {
1741*795d594fSAndroid Build Coastguard Worker HGraph* graph = input->GetBlock()->GetGraph();
1742*795d594fSAndroid Build Coastguard Worker if (input->IsIntConstant()) {
1743*795d594fSAndroid Build Coastguard Worker int32_t value = input->AsIntConstant()->GetValue();
1744*795d594fSAndroid Build Coastguard Worker switch (GetResultType()) {
1745*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
1746*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<int8_t>(value));
1747*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
1748*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<uint8_t>(value));
1749*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
1750*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<int16_t>(value));
1751*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
1752*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<uint16_t>(value));
1753*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
1754*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(static_cast<int64_t>(value));
1755*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
1756*795d594fSAndroid Build Coastguard Worker return graph->GetFloatConstant(static_cast<float>(value));
1757*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
1758*795d594fSAndroid Build Coastguard Worker return graph->GetDoubleConstant(static_cast<double>(value));
1759*795d594fSAndroid Build Coastguard Worker default:
1760*795d594fSAndroid Build Coastguard Worker return nullptr;
1761*795d594fSAndroid Build Coastguard Worker }
1762*795d594fSAndroid Build Coastguard Worker } else if (input->IsLongConstant()) {
1763*795d594fSAndroid Build Coastguard Worker int64_t value = input->AsLongConstant()->GetValue();
1764*795d594fSAndroid Build Coastguard Worker switch (GetResultType()) {
1765*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt8:
1766*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<int8_t>(value));
1767*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint8:
1768*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<uint8_t>(value));
1769*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt16:
1770*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<int16_t>(value));
1771*795d594fSAndroid Build Coastguard Worker case DataType::Type::kUint16:
1772*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<uint16_t>(value));
1773*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
1774*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<int32_t>(value));
1775*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
1776*795d594fSAndroid Build Coastguard Worker return graph->GetFloatConstant(static_cast<float>(value));
1777*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
1778*795d594fSAndroid Build Coastguard Worker return graph->GetDoubleConstant(static_cast<double>(value));
1779*795d594fSAndroid Build Coastguard Worker default:
1780*795d594fSAndroid Build Coastguard Worker return nullptr;
1781*795d594fSAndroid Build Coastguard Worker }
1782*795d594fSAndroid Build Coastguard Worker } else if (input->IsFloatConstant()) {
1783*795d594fSAndroid Build Coastguard Worker float value = input->AsFloatConstant()->GetValue();
1784*795d594fSAndroid Build Coastguard Worker switch (GetResultType()) {
1785*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
1786*795d594fSAndroid Build Coastguard Worker if (std::isnan(value))
1787*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(0);
1788*795d594fSAndroid Build Coastguard Worker if (value >= static_cast<float>(kPrimIntMax))
1789*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(kPrimIntMax);
1790*795d594fSAndroid Build Coastguard Worker if (value <= kPrimIntMin)
1791*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(kPrimIntMin);
1792*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<int32_t>(value));
1793*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
1794*795d594fSAndroid Build Coastguard Worker if (std::isnan(value))
1795*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(0);
1796*795d594fSAndroid Build Coastguard Worker if (value >= static_cast<float>(kPrimLongMax))
1797*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(kPrimLongMax);
1798*795d594fSAndroid Build Coastguard Worker if (value <= kPrimLongMin)
1799*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(kPrimLongMin);
1800*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(static_cast<int64_t>(value));
1801*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat64:
1802*795d594fSAndroid Build Coastguard Worker return graph->GetDoubleConstant(static_cast<double>(value));
1803*795d594fSAndroid Build Coastguard Worker default:
1804*795d594fSAndroid Build Coastguard Worker return nullptr;
1805*795d594fSAndroid Build Coastguard Worker }
1806*795d594fSAndroid Build Coastguard Worker } else if (input->IsDoubleConstant()) {
1807*795d594fSAndroid Build Coastguard Worker double value = input->AsDoubleConstant()->GetValue();
1808*795d594fSAndroid Build Coastguard Worker switch (GetResultType()) {
1809*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt32:
1810*795d594fSAndroid Build Coastguard Worker if (std::isnan(value))
1811*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(0);
1812*795d594fSAndroid Build Coastguard Worker if (value >= kPrimIntMax)
1813*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(kPrimIntMax);
1814*795d594fSAndroid Build Coastguard Worker if (value <= kPrimLongMin)
1815*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(kPrimIntMin);
1816*795d594fSAndroid Build Coastguard Worker return graph->GetIntConstant(static_cast<int32_t>(value));
1817*795d594fSAndroid Build Coastguard Worker case DataType::Type::kInt64:
1818*795d594fSAndroid Build Coastguard Worker if (std::isnan(value))
1819*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(0);
1820*795d594fSAndroid Build Coastguard Worker if (value >= static_cast<double>(kPrimLongMax))
1821*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(kPrimLongMax);
1822*795d594fSAndroid Build Coastguard Worker if (value <= kPrimLongMin)
1823*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(kPrimLongMin);
1824*795d594fSAndroid Build Coastguard Worker return graph->GetLongConstant(static_cast<int64_t>(value));
1825*795d594fSAndroid Build Coastguard Worker case DataType::Type::kFloat32:
1826*795d594fSAndroid Build Coastguard Worker return graph->GetFloatConstant(static_cast<float>(value));
1827*795d594fSAndroid Build Coastguard Worker default:
1828*795d594fSAndroid Build Coastguard Worker return nullptr;
1829*795d594fSAndroid Build Coastguard Worker }
1830*795d594fSAndroid Build Coastguard Worker }
1831*795d594fSAndroid Build Coastguard Worker return nullptr;
1832*795d594fSAndroid Build Coastguard Worker }
1833*795d594fSAndroid Build Coastguard Worker
TryStaticEvaluation() const1834*795d594fSAndroid Build Coastguard Worker HConstant* HUnaryOperation::TryStaticEvaluation() const { return TryStaticEvaluation(GetInput()); }
1835*795d594fSAndroid Build Coastguard Worker
TryStaticEvaluation(HInstruction * input) const1836*795d594fSAndroid Build Coastguard Worker HConstant* HUnaryOperation::TryStaticEvaluation(HInstruction* input) const {
1837*795d594fSAndroid Build Coastguard Worker if (input->IsIntConstant()) {
1838*795d594fSAndroid Build Coastguard Worker return Evaluate(input->AsIntConstant());
1839*795d594fSAndroid Build Coastguard Worker } else if (input->IsLongConstant()) {
1840*795d594fSAndroid Build Coastguard Worker return Evaluate(input->AsLongConstant());
1841*795d594fSAndroid Build Coastguard Worker } else if (kEnableFloatingPointStaticEvaluation) {
1842*795d594fSAndroid Build Coastguard Worker if (input->IsFloatConstant()) {
1843*795d594fSAndroid Build Coastguard Worker return Evaluate(input->AsFloatConstant());
1844*795d594fSAndroid Build Coastguard Worker } else if (input->IsDoubleConstant()) {
1845*795d594fSAndroid Build Coastguard Worker return Evaluate(input->AsDoubleConstant());
1846*795d594fSAndroid Build Coastguard Worker }
1847*795d594fSAndroid Build Coastguard Worker }
1848*795d594fSAndroid Build Coastguard Worker return nullptr;
1849*795d594fSAndroid Build Coastguard Worker }
1850*795d594fSAndroid Build Coastguard Worker
TryStaticEvaluation() const1851*795d594fSAndroid Build Coastguard Worker HConstant* HBinaryOperation::TryStaticEvaluation() const {
1852*795d594fSAndroid Build Coastguard Worker return TryStaticEvaluation(GetLeft(), GetRight());
1853*795d594fSAndroid Build Coastguard Worker }
1854*795d594fSAndroid Build Coastguard Worker
TryStaticEvaluation(HInstruction * left,HInstruction * right) const1855*795d594fSAndroid Build Coastguard Worker HConstant* HBinaryOperation::TryStaticEvaluation(HInstruction* left, HInstruction* right) const {
1856*795d594fSAndroid Build Coastguard Worker if (left->IsIntConstant() && right->IsIntConstant()) {
1857*795d594fSAndroid Build Coastguard Worker return Evaluate(left->AsIntConstant(), right->AsIntConstant());
1858*795d594fSAndroid Build Coastguard Worker } else if (left->IsLongConstant()) {
1859*795d594fSAndroid Build Coastguard Worker if (right->IsIntConstant()) {
1860*795d594fSAndroid Build Coastguard Worker // The binop(long, int) case is only valid for shifts and rotations.
1861*795d594fSAndroid Build Coastguard Worker DCHECK(IsShl() || IsShr() || IsUShr() || IsRol() || IsRor()) << DebugName();
1862*795d594fSAndroid Build Coastguard Worker return Evaluate(left->AsLongConstant(), right->AsIntConstant());
1863*795d594fSAndroid Build Coastguard Worker } else if (right->IsLongConstant()) {
1864*795d594fSAndroid Build Coastguard Worker return Evaluate(left->AsLongConstant(), right->AsLongConstant());
1865*795d594fSAndroid Build Coastguard Worker }
1866*795d594fSAndroid Build Coastguard Worker } else if (left->IsNullConstant() && right->IsNullConstant()) {
1867*795d594fSAndroid Build Coastguard Worker // The binop(null, null) case is only valid for equal and not-equal conditions.
1868*795d594fSAndroid Build Coastguard Worker DCHECK(IsEqual() || IsNotEqual()) << DebugName();
1869*795d594fSAndroid Build Coastguard Worker return Evaluate(left->AsNullConstant(), right->AsNullConstant());
1870*795d594fSAndroid Build Coastguard Worker } else if (kEnableFloatingPointStaticEvaluation) {
1871*795d594fSAndroid Build Coastguard Worker if (left->IsFloatConstant() && right->IsFloatConstant()) {
1872*795d594fSAndroid Build Coastguard Worker return Evaluate(left->AsFloatConstant(), right->AsFloatConstant());
1873*795d594fSAndroid Build Coastguard Worker } else if (left->IsDoubleConstant() && right->IsDoubleConstant()) {
1874*795d594fSAndroid Build Coastguard Worker return Evaluate(left->AsDoubleConstant(), right->AsDoubleConstant());
1875*795d594fSAndroid Build Coastguard Worker }
1876*795d594fSAndroid Build Coastguard Worker }
1877*795d594fSAndroid Build Coastguard Worker return nullptr;
1878*795d594fSAndroid Build Coastguard Worker }
1879*795d594fSAndroid Build Coastguard Worker
GetConstantRight() const1880*795d594fSAndroid Build Coastguard Worker HConstant* HBinaryOperation::GetConstantRight() const {
1881*795d594fSAndroid Build Coastguard Worker if (GetRight()->IsConstant()) {
1882*795d594fSAndroid Build Coastguard Worker return GetRight()->AsConstant();
1883*795d594fSAndroid Build Coastguard Worker } else if (IsCommutative() && GetLeft()->IsConstant()) {
1884*795d594fSAndroid Build Coastguard Worker return GetLeft()->AsConstant();
1885*795d594fSAndroid Build Coastguard Worker } else {
1886*795d594fSAndroid Build Coastguard Worker return nullptr;
1887*795d594fSAndroid Build Coastguard Worker }
1888*795d594fSAndroid Build Coastguard Worker }
1889*795d594fSAndroid Build Coastguard Worker
1890*795d594fSAndroid Build Coastguard Worker // If `GetConstantRight()` returns one of the input, this returns the other
1891*795d594fSAndroid Build Coastguard Worker // one. Otherwise it returns null.
GetLeastConstantLeft() const1892*795d594fSAndroid Build Coastguard Worker HInstruction* HBinaryOperation::GetLeastConstantLeft() const {
1893*795d594fSAndroid Build Coastguard Worker HInstruction* most_constant_right = GetConstantRight();
1894*795d594fSAndroid Build Coastguard Worker if (most_constant_right == nullptr) {
1895*795d594fSAndroid Build Coastguard Worker return nullptr;
1896*795d594fSAndroid Build Coastguard Worker } else if (most_constant_right == GetLeft()) {
1897*795d594fSAndroid Build Coastguard Worker return GetRight();
1898*795d594fSAndroid Build Coastguard Worker } else {
1899*795d594fSAndroid Build Coastguard Worker return GetLeft();
1900*795d594fSAndroid Build Coastguard Worker }
1901*795d594fSAndroid Build Coastguard Worker }
1902*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,ComparisonBias rhs)1903*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ComparisonBias rhs) {
1904*795d594fSAndroid Build Coastguard Worker // TODO: Replace with auto-generated operator<<.
1905*795d594fSAndroid Build Coastguard Worker switch (rhs) {
1906*795d594fSAndroid Build Coastguard Worker case ComparisonBias::kNoBias:
1907*795d594fSAndroid Build Coastguard Worker return os << "none";
1908*795d594fSAndroid Build Coastguard Worker case ComparisonBias::kGtBias:
1909*795d594fSAndroid Build Coastguard Worker return os << "gt";
1910*795d594fSAndroid Build Coastguard Worker case ComparisonBias::kLtBias:
1911*795d594fSAndroid Build Coastguard Worker return os << "lt";
1912*795d594fSAndroid Build Coastguard Worker }
1913*795d594fSAndroid Build Coastguard Worker }
1914*795d594fSAndroid Build Coastguard Worker
Create(HGraph * graph,IfCondition cond,HInstruction * lhs,HInstruction * rhs,uint32_t dex_pc)1915*795d594fSAndroid Build Coastguard Worker HCondition* HCondition::Create(HGraph* graph,
1916*795d594fSAndroid Build Coastguard Worker IfCondition cond,
1917*795d594fSAndroid Build Coastguard Worker HInstruction* lhs,
1918*795d594fSAndroid Build Coastguard Worker HInstruction* rhs,
1919*795d594fSAndroid Build Coastguard Worker uint32_t dex_pc) {
1920*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = graph->GetAllocator();
1921*795d594fSAndroid Build Coastguard Worker switch (cond) {
1922*795d594fSAndroid Build Coastguard Worker case kCondEQ: return new (allocator) HEqual(lhs, rhs, dex_pc);
1923*795d594fSAndroid Build Coastguard Worker case kCondNE: return new (allocator) HNotEqual(lhs, rhs, dex_pc);
1924*795d594fSAndroid Build Coastguard Worker case kCondLT: return new (allocator) HLessThan(lhs, rhs, dex_pc);
1925*795d594fSAndroid Build Coastguard Worker case kCondLE: return new (allocator) HLessThanOrEqual(lhs, rhs, dex_pc);
1926*795d594fSAndroid Build Coastguard Worker case kCondGT: return new (allocator) HGreaterThan(lhs, rhs, dex_pc);
1927*795d594fSAndroid Build Coastguard Worker case kCondGE: return new (allocator) HGreaterThanOrEqual(lhs, rhs, dex_pc);
1928*795d594fSAndroid Build Coastguard Worker case kCondB: return new (allocator) HBelow(lhs, rhs, dex_pc);
1929*795d594fSAndroid Build Coastguard Worker case kCondBE: return new (allocator) HBelowOrEqual(lhs, rhs, dex_pc);
1930*795d594fSAndroid Build Coastguard Worker case kCondA: return new (allocator) HAbove(lhs, rhs, dex_pc);
1931*795d594fSAndroid Build Coastguard Worker case kCondAE: return new (allocator) HAboveOrEqual(lhs, rhs, dex_pc);
1932*795d594fSAndroid Build Coastguard Worker default:
1933*795d594fSAndroid Build Coastguard Worker LOG(FATAL) << "Unexpected condition " << cond;
1934*795d594fSAndroid Build Coastguard Worker UNREACHABLE();
1935*795d594fSAndroid Build Coastguard Worker }
1936*795d594fSAndroid Build Coastguard Worker }
1937*795d594fSAndroid Build Coastguard Worker
IsBeforeWhenDisregardMoves(HInstruction * instruction) const1938*795d594fSAndroid Build Coastguard Worker bool HCondition::IsBeforeWhenDisregardMoves(HInstruction* instruction) const {
1939*795d594fSAndroid Build Coastguard Worker return this == instruction->GetPreviousDisregardingMoves();
1940*795d594fSAndroid Build Coastguard Worker }
1941*795d594fSAndroid Build Coastguard Worker
Equals(const HInstruction * other) const1942*795d594fSAndroid Build Coastguard Worker bool HInstruction::Equals(const HInstruction* other) const {
1943*795d594fSAndroid Build Coastguard Worker if (GetKind() != other->GetKind()) return false;
1944*795d594fSAndroid Build Coastguard Worker if (GetType() != other->GetType()) return false;
1945*795d594fSAndroid Build Coastguard Worker if (!InstructionDataEquals(other)) return false;
1946*795d594fSAndroid Build Coastguard Worker HConstInputsRef inputs = GetInputs();
1947*795d594fSAndroid Build Coastguard Worker HConstInputsRef other_inputs = other->GetInputs();
1948*795d594fSAndroid Build Coastguard Worker if (inputs.size() != other_inputs.size()) return false;
1949*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i != inputs.size(); ++i) {
1950*795d594fSAndroid Build Coastguard Worker if (inputs[i] != other_inputs[i]) return false;
1951*795d594fSAndroid Build Coastguard Worker }
1952*795d594fSAndroid Build Coastguard Worker
1953*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(ComputeHashCode(), other->ComputeHashCode());
1954*795d594fSAndroid Build Coastguard Worker return true;
1955*795d594fSAndroid Build Coastguard Worker }
1956*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,HInstruction::InstructionKind rhs)1957*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, HInstruction::InstructionKind rhs) {
1958*795d594fSAndroid Build Coastguard Worker #define DECLARE_CASE(type, super) case HInstruction::k##type: os << #type; break;
1959*795d594fSAndroid Build Coastguard Worker switch (rhs) {
1960*795d594fSAndroid Build Coastguard Worker FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_CASE)
1961*795d594fSAndroid Build Coastguard Worker default:
1962*795d594fSAndroid Build Coastguard Worker os << "Unknown instruction kind " << static_cast<int>(rhs);
1963*795d594fSAndroid Build Coastguard Worker break;
1964*795d594fSAndroid Build Coastguard Worker }
1965*795d594fSAndroid Build Coastguard Worker #undef DECLARE_CASE
1966*795d594fSAndroid Build Coastguard Worker return os;
1967*795d594fSAndroid Build Coastguard Worker }
1968*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const HInstruction::NoArgsDump rhs)1969*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const HInstruction::NoArgsDump rhs) {
1970*795d594fSAndroid Build Coastguard Worker // TODO Really this should be const but that would require const-ifying
1971*795d594fSAndroid Build Coastguard Worker // graph-visualizer and HGraphVisitor which are tangled up everywhere.
1972*795d594fSAndroid Build Coastguard Worker return const_cast<HInstruction*>(rhs.ins)->Dump(os, /* dump_args= */ false);
1973*795d594fSAndroid Build Coastguard Worker }
1974*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const HInstruction::ArgsDump rhs)1975*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const HInstruction::ArgsDump rhs) {
1976*795d594fSAndroid Build Coastguard Worker // TODO Really this should be const but that would require const-ifying
1977*795d594fSAndroid Build Coastguard Worker // graph-visualizer and HGraphVisitor which are tangled up everywhere.
1978*795d594fSAndroid Build Coastguard Worker return const_cast<HInstruction*>(rhs.ins)->Dump(os, /* dump_args= */ true);
1979*795d594fSAndroid Build Coastguard Worker }
1980*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const HInstruction & rhs)1981*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const HInstruction& rhs) {
1982*795d594fSAndroid Build Coastguard Worker return os << rhs.DumpWithoutArgs();
1983*795d594fSAndroid Build Coastguard Worker }
1984*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const HUseList<HInstruction * > & lst)1985*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const HUseList<HInstruction*>& lst) {
1986*795d594fSAndroid Build Coastguard Worker os << "Instructions[";
1987*795d594fSAndroid Build Coastguard Worker bool first = true;
1988*795d594fSAndroid Build Coastguard Worker for (const auto& hi : lst) {
1989*795d594fSAndroid Build Coastguard Worker if (!first) {
1990*795d594fSAndroid Build Coastguard Worker os << ", ";
1991*795d594fSAndroid Build Coastguard Worker }
1992*795d594fSAndroid Build Coastguard Worker first = false;
1993*795d594fSAndroid Build Coastguard Worker os << hi.GetUser()->DebugName() << "[id: " << hi.GetUser()->GetId()
1994*795d594fSAndroid Build Coastguard Worker << ", blk: " << hi.GetUser()->GetBlock()->GetBlockId() << "]@" << hi.GetIndex();
1995*795d594fSAndroid Build Coastguard Worker }
1996*795d594fSAndroid Build Coastguard Worker os << "]";
1997*795d594fSAndroid Build Coastguard Worker return os;
1998*795d594fSAndroid Build Coastguard Worker }
1999*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const HUseList<HEnvironment * > & lst)2000*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const HUseList<HEnvironment*>& lst) {
2001*795d594fSAndroid Build Coastguard Worker os << "Environments[";
2002*795d594fSAndroid Build Coastguard Worker bool first = true;
2003*795d594fSAndroid Build Coastguard Worker for (const auto& hi : lst) {
2004*795d594fSAndroid Build Coastguard Worker if (!first) {
2005*795d594fSAndroid Build Coastguard Worker os << ", ";
2006*795d594fSAndroid Build Coastguard Worker }
2007*795d594fSAndroid Build Coastguard Worker first = false;
2008*795d594fSAndroid Build Coastguard Worker os << *hi.GetUser()->GetHolder() << "@" << hi.GetIndex();
2009*795d594fSAndroid Build Coastguard Worker }
2010*795d594fSAndroid Build Coastguard Worker os << "]";
2011*795d594fSAndroid Build Coastguard Worker return os;
2012*795d594fSAndroid Build Coastguard Worker }
2013*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os,CodeGenerator * codegen,std::optional<std::reference_wrapper<const BlockNamer>> namer)2014*795d594fSAndroid Build Coastguard Worker std::ostream& HGraph::Dump(std::ostream& os,
2015*795d594fSAndroid Build Coastguard Worker CodeGenerator* codegen,
2016*795d594fSAndroid Build Coastguard Worker std::optional<std::reference_wrapper<const BlockNamer>> namer) {
2017*795d594fSAndroid Build Coastguard Worker HGraphVisualizer vis(&os, this, codegen, namer);
2018*795d594fSAndroid Build Coastguard Worker vis.DumpGraphDebug();
2019*795d594fSAndroid Build Coastguard Worker return os;
2020*795d594fSAndroid Build Coastguard Worker }
2021*795d594fSAndroid Build Coastguard Worker
MoveBefore(HInstruction * cursor,bool do_checks)2022*795d594fSAndroid Build Coastguard Worker void HInstruction::MoveBefore(HInstruction* cursor, bool do_checks) {
2023*795d594fSAndroid Build Coastguard Worker if (do_checks) {
2024*795d594fSAndroid Build Coastguard Worker DCHECK(!IsPhi());
2025*795d594fSAndroid Build Coastguard Worker DCHECK(!IsControlFlow());
2026*795d594fSAndroid Build Coastguard Worker DCHECK(CanBeMoved() ||
2027*795d594fSAndroid Build Coastguard Worker // HShouldDeoptimizeFlag can only be moved by CHAGuardOptimization.
2028*795d594fSAndroid Build Coastguard Worker IsShouldDeoptimizeFlag());
2029*795d594fSAndroid Build Coastguard Worker DCHECK(!cursor->IsPhi());
2030*795d594fSAndroid Build Coastguard Worker }
2031*795d594fSAndroid Build Coastguard Worker
2032*795d594fSAndroid Build Coastguard Worker next_->previous_ = previous_;
2033*795d594fSAndroid Build Coastguard Worker if (previous_ != nullptr) {
2034*795d594fSAndroid Build Coastguard Worker previous_->next_ = next_;
2035*795d594fSAndroid Build Coastguard Worker }
2036*795d594fSAndroid Build Coastguard Worker if (block_->instructions_.first_instruction_ == this) {
2037*795d594fSAndroid Build Coastguard Worker block_->instructions_.first_instruction_ = next_;
2038*795d594fSAndroid Build Coastguard Worker }
2039*795d594fSAndroid Build Coastguard Worker DCHECK_NE(block_->instructions_.last_instruction_, this);
2040*795d594fSAndroid Build Coastguard Worker
2041*795d594fSAndroid Build Coastguard Worker previous_ = cursor->previous_;
2042*795d594fSAndroid Build Coastguard Worker if (previous_ != nullptr) {
2043*795d594fSAndroid Build Coastguard Worker previous_->next_ = this;
2044*795d594fSAndroid Build Coastguard Worker }
2045*795d594fSAndroid Build Coastguard Worker next_ = cursor;
2046*795d594fSAndroid Build Coastguard Worker cursor->previous_ = this;
2047*795d594fSAndroid Build Coastguard Worker block_ = cursor->block_;
2048*795d594fSAndroid Build Coastguard Worker
2049*795d594fSAndroid Build Coastguard Worker if (block_->instructions_.first_instruction_ == cursor) {
2050*795d594fSAndroid Build Coastguard Worker block_->instructions_.first_instruction_ = this;
2051*795d594fSAndroid Build Coastguard Worker }
2052*795d594fSAndroid Build Coastguard Worker }
2053*795d594fSAndroid Build Coastguard Worker
MoveBeforeFirstUserAndOutOfLoops()2054*795d594fSAndroid Build Coastguard Worker void HInstruction::MoveBeforeFirstUserAndOutOfLoops() {
2055*795d594fSAndroid Build Coastguard Worker DCHECK(!CanThrow());
2056*795d594fSAndroid Build Coastguard Worker DCHECK(!HasSideEffects());
2057*795d594fSAndroid Build Coastguard Worker DCHECK(!HasEnvironmentUses());
2058*795d594fSAndroid Build Coastguard Worker DCHECK(HasNonEnvironmentUses());
2059*795d594fSAndroid Build Coastguard Worker DCHECK(!IsPhi()); // Makes no sense for Phi.
2060*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(InputCount(), 0u);
2061*795d594fSAndroid Build Coastguard Worker
2062*795d594fSAndroid Build Coastguard Worker // Find the target block.
2063*795d594fSAndroid Build Coastguard Worker auto uses_it = GetUses().begin();
2064*795d594fSAndroid Build Coastguard Worker auto uses_end = GetUses().end();
2065*795d594fSAndroid Build Coastguard Worker HBasicBlock* target_block = uses_it->GetUser()->GetBlock();
2066*795d594fSAndroid Build Coastguard Worker ++uses_it;
2067*795d594fSAndroid Build Coastguard Worker while (uses_it != uses_end && uses_it->GetUser()->GetBlock() == target_block) {
2068*795d594fSAndroid Build Coastguard Worker ++uses_it;
2069*795d594fSAndroid Build Coastguard Worker }
2070*795d594fSAndroid Build Coastguard Worker if (uses_it != uses_end) {
2071*795d594fSAndroid Build Coastguard Worker // This instruction has uses in two or more blocks. Find the common dominator.
2072*795d594fSAndroid Build Coastguard Worker CommonDominator finder(target_block);
2073*795d594fSAndroid Build Coastguard Worker for (; uses_it != uses_end; ++uses_it) {
2074*795d594fSAndroid Build Coastguard Worker finder.Update(uses_it->GetUser()->GetBlock());
2075*795d594fSAndroid Build Coastguard Worker }
2076*795d594fSAndroid Build Coastguard Worker target_block = finder.Get();
2077*795d594fSAndroid Build Coastguard Worker DCHECK(target_block != nullptr);
2078*795d594fSAndroid Build Coastguard Worker }
2079*795d594fSAndroid Build Coastguard Worker // Move to the first dominator not in a loop.
2080*795d594fSAndroid Build Coastguard Worker while (target_block->IsInLoop()) {
2081*795d594fSAndroid Build Coastguard Worker target_block = target_block->GetDominator();
2082*795d594fSAndroid Build Coastguard Worker DCHECK(target_block != nullptr);
2083*795d594fSAndroid Build Coastguard Worker }
2084*795d594fSAndroid Build Coastguard Worker
2085*795d594fSAndroid Build Coastguard Worker // Find insertion position.
2086*795d594fSAndroid Build Coastguard Worker HInstruction* insert_pos = nullptr;
2087*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HInstruction*>& use : GetUses()) {
2088*795d594fSAndroid Build Coastguard Worker if (use.GetUser()->GetBlock() == target_block &&
2089*795d594fSAndroid Build Coastguard Worker (insert_pos == nullptr || use.GetUser()->StrictlyDominates(insert_pos))) {
2090*795d594fSAndroid Build Coastguard Worker insert_pos = use.GetUser();
2091*795d594fSAndroid Build Coastguard Worker }
2092*795d594fSAndroid Build Coastguard Worker }
2093*795d594fSAndroid Build Coastguard Worker if (insert_pos == nullptr) {
2094*795d594fSAndroid Build Coastguard Worker // No user in `target_block`, insert before the control flow instruction.
2095*795d594fSAndroid Build Coastguard Worker insert_pos = target_block->GetLastInstruction();
2096*795d594fSAndroid Build Coastguard Worker DCHECK(insert_pos->IsControlFlow());
2097*795d594fSAndroid Build Coastguard Worker // Avoid splitting HCondition from HIf to prevent unnecessary materialization.
2098*795d594fSAndroid Build Coastguard Worker if (insert_pos->IsIf()) {
2099*795d594fSAndroid Build Coastguard Worker HInstruction* if_input = insert_pos->AsIf()->InputAt(0);
2100*795d594fSAndroid Build Coastguard Worker if (if_input == insert_pos->GetPrevious()) {
2101*795d594fSAndroid Build Coastguard Worker insert_pos = if_input;
2102*795d594fSAndroid Build Coastguard Worker }
2103*795d594fSAndroid Build Coastguard Worker }
2104*795d594fSAndroid Build Coastguard Worker }
2105*795d594fSAndroid Build Coastguard Worker MoveBefore(insert_pos);
2106*795d594fSAndroid Build Coastguard Worker }
2107*795d594fSAndroid Build Coastguard Worker
SplitBefore(HInstruction * cursor,bool require_graph_not_in_ssa_form)2108*795d594fSAndroid Build Coastguard Worker HBasicBlock* HBasicBlock::SplitBefore(HInstruction* cursor, bool require_graph_not_in_ssa_form) {
2109*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(require_graph_not_in_ssa_form, !graph_->IsInSsaForm())
2110*795d594fSAndroid Build Coastguard Worker << "Support for SSA form not implemented.";
2111*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cursor->GetBlock(), this);
2112*795d594fSAndroid Build Coastguard Worker
2113*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block =
2114*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), cursor->GetDexPc());
2115*795d594fSAndroid Build Coastguard Worker new_block->instructions_.first_instruction_ = cursor;
2116*795d594fSAndroid Build Coastguard Worker new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
2117*795d594fSAndroid Build Coastguard Worker instructions_.last_instruction_ = cursor->previous_;
2118*795d594fSAndroid Build Coastguard Worker if (cursor->previous_ == nullptr) {
2119*795d594fSAndroid Build Coastguard Worker instructions_.first_instruction_ = nullptr;
2120*795d594fSAndroid Build Coastguard Worker } else {
2121*795d594fSAndroid Build Coastguard Worker cursor->previous_->next_ = nullptr;
2122*795d594fSAndroid Build Coastguard Worker cursor->previous_ = nullptr;
2123*795d594fSAndroid Build Coastguard Worker }
2124*795d594fSAndroid Build Coastguard Worker
2125*795d594fSAndroid Build Coastguard Worker new_block->instructions_.SetBlockOfInstructions(new_block);
2126*795d594fSAndroid Build Coastguard Worker AddInstruction(new (GetGraph()->GetAllocator()) HGoto(new_block->GetDexPc()));
2127*795d594fSAndroid Build Coastguard Worker
2128*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : GetSuccessors()) {
2129*795d594fSAndroid Build Coastguard Worker successor->predecessors_[successor->GetPredecessorIndexOf(this)] = new_block;
2130*795d594fSAndroid Build Coastguard Worker }
2131*795d594fSAndroid Build Coastguard Worker new_block->successors_.swap(successors_);
2132*795d594fSAndroid Build Coastguard Worker DCHECK(successors_.empty());
2133*795d594fSAndroid Build Coastguard Worker AddSuccessor(new_block);
2134*795d594fSAndroid Build Coastguard Worker
2135*795d594fSAndroid Build Coastguard Worker GetGraph()->AddBlock(new_block);
2136*795d594fSAndroid Build Coastguard Worker return new_block;
2137*795d594fSAndroid Build Coastguard Worker }
2138*795d594fSAndroid Build Coastguard Worker
CreateImmediateDominator()2139*795d594fSAndroid Build Coastguard Worker HBasicBlock* HBasicBlock::CreateImmediateDominator() {
2140*795d594fSAndroid Build Coastguard Worker DCHECK(!graph_->IsInSsaForm()) << "Support for SSA form not implemented.";
2141*795d594fSAndroid Build Coastguard Worker DCHECK(!IsCatchBlock()) << "Support for updating try/catch information not implemented.";
2142*795d594fSAndroid Build Coastguard Worker
2143*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block = new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), GetDexPc());
2144*795d594fSAndroid Build Coastguard Worker
2145*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : GetPredecessors()) {
2146*795d594fSAndroid Build Coastguard Worker predecessor->successors_[predecessor->GetSuccessorIndexOf(this)] = new_block;
2147*795d594fSAndroid Build Coastguard Worker }
2148*795d594fSAndroid Build Coastguard Worker new_block->predecessors_.swap(predecessors_);
2149*795d594fSAndroid Build Coastguard Worker DCHECK(predecessors_.empty());
2150*795d594fSAndroid Build Coastguard Worker AddPredecessor(new_block);
2151*795d594fSAndroid Build Coastguard Worker
2152*795d594fSAndroid Build Coastguard Worker GetGraph()->AddBlock(new_block);
2153*795d594fSAndroid Build Coastguard Worker return new_block;
2154*795d594fSAndroid Build Coastguard Worker }
2155*795d594fSAndroid Build Coastguard Worker
SplitBeforeForInlining(HInstruction * cursor)2156*795d594fSAndroid Build Coastguard Worker HBasicBlock* HBasicBlock::SplitBeforeForInlining(HInstruction* cursor) {
2157*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cursor->GetBlock(), this);
2158*795d594fSAndroid Build Coastguard Worker
2159*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block =
2160*795d594fSAndroid Build Coastguard Worker new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), cursor->GetDexPc());
2161*795d594fSAndroid Build Coastguard Worker new_block->instructions_.first_instruction_ = cursor;
2162*795d594fSAndroid Build Coastguard Worker new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
2163*795d594fSAndroid Build Coastguard Worker instructions_.last_instruction_ = cursor->previous_;
2164*795d594fSAndroid Build Coastguard Worker if (cursor->previous_ == nullptr) {
2165*795d594fSAndroid Build Coastguard Worker instructions_.first_instruction_ = nullptr;
2166*795d594fSAndroid Build Coastguard Worker } else {
2167*795d594fSAndroid Build Coastguard Worker cursor->previous_->next_ = nullptr;
2168*795d594fSAndroid Build Coastguard Worker cursor->previous_ = nullptr;
2169*795d594fSAndroid Build Coastguard Worker }
2170*795d594fSAndroid Build Coastguard Worker
2171*795d594fSAndroid Build Coastguard Worker new_block->instructions_.SetBlockOfInstructions(new_block);
2172*795d594fSAndroid Build Coastguard Worker
2173*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : GetSuccessors()) {
2174*795d594fSAndroid Build Coastguard Worker successor->predecessors_[successor->GetPredecessorIndexOf(this)] = new_block;
2175*795d594fSAndroid Build Coastguard Worker }
2176*795d594fSAndroid Build Coastguard Worker new_block->successors_.swap(successors_);
2177*795d594fSAndroid Build Coastguard Worker DCHECK(successors_.empty());
2178*795d594fSAndroid Build Coastguard Worker
2179*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* dominated : GetDominatedBlocks()) {
2180*795d594fSAndroid Build Coastguard Worker dominated->dominator_ = new_block;
2181*795d594fSAndroid Build Coastguard Worker }
2182*795d594fSAndroid Build Coastguard Worker new_block->dominated_blocks_.swap(dominated_blocks_);
2183*795d594fSAndroid Build Coastguard Worker DCHECK(dominated_blocks_.empty());
2184*795d594fSAndroid Build Coastguard Worker return new_block;
2185*795d594fSAndroid Build Coastguard Worker }
2186*795d594fSAndroid Build Coastguard Worker
SplitAfterForInlining(HInstruction * cursor)2187*795d594fSAndroid Build Coastguard Worker HBasicBlock* HBasicBlock::SplitAfterForInlining(HInstruction* cursor) {
2188*795d594fSAndroid Build Coastguard Worker DCHECK(!cursor->IsControlFlow());
2189*795d594fSAndroid Build Coastguard Worker DCHECK_NE(instructions_.last_instruction_, cursor);
2190*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(cursor->GetBlock(), this);
2191*795d594fSAndroid Build Coastguard Worker
2192*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block = new (GetGraph()->GetAllocator()) HBasicBlock(GetGraph(), GetDexPc());
2193*795d594fSAndroid Build Coastguard Worker new_block->instructions_.first_instruction_ = cursor->GetNext();
2194*795d594fSAndroid Build Coastguard Worker new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
2195*795d594fSAndroid Build Coastguard Worker cursor->next_->previous_ = nullptr;
2196*795d594fSAndroid Build Coastguard Worker cursor->next_ = nullptr;
2197*795d594fSAndroid Build Coastguard Worker instructions_.last_instruction_ = cursor;
2198*795d594fSAndroid Build Coastguard Worker
2199*795d594fSAndroid Build Coastguard Worker new_block->instructions_.SetBlockOfInstructions(new_block);
2200*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : GetSuccessors()) {
2201*795d594fSAndroid Build Coastguard Worker successor->predecessors_[successor->GetPredecessorIndexOf(this)] = new_block;
2202*795d594fSAndroid Build Coastguard Worker }
2203*795d594fSAndroid Build Coastguard Worker new_block->successors_.swap(successors_);
2204*795d594fSAndroid Build Coastguard Worker DCHECK(successors_.empty());
2205*795d594fSAndroid Build Coastguard Worker
2206*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* dominated : GetDominatedBlocks()) {
2207*795d594fSAndroid Build Coastguard Worker dominated->dominator_ = new_block;
2208*795d594fSAndroid Build Coastguard Worker }
2209*795d594fSAndroid Build Coastguard Worker new_block->dominated_blocks_.swap(dominated_blocks_);
2210*795d594fSAndroid Build Coastguard Worker DCHECK(dominated_blocks_.empty());
2211*795d594fSAndroid Build Coastguard Worker return new_block;
2212*795d594fSAndroid Build Coastguard Worker }
2213*795d594fSAndroid Build Coastguard Worker
ComputeTryEntryOfSuccessors() const2214*795d594fSAndroid Build Coastguard Worker const HTryBoundary* HBasicBlock::ComputeTryEntryOfSuccessors() const {
2215*795d594fSAndroid Build Coastguard Worker if (EndsWithTryBoundary()) {
2216*795d594fSAndroid Build Coastguard Worker HTryBoundary* try_boundary = GetLastInstruction()->AsTryBoundary();
2217*795d594fSAndroid Build Coastguard Worker if (try_boundary->IsEntry()) {
2218*795d594fSAndroid Build Coastguard Worker DCHECK(!IsTryBlock());
2219*795d594fSAndroid Build Coastguard Worker return try_boundary;
2220*795d594fSAndroid Build Coastguard Worker } else {
2221*795d594fSAndroid Build Coastguard Worker DCHECK(IsTryBlock());
2222*795d594fSAndroid Build Coastguard Worker DCHECK(try_catch_information_->GetTryEntry().HasSameExceptionHandlersAs(*try_boundary));
2223*795d594fSAndroid Build Coastguard Worker return nullptr;
2224*795d594fSAndroid Build Coastguard Worker }
2225*795d594fSAndroid Build Coastguard Worker } else if (IsTryBlock()) {
2226*795d594fSAndroid Build Coastguard Worker return &try_catch_information_->GetTryEntry();
2227*795d594fSAndroid Build Coastguard Worker } else {
2228*795d594fSAndroid Build Coastguard Worker return nullptr;
2229*795d594fSAndroid Build Coastguard Worker }
2230*795d594fSAndroid Build Coastguard Worker }
2231*795d594fSAndroid Build Coastguard Worker
HasThrowingInstructions() const2232*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::HasThrowingInstructions() const {
2233*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(GetInstructions()); !it.Done(); it.Advance()) {
2234*795d594fSAndroid Build Coastguard Worker if (it.Current()->CanThrow()) {
2235*795d594fSAndroid Build Coastguard Worker return true;
2236*795d594fSAndroid Build Coastguard Worker }
2237*795d594fSAndroid Build Coastguard Worker }
2238*795d594fSAndroid Build Coastguard Worker return false;
2239*795d594fSAndroid Build Coastguard Worker }
2240*795d594fSAndroid Build Coastguard Worker
HasOnlyOneInstruction(const HBasicBlock & block)2241*795d594fSAndroid Build Coastguard Worker static bool HasOnlyOneInstruction(const HBasicBlock& block) {
2242*795d594fSAndroid Build Coastguard Worker return block.GetPhis().IsEmpty()
2243*795d594fSAndroid Build Coastguard Worker && !block.GetInstructions().IsEmpty()
2244*795d594fSAndroid Build Coastguard Worker && block.GetFirstInstruction() == block.GetLastInstruction();
2245*795d594fSAndroid Build Coastguard Worker }
2246*795d594fSAndroid Build Coastguard Worker
IsSingleGoto() const2247*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::IsSingleGoto() const {
2248*795d594fSAndroid Build Coastguard Worker return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsGoto();
2249*795d594fSAndroid Build Coastguard Worker }
2250*795d594fSAndroid Build Coastguard Worker
IsSingleReturn() const2251*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::IsSingleReturn() const {
2252*795d594fSAndroid Build Coastguard Worker return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsReturn();
2253*795d594fSAndroid Build Coastguard Worker }
2254*795d594fSAndroid Build Coastguard Worker
IsSingleReturnOrReturnVoidAllowingPhis() const2255*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::IsSingleReturnOrReturnVoidAllowingPhis() const {
2256*795d594fSAndroid Build Coastguard Worker return (GetFirstInstruction() == GetLastInstruction()) &&
2257*795d594fSAndroid Build Coastguard Worker (GetLastInstruction()->IsReturn() || GetLastInstruction()->IsReturnVoid());
2258*795d594fSAndroid Build Coastguard Worker }
2259*795d594fSAndroid Build Coastguard Worker
IsSingleTryBoundary() const2260*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::IsSingleTryBoundary() const {
2261*795d594fSAndroid Build Coastguard Worker return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsTryBoundary();
2262*795d594fSAndroid Build Coastguard Worker }
2263*795d594fSAndroid Build Coastguard Worker
EndsWithControlFlowInstruction() const2264*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::EndsWithControlFlowInstruction() const {
2265*795d594fSAndroid Build Coastguard Worker return !GetInstructions().IsEmpty() && GetLastInstruction()->IsControlFlow();
2266*795d594fSAndroid Build Coastguard Worker }
2267*795d594fSAndroid Build Coastguard Worker
EndsWithReturn() const2268*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::EndsWithReturn() const {
2269*795d594fSAndroid Build Coastguard Worker return !GetInstructions().IsEmpty() &&
2270*795d594fSAndroid Build Coastguard Worker (GetLastInstruction()->IsReturn() || GetLastInstruction()->IsReturnVoid());
2271*795d594fSAndroid Build Coastguard Worker }
2272*795d594fSAndroid Build Coastguard Worker
EndsWithIf() const2273*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::EndsWithIf() const {
2274*795d594fSAndroid Build Coastguard Worker return !GetInstructions().IsEmpty() && GetLastInstruction()->IsIf();
2275*795d594fSAndroid Build Coastguard Worker }
2276*795d594fSAndroid Build Coastguard Worker
EndsWithTryBoundary() const2277*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::EndsWithTryBoundary() const {
2278*795d594fSAndroid Build Coastguard Worker return !GetInstructions().IsEmpty() && GetLastInstruction()->IsTryBoundary();
2279*795d594fSAndroid Build Coastguard Worker }
2280*795d594fSAndroid Build Coastguard Worker
HasSinglePhi() const2281*795d594fSAndroid Build Coastguard Worker bool HBasicBlock::HasSinglePhi() const {
2282*795d594fSAndroid Build Coastguard Worker return !GetPhis().IsEmpty() && GetFirstPhi()->GetNext() == nullptr;
2283*795d594fSAndroid Build Coastguard Worker }
2284*795d594fSAndroid Build Coastguard Worker
GetNormalSuccessors() const2285*795d594fSAndroid Build Coastguard Worker ArrayRef<HBasicBlock* const> HBasicBlock::GetNormalSuccessors() const {
2286*795d594fSAndroid Build Coastguard Worker if (EndsWithTryBoundary()) {
2287*795d594fSAndroid Build Coastguard Worker // The normal-flow successor of HTryBoundary is always stored at index zero.
2288*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(successors_[0], GetLastInstruction()->AsTryBoundary()->GetNormalFlowSuccessor());
2289*795d594fSAndroid Build Coastguard Worker return ArrayRef<HBasicBlock* const>(successors_).SubArray(0u, 1u);
2290*795d594fSAndroid Build Coastguard Worker } else {
2291*795d594fSAndroid Build Coastguard Worker // All successors of blocks not ending with TryBoundary are normal.
2292*795d594fSAndroid Build Coastguard Worker return ArrayRef<HBasicBlock* const>(successors_);
2293*795d594fSAndroid Build Coastguard Worker }
2294*795d594fSAndroid Build Coastguard Worker }
2295*795d594fSAndroid Build Coastguard Worker
GetExceptionalSuccessors() const2296*795d594fSAndroid Build Coastguard Worker ArrayRef<HBasicBlock* const> HBasicBlock::GetExceptionalSuccessors() const {
2297*795d594fSAndroid Build Coastguard Worker if (EndsWithTryBoundary()) {
2298*795d594fSAndroid Build Coastguard Worker return GetLastInstruction()->AsTryBoundary()->GetExceptionHandlers();
2299*795d594fSAndroid Build Coastguard Worker } else {
2300*795d594fSAndroid Build Coastguard Worker // Blocks not ending with TryBoundary do not have exceptional successors.
2301*795d594fSAndroid Build Coastguard Worker return ArrayRef<HBasicBlock* const>();
2302*795d594fSAndroid Build Coastguard Worker }
2303*795d594fSAndroid Build Coastguard Worker }
2304*795d594fSAndroid Build Coastguard Worker
HasSameExceptionHandlersAs(const HTryBoundary & other) const2305*795d594fSAndroid Build Coastguard Worker bool HTryBoundary::HasSameExceptionHandlersAs(const HTryBoundary& other) const {
2306*795d594fSAndroid Build Coastguard Worker ArrayRef<HBasicBlock* const> handlers1 = GetExceptionHandlers();
2307*795d594fSAndroid Build Coastguard Worker ArrayRef<HBasicBlock* const> handlers2 = other.GetExceptionHandlers();
2308*795d594fSAndroid Build Coastguard Worker
2309*795d594fSAndroid Build Coastguard Worker size_t length = handlers1.size();
2310*795d594fSAndroid Build Coastguard Worker if (length != handlers2.size()) {
2311*795d594fSAndroid Build Coastguard Worker return false;
2312*795d594fSAndroid Build Coastguard Worker }
2313*795d594fSAndroid Build Coastguard Worker
2314*795d594fSAndroid Build Coastguard Worker // Exception handlers need to be stored in the same order.
2315*795d594fSAndroid Build Coastguard Worker for (size_t i = 0; i < length; ++i) {
2316*795d594fSAndroid Build Coastguard Worker if (handlers1[i] != handlers2[i]) {
2317*795d594fSAndroid Build Coastguard Worker return false;
2318*795d594fSAndroid Build Coastguard Worker }
2319*795d594fSAndroid Build Coastguard Worker }
2320*795d594fSAndroid Build Coastguard Worker return true;
2321*795d594fSAndroid Build Coastguard Worker }
2322*795d594fSAndroid Build Coastguard Worker
CountSize() const2323*795d594fSAndroid Build Coastguard Worker size_t HInstructionList::CountSize() const {
2324*795d594fSAndroid Build Coastguard Worker size_t size = 0;
2325*795d594fSAndroid Build Coastguard Worker HInstruction* current = first_instruction_;
2326*795d594fSAndroid Build Coastguard Worker for (; current != nullptr; current = current->GetNext()) {
2327*795d594fSAndroid Build Coastguard Worker size++;
2328*795d594fSAndroid Build Coastguard Worker }
2329*795d594fSAndroid Build Coastguard Worker return size;
2330*795d594fSAndroid Build Coastguard Worker }
2331*795d594fSAndroid Build Coastguard Worker
SetBlockOfInstructions(HBasicBlock * block) const2332*795d594fSAndroid Build Coastguard Worker void HInstructionList::SetBlockOfInstructions(HBasicBlock* block) const {
2333*795d594fSAndroid Build Coastguard Worker for (HInstruction* current = first_instruction_;
2334*795d594fSAndroid Build Coastguard Worker current != nullptr;
2335*795d594fSAndroid Build Coastguard Worker current = current->GetNext()) {
2336*795d594fSAndroid Build Coastguard Worker current->SetBlock(block);
2337*795d594fSAndroid Build Coastguard Worker }
2338*795d594fSAndroid Build Coastguard Worker }
2339*795d594fSAndroid Build Coastguard Worker
AddAfter(HInstruction * cursor,const HInstructionList & instruction_list)2340*795d594fSAndroid Build Coastguard Worker void HInstructionList::AddAfter(HInstruction* cursor, const HInstructionList& instruction_list) {
2341*795d594fSAndroid Build Coastguard Worker DCHECK(Contains(cursor));
2342*795d594fSAndroid Build Coastguard Worker if (!instruction_list.IsEmpty()) {
2343*795d594fSAndroid Build Coastguard Worker if (cursor == last_instruction_) {
2344*795d594fSAndroid Build Coastguard Worker last_instruction_ = instruction_list.last_instruction_;
2345*795d594fSAndroid Build Coastguard Worker } else {
2346*795d594fSAndroid Build Coastguard Worker cursor->next_->previous_ = instruction_list.last_instruction_;
2347*795d594fSAndroid Build Coastguard Worker }
2348*795d594fSAndroid Build Coastguard Worker instruction_list.last_instruction_->next_ = cursor->next_;
2349*795d594fSAndroid Build Coastguard Worker cursor->next_ = instruction_list.first_instruction_;
2350*795d594fSAndroid Build Coastguard Worker instruction_list.first_instruction_->previous_ = cursor;
2351*795d594fSAndroid Build Coastguard Worker }
2352*795d594fSAndroid Build Coastguard Worker }
2353*795d594fSAndroid Build Coastguard Worker
AddBefore(HInstruction * cursor,const HInstructionList & instruction_list)2354*795d594fSAndroid Build Coastguard Worker void HInstructionList::AddBefore(HInstruction* cursor, const HInstructionList& instruction_list) {
2355*795d594fSAndroid Build Coastguard Worker DCHECK(Contains(cursor));
2356*795d594fSAndroid Build Coastguard Worker if (!instruction_list.IsEmpty()) {
2357*795d594fSAndroid Build Coastguard Worker if (cursor == first_instruction_) {
2358*795d594fSAndroid Build Coastguard Worker first_instruction_ = instruction_list.first_instruction_;
2359*795d594fSAndroid Build Coastguard Worker } else {
2360*795d594fSAndroid Build Coastguard Worker cursor->previous_->next_ = instruction_list.first_instruction_;
2361*795d594fSAndroid Build Coastguard Worker }
2362*795d594fSAndroid Build Coastguard Worker instruction_list.last_instruction_->next_ = cursor;
2363*795d594fSAndroid Build Coastguard Worker instruction_list.first_instruction_->previous_ = cursor->previous_;
2364*795d594fSAndroid Build Coastguard Worker cursor->previous_ = instruction_list.last_instruction_;
2365*795d594fSAndroid Build Coastguard Worker }
2366*795d594fSAndroid Build Coastguard Worker }
2367*795d594fSAndroid Build Coastguard Worker
Add(const HInstructionList & instruction_list)2368*795d594fSAndroid Build Coastguard Worker void HInstructionList::Add(const HInstructionList& instruction_list) {
2369*795d594fSAndroid Build Coastguard Worker if (IsEmpty()) {
2370*795d594fSAndroid Build Coastguard Worker first_instruction_ = instruction_list.first_instruction_;
2371*795d594fSAndroid Build Coastguard Worker last_instruction_ = instruction_list.last_instruction_;
2372*795d594fSAndroid Build Coastguard Worker } else {
2373*795d594fSAndroid Build Coastguard Worker AddAfter(last_instruction_, instruction_list);
2374*795d594fSAndroid Build Coastguard Worker }
2375*795d594fSAndroid Build Coastguard Worker }
2376*795d594fSAndroid Build Coastguard Worker
DisconnectAndDelete()2377*795d594fSAndroid Build Coastguard Worker void HBasicBlock::DisconnectAndDelete() {
2378*795d594fSAndroid Build Coastguard Worker // Dominators must be removed after all the blocks they dominate. This way
2379*795d594fSAndroid Build Coastguard Worker // a loop header is removed last, a requirement for correct loop information
2380*795d594fSAndroid Build Coastguard Worker // iteration.
2381*795d594fSAndroid Build Coastguard Worker DCHECK(dominated_blocks_.empty());
2382*795d594fSAndroid Build Coastguard Worker
2383*795d594fSAndroid Build Coastguard Worker // The following steps gradually remove the block from all its dependants in
2384*795d594fSAndroid Build Coastguard Worker // post order (b/27683071).
2385*795d594fSAndroid Build Coastguard Worker
2386*795d594fSAndroid Build Coastguard Worker // (1) Store a basic block that we'll use in step (5) to find loops to be updated.
2387*795d594fSAndroid Build Coastguard Worker // We need to do this before step (4) which destroys the predecessor list.
2388*795d594fSAndroid Build Coastguard Worker HBasicBlock* loop_update_start = this;
2389*795d594fSAndroid Build Coastguard Worker if (IsLoopHeader()) {
2390*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info = GetLoopInformation();
2391*795d594fSAndroid Build Coastguard Worker // All other blocks in this loop should have been removed because the header
2392*795d594fSAndroid Build Coastguard Worker // was their dominator.
2393*795d594fSAndroid Build Coastguard Worker // Note that we do not remove `this` from `loop_info` as it is unreachable.
2394*795d594fSAndroid Build Coastguard Worker DCHECK(!loop_info->IsIrreducible());
2395*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(loop_info->GetBlocks().NumSetBits(), 1u);
2396*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(static_cast<uint32_t>(loop_info->GetBlocks().GetHighestBitSet()), GetBlockId());
2397*795d594fSAndroid Build Coastguard Worker loop_update_start = loop_info->GetPreHeader();
2398*795d594fSAndroid Build Coastguard Worker }
2399*795d594fSAndroid Build Coastguard Worker
2400*795d594fSAndroid Build Coastguard Worker // (2) Disconnect the block from its successors and update their phis.
2401*795d594fSAndroid Build Coastguard Worker DisconnectFromSuccessors();
2402*795d594fSAndroid Build Coastguard Worker
2403*795d594fSAndroid Build Coastguard Worker // (3) Remove instructions and phis. Instructions should have no remaining uses
2404*795d594fSAndroid Build Coastguard Worker // except in catch phis. If an instruction is used by a catch phi at `index`,
2405*795d594fSAndroid Build Coastguard Worker // remove `index`-th input of all phis in the catch block since they are
2406*795d594fSAndroid Build Coastguard Worker // guaranteed dead. Note that we may miss dead inputs this way but the
2407*795d594fSAndroid Build Coastguard Worker // graph will always remain consistent.
2408*795d594fSAndroid Build Coastguard Worker RemoveCatchPhiUsesAndInstruction(/* building_dominator_tree = */ false);
2409*795d594fSAndroid Build Coastguard Worker
2410*795d594fSAndroid Build Coastguard Worker // (4) Disconnect the block from its predecessors and update their
2411*795d594fSAndroid Build Coastguard Worker // control-flow instructions.
2412*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* predecessor : predecessors_) {
2413*795d594fSAndroid Build Coastguard Worker // We should not see any back edges as they would have been removed by step (3).
2414*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(IsInLoop(), !GetLoopInformation()->IsBackEdge(*predecessor));
2415*795d594fSAndroid Build Coastguard Worker
2416*795d594fSAndroid Build Coastguard Worker HInstruction* last_instruction = predecessor->GetLastInstruction();
2417*795d594fSAndroid Build Coastguard Worker if (last_instruction->IsTryBoundary() && !IsCatchBlock()) {
2418*795d594fSAndroid Build Coastguard Worker // This block is the only normal-flow successor of the TryBoundary which
2419*795d594fSAndroid Build Coastguard Worker // makes `predecessor` dead. Since DCE removes blocks in post order,
2420*795d594fSAndroid Build Coastguard Worker // exception handlers of this TryBoundary were already visited and any
2421*795d594fSAndroid Build Coastguard Worker // remaining handlers therefore must be live. We remove `predecessor` from
2422*795d594fSAndroid Build Coastguard Worker // their list of predecessors.
2423*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(last_instruction->AsTryBoundary()->GetNormalFlowSuccessor(), this);
2424*795d594fSAndroid Build Coastguard Worker while (predecessor->GetSuccessors().size() > 1) {
2425*795d594fSAndroid Build Coastguard Worker HBasicBlock* handler = predecessor->GetSuccessors()[1];
2426*795d594fSAndroid Build Coastguard Worker DCHECK(handler->IsCatchBlock());
2427*795d594fSAndroid Build Coastguard Worker predecessor->RemoveSuccessor(handler);
2428*795d594fSAndroid Build Coastguard Worker handler->RemovePredecessor(predecessor);
2429*795d594fSAndroid Build Coastguard Worker }
2430*795d594fSAndroid Build Coastguard Worker }
2431*795d594fSAndroid Build Coastguard Worker
2432*795d594fSAndroid Build Coastguard Worker predecessor->RemoveSuccessor(this);
2433*795d594fSAndroid Build Coastguard Worker uint32_t num_pred_successors = predecessor->GetSuccessors().size();
2434*795d594fSAndroid Build Coastguard Worker if (num_pred_successors == 1u) {
2435*795d594fSAndroid Build Coastguard Worker // If we have one successor after removing one, then we must have
2436*795d594fSAndroid Build Coastguard Worker // had an HIf, HPackedSwitch or HTryBoundary, as they have more than one
2437*795d594fSAndroid Build Coastguard Worker // successor. Replace those with a HGoto.
2438*795d594fSAndroid Build Coastguard Worker DCHECK(last_instruction->IsIf() ||
2439*795d594fSAndroid Build Coastguard Worker last_instruction->IsPackedSwitch() ||
2440*795d594fSAndroid Build Coastguard Worker (last_instruction->IsTryBoundary() && IsCatchBlock()));
2441*795d594fSAndroid Build Coastguard Worker predecessor->RemoveInstruction(last_instruction);
2442*795d594fSAndroid Build Coastguard Worker predecessor->AddInstruction(new (graph_->GetAllocator()) HGoto(last_instruction->GetDexPc()));
2443*795d594fSAndroid Build Coastguard Worker } else if (num_pred_successors == 0u) {
2444*795d594fSAndroid Build Coastguard Worker // The predecessor has no remaining successors and therefore must be dead.
2445*795d594fSAndroid Build Coastguard Worker // We deliberately leave it without a control-flow instruction so that the
2446*795d594fSAndroid Build Coastguard Worker // GraphChecker fails unless it is not removed during the pass too.
2447*795d594fSAndroid Build Coastguard Worker predecessor->RemoveInstruction(last_instruction);
2448*795d594fSAndroid Build Coastguard Worker } else {
2449*795d594fSAndroid Build Coastguard Worker // There are multiple successors left. The removed block might be a successor
2450*795d594fSAndroid Build Coastguard Worker // of a PackedSwitch which will be completely removed (perhaps replaced with
2451*795d594fSAndroid Build Coastguard Worker // a Goto), or we are deleting a catch block from a TryBoundary. In either
2452*795d594fSAndroid Build Coastguard Worker // case, leave `last_instruction` as is for now.
2453*795d594fSAndroid Build Coastguard Worker DCHECK(last_instruction->IsPackedSwitch() ||
2454*795d594fSAndroid Build Coastguard Worker (last_instruction->IsTryBoundary() && IsCatchBlock()));
2455*795d594fSAndroid Build Coastguard Worker }
2456*795d594fSAndroid Build Coastguard Worker }
2457*795d594fSAndroid Build Coastguard Worker predecessors_.clear();
2458*795d594fSAndroid Build Coastguard Worker
2459*795d594fSAndroid Build Coastguard Worker // (5) Remove the block from all loops it is included in. Skip the inner-most
2460*795d594fSAndroid Build Coastguard Worker // loop if this is the loop header (see definition of `loop_update_start`)
2461*795d594fSAndroid Build Coastguard Worker // because the loop header's predecessor list has been destroyed in step (4).
2462*795d594fSAndroid Build Coastguard Worker for (HLoopInformationOutwardIterator it(*loop_update_start); !it.Done(); it.Advance()) {
2463*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info = it.Current();
2464*795d594fSAndroid Build Coastguard Worker loop_info->Remove(this);
2465*795d594fSAndroid Build Coastguard Worker if (loop_info->IsBackEdge(*this)) {
2466*795d594fSAndroid Build Coastguard Worker // If this was the last back edge of the loop, we deliberately leave the
2467*795d594fSAndroid Build Coastguard Worker // loop in an inconsistent state and will fail GraphChecker unless the
2468*795d594fSAndroid Build Coastguard Worker // entire loop is removed during the pass.
2469*795d594fSAndroid Build Coastguard Worker loop_info->RemoveBackEdge(this);
2470*795d594fSAndroid Build Coastguard Worker }
2471*795d594fSAndroid Build Coastguard Worker }
2472*795d594fSAndroid Build Coastguard Worker
2473*795d594fSAndroid Build Coastguard Worker // (6) Disconnect from the dominator.
2474*795d594fSAndroid Build Coastguard Worker dominator_->RemoveDominatedBlock(this);
2475*795d594fSAndroid Build Coastguard Worker SetDominator(nullptr);
2476*795d594fSAndroid Build Coastguard Worker
2477*795d594fSAndroid Build Coastguard Worker // (7) Delete from the graph, update reverse post order.
2478*795d594fSAndroid Build Coastguard Worker graph_->DeleteDeadEmptyBlock(this);
2479*795d594fSAndroid Build Coastguard Worker }
2480*795d594fSAndroid Build Coastguard Worker
DisconnectFromSuccessors(const ArenaBitVector * visited)2481*795d594fSAndroid Build Coastguard Worker void HBasicBlock::DisconnectFromSuccessors(const ArenaBitVector* visited) {
2482*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : successors_) {
2483*795d594fSAndroid Build Coastguard Worker // Delete this block from the list of predecessors.
2484*795d594fSAndroid Build Coastguard Worker size_t this_index = successor->GetPredecessorIndexOf(this);
2485*795d594fSAndroid Build Coastguard Worker successor->predecessors_.erase(successor->predecessors_.begin() + this_index);
2486*795d594fSAndroid Build Coastguard Worker
2487*795d594fSAndroid Build Coastguard Worker if (visited != nullptr && !visited->IsBitSet(successor->GetBlockId())) {
2488*795d594fSAndroid Build Coastguard Worker // `successor` itself is dead. Therefore, there is no need to update its phis.
2489*795d594fSAndroid Build Coastguard Worker continue;
2490*795d594fSAndroid Build Coastguard Worker }
2491*795d594fSAndroid Build Coastguard Worker
2492*795d594fSAndroid Build Coastguard Worker DCHECK(!successor->predecessors_.empty());
2493*795d594fSAndroid Build Coastguard Worker
2494*795d594fSAndroid Build Coastguard Worker // Remove this block's entries in the successor's phis. Skips exceptional
2495*795d594fSAndroid Build Coastguard Worker // successors because catch phi inputs do not correspond to predecessor
2496*795d594fSAndroid Build Coastguard Worker // blocks but throwing instructions. They are removed in `RemoveCatchPhiUses`.
2497*795d594fSAndroid Build Coastguard Worker if (!successor->IsCatchBlock()) {
2498*795d594fSAndroid Build Coastguard Worker if (successor->predecessors_.size() == 1u) {
2499*795d594fSAndroid Build Coastguard Worker // The successor has just one predecessor left. Replace phis with the only
2500*795d594fSAndroid Build Coastguard Worker // remaining input.
2501*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
2502*795d594fSAndroid Build Coastguard Worker HPhi* phi = phi_it.Current()->AsPhi();
2503*795d594fSAndroid Build Coastguard Worker phi->ReplaceWith(phi->InputAt(1 - this_index));
2504*795d594fSAndroid Build Coastguard Worker successor->RemovePhi(phi);
2505*795d594fSAndroid Build Coastguard Worker }
2506*795d594fSAndroid Build Coastguard Worker } else {
2507*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator phi_it(successor->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
2508*795d594fSAndroid Build Coastguard Worker phi_it.Current()->AsPhi()->RemoveInputAt(this_index);
2509*795d594fSAndroid Build Coastguard Worker }
2510*795d594fSAndroid Build Coastguard Worker }
2511*795d594fSAndroid Build Coastguard Worker }
2512*795d594fSAndroid Build Coastguard Worker }
2513*795d594fSAndroid Build Coastguard Worker successors_.clear();
2514*795d594fSAndroid Build Coastguard Worker }
2515*795d594fSAndroid Build Coastguard Worker
RemoveCatchPhiUsesAndInstruction(bool building_dominator_tree)2516*795d594fSAndroid Build Coastguard Worker void HBasicBlock::RemoveCatchPhiUsesAndInstruction(bool building_dominator_tree) {
2517*795d594fSAndroid Build Coastguard Worker for (HBackwardInstructionIterator it(GetInstructions()); !it.Done(); it.Advance()) {
2518*795d594fSAndroid Build Coastguard Worker HInstruction* insn = it.Current();
2519*795d594fSAndroid Build Coastguard Worker RemoveCatchPhiUsesOfDeadInstruction(insn);
2520*795d594fSAndroid Build Coastguard Worker
2521*795d594fSAndroid Build Coastguard Worker // If we are building the dominator tree, we removed all input records previously.
2522*795d594fSAndroid Build Coastguard Worker // `RemoveInstruction` will try to remove them again but that's not something we support and we
2523*795d594fSAndroid Build Coastguard Worker // will crash. We check here since we won't be checking that in RemoveInstruction.
2524*795d594fSAndroid Build Coastguard Worker if (building_dominator_tree) {
2525*795d594fSAndroid Build Coastguard Worker DCHECK(insn->GetUses().empty());
2526*795d594fSAndroid Build Coastguard Worker DCHECK(insn->GetEnvUses().empty());
2527*795d594fSAndroid Build Coastguard Worker }
2528*795d594fSAndroid Build Coastguard Worker RemoveInstruction(insn, /* ensure_safety= */ !building_dominator_tree);
2529*795d594fSAndroid Build Coastguard Worker }
2530*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(GetPhis()); !it.Done(); it.Advance()) {
2531*795d594fSAndroid Build Coastguard Worker HPhi* insn = it.Current()->AsPhi();
2532*795d594fSAndroid Build Coastguard Worker RemoveCatchPhiUsesOfDeadInstruction(insn);
2533*795d594fSAndroid Build Coastguard Worker
2534*795d594fSAndroid Build Coastguard Worker // If we are building the dominator tree, we removed all input records previously.
2535*795d594fSAndroid Build Coastguard Worker // `RemovePhi` will try to remove them again but that's not something we support and we
2536*795d594fSAndroid Build Coastguard Worker // will crash. We check here since we won't be checking that in RemovePhi.
2537*795d594fSAndroid Build Coastguard Worker if (building_dominator_tree) {
2538*795d594fSAndroid Build Coastguard Worker DCHECK(insn->GetUses().empty());
2539*795d594fSAndroid Build Coastguard Worker DCHECK(insn->GetEnvUses().empty());
2540*795d594fSAndroid Build Coastguard Worker }
2541*795d594fSAndroid Build Coastguard Worker RemovePhi(insn, /* ensure_safety= */ !building_dominator_tree);
2542*795d594fSAndroid Build Coastguard Worker }
2543*795d594fSAndroid Build Coastguard Worker }
2544*795d594fSAndroid Build Coastguard Worker
MergeInstructionsWith(HBasicBlock * other)2545*795d594fSAndroid Build Coastguard Worker void HBasicBlock::MergeInstructionsWith(HBasicBlock* other) {
2546*795d594fSAndroid Build Coastguard Worker DCHECK(EndsWithControlFlowInstruction());
2547*795d594fSAndroid Build Coastguard Worker RemoveInstruction(GetLastInstruction());
2548*795d594fSAndroid Build Coastguard Worker instructions_.Add(other->GetInstructions());
2549*795d594fSAndroid Build Coastguard Worker other->instructions_.SetBlockOfInstructions(this);
2550*795d594fSAndroid Build Coastguard Worker other->instructions_.Clear();
2551*795d594fSAndroid Build Coastguard Worker }
2552*795d594fSAndroid Build Coastguard Worker
MergeWith(HBasicBlock * other)2553*795d594fSAndroid Build Coastguard Worker void HBasicBlock::MergeWith(HBasicBlock* other) {
2554*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(GetGraph(), other->GetGraph());
2555*795d594fSAndroid Build Coastguard Worker DCHECK(ContainsElement(dominated_blocks_, other));
2556*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(GetSingleSuccessor(), other);
2557*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(other->GetSinglePredecessor(), this);
2558*795d594fSAndroid Build Coastguard Worker DCHECK(other->GetPhis().IsEmpty());
2559*795d594fSAndroid Build Coastguard Worker
2560*795d594fSAndroid Build Coastguard Worker // Move instructions from `other` to `this`.
2561*795d594fSAndroid Build Coastguard Worker MergeInstructionsWith(other);
2562*795d594fSAndroid Build Coastguard Worker
2563*795d594fSAndroid Build Coastguard Worker // Remove `other` from the loops it is included in.
2564*795d594fSAndroid Build Coastguard Worker for (HLoopInformationOutwardIterator it(*other); !it.Done(); it.Advance()) {
2565*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info = it.Current();
2566*795d594fSAndroid Build Coastguard Worker loop_info->Remove(other);
2567*795d594fSAndroid Build Coastguard Worker if (loop_info->IsBackEdge(*other)) {
2568*795d594fSAndroid Build Coastguard Worker loop_info->ReplaceBackEdge(other, this);
2569*795d594fSAndroid Build Coastguard Worker }
2570*795d594fSAndroid Build Coastguard Worker }
2571*795d594fSAndroid Build Coastguard Worker
2572*795d594fSAndroid Build Coastguard Worker // Update links to the successors of `other`.
2573*795d594fSAndroid Build Coastguard Worker successors_.clear();
2574*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : other->GetSuccessors()) {
2575*795d594fSAndroid Build Coastguard Worker successor->predecessors_[successor->GetPredecessorIndexOf(other)] = this;
2576*795d594fSAndroid Build Coastguard Worker }
2577*795d594fSAndroid Build Coastguard Worker successors_.swap(other->successors_);
2578*795d594fSAndroid Build Coastguard Worker DCHECK(other->successors_.empty());
2579*795d594fSAndroid Build Coastguard Worker
2580*795d594fSAndroid Build Coastguard Worker // Update the dominator tree.
2581*795d594fSAndroid Build Coastguard Worker RemoveDominatedBlock(other);
2582*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* dominated : other->GetDominatedBlocks()) {
2583*795d594fSAndroid Build Coastguard Worker dominated->SetDominator(this);
2584*795d594fSAndroid Build Coastguard Worker }
2585*795d594fSAndroid Build Coastguard Worker dominated_blocks_.insert(
2586*795d594fSAndroid Build Coastguard Worker dominated_blocks_.end(), other->dominated_blocks_.begin(), other->dominated_blocks_.end());
2587*795d594fSAndroid Build Coastguard Worker other->dominated_blocks_.clear();
2588*795d594fSAndroid Build Coastguard Worker other->dominator_ = nullptr;
2589*795d594fSAndroid Build Coastguard Worker
2590*795d594fSAndroid Build Coastguard Worker // Clear the list of predecessors of `other` in preparation of deleting it.
2591*795d594fSAndroid Build Coastguard Worker other->predecessors_.clear();
2592*795d594fSAndroid Build Coastguard Worker
2593*795d594fSAndroid Build Coastguard Worker // Delete `other` from the graph. The function updates reverse post order.
2594*795d594fSAndroid Build Coastguard Worker graph_->DeleteDeadEmptyBlock(other);
2595*795d594fSAndroid Build Coastguard Worker }
2596*795d594fSAndroid Build Coastguard Worker
MergeWithInlined(HBasicBlock * other)2597*795d594fSAndroid Build Coastguard Worker void HBasicBlock::MergeWithInlined(HBasicBlock* other) {
2598*795d594fSAndroid Build Coastguard Worker DCHECK_NE(GetGraph(), other->GetGraph());
2599*795d594fSAndroid Build Coastguard Worker DCHECK(GetDominatedBlocks().empty());
2600*795d594fSAndroid Build Coastguard Worker DCHECK(GetSuccessors().empty());
2601*795d594fSAndroid Build Coastguard Worker DCHECK(!EndsWithControlFlowInstruction());
2602*795d594fSAndroid Build Coastguard Worker DCHECK(other->GetSinglePredecessor()->IsEntryBlock());
2603*795d594fSAndroid Build Coastguard Worker DCHECK(other->GetPhis().IsEmpty());
2604*795d594fSAndroid Build Coastguard Worker DCHECK(!other->IsInLoop());
2605*795d594fSAndroid Build Coastguard Worker
2606*795d594fSAndroid Build Coastguard Worker // Move instructions from `other` to `this`.
2607*795d594fSAndroid Build Coastguard Worker instructions_.Add(other->GetInstructions());
2608*795d594fSAndroid Build Coastguard Worker other->instructions_.SetBlockOfInstructions(this);
2609*795d594fSAndroid Build Coastguard Worker
2610*795d594fSAndroid Build Coastguard Worker // Update links to the successors of `other`.
2611*795d594fSAndroid Build Coastguard Worker successors_.clear();
2612*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* successor : other->GetSuccessors()) {
2613*795d594fSAndroid Build Coastguard Worker successor->predecessors_[successor->GetPredecessorIndexOf(other)] = this;
2614*795d594fSAndroid Build Coastguard Worker }
2615*795d594fSAndroid Build Coastguard Worker successors_.swap(other->successors_);
2616*795d594fSAndroid Build Coastguard Worker DCHECK(other->successors_.empty());
2617*795d594fSAndroid Build Coastguard Worker
2618*795d594fSAndroid Build Coastguard Worker // Update the dominator tree.
2619*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* dominated : other->GetDominatedBlocks()) {
2620*795d594fSAndroid Build Coastguard Worker dominated->SetDominator(this);
2621*795d594fSAndroid Build Coastguard Worker }
2622*795d594fSAndroid Build Coastguard Worker dominated_blocks_.insert(
2623*795d594fSAndroid Build Coastguard Worker dominated_blocks_.end(), other->dominated_blocks_.begin(), other->dominated_blocks_.end());
2624*795d594fSAndroid Build Coastguard Worker other->dominated_blocks_.clear();
2625*795d594fSAndroid Build Coastguard Worker other->dominator_ = nullptr;
2626*795d594fSAndroid Build Coastguard Worker other->graph_ = nullptr;
2627*795d594fSAndroid Build Coastguard Worker }
2628*795d594fSAndroid Build Coastguard Worker
ReplaceWith(HBasicBlock * other)2629*795d594fSAndroid Build Coastguard Worker void HBasicBlock::ReplaceWith(HBasicBlock* other) {
2630*795d594fSAndroid Build Coastguard Worker while (!GetPredecessors().empty()) {
2631*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = GetPredecessors()[0];
2632*795d594fSAndroid Build Coastguard Worker predecessor->ReplaceSuccessor(this, other);
2633*795d594fSAndroid Build Coastguard Worker }
2634*795d594fSAndroid Build Coastguard Worker while (!GetSuccessors().empty()) {
2635*795d594fSAndroid Build Coastguard Worker HBasicBlock* successor = GetSuccessors()[0];
2636*795d594fSAndroid Build Coastguard Worker successor->ReplacePredecessor(this, other);
2637*795d594fSAndroid Build Coastguard Worker }
2638*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* dominated : GetDominatedBlocks()) {
2639*795d594fSAndroid Build Coastguard Worker other->AddDominatedBlock(dominated);
2640*795d594fSAndroid Build Coastguard Worker }
2641*795d594fSAndroid Build Coastguard Worker GetDominator()->ReplaceDominatedBlock(this, other);
2642*795d594fSAndroid Build Coastguard Worker other->SetDominator(GetDominator());
2643*795d594fSAndroid Build Coastguard Worker dominator_ = nullptr;
2644*795d594fSAndroid Build Coastguard Worker graph_ = nullptr;
2645*795d594fSAndroid Build Coastguard Worker }
2646*795d594fSAndroid Build Coastguard Worker
DeleteDeadEmptyBlock(HBasicBlock * block)2647*795d594fSAndroid Build Coastguard Worker void HGraph::DeleteDeadEmptyBlock(HBasicBlock* block) {
2648*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(block->GetGraph(), this);
2649*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetSuccessors().empty());
2650*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetPredecessors().empty());
2651*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetDominatedBlocks().empty());
2652*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetDominator() == nullptr);
2653*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetInstructions().IsEmpty());
2654*795d594fSAndroid Build Coastguard Worker DCHECK(block->GetPhis().IsEmpty());
2655*795d594fSAndroid Build Coastguard Worker
2656*795d594fSAndroid Build Coastguard Worker if (block->IsExitBlock()) {
2657*795d594fSAndroid Build Coastguard Worker SetExitBlock(nullptr);
2658*795d594fSAndroid Build Coastguard Worker }
2659*795d594fSAndroid Build Coastguard Worker
2660*795d594fSAndroid Build Coastguard Worker RemoveElement(reverse_post_order_, block);
2661*795d594fSAndroid Build Coastguard Worker blocks_[block->GetBlockId()] = nullptr;
2662*795d594fSAndroid Build Coastguard Worker block->SetGraph(nullptr);
2663*795d594fSAndroid Build Coastguard Worker }
2664*795d594fSAndroid Build Coastguard Worker
UpdateLoopAndTryInformationOfNewBlock(HBasicBlock * block,HBasicBlock * reference,bool replace_if_back_edge,bool has_more_specific_try_catch_info)2665*795d594fSAndroid Build Coastguard Worker void HGraph::UpdateLoopAndTryInformationOfNewBlock(HBasicBlock* block,
2666*795d594fSAndroid Build Coastguard Worker HBasicBlock* reference,
2667*795d594fSAndroid Build Coastguard Worker bool replace_if_back_edge,
2668*795d594fSAndroid Build Coastguard Worker bool has_more_specific_try_catch_info) {
2669*795d594fSAndroid Build Coastguard Worker if (block->IsLoopHeader()) {
2670*795d594fSAndroid Build Coastguard Worker // Clear the information of which blocks are contained in that loop. Since the
2671*795d594fSAndroid Build Coastguard Worker // information is stored as a bit vector based on block ids, we have to update
2672*795d594fSAndroid Build Coastguard Worker // it, as those block ids were specific to the callee graph and we are now adding
2673*795d594fSAndroid Build Coastguard Worker // these blocks to the caller graph.
2674*795d594fSAndroid Build Coastguard Worker block->GetLoopInformation()->ClearAllBlocks();
2675*795d594fSAndroid Build Coastguard Worker }
2676*795d594fSAndroid Build Coastguard Worker
2677*795d594fSAndroid Build Coastguard Worker // If not already in a loop, update the loop information.
2678*795d594fSAndroid Build Coastguard Worker if (!block->IsInLoop()) {
2679*795d594fSAndroid Build Coastguard Worker block->SetLoopInformation(reference->GetLoopInformation());
2680*795d594fSAndroid Build Coastguard Worker }
2681*795d594fSAndroid Build Coastguard Worker
2682*795d594fSAndroid Build Coastguard Worker // If the block is in a loop, update all its outward loops.
2683*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info = block->GetLoopInformation();
2684*795d594fSAndroid Build Coastguard Worker if (loop_info != nullptr) {
2685*795d594fSAndroid Build Coastguard Worker for (HLoopInformationOutwardIterator loop_it(*block);
2686*795d594fSAndroid Build Coastguard Worker !loop_it.Done();
2687*795d594fSAndroid Build Coastguard Worker loop_it.Advance()) {
2688*795d594fSAndroid Build Coastguard Worker loop_it.Current()->Add(block);
2689*795d594fSAndroid Build Coastguard Worker }
2690*795d594fSAndroid Build Coastguard Worker if (replace_if_back_edge && loop_info->IsBackEdge(*reference)) {
2691*795d594fSAndroid Build Coastguard Worker loop_info->ReplaceBackEdge(reference, block);
2692*795d594fSAndroid Build Coastguard Worker }
2693*795d594fSAndroid Build Coastguard Worker }
2694*795d594fSAndroid Build Coastguard Worker
2695*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(has_more_specific_try_catch_info, !reference->IsTryBlock())
2696*795d594fSAndroid Build Coastguard Worker << "We don't allow to inline try catches inside of other try blocks.";
2697*795d594fSAndroid Build Coastguard Worker
2698*795d594fSAndroid Build Coastguard Worker // Update the TryCatchInformation, if we are not inlining a try catch.
2699*795d594fSAndroid Build Coastguard Worker if (!has_more_specific_try_catch_info) {
2700*795d594fSAndroid Build Coastguard Worker // Copy TryCatchInformation if `reference` is a try block, not if it is a catch block.
2701*795d594fSAndroid Build Coastguard Worker TryCatchInformation* try_catch_info =
2702*795d594fSAndroid Build Coastguard Worker reference->IsTryBlock() ? reference->GetTryCatchInformation() : nullptr;
2703*795d594fSAndroid Build Coastguard Worker block->SetTryCatchInformation(try_catch_info);
2704*795d594fSAndroid Build Coastguard Worker }
2705*795d594fSAndroid Build Coastguard Worker }
2706*795d594fSAndroid Build Coastguard Worker
InlineInto(HGraph * outer_graph,HInvoke * invoke)2707*795d594fSAndroid Build Coastguard Worker HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
2708*795d594fSAndroid Build Coastguard Worker DCHECK(HasExitBlock()) << "Unimplemented scenario";
2709*795d594fSAndroid Build Coastguard Worker // Update the environments in this graph to have the invoke's environment
2710*795d594fSAndroid Build Coastguard Worker // as parent.
2711*795d594fSAndroid Build Coastguard Worker {
2712*795d594fSAndroid Build Coastguard Worker // Skip the entry block, we do not need to update the entry's suspend check.
2713*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* block : GetReversePostOrderSkipEntryBlock()) {
2714*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator instr_it(block->GetInstructions());
2715*795d594fSAndroid Build Coastguard Worker !instr_it.Done();
2716*795d594fSAndroid Build Coastguard Worker instr_it.Advance()) {
2717*795d594fSAndroid Build Coastguard Worker HInstruction* current = instr_it.Current();
2718*795d594fSAndroid Build Coastguard Worker if (current->NeedsEnvironment()) {
2719*795d594fSAndroid Build Coastguard Worker DCHECK(current->HasEnvironment());
2720*795d594fSAndroid Build Coastguard Worker current->GetEnvironment()->SetAndCopyParentChain(
2721*795d594fSAndroid Build Coastguard Worker outer_graph->GetAllocator(), invoke->GetEnvironment());
2722*795d594fSAndroid Build Coastguard Worker }
2723*795d594fSAndroid Build Coastguard Worker }
2724*795d594fSAndroid Build Coastguard Worker }
2725*795d594fSAndroid Build Coastguard Worker }
2726*795d594fSAndroid Build Coastguard Worker
2727*795d594fSAndroid Build Coastguard Worker if (HasBoundsChecks()) {
2728*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasBoundsChecks(true);
2729*795d594fSAndroid Build Coastguard Worker }
2730*795d594fSAndroid Build Coastguard Worker if (HasLoops()) {
2731*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasLoops(true);
2732*795d594fSAndroid Build Coastguard Worker }
2733*795d594fSAndroid Build Coastguard Worker if (HasIrreducibleLoops()) {
2734*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasIrreducibleLoops(true);
2735*795d594fSAndroid Build Coastguard Worker }
2736*795d594fSAndroid Build Coastguard Worker if (HasDirectCriticalNativeCall()) {
2737*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasDirectCriticalNativeCall(true);
2738*795d594fSAndroid Build Coastguard Worker }
2739*795d594fSAndroid Build Coastguard Worker if (HasTryCatch()) {
2740*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasTryCatch(true);
2741*795d594fSAndroid Build Coastguard Worker }
2742*795d594fSAndroid Build Coastguard Worker if (HasMonitorOperations()) {
2743*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasMonitorOperations(true);
2744*795d594fSAndroid Build Coastguard Worker }
2745*795d594fSAndroid Build Coastguard Worker if (HasTraditionalSIMD()) {
2746*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasTraditionalSIMD(true);
2747*795d594fSAndroid Build Coastguard Worker }
2748*795d594fSAndroid Build Coastguard Worker if (HasPredicatedSIMD()) {
2749*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasPredicatedSIMD(true);
2750*795d594fSAndroid Build Coastguard Worker }
2751*795d594fSAndroid Build Coastguard Worker if (HasAlwaysThrowingInvokes()) {
2752*795d594fSAndroid Build Coastguard Worker outer_graph->SetHasAlwaysThrowingInvokes(true);
2753*795d594fSAndroid Build Coastguard Worker }
2754*795d594fSAndroid Build Coastguard Worker
2755*795d594fSAndroid Build Coastguard Worker HInstruction* return_value = nullptr;
2756*795d594fSAndroid Build Coastguard Worker if (GetBlocks().size() == 3) {
2757*795d594fSAndroid Build Coastguard Worker // Inliner already made sure we don't inline methods that always throw.
2758*795d594fSAndroid Build Coastguard Worker DCHECK(!GetBlocks()[1]->GetLastInstruction()->IsThrow());
2759*795d594fSAndroid Build Coastguard Worker // Simple case of an entry block, a body block, and an exit block.
2760*795d594fSAndroid Build Coastguard Worker // Put the body block's instruction into `invoke`'s block.
2761*795d594fSAndroid Build Coastguard Worker HBasicBlock* body = GetBlocks()[1];
2762*795d594fSAndroid Build Coastguard Worker DCHECK(GetBlocks()[0]->IsEntryBlock());
2763*795d594fSAndroid Build Coastguard Worker DCHECK(GetBlocks()[2]->IsExitBlock());
2764*795d594fSAndroid Build Coastguard Worker DCHECK(!body->IsExitBlock());
2765*795d594fSAndroid Build Coastguard Worker DCHECK(!body->IsInLoop());
2766*795d594fSAndroid Build Coastguard Worker HInstruction* last = body->GetLastInstruction();
2767*795d594fSAndroid Build Coastguard Worker
2768*795d594fSAndroid Build Coastguard Worker // Note that we add instructions before the invoke only to simplify polymorphic inlining.
2769*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->instructions_.AddBefore(invoke, body->GetInstructions());
2770*795d594fSAndroid Build Coastguard Worker body->GetInstructions().SetBlockOfInstructions(invoke->GetBlock());
2771*795d594fSAndroid Build Coastguard Worker
2772*795d594fSAndroid Build Coastguard Worker // Replace the invoke with the return value of the inlined graph.
2773*795d594fSAndroid Build Coastguard Worker if (last->IsReturn()) {
2774*795d594fSAndroid Build Coastguard Worker return_value = last->InputAt(0);
2775*795d594fSAndroid Build Coastguard Worker } else {
2776*795d594fSAndroid Build Coastguard Worker DCHECK(last->IsReturnVoid());
2777*795d594fSAndroid Build Coastguard Worker }
2778*795d594fSAndroid Build Coastguard Worker
2779*795d594fSAndroid Build Coastguard Worker invoke->GetBlock()->RemoveInstruction(last);
2780*795d594fSAndroid Build Coastguard Worker } else {
2781*795d594fSAndroid Build Coastguard Worker // Need to inline multiple blocks. We split `invoke`'s block
2782*795d594fSAndroid Build Coastguard Worker // into two blocks, merge the first block of the inlined graph into
2783*795d594fSAndroid Build Coastguard Worker // the first half, and replace the exit block of the inlined graph
2784*795d594fSAndroid Build Coastguard Worker // with the second half.
2785*795d594fSAndroid Build Coastguard Worker ArenaAllocator* allocator = outer_graph->GetAllocator();
2786*795d594fSAndroid Build Coastguard Worker HBasicBlock* at = invoke->GetBlock();
2787*795d594fSAndroid Build Coastguard Worker // Note that we split before the invoke only to simplify polymorphic inlining.
2788*795d594fSAndroid Build Coastguard Worker HBasicBlock* to = at->SplitBeforeForInlining(invoke);
2789*795d594fSAndroid Build Coastguard Worker
2790*795d594fSAndroid Build Coastguard Worker HBasicBlock* first = entry_block_->GetSuccessors()[0];
2791*795d594fSAndroid Build Coastguard Worker DCHECK(!first->IsInLoop());
2792*795d594fSAndroid Build Coastguard Worker DCHECK(first->GetTryCatchInformation() == nullptr);
2793*795d594fSAndroid Build Coastguard Worker at->MergeWithInlined(first);
2794*795d594fSAndroid Build Coastguard Worker exit_block_->ReplaceWith(to);
2795*795d594fSAndroid Build Coastguard Worker
2796*795d594fSAndroid Build Coastguard Worker // Update the meta information surrounding blocks:
2797*795d594fSAndroid Build Coastguard Worker // (1) the graph they are now in,
2798*795d594fSAndroid Build Coastguard Worker // (2) the reverse post order of that graph,
2799*795d594fSAndroid Build Coastguard Worker // (3) their potential loop information, inner and outer,
2800*795d594fSAndroid Build Coastguard Worker // (4) try block membership.
2801*795d594fSAndroid Build Coastguard Worker // Note that we do not need to update catch phi inputs because they
2802*795d594fSAndroid Build Coastguard Worker // correspond to the register file of the outer method which the inlinee
2803*795d594fSAndroid Build Coastguard Worker // cannot modify.
2804*795d594fSAndroid Build Coastguard Worker
2805*795d594fSAndroid Build Coastguard Worker // We don't add the entry block, the exit block, and the first block, which
2806*795d594fSAndroid Build Coastguard Worker // has been merged with `at`.
2807*795d594fSAndroid Build Coastguard Worker static constexpr int kNumberOfSkippedBlocksInCallee = 3;
2808*795d594fSAndroid Build Coastguard Worker
2809*795d594fSAndroid Build Coastguard Worker // We add the `to` block.
2810*795d594fSAndroid Build Coastguard Worker static constexpr int kNumberOfNewBlocksInCaller = 1;
2811*795d594fSAndroid Build Coastguard Worker size_t blocks_added = (reverse_post_order_.size() - kNumberOfSkippedBlocksInCallee)
2812*795d594fSAndroid Build Coastguard Worker + kNumberOfNewBlocksInCaller;
2813*795d594fSAndroid Build Coastguard Worker
2814*795d594fSAndroid Build Coastguard Worker // Find the location of `at` in the outer graph's reverse post order. The new
2815*795d594fSAndroid Build Coastguard Worker // blocks will be added after it.
2816*795d594fSAndroid Build Coastguard Worker size_t index_of_at = IndexOfElement(outer_graph->reverse_post_order_, at);
2817*795d594fSAndroid Build Coastguard Worker MakeRoomFor(&outer_graph->reverse_post_order_, blocks_added, index_of_at);
2818*795d594fSAndroid Build Coastguard Worker
2819*795d594fSAndroid Build Coastguard Worker // Do a reverse post order of the blocks in the callee and do (1), (2), (3)
2820*795d594fSAndroid Build Coastguard Worker // and (4) to the blocks that apply.
2821*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* current : GetReversePostOrder()) {
2822*795d594fSAndroid Build Coastguard Worker if (current != exit_block_ && current != entry_block_ && current != first) {
2823*795d594fSAndroid Build Coastguard Worker DCHECK(current->GetGraph() == this);
2824*795d594fSAndroid Build Coastguard Worker current->SetGraph(outer_graph);
2825*795d594fSAndroid Build Coastguard Worker outer_graph->AddBlock(current);
2826*795d594fSAndroid Build Coastguard Worker outer_graph->reverse_post_order_[++index_of_at] = current;
2827*795d594fSAndroid Build Coastguard Worker UpdateLoopAndTryInformationOfNewBlock(current,
2828*795d594fSAndroid Build Coastguard Worker at,
2829*795d594fSAndroid Build Coastguard Worker /* replace_if_back_edge= */ false,
2830*795d594fSAndroid Build Coastguard Worker current->GetTryCatchInformation() != nullptr);
2831*795d594fSAndroid Build Coastguard Worker }
2832*795d594fSAndroid Build Coastguard Worker }
2833*795d594fSAndroid Build Coastguard Worker
2834*795d594fSAndroid Build Coastguard Worker // Do (1), (2), (3) and (4) to `to`.
2835*795d594fSAndroid Build Coastguard Worker to->SetGraph(outer_graph);
2836*795d594fSAndroid Build Coastguard Worker outer_graph->AddBlock(to);
2837*795d594fSAndroid Build Coastguard Worker outer_graph->reverse_post_order_[++index_of_at] = to;
2838*795d594fSAndroid Build Coastguard Worker // Only `to` can become a back edge, as the inlined blocks
2839*795d594fSAndroid Build Coastguard Worker // are predecessors of `to`.
2840*795d594fSAndroid Build Coastguard Worker UpdateLoopAndTryInformationOfNewBlock(to, at, /* replace_if_back_edge= */ true);
2841*795d594fSAndroid Build Coastguard Worker
2842*795d594fSAndroid Build Coastguard Worker // Update all predecessors of the exit block (now the `to` block)
2843*795d594fSAndroid Build Coastguard Worker // to not `HReturn` but `HGoto` instead. Special case throwing blocks
2844*795d594fSAndroid Build Coastguard Worker // to now get the outer graph exit block as successor.
2845*795d594fSAndroid Build Coastguard Worker HPhi* return_value_phi = nullptr;
2846*795d594fSAndroid Build Coastguard Worker bool rerun_dominance = false;
2847*795d594fSAndroid Build Coastguard Worker bool rerun_loop_analysis = false;
2848*795d594fSAndroid Build Coastguard Worker for (size_t pred = 0; pred < to->GetPredecessors().size(); ++pred) {
2849*795d594fSAndroid Build Coastguard Worker HBasicBlock* predecessor = to->GetPredecessors()[pred];
2850*795d594fSAndroid Build Coastguard Worker HInstruction* last = predecessor->GetLastInstruction();
2851*795d594fSAndroid Build Coastguard Worker
2852*795d594fSAndroid Build Coastguard Worker // At this point we might either have:
2853*795d594fSAndroid Build Coastguard Worker // A) Return/ReturnVoid/Throw as the last instruction, or
2854*795d594fSAndroid Build Coastguard Worker // B) `Return/ReturnVoid/Throw->TryBoundary` as the last instruction chain
2855*795d594fSAndroid Build Coastguard Worker
2856*795d594fSAndroid Build Coastguard Worker const bool saw_try_boundary = last->IsTryBoundary();
2857*795d594fSAndroid Build Coastguard Worker if (saw_try_boundary) {
2858*795d594fSAndroid Build Coastguard Worker DCHECK(predecessor->IsSingleTryBoundary());
2859*795d594fSAndroid Build Coastguard Worker DCHECK(!last->AsTryBoundary()->IsEntry());
2860*795d594fSAndroid Build Coastguard Worker predecessor = predecessor->GetSinglePredecessor();
2861*795d594fSAndroid Build Coastguard Worker last = predecessor->GetLastInstruction();
2862*795d594fSAndroid Build Coastguard Worker }
2863*795d594fSAndroid Build Coastguard Worker
2864*795d594fSAndroid Build Coastguard Worker if (last->IsThrow()) {
2865*795d594fSAndroid Build Coastguard Worker if (at->IsTryBlock()) {
2866*795d594fSAndroid Build Coastguard Worker DCHECK(!saw_try_boundary) << "We don't support inlining of try blocks into try blocks.";
2867*795d594fSAndroid Build Coastguard Worker // Create a TryBoundary of kind:exit and point it to the Exit block.
2868*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_block = outer_graph->SplitEdge(predecessor, to);
2869*795d594fSAndroid Build Coastguard Worker new_block->AddInstruction(
2870*795d594fSAndroid Build Coastguard Worker new (allocator) HTryBoundary(HTryBoundary::BoundaryKind::kExit, last->GetDexPc()));
2871*795d594fSAndroid Build Coastguard Worker new_block->ReplaceSuccessor(to, outer_graph->GetExitBlock());
2872*795d594fSAndroid Build Coastguard Worker
2873*795d594fSAndroid Build Coastguard Worker // Copy information from the predecessor.
2874*795d594fSAndroid Build Coastguard Worker new_block->SetLoopInformation(predecessor->GetLoopInformation());
2875*795d594fSAndroid Build Coastguard Worker TryCatchInformation* try_catch_info = predecessor->GetTryCatchInformation();
2876*795d594fSAndroid Build Coastguard Worker new_block->SetTryCatchInformation(try_catch_info);
2877*795d594fSAndroid Build Coastguard Worker for (HBasicBlock* xhandler :
2878*795d594fSAndroid Build Coastguard Worker try_catch_info->GetTryEntry().GetBlock()->GetExceptionalSuccessors()) {
2879*795d594fSAndroid Build Coastguard Worker new_block->AddSuccessor(xhandler);
2880*795d594fSAndroid Build Coastguard Worker }
2881*795d594fSAndroid Build Coastguard Worker DCHECK(try_catch_info->GetTryEntry().HasSameExceptionHandlersAs(
2882*795d594fSAndroid Build Coastguard Worker *new_block->GetLastInstruction()->AsTryBoundary()));
2883*795d594fSAndroid Build Coastguard Worker } else {
2884*795d594fSAndroid Build Coastguard Worker // We either have `Throw->TryBoundary` or `Throw`. We want to point the whole chain to the
2885*795d594fSAndroid Build Coastguard Worker // exit, so we recompute `predecessor`
2886*795d594fSAndroid Build Coastguard Worker predecessor = to->GetPredecessors()[pred];
2887*795d594fSAndroid Build Coastguard Worker predecessor->ReplaceSuccessor(to, outer_graph->GetExitBlock());
2888*795d594fSAndroid Build Coastguard Worker }
2889*795d594fSAndroid Build Coastguard Worker
2890*795d594fSAndroid Build Coastguard Worker --pred;
2891*795d594fSAndroid Build Coastguard Worker // We need to re-run dominance information, as the exit block now has
2892*795d594fSAndroid Build Coastguard Worker // a new predecessor and potential new dominator.
2893*795d594fSAndroid Build Coastguard Worker // TODO(solanes): See if it's worth it to hand-modify the domination chain instead of
2894*795d594fSAndroid Build Coastguard Worker // rerunning the dominance for the whole graph.
2895*795d594fSAndroid Build Coastguard Worker rerun_dominance = true;
2896*795d594fSAndroid Build Coastguard Worker if (predecessor->GetLoopInformation() != nullptr) {
2897*795d594fSAndroid Build Coastguard Worker // The loop information might have changed e.g. `predecessor` might not be in a loop
2898*795d594fSAndroid Build Coastguard Worker // anymore. We only do this if `predecessor` has loop information as it is impossible for
2899*795d594fSAndroid Build Coastguard Worker // predecessor to end up in a loop if it wasn't in one before.
2900*795d594fSAndroid Build Coastguard Worker rerun_loop_analysis = true;
2901*795d594fSAndroid Build Coastguard Worker }
2902*795d594fSAndroid Build Coastguard Worker } else {
2903*795d594fSAndroid Build Coastguard Worker if (last->IsReturnVoid()) {
2904*795d594fSAndroid Build Coastguard Worker DCHECK(return_value == nullptr);
2905*795d594fSAndroid Build Coastguard Worker DCHECK(return_value_phi == nullptr);
2906*795d594fSAndroid Build Coastguard Worker } else {
2907*795d594fSAndroid Build Coastguard Worker DCHECK(last->IsReturn());
2908*795d594fSAndroid Build Coastguard Worker if (return_value_phi != nullptr) {
2909*795d594fSAndroid Build Coastguard Worker return_value_phi->AddInput(last->InputAt(0));
2910*795d594fSAndroid Build Coastguard Worker } else if (return_value == nullptr) {
2911*795d594fSAndroid Build Coastguard Worker return_value = last->InputAt(0);
2912*795d594fSAndroid Build Coastguard Worker } else {
2913*795d594fSAndroid Build Coastguard Worker // There will be multiple returns.
2914*795d594fSAndroid Build Coastguard Worker return_value_phi = new (allocator) HPhi(
2915*795d594fSAndroid Build Coastguard Worker allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc());
2916*795d594fSAndroid Build Coastguard Worker to->AddPhi(return_value_phi);
2917*795d594fSAndroid Build Coastguard Worker return_value_phi->AddInput(return_value);
2918*795d594fSAndroid Build Coastguard Worker return_value_phi->AddInput(last->InputAt(0));
2919*795d594fSAndroid Build Coastguard Worker return_value = return_value_phi;
2920*795d594fSAndroid Build Coastguard Worker }
2921*795d594fSAndroid Build Coastguard Worker }
2922*795d594fSAndroid Build Coastguard Worker predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
2923*795d594fSAndroid Build Coastguard Worker predecessor->RemoveInstruction(last);
2924*795d594fSAndroid Build Coastguard Worker
2925*795d594fSAndroid Build Coastguard Worker if (saw_try_boundary) {
2926*795d594fSAndroid Build Coastguard Worker predecessor = to->GetPredecessors()[pred];
2927*795d594fSAndroid Build Coastguard Worker DCHECK(predecessor->EndsWithTryBoundary());
2928*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(predecessor->GetNormalSuccessors().size(), 1u);
2929*795d594fSAndroid Build Coastguard Worker if (predecessor->GetSuccessors()[0]->GetPredecessors().size() > 1) {
2930*795d594fSAndroid Build Coastguard Worker outer_graph->SplitCriticalEdge(predecessor, to);
2931*795d594fSAndroid Build Coastguard Worker rerun_dominance = true;
2932*795d594fSAndroid Build Coastguard Worker if (predecessor->GetLoopInformation() != nullptr) {
2933*795d594fSAndroid Build Coastguard Worker rerun_loop_analysis = true;
2934*795d594fSAndroid Build Coastguard Worker }
2935*795d594fSAndroid Build Coastguard Worker }
2936*795d594fSAndroid Build Coastguard Worker }
2937*795d594fSAndroid Build Coastguard Worker }
2938*795d594fSAndroid Build Coastguard Worker }
2939*795d594fSAndroid Build Coastguard Worker if (rerun_loop_analysis) {
2940*795d594fSAndroid Build Coastguard Worker outer_graph->RecomputeDominatorTree();
2941*795d594fSAndroid Build Coastguard Worker } else if (rerun_dominance) {
2942*795d594fSAndroid Build Coastguard Worker outer_graph->ClearDominanceInformation();
2943*795d594fSAndroid Build Coastguard Worker outer_graph->ComputeDominanceInformation();
2944*795d594fSAndroid Build Coastguard Worker }
2945*795d594fSAndroid Build Coastguard Worker }
2946*795d594fSAndroid Build Coastguard Worker
2947*795d594fSAndroid Build Coastguard Worker // Walk over the entry block and:
2948*795d594fSAndroid Build Coastguard Worker // - Move constants from the entry block to the outer_graph's entry block,
2949*795d594fSAndroid Build Coastguard Worker // - Replace HParameterValue instructions with their real value.
2950*795d594fSAndroid Build Coastguard Worker // - Remove suspend checks, that hold an environment.
2951*795d594fSAndroid Build Coastguard Worker // We must do this after the other blocks have been inlined, otherwise ids of
2952*795d594fSAndroid Build Coastguard Worker // constants could overlap with the inner graph.
2953*795d594fSAndroid Build Coastguard Worker size_t parameter_index = 0;
2954*795d594fSAndroid Build Coastguard Worker for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
2955*795d594fSAndroid Build Coastguard Worker HInstruction* current = it.Current();
2956*795d594fSAndroid Build Coastguard Worker HInstruction* replacement = nullptr;
2957*795d594fSAndroid Build Coastguard Worker if (current->IsNullConstant()) {
2958*795d594fSAndroid Build Coastguard Worker replacement = outer_graph->GetNullConstant();
2959*795d594fSAndroid Build Coastguard Worker } else if (current->IsIntConstant()) {
2960*795d594fSAndroid Build Coastguard Worker replacement = outer_graph->GetIntConstant(current->AsIntConstant()->GetValue());
2961*795d594fSAndroid Build Coastguard Worker } else if (current->IsLongConstant()) {
2962*795d594fSAndroid Build Coastguard Worker replacement = outer_graph->GetLongConstant(current->AsLongConstant()->GetValue());
2963*795d594fSAndroid Build Coastguard Worker } else if (current->IsFloatConstant()) {
2964*795d594fSAndroid Build Coastguard Worker replacement = outer_graph->GetFloatConstant(current->AsFloatConstant()->GetValue());
2965*795d594fSAndroid Build Coastguard Worker } else if (current->IsDoubleConstant()) {
2966*795d594fSAndroid Build Coastguard Worker replacement = outer_graph->GetDoubleConstant(current->AsDoubleConstant()->GetValue());
2967*795d594fSAndroid Build Coastguard Worker } else if (current->IsParameterValue()) {
2968*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild &&
2969*795d594fSAndroid Build Coastguard Worker invoke->IsInvokeStaticOrDirect() &&
2970*795d594fSAndroid Build Coastguard Worker invoke->AsInvokeStaticOrDirect()->IsStaticWithExplicitClinitCheck()) {
2971*795d594fSAndroid Build Coastguard Worker // Ensure we do not use the last input of `invoke`, as it
2972*795d594fSAndroid Build Coastguard Worker // contains a clinit check which is not an actual argument.
2973*795d594fSAndroid Build Coastguard Worker size_t last_input_index = invoke->InputCount() - 1;
2974*795d594fSAndroid Build Coastguard Worker DCHECK(parameter_index != last_input_index);
2975*795d594fSAndroid Build Coastguard Worker }
2976*795d594fSAndroid Build Coastguard Worker replacement = invoke->InputAt(parameter_index++);
2977*795d594fSAndroid Build Coastguard Worker } else if (current->IsCurrentMethod()) {
2978*795d594fSAndroid Build Coastguard Worker replacement = outer_graph->GetCurrentMethod();
2979*795d594fSAndroid Build Coastguard Worker } else {
2980*795d594fSAndroid Build Coastguard Worker // It is OK to ignore MethodEntryHook for inlined functions.
2981*795d594fSAndroid Build Coastguard Worker // In debug mode we don't inline and in release mode method
2982*795d594fSAndroid Build Coastguard Worker // tracing is best effort so OK to ignore them.
2983*795d594fSAndroid Build Coastguard Worker DCHECK(current->IsGoto() || current->IsSuspendCheck() || current->IsMethodEntryHook());
2984*795d594fSAndroid Build Coastguard Worker entry_block_->RemoveInstruction(current);
2985*795d594fSAndroid Build Coastguard Worker }
2986*795d594fSAndroid Build Coastguard Worker if (replacement != nullptr) {
2987*795d594fSAndroid Build Coastguard Worker current->ReplaceWith(replacement);
2988*795d594fSAndroid Build Coastguard Worker // If the current is the return value then we need to update the latter.
2989*795d594fSAndroid Build Coastguard Worker if (current == return_value) {
2990*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(entry_block_, return_value->GetBlock());
2991*795d594fSAndroid Build Coastguard Worker return_value = replacement;
2992*795d594fSAndroid Build Coastguard Worker }
2993*795d594fSAndroid Build Coastguard Worker }
2994*795d594fSAndroid Build Coastguard Worker }
2995*795d594fSAndroid Build Coastguard Worker
2996*795d594fSAndroid Build Coastguard Worker return return_value;
2997*795d594fSAndroid Build Coastguard Worker }
2998*795d594fSAndroid Build Coastguard Worker
2999*795d594fSAndroid Build Coastguard Worker /*
3000*795d594fSAndroid Build Coastguard Worker * Loop will be transformed to:
3001*795d594fSAndroid Build Coastguard Worker * old_pre_header
3002*795d594fSAndroid Build Coastguard Worker * |
3003*795d594fSAndroid Build Coastguard Worker * if_block
3004*795d594fSAndroid Build Coastguard Worker * / \
3005*795d594fSAndroid Build Coastguard Worker * true_block false_block
3006*795d594fSAndroid Build Coastguard Worker * \ /
3007*795d594fSAndroid Build Coastguard Worker * new_pre_header
3008*795d594fSAndroid Build Coastguard Worker * |
3009*795d594fSAndroid Build Coastguard Worker * header
3010*795d594fSAndroid Build Coastguard Worker */
TransformLoopHeaderForBCE(HBasicBlock * header)3011*795d594fSAndroid Build Coastguard Worker void HGraph::TransformLoopHeaderForBCE(HBasicBlock* header) {
3012*795d594fSAndroid Build Coastguard Worker DCHECK(header->IsLoopHeader());
3013*795d594fSAndroid Build Coastguard Worker HBasicBlock* old_pre_header = header->GetDominator();
3014*795d594fSAndroid Build Coastguard Worker
3015*795d594fSAndroid Build Coastguard Worker // Need extra block to avoid critical edge.
3016*795d594fSAndroid Build Coastguard Worker HBasicBlock* if_block = new (allocator_) HBasicBlock(this, header->GetDexPc());
3017*795d594fSAndroid Build Coastguard Worker HBasicBlock* true_block = new (allocator_) HBasicBlock(this, header->GetDexPc());
3018*795d594fSAndroid Build Coastguard Worker HBasicBlock* false_block = new (allocator_) HBasicBlock(this, header->GetDexPc());
3019*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_pre_header = new (allocator_) HBasicBlock(this, header->GetDexPc());
3020*795d594fSAndroid Build Coastguard Worker AddBlock(if_block);
3021*795d594fSAndroid Build Coastguard Worker AddBlock(true_block);
3022*795d594fSAndroid Build Coastguard Worker AddBlock(false_block);
3023*795d594fSAndroid Build Coastguard Worker AddBlock(new_pre_header);
3024*795d594fSAndroid Build Coastguard Worker
3025*795d594fSAndroid Build Coastguard Worker header->ReplacePredecessor(old_pre_header, new_pre_header);
3026*795d594fSAndroid Build Coastguard Worker old_pre_header->successors_.clear();
3027*795d594fSAndroid Build Coastguard Worker old_pre_header->dominated_blocks_.clear();
3028*795d594fSAndroid Build Coastguard Worker
3029*795d594fSAndroid Build Coastguard Worker old_pre_header->AddSuccessor(if_block);
3030*795d594fSAndroid Build Coastguard Worker if_block->AddSuccessor(true_block); // True successor
3031*795d594fSAndroid Build Coastguard Worker if_block->AddSuccessor(false_block); // False successor
3032*795d594fSAndroid Build Coastguard Worker true_block->AddSuccessor(new_pre_header);
3033*795d594fSAndroid Build Coastguard Worker false_block->AddSuccessor(new_pre_header);
3034*795d594fSAndroid Build Coastguard Worker
3035*795d594fSAndroid Build Coastguard Worker old_pre_header->dominated_blocks_.push_back(if_block);
3036*795d594fSAndroid Build Coastguard Worker if_block->SetDominator(old_pre_header);
3037*795d594fSAndroid Build Coastguard Worker if_block->dominated_blocks_.push_back(true_block);
3038*795d594fSAndroid Build Coastguard Worker true_block->SetDominator(if_block);
3039*795d594fSAndroid Build Coastguard Worker if_block->dominated_blocks_.push_back(false_block);
3040*795d594fSAndroid Build Coastguard Worker false_block->SetDominator(if_block);
3041*795d594fSAndroid Build Coastguard Worker if_block->dominated_blocks_.push_back(new_pre_header);
3042*795d594fSAndroid Build Coastguard Worker new_pre_header->SetDominator(if_block);
3043*795d594fSAndroid Build Coastguard Worker new_pre_header->dominated_blocks_.push_back(header);
3044*795d594fSAndroid Build Coastguard Worker header->SetDominator(new_pre_header);
3045*795d594fSAndroid Build Coastguard Worker
3046*795d594fSAndroid Build Coastguard Worker // Fix reverse post order.
3047*795d594fSAndroid Build Coastguard Worker size_t index_of_header = IndexOfElement(reverse_post_order_, header);
3048*795d594fSAndroid Build Coastguard Worker MakeRoomFor(&reverse_post_order_, 4, index_of_header - 1);
3049*795d594fSAndroid Build Coastguard Worker reverse_post_order_[index_of_header++] = if_block;
3050*795d594fSAndroid Build Coastguard Worker reverse_post_order_[index_of_header++] = true_block;
3051*795d594fSAndroid Build Coastguard Worker reverse_post_order_[index_of_header++] = false_block;
3052*795d594fSAndroid Build Coastguard Worker reverse_post_order_[index_of_header++] = new_pre_header;
3053*795d594fSAndroid Build Coastguard Worker
3054*795d594fSAndroid Build Coastguard Worker // The pre_header can never be a back edge of a loop.
3055*795d594fSAndroid Build Coastguard Worker DCHECK((old_pre_header->GetLoopInformation() == nullptr) ||
3056*795d594fSAndroid Build Coastguard Worker !old_pre_header->GetLoopInformation()->IsBackEdge(*old_pre_header));
3057*795d594fSAndroid Build Coastguard Worker UpdateLoopAndTryInformationOfNewBlock(
3058*795d594fSAndroid Build Coastguard Worker if_block, old_pre_header, /* replace_if_back_edge= */ false);
3059*795d594fSAndroid Build Coastguard Worker UpdateLoopAndTryInformationOfNewBlock(
3060*795d594fSAndroid Build Coastguard Worker true_block, old_pre_header, /* replace_if_back_edge= */ false);
3061*795d594fSAndroid Build Coastguard Worker UpdateLoopAndTryInformationOfNewBlock(
3062*795d594fSAndroid Build Coastguard Worker false_block, old_pre_header, /* replace_if_back_edge= */ false);
3063*795d594fSAndroid Build Coastguard Worker UpdateLoopAndTryInformationOfNewBlock(
3064*795d594fSAndroid Build Coastguard Worker new_pre_header, old_pre_header, /* replace_if_back_edge= */ false);
3065*795d594fSAndroid Build Coastguard Worker }
3066*795d594fSAndroid Build Coastguard Worker
3067*795d594fSAndroid Build Coastguard Worker // Creates a new two-basic-block loop and inserts it between original loop header and
3068*795d594fSAndroid Build Coastguard Worker // original loop exit; also adjusts dominators, post order and new LoopInformation.
TransformLoopForVectorization(HBasicBlock * header,HBasicBlock * body,HBasicBlock * exit)3069*795d594fSAndroid Build Coastguard Worker HBasicBlock* HGraph::TransformLoopForVectorization(HBasicBlock* header,
3070*795d594fSAndroid Build Coastguard Worker HBasicBlock* body,
3071*795d594fSAndroid Build Coastguard Worker HBasicBlock* exit) {
3072*795d594fSAndroid Build Coastguard Worker DCHECK(header->IsLoopHeader());
3073*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop = header->GetLoopInformation();
3074*795d594fSAndroid Build Coastguard Worker
3075*795d594fSAndroid Build Coastguard Worker // Add new loop blocks.
3076*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_pre_header = new (allocator_) HBasicBlock(this, header->GetDexPc());
3077*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_header = new (allocator_) HBasicBlock(this, header->GetDexPc());
3078*795d594fSAndroid Build Coastguard Worker HBasicBlock* new_body = new (allocator_) HBasicBlock(this, header->GetDexPc());
3079*795d594fSAndroid Build Coastguard Worker AddBlock(new_pre_header);
3080*795d594fSAndroid Build Coastguard Worker AddBlock(new_header);
3081*795d594fSAndroid Build Coastguard Worker AddBlock(new_body);
3082*795d594fSAndroid Build Coastguard Worker
3083*795d594fSAndroid Build Coastguard Worker // Set up control flow.
3084*795d594fSAndroid Build Coastguard Worker header->ReplaceSuccessor(exit, new_pre_header);
3085*795d594fSAndroid Build Coastguard Worker new_pre_header->AddSuccessor(new_header);
3086*795d594fSAndroid Build Coastguard Worker new_header->AddSuccessor(exit);
3087*795d594fSAndroid Build Coastguard Worker new_header->AddSuccessor(new_body);
3088*795d594fSAndroid Build Coastguard Worker new_body->AddSuccessor(new_header);
3089*795d594fSAndroid Build Coastguard Worker
3090*795d594fSAndroid Build Coastguard Worker // Set up dominators.
3091*795d594fSAndroid Build Coastguard Worker header->ReplaceDominatedBlock(exit, new_pre_header);
3092*795d594fSAndroid Build Coastguard Worker new_pre_header->SetDominator(header);
3093*795d594fSAndroid Build Coastguard Worker new_pre_header->dominated_blocks_.push_back(new_header);
3094*795d594fSAndroid Build Coastguard Worker new_header->SetDominator(new_pre_header);
3095*795d594fSAndroid Build Coastguard Worker new_header->dominated_blocks_.push_back(new_body);
3096*795d594fSAndroid Build Coastguard Worker new_body->SetDominator(new_header);
3097*795d594fSAndroid Build Coastguard Worker new_header->dominated_blocks_.push_back(exit);
3098*795d594fSAndroid Build Coastguard Worker exit->SetDominator(new_header);
3099*795d594fSAndroid Build Coastguard Worker
3100*795d594fSAndroid Build Coastguard Worker // Fix reverse post order.
3101*795d594fSAndroid Build Coastguard Worker size_t index_of_header = IndexOfElement(reverse_post_order_, header);
3102*795d594fSAndroid Build Coastguard Worker MakeRoomFor(&reverse_post_order_, 2, index_of_header);
3103*795d594fSAndroid Build Coastguard Worker reverse_post_order_[++index_of_header] = new_pre_header;
3104*795d594fSAndroid Build Coastguard Worker reverse_post_order_[++index_of_header] = new_header;
3105*795d594fSAndroid Build Coastguard Worker size_t index_of_body = IndexOfElement(reverse_post_order_, body);
3106*795d594fSAndroid Build Coastguard Worker MakeRoomFor(&reverse_post_order_, 1, index_of_body - 1);
3107*795d594fSAndroid Build Coastguard Worker reverse_post_order_[index_of_body] = new_body;
3108*795d594fSAndroid Build Coastguard Worker
3109*795d594fSAndroid Build Coastguard Worker // Add gotos and suspend check (client must add conditional in header).
3110*795d594fSAndroid Build Coastguard Worker new_pre_header->AddInstruction(new (allocator_) HGoto());
3111*795d594fSAndroid Build Coastguard Worker HSuspendCheck* suspend_check = new (allocator_) HSuspendCheck(header->GetDexPc());
3112*795d594fSAndroid Build Coastguard Worker new_header->AddInstruction(suspend_check);
3113*795d594fSAndroid Build Coastguard Worker new_body->AddInstruction(new (allocator_) HGoto());
3114*795d594fSAndroid Build Coastguard Worker DCHECK(loop->GetSuspendCheck() != nullptr);
3115*795d594fSAndroid Build Coastguard Worker suspend_check->CopyEnvironmentFromWithLoopPhiAdjustment(
3116*795d594fSAndroid Build Coastguard Worker loop->GetSuspendCheck()->GetEnvironment(), header);
3117*795d594fSAndroid Build Coastguard Worker
3118*795d594fSAndroid Build Coastguard Worker // Update loop information.
3119*795d594fSAndroid Build Coastguard Worker new_header->AddBackEdge(new_body);
3120*795d594fSAndroid Build Coastguard Worker new_header->GetLoopInformation()->SetSuspendCheck(suspend_check);
3121*795d594fSAndroid Build Coastguard Worker new_header->GetLoopInformation()->Populate();
3122*795d594fSAndroid Build Coastguard Worker new_pre_header->SetLoopInformation(loop->GetPreHeader()->GetLoopInformation()); // outward
3123*795d594fSAndroid Build Coastguard Worker HLoopInformationOutwardIterator it(*new_header);
3124*795d594fSAndroid Build Coastguard Worker for (it.Advance(); !it.Done(); it.Advance()) {
3125*795d594fSAndroid Build Coastguard Worker it.Current()->Add(new_pre_header);
3126*795d594fSAndroid Build Coastguard Worker it.Current()->Add(new_header);
3127*795d594fSAndroid Build Coastguard Worker it.Current()->Add(new_body);
3128*795d594fSAndroid Build Coastguard Worker }
3129*795d594fSAndroid Build Coastguard Worker return new_pre_header;
3130*795d594fSAndroid Build Coastguard Worker }
3131*795d594fSAndroid Build Coastguard Worker
CheckAgainstUpperBound(ReferenceTypeInfo rti,ReferenceTypeInfo upper_bound_rti)3132*795d594fSAndroid Build Coastguard Worker static void CheckAgainstUpperBound(ReferenceTypeInfo rti, ReferenceTypeInfo upper_bound_rti) {
3133*795d594fSAndroid Build Coastguard Worker if (rti.IsValid()) {
3134*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3135*795d594fSAndroid Build Coastguard Worker DCHECK(upper_bound_rti.IsSupertypeOf(rti))
3136*795d594fSAndroid Build Coastguard Worker << " upper_bound_rti: " << upper_bound_rti
3137*795d594fSAndroid Build Coastguard Worker << " rti: " << rti;
3138*795d594fSAndroid Build Coastguard Worker DCHECK_IMPLIES(upper_bound_rti.GetTypeHandle()->CannotBeAssignedFromOtherTypes(), rti.IsExact())
3139*795d594fSAndroid Build Coastguard Worker << " upper_bound_rti: " << upper_bound_rti
3140*795d594fSAndroid Build Coastguard Worker << " rti: " << rti;
3141*795d594fSAndroid Build Coastguard Worker }
3142*795d594fSAndroid Build Coastguard Worker }
3143*795d594fSAndroid Build Coastguard Worker
SetReferenceTypeInfo(ReferenceTypeInfo rti)3144*795d594fSAndroid Build Coastguard Worker void HInstruction::SetReferenceTypeInfo(ReferenceTypeInfo rti) {
3145*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
3146*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(GetType(), DataType::Type::kReference);
3147*795d594fSAndroid Build Coastguard Worker DCHECK(rti.IsValid()) << "Invalid RTI for " << DebugName();
3148*795d594fSAndroid Build Coastguard Worker if (IsBoundType()) {
3149*795d594fSAndroid Build Coastguard Worker // Having the test here spares us from making the method virtual just for
3150*795d594fSAndroid Build Coastguard Worker // the sake of a DCHECK.
3151*795d594fSAndroid Build Coastguard Worker CheckAgainstUpperBound(rti, AsBoundType()->GetUpperBound());
3152*795d594fSAndroid Build Coastguard Worker }
3153*795d594fSAndroid Build Coastguard Worker }
3154*795d594fSAndroid Build Coastguard Worker reference_type_handle_ = rti.GetTypeHandle();
3155*795d594fSAndroid Build Coastguard Worker SetPackedFlag<kFlagReferenceTypeIsExact>(rti.IsExact());
3156*795d594fSAndroid Build Coastguard Worker }
3157*795d594fSAndroid Build Coastguard Worker
SetReferenceTypeInfoIfValid(ReferenceTypeInfo rti)3158*795d594fSAndroid Build Coastguard Worker void HInstruction::SetReferenceTypeInfoIfValid(ReferenceTypeInfo rti) {
3159*795d594fSAndroid Build Coastguard Worker if (rti.IsValid()) {
3160*795d594fSAndroid Build Coastguard Worker SetReferenceTypeInfo(rti);
3161*795d594fSAndroid Build Coastguard Worker }
3162*795d594fSAndroid Build Coastguard Worker }
3163*795d594fSAndroid Build Coastguard Worker
InstructionDataEquals(const HInstruction * other) const3164*795d594fSAndroid Build Coastguard Worker bool HBoundType::InstructionDataEquals(const HInstruction* other) const {
3165*795d594fSAndroid Build Coastguard Worker const HBoundType* other_bt = other->AsBoundType();
3166*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3167*795d594fSAndroid Build Coastguard Worker return GetUpperBound().IsEqual(other_bt->GetUpperBound()) &&
3168*795d594fSAndroid Build Coastguard Worker GetUpperCanBeNull() == other_bt->GetUpperCanBeNull() &&
3169*795d594fSAndroid Build Coastguard Worker CanBeNull() == other_bt->CanBeNull();
3170*795d594fSAndroid Build Coastguard Worker }
3171*795d594fSAndroid Build Coastguard Worker
SetUpperBound(const ReferenceTypeInfo & upper_bound,bool can_be_null)3172*795d594fSAndroid Build Coastguard Worker void HBoundType::SetUpperBound(const ReferenceTypeInfo& upper_bound, bool can_be_null) {
3173*795d594fSAndroid Build Coastguard Worker if (kIsDebugBuild) {
3174*795d594fSAndroid Build Coastguard Worker DCHECK(upper_bound.IsValid());
3175*795d594fSAndroid Build Coastguard Worker DCHECK(!upper_bound_.IsValid()) << "Upper bound should only be set once.";
3176*795d594fSAndroid Build Coastguard Worker CheckAgainstUpperBound(GetReferenceTypeInfo(), upper_bound);
3177*795d594fSAndroid Build Coastguard Worker }
3178*795d594fSAndroid Build Coastguard Worker upper_bound_ = upper_bound;
3179*795d594fSAndroid Build Coastguard Worker SetPackedFlag<kFlagUpperCanBeNull>(can_be_null);
3180*795d594fSAndroid Build Coastguard Worker }
3181*795d594fSAndroid Build Coastguard Worker
HasAnyEnvironmentUseBefore(HInstruction * other)3182*795d594fSAndroid Build Coastguard Worker bool HInstruction::HasAnyEnvironmentUseBefore(HInstruction* other) {
3183*795d594fSAndroid Build Coastguard Worker // For now, assume that instructions in different blocks may use the
3184*795d594fSAndroid Build Coastguard Worker // environment.
3185*795d594fSAndroid Build Coastguard Worker // TODO: Use the control flow to decide if this is true.
3186*795d594fSAndroid Build Coastguard Worker if (GetBlock() != other->GetBlock()) {
3187*795d594fSAndroid Build Coastguard Worker return true;
3188*795d594fSAndroid Build Coastguard Worker }
3189*795d594fSAndroid Build Coastguard Worker
3190*795d594fSAndroid Build Coastguard Worker // We know that we are in the same block. Walk from 'this' to 'other',
3191*795d594fSAndroid Build Coastguard Worker // checking to see if there is any instruction with an environment.
3192*795d594fSAndroid Build Coastguard Worker HInstruction* current = this;
3193*795d594fSAndroid Build Coastguard Worker for (; current != other && current != nullptr; current = current->GetNext()) {
3194*795d594fSAndroid Build Coastguard Worker // This is a conservative check, as the instruction result may not be in
3195*795d594fSAndroid Build Coastguard Worker // the referenced environment.
3196*795d594fSAndroid Build Coastguard Worker if (current->HasEnvironment()) {
3197*795d594fSAndroid Build Coastguard Worker return true;
3198*795d594fSAndroid Build Coastguard Worker }
3199*795d594fSAndroid Build Coastguard Worker }
3200*795d594fSAndroid Build Coastguard Worker
3201*795d594fSAndroid Build Coastguard Worker // We should have been called with 'this' before 'other' in the block.
3202*795d594fSAndroid Build Coastguard Worker // Just confirm this.
3203*795d594fSAndroid Build Coastguard Worker DCHECK(current != nullptr);
3204*795d594fSAndroid Build Coastguard Worker return false;
3205*795d594fSAndroid Build Coastguard Worker }
3206*795d594fSAndroid Build Coastguard Worker
SetIntrinsic(Intrinsics intrinsic,IntrinsicNeedsEnvironment needs_env,IntrinsicSideEffects side_effects,IntrinsicExceptions exceptions)3207*795d594fSAndroid Build Coastguard Worker void HInvoke::SetIntrinsic(Intrinsics intrinsic,
3208*795d594fSAndroid Build Coastguard Worker IntrinsicNeedsEnvironment needs_env,
3209*795d594fSAndroid Build Coastguard Worker IntrinsicSideEffects side_effects,
3210*795d594fSAndroid Build Coastguard Worker IntrinsicExceptions exceptions) {
3211*795d594fSAndroid Build Coastguard Worker intrinsic_ = intrinsic;
3212*795d594fSAndroid Build Coastguard Worker IntrinsicOptimizations opt(this);
3213*795d594fSAndroid Build Coastguard Worker
3214*795d594fSAndroid Build Coastguard Worker // Adjust method's side effects from intrinsic table.
3215*795d594fSAndroid Build Coastguard Worker switch (side_effects) {
3216*795d594fSAndroid Build Coastguard Worker case kNoSideEffects: SetSideEffects(SideEffects::None()); break;
3217*795d594fSAndroid Build Coastguard Worker case kReadSideEffects: SetSideEffects(SideEffects::AllReads()); break;
3218*795d594fSAndroid Build Coastguard Worker case kWriteSideEffects: SetSideEffects(SideEffects::AllWrites()); break;
3219*795d594fSAndroid Build Coastguard Worker case kAllSideEffects: SetSideEffects(SideEffects::AllExceptGCDependency()); break;
3220*795d594fSAndroid Build Coastguard Worker }
3221*795d594fSAndroid Build Coastguard Worker
3222*795d594fSAndroid Build Coastguard Worker if (needs_env == kNoEnvironment) {
3223*795d594fSAndroid Build Coastguard Worker opt.SetDoesNotNeedEnvironment();
3224*795d594fSAndroid Build Coastguard Worker } else {
3225*795d594fSAndroid Build Coastguard Worker // If we need an environment, that means there will be a call, which can trigger GC.
3226*795d594fSAndroid Build Coastguard Worker SetSideEffects(GetSideEffects().Union(SideEffects::CanTriggerGC()));
3227*795d594fSAndroid Build Coastguard Worker }
3228*795d594fSAndroid Build Coastguard Worker // Adjust method's exception status from intrinsic table.
3229*795d594fSAndroid Build Coastguard Worker SetCanThrow(exceptions == kCanThrow);
3230*795d594fSAndroid Build Coastguard Worker }
3231*795d594fSAndroid Build Coastguard Worker
IsStringAlloc() const3232*795d594fSAndroid Build Coastguard Worker bool HNewInstance::IsStringAlloc() const {
3233*795d594fSAndroid Build Coastguard Worker return GetEntrypoint() == kQuickAllocStringObject;
3234*795d594fSAndroid Build Coastguard Worker }
3235*795d594fSAndroid Build Coastguard Worker
NeedsEnvironment() const3236*795d594fSAndroid Build Coastguard Worker bool HInvoke::NeedsEnvironment() const {
3237*795d594fSAndroid Build Coastguard Worker if (!IsIntrinsic()) {
3238*795d594fSAndroid Build Coastguard Worker return true;
3239*795d594fSAndroid Build Coastguard Worker }
3240*795d594fSAndroid Build Coastguard Worker IntrinsicOptimizations opt(*this);
3241*795d594fSAndroid Build Coastguard Worker return !opt.GetDoesNotNeedEnvironment();
3242*795d594fSAndroid Build Coastguard Worker }
3243*795d594fSAndroid Build Coastguard Worker
GetDexFileForPcRelativeDexCache() const3244*795d594fSAndroid Build Coastguard Worker const DexFile& HInvokeStaticOrDirect::GetDexFileForPcRelativeDexCache() const {
3245*795d594fSAndroid Build Coastguard Worker ArtMethod* caller = GetEnvironment()->GetMethod();
3246*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3247*795d594fSAndroid Build Coastguard Worker // `caller` is null for a top-level graph representing a method whose declaring
3248*795d594fSAndroid Build Coastguard Worker // class was not resolved.
3249*795d594fSAndroid Build Coastguard Worker return caller == nullptr ? GetBlock()->GetGraph()->GetDexFile() : *caller->GetDexFile();
3250*795d594fSAndroid Build Coastguard Worker }
3251*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,HInvokeStaticOrDirect::ClinitCheckRequirement rhs)3252*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::ClinitCheckRequirement rhs) {
3253*795d594fSAndroid Build Coastguard Worker switch (rhs) {
3254*795d594fSAndroid Build Coastguard Worker case HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit:
3255*795d594fSAndroid Build Coastguard Worker return os << "explicit";
3256*795d594fSAndroid Build Coastguard Worker case HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit:
3257*795d594fSAndroid Build Coastguard Worker return os << "implicit";
3258*795d594fSAndroid Build Coastguard Worker case HInvokeStaticOrDirect::ClinitCheckRequirement::kNone:
3259*795d594fSAndroid Build Coastguard Worker return os << "none";
3260*795d594fSAndroid Build Coastguard Worker }
3261*795d594fSAndroid Build Coastguard Worker }
3262*795d594fSAndroid Build Coastguard Worker
CanBeNull() const3263*795d594fSAndroid Build Coastguard Worker bool HInvokeStaticOrDirect::CanBeNull() const {
3264*795d594fSAndroid Build Coastguard Worker if (IsStringInit()) {
3265*795d594fSAndroid Build Coastguard Worker return false;
3266*795d594fSAndroid Build Coastguard Worker }
3267*795d594fSAndroid Build Coastguard Worker return HInvoke::CanBeNull();
3268*795d594fSAndroid Build Coastguard Worker }
3269*795d594fSAndroid Build Coastguard Worker
CanBeNull() const3270*795d594fSAndroid Build Coastguard Worker bool HInvoke::CanBeNull() const {
3271*795d594fSAndroid Build Coastguard Worker switch (GetIntrinsic()) {
3272*795d594fSAndroid Build Coastguard Worker case Intrinsics::kThreadCurrentThread:
3273*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBufferAppend:
3274*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBufferToString:
3275*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendObject:
3276*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendString:
3277*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendCharSequence:
3278*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendCharArray:
3279*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendBoolean:
3280*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendChar:
3281*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendInt:
3282*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendLong:
3283*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendFloat:
3284*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderAppendDouble:
3285*795d594fSAndroid Build Coastguard Worker case Intrinsics::kStringBuilderToString:
3286*795d594fSAndroid Build Coastguard Worker #define DEFINE_BOXED_CASE(name, unused1, unused2, unused3, unused4) \
3287*795d594fSAndroid Build Coastguard Worker case Intrinsics::k##name##ValueOf:
3288*795d594fSAndroid Build Coastguard Worker BOXED_TYPES(DEFINE_BOXED_CASE)
3289*795d594fSAndroid Build Coastguard Worker #undef DEFINE_BOXED_CASE
3290*795d594fSAndroid Build Coastguard Worker return false;
3291*795d594fSAndroid Build Coastguard Worker default:
3292*795d594fSAndroid Build Coastguard Worker return GetType() == DataType::Type::kReference;
3293*795d594fSAndroid Build Coastguard Worker }
3294*795d594fSAndroid Build Coastguard Worker }
3295*795d594fSAndroid Build Coastguard Worker
CanDoImplicitNullCheckOn(HInstruction * obj) const3296*795d594fSAndroid Build Coastguard Worker bool HInvokeVirtual::CanDoImplicitNullCheckOn(HInstruction* obj) const {
3297*795d594fSAndroid Build Coastguard Worker if (obj != InputAt(0)) {
3298*795d594fSAndroid Build Coastguard Worker return false;
3299*795d594fSAndroid Build Coastguard Worker }
3300*795d594fSAndroid Build Coastguard Worker switch (GetIntrinsic()) {
3301*795d594fSAndroid Build Coastguard Worker case Intrinsics::kNone:
3302*795d594fSAndroid Build Coastguard Worker return true;
3303*795d594fSAndroid Build Coastguard Worker case Intrinsics::kReferenceRefersTo:
3304*795d594fSAndroid Build Coastguard Worker return true;
3305*795d594fSAndroid Build Coastguard Worker default:
3306*795d594fSAndroid Build Coastguard Worker // TODO: Add implicit null checks in more intrinsics.
3307*795d594fSAndroid Build Coastguard Worker return false;
3308*795d594fSAndroid Build Coastguard Worker }
3309*795d594fSAndroid Build Coastguard Worker }
3310*795d594fSAndroid Build Coastguard Worker
InstructionDataEquals(const HInstruction * other) const3311*795d594fSAndroid Build Coastguard Worker bool HLoadClass::InstructionDataEquals(const HInstruction* other) const {
3312*795d594fSAndroid Build Coastguard Worker const HLoadClass* other_load_class = other->AsLoadClass();
3313*795d594fSAndroid Build Coastguard Worker // TODO: To allow GVN for HLoadClass from different dex files, we should compare the type
3314*795d594fSAndroid Build Coastguard Worker // names rather than type indexes. However, we shall also have to re-think the hash code.
3315*795d594fSAndroid Build Coastguard Worker if (type_index_ != other_load_class->type_index_ ||
3316*795d594fSAndroid Build Coastguard Worker GetPackedFields() != other_load_class->GetPackedFields()) {
3317*795d594fSAndroid Build Coastguard Worker return false;
3318*795d594fSAndroid Build Coastguard Worker }
3319*795d594fSAndroid Build Coastguard Worker switch (GetLoadKind()) {
3320*795d594fSAndroid Build Coastguard Worker case LoadKind::kBootImageRelRo:
3321*795d594fSAndroid Build Coastguard Worker case LoadKind::kJitBootImageAddress:
3322*795d594fSAndroid Build Coastguard Worker case LoadKind::kJitTableAddress: {
3323*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3324*795d594fSAndroid Build Coastguard Worker return GetClass().Get() == other_load_class->GetClass().Get();
3325*795d594fSAndroid Build Coastguard Worker }
3326*795d594fSAndroid Build Coastguard Worker default:
3327*795d594fSAndroid Build Coastguard Worker DCHECK(HasTypeReference(GetLoadKind()));
3328*795d594fSAndroid Build Coastguard Worker return IsSameDexFile(GetDexFile(), other_load_class->GetDexFile());
3329*795d594fSAndroid Build Coastguard Worker }
3330*795d594fSAndroid Build Coastguard Worker }
3331*795d594fSAndroid Build Coastguard Worker
InstructionDataEquals(const HInstruction * other) const3332*795d594fSAndroid Build Coastguard Worker bool HLoadString::InstructionDataEquals(const HInstruction* other) const {
3333*795d594fSAndroid Build Coastguard Worker const HLoadString* other_load_string = other->AsLoadString();
3334*795d594fSAndroid Build Coastguard Worker // TODO: To allow GVN for HLoadString from different dex files, we should compare the strings
3335*795d594fSAndroid Build Coastguard Worker // rather than their indexes. However, we shall also have to re-think the hash code.
3336*795d594fSAndroid Build Coastguard Worker if (string_index_ != other_load_string->string_index_ ||
3337*795d594fSAndroid Build Coastguard Worker GetPackedFields() != other_load_string->GetPackedFields()) {
3338*795d594fSAndroid Build Coastguard Worker return false;
3339*795d594fSAndroid Build Coastguard Worker }
3340*795d594fSAndroid Build Coastguard Worker switch (GetLoadKind()) {
3341*795d594fSAndroid Build Coastguard Worker case LoadKind::kBootImageRelRo:
3342*795d594fSAndroid Build Coastguard Worker case LoadKind::kJitBootImageAddress:
3343*795d594fSAndroid Build Coastguard Worker case LoadKind::kJitTableAddress: {
3344*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
3345*795d594fSAndroid Build Coastguard Worker return GetString().Get() == other_load_string->GetString().Get();
3346*795d594fSAndroid Build Coastguard Worker }
3347*795d594fSAndroid Build Coastguard Worker default:
3348*795d594fSAndroid Build Coastguard Worker return IsSameDexFile(GetDexFile(), other_load_string->GetDexFile());
3349*795d594fSAndroid Build Coastguard Worker }
3350*795d594fSAndroid Build Coastguard Worker }
3351*795d594fSAndroid Build Coastguard Worker
RemoveEnvironmentUsers()3352*795d594fSAndroid Build Coastguard Worker void HInstruction::RemoveEnvironmentUsers() {
3353*795d594fSAndroid Build Coastguard Worker for (const HUseListNode<HEnvironment*>& use : GetEnvUses()) {
3354*795d594fSAndroid Build Coastguard Worker HEnvironment* user = use.GetUser();
3355*795d594fSAndroid Build Coastguard Worker user->SetRawEnvAt(use.GetIndex(), nullptr);
3356*795d594fSAndroid Build Coastguard Worker }
3357*795d594fSAndroid Build Coastguard Worker env_uses_.clear();
3358*795d594fSAndroid Build Coastguard Worker }
3359*795d594fSAndroid Build Coastguard Worker
ReplaceInstrOrPhiByClone(HInstruction * instr)3360*795d594fSAndroid Build Coastguard Worker HInstruction* ReplaceInstrOrPhiByClone(HInstruction* instr) {
3361*795d594fSAndroid Build Coastguard Worker HInstruction* clone = instr->Clone(instr->GetBlock()->GetGraph()->GetAllocator());
3362*795d594fSAndroid Build Coastguard Worker HBasicBlock* block = instr->GetBlock();
3363*795d594fSAndroid Build Coastguard Worker
3364*795d594fSAndroid Build Coastguard Worker if (instr->IsPhi()) {
3365*795d594fSAndroid Build Coastguard Worker HPhi* phi = instr->AsPhi();
3366*795d594fSAndroid Build Coastguard Worker DCHECK(!phi->HasEnvironment());
3367*795d594fSAndroid Build Coastguard Worker HPhi* phi_clone = clone->AsPhi();
3368*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemovePhiWith(phi, phi_clone);
3369*795d594fSAndroid Build Coastguard Worker } else {
3370*795d594fSAndroid Build Coastguard Worker block->ReplaceAndRemoveInstructionWith(instr, clone);
3371*795d594fSAndroid Build Coastguard Worker if (instr->HasEnvironment()) {
3372*795d594fSAndroid Build Coastguard Worker clone->CopyEnvironmentFrom(instr->GetEnvironment());
3373*795d594fSAndroid Build Coastguard Worker HLoopInformation* loop_info = block->GetLoopInformation();
3374*795d594fSAndroid Build Coastguard Worker if (instr->IsSuspendCheck() && loop_info != nullptr) {
3375*795d594fSAndroid Build Coastguard Worker loop_info->SetSuspendCheck(clone->AsSuspendCheck());
3376*795d594fSAndroid Build Coastguard Worker }
3377*795d594fSAndroid Build Coastguard Worker }
3378*795d594fSAndroid Build Coastguard Worker }
3379*795d594fSAndroid Build Coastguard Worker return clone;
3380*795d594fSAndroid Build Coastguard Worker }
3381*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,const MoveOperands & rhs)3382*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const MoveOperands& rhs) {
3383*795d594fSAndroid Build Coastguard Worker os << "["
3384*795d594fSAndroid Build Coastguard Worker << " source=" << rhs.GetSource()
3385*795d594fSAndroid Build Coastguard Worker << " destination=" << rhs.GetDestination()
3386*795d594fSAndroid Build Coastguard Worker << " type=" << rhs.GetType()
3387*795d594fSAndroid Build Coastguard Worker << " instruction=";
3388*795d594fSAndroid Build Coastguard Worker if (rhs.GetInstruction() != nullptr) {
3389*795d594fSAndroid Build Coastguard Worker os << rhs.GetInstruction()->DebugName() << ' ' << rhs.GetInstruction()->GetId();
3390*795d594fSAndroid Build Coastguard Worker } else {
3391*795d594fSAndroid Build Coastguard Worker os << "null";
3392*795d594fSAndroid Build Coastguard Worker }
3393*795d594fSAndroid Build Coastguard Worker os << " ]";
3394*795d594fSAndroid Build Coastguard Worker return os;
3395*795d594fSAndroid Build Coastguard Worker }
3396*795d594fSAndroid Build Coastguard Worker
operator <<(std::ostream & os,TypeCheckKind rhs)3397*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs) {
3398*795d594fSAndroid Build Coastguard Worker switch (rhs) {
3399*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kUnresolvedCheck:
3400*795d594fSAndroid Build Coastguard Worker return os << "unresolved_check";
3401*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kExactCheck:
3402*795d594fSAndroid Build Coastguard Worker return os << "exact_check";
3403*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kClassHierarchyCheck:
3404*795d594fSAndroid Build Coastguard Worker return os << "class_hierarchy_check";
3405*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kAbstractClassCheck:
3406*795d594fSAndroid Build Coastguard Worker return os << "abstract_class_check";
3407*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kInterfaceCheck:
3408*795d594fSAndroid Build Coastguard Worker return os << "interface_check";
3409*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayObjectCheck:
3410*795d594fSAndroid Build Coastguard Worker return os << "array_object_check";
3411*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kArrayCheck:
3412*795d594fSAndroid Build Coastguard Worker return os << "array_check";
3413*795d594fSAndroid Build Coastguard Worker case TypeCheckKind::kBitstringCheck:
3414*795d594fSAndroid Build Coastguard Worker return os << "bitstring_check";
3415*795d594fSAndroid Build Coastguard Worker }
3416*795d594fSAndroid Build Coastguard Worker }
3417*795d594fSAndroid Build Coastguard Worker
3418*795d594fSAndroid Build Coastguard Worker // Check that intrinsic enum values fit within space set aside in ArtMethod modifier flags.
3419*795d594fSAndroid Build Coastguard Worker #define CHECK_INTRINSICS_ENUM_VALUES(Name, InvokeType, _, SideEffects, Exceptions, ...) \
3420*795d594fSAndroid Build Coastguard Worker static_assert( \
3421*795d594fSAndroid Build Coastguard Worker static_cast<uint32_t>(Intrinsics::k ## Name) <= (kAccIntrinsicBits >> CTZ(kAccIntrinsicBits)), \
3422*795d594fSAndroid Build Coastguard Worker "Intrinsics enumeration space overflow.");
ART_INTRINSICS_LIST(CHECK_INTRINSICS_ENUM_VALUES)3423*795d594fSAndroid Build Coastguard Worker ART_INTRINSICS_LIST(CHECK_INTRINSICS_ENUM_VALUES)
3424*795d594fSAndroid Build Coastguard Worker #undef CHECK_INTRINSICS_ENUM_VALUES
3425*795d594fSAndroid Build Coastguard Worker
3426*795d594fSAndroid Build Coastguard Worker // Function that returns whether an intrinsic needs an environment or not.
3427*795d594fSAndroid Build Coastguard Worker static inline IntrinsicNeedsEnvironment NeedsEnvironmentIntrinsic(Intrinsics i) {
3428*795d594fSAndroid Build Coastguard Worker switch (i) {
3429*795d594fSAndroid Build Coastguard Worker case Intrinsics::kNone:
3430*795d594fSAndroid Build Coastguard Worker return kNeedsEnvironment; // Non-sensical for intrinsic.
3431*795d594fSAndroid Build Coastguard Worker #define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnv, SideEffects, Exceptions, ...) \
3432*795d594fSAndroid Build Coastguard Worker case Intrinsics::k ## Name: \
3433*795d594fSAndroid Build Coastguard Worker return NeedsEnv;
3434*795d594fSAndroid Build Coastguard Worker ART_INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
3435*795d594fSAndroid Build Coastguard Worker #undef OPTIMIZING_INTRINSICS
3436*795d594fSAndroid Build Coastguard Worker }
3437*795d594fSAndroid Build Coastguard Worker return kNeedsEnvironment;
3438*795d594fSAndroid Build Coastguard Worker }
3439*795d594fSAndroid Build Coastguard Worker
3440*795d594fSAndroid Build Coastguard Worker // Function that returns whether an intrinsic has side effects.
GetSideEffectsIntrinsic(Intrinsics i)3441*795d594fSAndroid Build Coastguard Worker static inline IntrinsicSideEffects GetSideEffectsIntrinsic(Intrinsics i) {
3442*795d594fSAndroid Build Coastguard Worker switch (i) {
3443*795d594fSAndroid Build Coastguard Worker case Intrinsics::kNone:
3444*795d594fSAndroid Build Coastguard Worker return kAllSideEffects;
3445*795d594fSAndroid Build Coastguard Worker #define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnv, SideEffects, Exceptions, ...) \
3446*795d594fSAndroid Build Coastguard Worker case Intrinsics::k ## Name: \
3447*795d594fSAndroid Build Coastguard Worker return SideEffects;
3448*795d594fSAndroid Build Coastguard Worker ART_INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
3449*795d594fSAndroid Build Coastguard Worker #undef OPTIMIZING_INTRINSICS
3450*795d594fSAndroid Build Coastguard Worker }
3451*795d594fSAndroid Build Coastguard Worker return kAllSideEffects;
3452*795d594fSAndroid Build Coastguard Worker }
3453*795d594fSAndroid Build Coastguard Worker
3454*795d594fSAndroid Build Coastguard Worker // Function that returns whether an intrinsic can throw exceptions.
GetExceptionsIntrinsic(Intrinsics i)3455*795d594fSAndroid Build Coastguard Worker static inline IntrinsicExceptions GetExceptionsIntrinsic(Intrinsics i) {
3456*795d594fSAndroid Build Coastguard Worker switch (i) {
3457*795d594fSAndroid Build Coastguard Worker case Intrinsics::kNone:
3458*795d594fSAndroid Build Coastguard Worker return kCanThrow;
3459*795d594fSAndroid Build Coastguard Worker #define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnv, SideEffects, Exceptions, ...) \
3460*795d594fSAndroid Build Coastguard Worker case Intrinsics::k ## Name: \
3461*795d594fSAndroid Build Coastguard Worker return Exceptions;
3462*795d594fSAndroid Build Coastguard Worker ART_INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
3463*795d594fSAndroid Build Coastguard Worker #undef OPTIMIZING_INTRINSICS
3464*795d594fSAndroid Build Coastguard Worker }
3465*795d594fSAndroid Build Coastguard Worker return kCanThrow;
3466*795d594fSAndroid Build Coastguard Worker }
3467*795d594fSAndroid Build Coastguard Worker
SetResolvedMethod(ArtMethod * method,bool enable_intrinsic_opt)3468*795d594fSAndroid Build Coastguard Worker void HInvoke::SetResolvedMethod(ArtMethod* method, bool enable_intrinsic_opt) {
3469*795d594fSAndroid Build Coastguard Worker if (method != nullptr && method->IsIntrinsic() && enable_intrinsic_opt) {
3470*795d594fSAndroid Build Coastguard Worker Intrinsics intrinsic = method->GetIntrinsic();
3471*795d594fSAndroid Build Coastguard Worker SetIntrinsic(intrinsic,
3472*795d594fSAndroid Build Coastguard Worker NeedsEnvironmentIntrinsic(intrinsic),
3473*795d594fSAndroid Build Coastguard Worker GetSideEffectsIntrinsic(intrinsic),
3474*795d594fSAndroid Build Coastguard Worker GetExceptionsIntrinsic(intrinsic));
3475*795d594fSAndroid Build Coastguard Worker }
3476*795d594fSAndroid Build Coastguard Worker resolved_method_ = method;
3477*795d594fSAndroid Build Coastguard Worker }
3478*795d594fSAndroid Build Coastguard Worker
IsGEZero(HInstruction * instruction)3479*795d594fSAndroid Build Coastguard Worker bool IsGEZero(HInstruction* instruction) {
3480*795d594fSAndroid Build Coastguard Worker DCHECK(instruction != nullptr);
3481*795d594fSAndroid Build Coastguard Worker if (instruction->IsArrayLength()) {
3482*795d594fSAndroid Build Coastguard Worker return true;
3483*795d594fSAndroid Build Coastguard Worker } else if (instruction->IsMin()) {
3484*795d594fSAndroid Build Coastguard Worker // Instruction MIN(>=0, >=0) is >= 0.
3485*795d594fSAndroid Build Coastguard Worker return IsGEZero(instruction->InputAt(0)) &&
3486*795d594fSAndroid Build Coastguard Worker IsGEZero(instruction->InputAt(1));
3487*795d594fSAndroid Build Coastguard Worker } else if (instruction->IsAbs()) {
3488*795d594fSAndroid Build Coastguard Worker // Instruction ABS(>=0) is >= 0.
3489*795d594fSAndroid Build Coastguard Worker // NOTE: ABS(minint) = minint prevents assuming
3490*795d594fSAndroid Build Coastguard Worker // >= 0 without looking at the argument.
3491*795d594fSAndroid Build Coastguard Worker return IsGEZero(instruction->InputAt(0));
3492*795d594fSAndroid Build Coastguard Worker }
3493*795d594fSAndroid Build Coastguard Worker int64_t value = -1;
3494*795d594fSAndroid Build Coastguard Worker return IsInt64AndGet(instruction, &value) && value >= 0;
3495*795d594fSAndroid Build Coastguard Worker }
3496*795d594fSAndroid Build Coastguard Worker
3497*795d594fSAndroid Build Coastguard Worker } // namespace art
3498