xref: /aosp_15_r20/art/compiler/optimizing/code_sinking.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "code_sinking.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <sstream>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/arena_bit_vector.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/globals.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
27*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
28*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
29*795d594fSAndroid Build Coastguard Worker #include "common_dominator.h"
30*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
33*795d594fSAndroid Build Coastguard Worker 
Run()34*795d594fSAndroid Build Coastguard Worker bool CodeSinking::Run() {
35*795d594fSAndroid Build Coastguard Worker   if (graph_->GetExitBlock() == nullptr) {
36*795d594fSAndroid Build Coastguard Worker     // Infinite loop, just bail.
37*795d594fSAndroid Build Coastguard Worker     return false;
38*795d594fSAndroid Build Coastguard Worker   }
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker   UncommonBranchSinking();
41*795d594fSAndroid Build Coastguard Worker   ReturnSinking();
42*795d594fSAndroid Build Coastguard Worker   return true;
43*795d594fSAndroid Build Coastguard Worker }
44*795d594fSAndroid Build Coastguard Worker 
UncommonBranchSinking()45*795d594fSAndroid Build Coastguard Worker void CodeSinking::UncommonBranchSinking() {
46*795d594fSAndroid Build Coastguard Worker   HBasicBlock* exit = graph_->GetExitBlock();
47*795d594fSAndroid Build Coastguard Worker   DCHECK(exit != nullptr);
48*795d594fSAndroid Build Coastguard Worker   // TODO(ngeoffray): we do not profile branches yet, so use throw instructions
49*795d594fSAndroid Build Coastguard Worker   // as an indicator of an uncommon branch.
50*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* exit_predecessor : exit->GetPredecessors()) {
51*795d594fSAndroid Build Coastguard Worker     HInstruction* last = exit_predecessor->GetLastInstruction();
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker     // TryBoundary instructions are sometimes inserted between the last instruction (e.g. Throw,
54*795d594fSAndroid Build Coastguard Worker     // Return) and Exit. We don't want to use that instruction for our "uncommon branch" heuristic
55*795d594fSAndroid Build Coastguard Worker     // because they are not as good an indicator as throwing branches, so we skip them and fetch the
56*795d594fSAndroid Build Coastguard Worker     // actual last instruction.
57*795d594fSAndroid Build Coastguard Worker     if (last->IsTryBoundary()) {
58*795d594fSAndroid Build Coastguard Worker       // We have an exit try boundary. Fetch the previous instruction.
59*795d594fSAndroid Build Coastguard Worker       DCHECK(!last->AsTryBoundary()->IsEntry());
60*795d594fSAndroid Build Coastguard Worker       if (last->GetPrevious() == nullptr) {
61*795d594fSAndroid Build Coastguard Worker         DCHECK(exit_predecessor->IsSingleTryBoundary());
62*795d594fSAndroid Build Coastguard Worker         exit_predecessor = exit_predecessor->GetSinglePredecessor();
63*795d594fSAndroid Build Coastguard Worker         last = exit_predecessor->GetLastInstruction();
64*795d594fSAndroid Build Coastguard Worker       } else {
65*795d594fSAndroid Build Coastguard Worker         last = last->GetPrevious();
66*795d594fSAndroid Build Coastguard Worker       }
67*795d594fSAndroid Build Coastguard Worker     }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker     // Any predecessor of the exit that does not return, throws an exception.
70*795d594fSAndroid Build Coastguard Worker     if (!last->IsReturn() && !last->IsReturnVoid()) {
71*795d594fSAndroid Build Coastguard Worker       SinkCodeToUncommonBranch(exit_predecessor);
72*795d594fSAndroid Build Coastguard Worker     }
73*795d594fSAndroid Build Coastguard Worker   }
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker 
IsInterestingInstruction(HInstruction * instruction)76*795d594fSAndroid Build Coastguard Worker static bool IsInterestingInstruction(HInstruction* instruction) {
77*795d594fSAndroid Build Coastguard Worker   // Instructions from the entry graph (for example constants) are never interesting to move.
78*795d594fSAndroid Build Coastguard Worker   if (instruction->GetBlock() == instruction->GetBlock()->GetGraph()->GetEntryBlock()) {
79*795d594fSAndroid Build Coastguard Worker     return false;
80*795d594fSAndroid Build Coastguard Worker   }
81*795d594fSAndroid Build Coastguard Worker   // We want to move moveable instructions that cannot throw, as well as
82*795d594fSAndroid Build Coastguard Worker   // heap stores and allocations.
83*795d594fSAndroid Build Coastguard Worker 
84*795d594fSAndroid Build Coastguard Worker   // Volatile stores cannot be moved.
85*795d594fSAndroid Build Coastguard Worker   if (instruction->IsInstanceFieldSet()) {
86*795d594fSAndroid Build Coastguard Worker     if (instruction->AsInstanceFieldSet()->IsVolatile()) {
87*795d594fSAndroid Build Coastguard Worker       return false;
88*795d594fSAndroid Build Coastguard Worker     }
89*795d594fSAndroid Build Coastguard Worker   }
90*795d594fSAndroid Build Coastguard Worker 
91*795d594fSAndroid Build Coastguard Worker   // Check allocations and strings first, as they can throw, but it is safe to move them.
92*795d594fSAndroid Build Coastguard Worker   if (instruction->IsNewInstance() || instruction->IsNewArray() || instruction->IsLoadString()) {
93*795d594fSAndroid Build Coastguard Worker     return true;
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   // Check it is safe to move ConstructorFence.
97*795d594fSAndroid Build Coastguard Worker   // (Safe to move ConstructorFence for only protecting the new-instance but not for finals.)
98*795d594fSAndroid Build Coastguard Worker   if (instruction->IsConstructorFence()) {
99*795d594fSAndroid Build Coastguard Worker     HConstructorFence* ctor_fence = instruction->AsConstructorFence();
100*795d594fSAndroid Build Coastguard Worker 
101*795d594fSAndroid Build Coastguard Worker     // A fence with "0" inputs is dead and should've been removed in a prior pass.
102*795d594fSAndroid Build Coastguard Worker     DCHECK_NE(0u, ctor_fence->InputCount());
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker     // TODO: this should be simplified to 'return true' since it's
105*795d594fSAndroid Build Coastguard Worker     // potentially pessimizing any code sinking for inlined constructors with final fields.
106*795d594fSAndroid Build Coastguard Worker     // TODO: double check that if the final field assignments are not moved,
107*795d594fSAndroid Build Coastguard Worker     // then the fence is not moved either.
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker     return ctor_fence->GetAssociatedAllocation() != nullptr;
110*795d594fSAndroid Build Coastguard Worker   }
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker   // All other instructions that can throw cannot be moved.
113*795d594fSAndroid Build Coastguard Worker   if (instruction->CanThrow()) {
114*795d594fSAndroid Build Coastguard Worker     return false;
115*795d594fSAndroid Build Coastguard Worker   }
116*795d594fSAndroid Build Coastguard Worker 
117*795d594fSAndroid Build Coastguard Worker   // We can only store on local allocations. Other heap references can
118*795d594fSAndroid Build Coastguard Worker   // be escaping. Note that allocations can escape too, but we only move
119*795d594fSAndroid Build Coastguard Worker   // allocations if their users can move too, or are in the list of
120*795d594fSAndroid Build Coastguard Worker   // post dominated blocks.
121*795d594fSAndroid Build Coastguard Worker   if (instruction->IsInstanceFieldSet()) {
122*795d594fSAndroid Build Coastguard Worker     if (!instruction->InputAt(0)->IsNewInstance()) {
123*795d594fSAndroid Build Coastguard Worker       return false;
124*795d594fSAndroid Build Coastguard Worker     }
125*795d594fSAndroid Build Coastguard Worker   }
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   if (instruction->IsArraySet()) {
128*795d594fSAndroid Build Coastguard Worker     if (!instruction->InputAt(0)->IsNewArray()) {
129*795d594fSAndroid Build Coastguard Worker       return false;
130*795d594fSAndroid Build Coastguard Worker     }
131*795d594fSAndroid Build Coastguard Worker   }
132*795d594fSAndroid Build Coastguard Worker 
133*795d594fSAndroid Build Coastguard Worker   // Heap accesses cannot go past instructions that have memory side effects, which
134*795d594fSAndroid Build Coastguard Worker   // we are not tracking here. Note that the load/store elimination optimization
135*795d594fSAndroid Build Coastguard Worker   // runs before this optimization, and should have removed interesting ones.
136*795d594fSAndroid Build Coastguard Worker   // In theory, we could handle loads of local allocations, but this is currently
137*795d594fSAndroid Build Coastguard Worker   // hard to test, as LSE removes them.
138*795d594fSAndroid Build Coastguard Worker   if (instruction->IsStaticFieldGet() ||
139*795d594fSAndroid Build Coastguard Worker       instruction->IsInstanceFieldGet() ||
140*795d594fSAndroid Build Coastguard Worker       instruction->IsArrayGet()) {
141*795d594fSAndroid Build Coastguard Worker     return false;
142*795d594fSAndroid Build Coastguard Worker   }
143*795d594fSAndroid Build Coastguard Worker 
144*795d594fSAndroid Build Coastguard Worker   if (instruction->IsInstanceFieldSet() ||
145*795d594fSAndroid Build Coastguard Worker       instruction->IsArraySet() ||
146*795d594fSAndroid Build Coastguard Worker       instruction->CanBeMoved()) {
147*795d594fSAndroid Build Coastguard Worker     return true;
148*795d594fSAndroid Build Coastguard Worker   }
149*795d594fSAndroid Build Coastguard Worker   return false;
150*795d594fSAndroid Build Coastguard Worker }
151*795d594fSAndroid Build Coastguard Worker 
AddInstruction(HInstruction * instruction,const ArenaBitVector & processed_instructions,const ArenaBitVector & discard_blocks,ScopedArenaVector<HInstruction * > * worklist)152*795d594fSAndroid Build Coastguard Worker static void AddInstruction(HInstruction* instruction,
153*795d594fSAndroid Build Coastguard Worker                            const ArenaBitVector& processed_instructions,
154*795d594fSAndroid Build Coastguard Worker                            const ArenaBitVector& discard_blocks,
155*795d594fSAndroid Build Coastguard Worker                            ScopedArenaVector<HInstruction*>* worklist) {
156*795d594fSAndroid Build Coastguard Worker   // Add to the work list if the instruction is not in the list of blocks
157*795d594fSAndroid Build Coastguard Worker   // to discard, hasn't been already processed and is of interest.
158*795d594fSAndroid Build Coastguard Worker   if (!discard_blocks.IsBitSet(instruction->GetBlock()->GetBlockId()) &&
159*795d594fSAndroid Build Coastguard Worker       !processed_instructions.IsBitSet(instruction->GetId()) &&
160*795d594fSAndroid Build Coastguard Worker       IsInterestingInstruction(instruction)) {
161*795d594fSAndroid Build Coastguard Worker     worklist->push_back(instruction);
162*795d594fSAndroid Build Coastguard Worker   }
163*795d594fSAndroid Build Coastguard Worker }
164*795d594fSAndroid Build Coastguard Worker 
AddInputs(HInstruction * instruction,const ArenaBitVector & processed_instructions,const ArenaBitVector & discard_blocks,ScopedArenaVector<HInstruction * > * worklist)165*795d594fSAndroid Build Coastguard Worker static void AddInputs(HInstruction* instruction,
166*795d594fSAndroid Build Coastguard Worker                       const ArenaBitVector& processed_instructions,
167*795d594fSAndroid Build Coastguard Worker                       const ArenaBitVector& discard_blocks,
168*795d594fSAndroid Build Coastguard Worker                       ScopedArenaVector<HInstruction*>* worklist) {
169*795d594fSAndroid Build Coastguard Worker   for (HInstruction* input : instruction->GetInputs()) {
170*795d594fSAndroid Build Coastguard Worker     AddInstruction(input, processed_instructions, discard_blocks, worklist);
171*795d594fSAndroid Build Coastguard Worker   }
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker 
AddInputs(HBasicBlock * block,const ArenaBitVector & processed_instructions,const ArenaBitVector & discard_blocks,ScopedArenaVector<HInstruction * > * worklist)174*795d594fSAndroid Build Coastguard Worker static void AddInputs(HBasicBlock* block,
175*795d594fSAndroid Build Coastguard Worker                       const ArenaBitVector& processed_instructions,
176*795d594fSAndroid Build Coastguard Worker                       const ArenaBitVector& discard_blocks,
177*795d594fSAndroid Build Coastguard Worker                       ScopedArenaVector<HInstruction*>* worklist) {
178*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
179*795d594fSAndroid Build Coastguard Worker     AddInputs(it.Current(), processed_instructions, discard_blocks, worklist);
180*795d594fSAndroid Build Coastguard Worker   }
181*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
182*795d594fSAndroid Build Coastguard Worker     AddInputs(it.Current(), processed_instructions, discard_blocks, worklist);
183*795d594fSAndroid Build Coastguard Worker   }
184*795d594fSAndroid Build Coastguard Worker }
185*795d594fSAndroid Build Coastguard Worker 
ShouldFilterUse(HInstruction * instruction,HInstruction * user,const ArenaBitVector & post_dominated)186*795d594fSAndroid Build Coastguard Worker static bool ShouldFilterUse(HInstruction* instruction,
187*795d594fSAndroid Build Coastguard Worker                             HInstruction* user,
188*795d594fSAndroid Build Coastguard Worker                             const ArenaBitVector& post_dominated) {
189*795d594fSAndroid Build Coastguard Worker   if (instruction->IsNewInstance()) {
190*795d594fSAndroid Build Coastguard Worker     return (user->IsInstanceFieldSet() || user->IsConstructorFence()) &&
191*795d594fSAndroid Build Coastguard Worker         (user->InputAt(0) == instruction) &&
192*795d594fSAndroid Build Coastguard Worker         !post_dominated.IsBitSet(user->GetBlock()->GetBlockId());
193*795d594fSAndroid Build Coastguard Worker   } else if (instruction->IsNewArray()) {
194*795d594fSAndroid Build Coastguard Worker     return (user->IsArraySet() || user->IsConstructorFence()) &&
195*795d594fSAndroid Build Coastguard Worker         (user->InputAt(0) == instruction) &&
196*795d594fSAndroid Build Coastguard Worker         !post_dominated.IsBitSet(user->GetBlock()->GetBlockId());
197*795d594fSAndroid Build Coastguard Worker   }
198*795d594fSAndroid Build Coastguard Worker   return false;
199*795d594fSAndroid Build Coastguard Worker }
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker // Find the ideal position for moving `instruction`. If `filter` is true,
202*795d594fSAndroid Build Coastguard Worker // we filter out store instructions to that instruction, which are processed
203*795d594fSAndroid Build Coastguard Worker // first in the step (3) of the sinking algorithm.
204*795d594fSAndroid Build Coastguard Worker // This method is tailored to the sinking algorithm, unlike
205*795d594fSAndroid Build Coastguard Worker // the generic HInstruction::MoveBeforeFirstUserAndOutOfLoops.
FindIdealPosition(HInstruction * instruction,const ArenaBitVector & post_dominated,bool filter=false)206*795d594fSAndroid Build Coastguard Worker static HInstruction* FindIdealPosition(HInstruction* instruction,
207*795d594fSAndroid Build Coastguard Worker                                        const ArenaBitVector& post_dominated,
208*795d594fSAndroid Build Coastguard Worker                                        bool filter = false) {
209*795d594fSAndroid Build Coastguard Worker   DCHECK(!instruction->IsPhi());  // Makes no sense for Phi.
210*795d594fSAndroid Build Coastguard Worker 
211*795d594fSAndroid Build Coastguard Worker   // Find the target block.
212*795d594fSAndroid Build Coastguard Worker   CommonDominator finder(/* block= */ nullptr);
213*795d594fSAndroid Build Coastguard Worker   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
214*795d594fSAndroid Build Coastguard Worker     HInstruction* user = use.GetUser();
215*795d594fSAndroid Build Coastguard Worker     if (!(filter && ShouldFilterUse(instruction, user, post_dominated))) {
216*795d594fSAndroid Build Coastguard Worker       HBasicBlock* block = user->GetBlock();
217*795d594fSAndroid Build Coastguard Worker       if (user->IsPhi()) {
218*795d594fSAndroid Build Coastguard Worker         // Special case phis by taking the incoming block for regular ones,
219*795d594fSAndroid Build Coastguard Worker         // or the dominator for catch phis.
220*795d594fSAndroid Build Coastguard Worker         block = user->AsPhi()->IsCatchPhi()
221*795d594fSAndroid Build Coastguard Worker             ? block->GetDominator()
222*795d594fSAndroid Build Coastguard Worker             : block->GetPredecessors()[use.GetIndex()];
223*795d594fSAndroid Build Coastguard Worker       }
224*795d594fSAndroid Build Coastguard Worker       finder.Update(block);
225*795d594fSAndroid Build Coastguard Worker     }
226*795d594fSAndroid Build Coastguard Worker   }
227*795d594fSAndroid Build Coastguard Worker   for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
228*795d594fSAndroid Build Coastguard Worker     DCHECK(!use.GetUser()->GetHolder()->IsPhi());
229*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(filter,
230*795d594fSAndroid Build Coastguard Worker                    !ShouldFilterUse(instruction, use.GetUser()->GetHolder(), post_dominated));
231*795d594fSAndroid Build Coastguard Worker     finder.Update(use.GetUser()->GetHolder()->GetBlock());
232*795d594fSAndroid Build Coastguard Worker   }
233*795d594fSAndroid Build Coastguard Worker   HBasicBlock* target_block = finder.Get();
234*795d594fSAndroid Build Coastguard Worker   if (target_block == nullptr) {
235*795d594fSAndroid Build Coastguard Worker     // No user we can go next to? Likely a LSE or DCE limitation.
236*795d594fSAndroid Build Coastguard Worker     return nullptr;
237*795d594fSAndroid Build Coastguard Worker   }
238*795d594fSAndroid Build Coastguard Worker 
239*795d594fSAndroid Build Coastguard Worker   // Move to the first dominator not in a loop, if we can. We only do this if we are trying to hoist
240*795d594fSAndroid Build Coastguard Worker   // `instruction` out of a loop it wasn't a part of.
241*795d594fSAndroid Build Coastguard Worker   const HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
242*795d594fSAndroid Build Coastguard Worker   while (target_block->IsInLoop() && target_block->GetLoopInformation() != loop_info) {
243*795d594fSAndroid Build Coastguard Worker     if (!post_dominated.IsBitSet(target_block->GetDominator()->GetBlockId())) {
244*795d594fSAndroid Build Coastguard Worker       break;
245*795d594fSAndroid Build Coastguard Worker     }
246*795d594fSAndroid Build Coastguard Worker     target_block = target_block->GetDominator();
247*795d594fSAndroid Build Coastguard Worker     DCHECK(target_block != nullptr);
248*795d594fSAndroid Build Coastguard Worker   }
249*795d594fSAndroid Build Coastguard Worker 
250*795d594fSAndroid Build Coastguard Worker   if (instruction->CanThrow()) {
251*795d594fSAndroid Build Coastguard Worker     // Consistency check: We shouldn't land in a loop if we weren't in one before traversing up the
252*795d594fSAndroid Build Coastguard Worker     // dominator tree regarding try catches.
253*795d594fSAndroid Build Coastguard Worker     const bool was_in_loop = target_block->IsInLoop();
254*795d594fSAndroid Build Coastguard Worker 
255*795d594fSAndroid Build Coastguard Worker     // We cannot move an instruction that can throw into a try that said instruction is not a part
256*795d594fSAndroid Build Coastguard Worker     // of already, as that would mean it will throw into a different catch block. In short, for
257*795d594fSAndroid Build Coastguard Worker     // throwing instructions:
258*795d594fSAndroid Build Coastguard Worker     // * If the throwing instruction is part of a try, they should only be sunk into that same try.
259*795d594fSAndroid Build Coastguard Worker     // * If the throwing instruction is not part of any try, they shouldn't be sunk to any try.
260*795d594fSAndroid Build Coastguard Worker     if (instruction->GetBlock()->IsTryBlock()) {
261*795d594fSAndroid Build Coastguard Worker       const HTryBoundary& try_entry =
262*795d594fSAndroid Build Coastguard Worker           instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
263*795d594fSAndroid Build Coastguard Worker       while (!(target_block->IsTryBlock() &&
264*795d594fSAndroid Build Coastguard Worker                try_entry.HasSameExceptionHandlersAs(
265*795d594fSAndroid Build Coastguard Worker                    target_block->GetTryCatchInformation()->GetTryEntry()))) {
266*795d594fSAndroid Build Coastguard Worker         target_block = target_block->GetDominator();
267*795d594fSAndroid Build Coastguard Worker         if (!post_dominated.IsBitSet(target_block->GetBlockId())) {
268*795d594fSAndroid Build Coastguard Worker           // We couldn't find a suitable block.
269*795d594fSAndroid Build Coastguard Worker           return nullptr;
270*795d594fSAndroid Build Coastguard Worker         }
271*795d594fSAndroid Build Coastguard Worker       }
272*795d594fSAndroid Build Coastguard Worker     } else {
273*795d594fSAndroid Build Coastguard Worker       // Search for the first block also not in a try block
274*795d594fSAndroid Build Coastguard Worker       while (target_block->IsTryBlock()) {
275*795d594fSAndroid Build Coastguard Worker         target_block = target_block->GetDominator();
276*795d594fSAndroid Build Coastguard Worker         if (!post_dominated.IsBitSet(target_block->GetBlockId())) {
277*795d594fSAndroid Build Coastguard Worker           // We couldn't find a suitable block.
278*795d594fSAndroid Build Coastguard Worker           return nullptr;
279*795d594fSAndroid Build Coastguard Worker         }
280*795d594fSAndroid Build Coastguard Worker       }
281*795d594fSAndroid Build Coastguard Worker     }
282*795d594fSAndroid Build Coastguard Worker 
283*795d594fSAndroid Build Coastguard Worker     DCHECK_IMPLIES(target_block->IsInLoop(), was_in_loop);
284*795d594fSAndroid Build Coastguard Worker   }
285*795d594fSAndroid Build Coastguard Worker 
286*795d594fSAndroid Build Coastguard Worker   // Find insertion position. No need to filter anymore, as we have found a
287*795d594fSAndroid Build Coastguard Worker   // target block.
288*795d594fSAndroid Build Coastguard Worker   HInstruction* insert_pos = nullptr;
289*795d594fSAndroid Build Coastguard Worker   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
290*795d594fSAndroid Build Coastguard Worker     if (use.GetUser()->GetBlock() == target_block &&
291*795d594fSAndroid Build Coastguard Worker         (insert_pos == nullptr || use.GetUser()->StrictlyDominates(insert_pos))) {
292*795d594fSAndroid Build Coastguard Worker       insert_pos = use.GetUser();
293*795d594fSAndroid Build Coastguard Worker     }
294*795d594fSAndroid Build Coastguard Worker   }
295*795d594fSAndroid Build Coastguard Worker   for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
296*795d594fSAndroid Build Coastguard Worker     HEnvironment* env = use.GetUser();
297*795d594fSAndroid Build Coastguard Worker     HInstruction* user = env->GetHolder();
298*795d594fSAndroid Build Coastguard Worker     if (user->GetBlock() == target_block &&
299*795d594fSAndroid Build Coastguard Worker         (insert_pos == nullptr || user->StrictlyDominates(insert_pos))) {
300*795d594fSAndroid Build Coastguard Worker       if (target_block->IsCatchBlock() && target_block->GetFirstInstruction() == user) {
301*795d594fSAndroid Build Coastguard Worker         // We can sink the instructions past the environment setting Nop. If we do that, we have to
302*795d594fSAndroid Build Coastguard Worker         // remove said instruction from the environment. Since we know that we will be sinking the
303*795d594fSAndroid Build Coastguard Worker         // instruction to this block and there are no more instructions to consider, we can safely
304*795d594fSAndroid Build Coastguard Worker         // remove it from the environment now.
305*795d594fSAndroid Build Coastguard Worker         DCHECK(target_block->GetFirstInstruction()->IsNop());
306*795d594fSAndroid Build Coastguard Worker         env->RemoveAsUserOfInput(use.GetIndex());
307*795d594fSAndroid Build Coastguard Worker         env->SetRawEnvAt(use.GetIndex(), /*instruction=*/ nullptr);
308*795d594fSAndroid Build Coastguard Worker       } else {
309*795d594fSAndroid Build Coastguard Worker         insert_pos = user;
310*795d594fSAndroid Build Coastguard Worker       }
311*795d594fSAndroid Build Coastguard Worker     }
312*795d594fSAndroid Build Coastguard Worker   }
313*795d594fSAndroid Build Coastguard Worker   if (insert_pos == nullptr) {
314*795d594fSAndroid Build Coastguard Worker     // No user in `target_block`, insert before the control flow instruction.
315*795d594fSAndroid Build Coastguard Worker     insert_pos = target_block->GetLastInstruction();
316*795d594fSAndroid Build Coastguard Worker     DCHECK(insert_pos->IsControlFlow());
317*795d594fSAndroid Build Coastguard Worker     // Avoid splitting HCondition from HIf to prevent unnecessary materialization.
318*795d594fSAndroid Build Coastguard Worker     if (insert_pos->IsIf()) {
319*795d594fSAndroid Build Coastguard Worker       HInstruction* if_input = insert_pos->AsIf()->InputAt(0);
320*795d594fSAndroid Build Coastguard Worker       if (if_input == insert_pos->GetPrevious()) {
321*795d594fSAndroid Build Coastguard Worker         insert_pos = if_input;
322*795d594fSAndroid Build Coastguard Worker       }
323*795d594fSAndroid Build Coastguard Worker     }
324*795d594fSAndroid Build Coastguard Worker   }
325*795d594fSAndroid Build Coastguard Worker   DCHECK(!insert_pos->IsPhi());
326*795d594fSAndroid Build Coastguard Worker   return insert_pos;
327*795d594fSAndroid Build Coastguard Worker }
328*795d594fSAndroid Build Coastguard Worker 
329*795d594fSAndroid Build Coastguard Worker 
SinkCodeToUncommonBranch(HBasicBlock * end_block)330*795d594fSAndroid Build Coastguard Worker void CodeSinking::SinkCodeToUncommonBranch(HBasicBlock* end_block) {
331*795d594fSAndroid Build Coastguard Worker   // Local allocator to discard data structures created below at the end of this optimization.
332*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(graph_->GetArenaStack());
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker   size_t number_of_instructions = graph_->GetCurrentInstructionId();
335*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HInstruction*> worklist(allocator.Adapter(kArenaAllocMisc));
336*795d594fSAndroid Build Coastguard Worker   ArenaBitVector processed_instructions(
337*795d594fSAndroid Build Coastguard Worker       &allocator, number_of_instructions, /* expandable= */ false);
338*795d594fSAndroid Build Coastguard Worker   ArenaBitVector post_dominated(&allocator, graph_->GetBlocks().size(), /* expandable= */ false);
339*795d594fSAndroid Build Coastguard Worker 
340*795d594fSAndroid Build Coastguard Worker   // Step (1): Visit post order to get a subset of blocks post dominated by `end_block`.
341*795d594fSAndroid Build Coastguard Worker   // TODO(ngeoffray): Getting the full set of post-dominated should be done by
342*795d594fSAndroid Build Coastguard Worker   // computing the post dominator tree, but that could be too time consuming. Also,
343*795d594fSAndroid Build Coastguard Worker   // we should start the analysis from blocks dominated by an uncommon branch, but we
344*795d594fSAndroid Build Coastguard Worker   // don't profile branches yet.
345*795d594fSAndroid Build Coastguard Worker   bool found_block = false;
346*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
347*795d594fSAndroid Build Coastguard Worker     if (block == end_block) {
348*795d594fSAndroid Build Coastguard Worker       found_block = true;
349*795d594fSAndroid Build Coastguard Worker       post_dominated.SetBit(block->GetBlockId());
350*795d594fSAndroid Build Coastguard Worker     } else if (found_block) {
351*795d594fSAndroid Build Coastguard Worker       bool is_post_dominated = true;
352*795d594fSAndroid Build Coastguard Worker       DCHECK_NE(block, graph_->GetExitBlock())
353*795d594fSAndroid Build Coastguard Worker           << "We shouldn't encounter the exit block after `end_block`.";
354*795d594fSAndroid Build Coastguard Worker 
355*795d594fSAndroid Build Coastguard Worker       // BasicBlock that are try entries look like this:
356*795d594fSAndroid Build Coastguard Worker       //   BasicBlock i:
357*795d594fSAndroid Build Coastguard Worker       //     instr 1
358*795d594fSAndroid Build Coastguard Worker       //     ...
359*795d594fSAndroid Build Coastguard Worker       //     instr N
360*795d594fSAndroid Build Coastguard Worker       //     TryBoundary kind:entry ---Try begins here---
361*795d594fSAndroid Build Coastguard Worker       //
362*795d594fSAndroid Build Coastguard Worker       // Due to how our BasicBlocks are structured, BasicBlock i will have an xhandler successor
363*795d594fSAndroid Build Coastguard Worker       // since we are starting a try. If we use `GetSuccessors` for this case, we will check if
364*795d594fSAndroid Build Coastguard Worker       // the catch block is post_dominated.
365*795d594fSAndroid Build Coastguard Worker       //
366*795d594fSAndroid Build Coastguard Worker       // However, this catch block doesn't matter: when we sink the instruction into that
367*795d594fSAndroid Build Coastguard Worker       // BasicBlock i, we do it before the TryBoundary (i.e. outside of the try and outside the
368*795d594fSAndroid Build Coastguard Worker       // catch's domain). We can ignore catch blocks using `GetNormalSuccessors` to sink code
369*795d594fSAndroid Build Coastguard Worker       // right before the start of a try block.
370*795d594fSAndroid Build Coastguard Worker       //
371*795d594fSAndroid Build Coastguard Worker       // On the other side of the coin, BasicBlock that are try exits look like this:
372*795d594fSAndroid Build Coastguard Worker       //   BasicBlock j:
373*795d594fSAndroid Build Coastguard Worker       //     instr 1
374*795d594fSAndroid Build Coastguard Worker       //     ...
375*795d594fSAndroid Build Coastguard Worker       //     instr N
376*795d594fSAndroid Build Coastguard Worker       //     TryBoundary kind:exit ---Try ends here---
377*795d594fSAndroid Build Coastguard Worker       //
378*795d594fSAndroid Build Coastguard Worker       // If we sink to these basic blocks we would be sinking inside of the try so we would like
379*795d594fSAndroid Build Coastguard Worker       // to check the catch block for post dominance.
380*795d594fSAndroid Build Coastguard Worker       const bool ends_with_try_boundary_entry =
381*795d594fSAndroid Build Coastguard Worker           block->EndsWithTryBoundary() && block->GetLastInstruction()->AsTryBoundary()->IsEntry();
382*795d594fSAndroid Build Coastguard Worker       ArrayRef<HBasicBlock* const> successors =
383*795d594fSAndroid Build Coastguard Worker           ends_with_try_boundary_entry ? block->GetNormalSuccessors() :
384*795d594fSAndroid Build Coastguard Worker                                          ArrayRef<HBasicBlock* const>(block->GetSuccessors());
385*795d594fSAndroid Build Coastguard Worker       for (HBasicBlock* successor : successors) {
386*795d594fSAndroid Build Coastguard Worker         if (!post_dominated.IsBitSet(successor->GetBlockId())) {
387*795d594fSAndroid Build Coastguard Worker           is_post_dominated = false;
388*795d594fSAndroid Build Coastguard Worker           break;
389*795d594fSAndroid Build Coastguard Worker         }
390*795d594fSAndroid Build Coastguard Worker       }
391*795d594fSAndroid Build Coastguard Worker       if (is_post_dominated) {
392*795d594fSAndroid Build Coastguard Worker         post_dominated.SetBit(block->GetBlockId());
393*795d594fSAndroid Build Coastguard Worker       }
394*795d594fSAndroid Build Coastguard Worker     }
395*795d594fSAndroid Build Coastguard Worker   }
396*795d594fSAndroid Build Coastguard Worker 
397*795d594fSAndroid Build Coastguard Worker   // Now that we have found a subset of post-dominated blocks, add to the worklist all inputs
398*795d594fSAndroid Build Coastguard Worker   // of instructions in these blocks that are not themselves in these blocks.
399*795d594fSAndroid Build Coastguard Worker   // Also find the common dominator of the found post dominated blocks, to help filtering
400*795d594fSAndroid Build Coastguard Worker   // out un-movable uses in step (2).
401*795d594fSAndroid Build Coastguard Worker   CommonDominator finder(end_block);
402*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, e = graph_->GetBlocks().size(); i < e; ++i) {
403*795d594fSAndroid Build Coastguard Worker     if (post_dominated.IsBitSet(i)) {
404*795d594fSAndroid Build Coastguard Worker       finder.Update(graph_->GetBlocks()[i]);
405*795d594fSAndroid Build Coastguard Worker       AddInputs(graph_->GetBlocks()[i], processed_instructions, post_dominated, &worklist);
406*795d594fSAndroid Build Coastguard Worker     }
407*795d594fSAndroid Build Coastguard Worker   }
408*795d594fSAndroid Build Coastguard Worker   HBasicBlock* common_dominator = finder.Get();
409*795d594fSAndroid Build Coastguard Worker 
410*795d594fSAndroid Build Coastguard Worker   // Step (2): iterate over the worklist to find sinking candidates.
411*795d594fSAndroid Build Coastguard Worker   ArenaBitVector instructions_that_can_move(
412*795d594fSAndroid Build Coastguard Worker       &allocator, number_of_instructions, /* expandable= */ false);
413*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<ScopedArenaVector<HInstruction*>> instructions_to_move(
414*795d594fSAndroid Build Coastguard Worker       graph_->GetBlocks().size(),
415*795d594fSAndroid Build Coastguard Worker       ScopedArenaVector<HInstruction*>(allocator.Adapter(kArenaAllocMisc)),
416*795d594fSAndroid Build Coastguard Worker       allocator.Adapter(kArenaAllocMisc));
417*795d594fSAndroid Build Coastguard Worker   while (!worklist.empty()) {
418*795d594fSAndroid Build Coastguard Worker     HInstruction* instruction = worklist.back();
419*795d594fSAndroid Build Coastguard Worker     if (processed_instructions.IsBitSet(instruction->GetId())) {
420*795d594fSAndroid Build Coastguard Worker       // The instruction has already been processed, continue. This happens
421*795d594fSAndroid Build Coastguard Worker       // when the instruction is the input/user of multiple instructions.
422*795d594fSAndroid Build Coastguard Worker       worklist.pop_back();
423*795d594fSAndroid Build Coastguard Worker       continue;
424*795d594fSAndroid Build Coastguard Worker     }
425*795d594fSAndroid Build Coastguard Worker     bool all_users_in_post_dominated_blocks = true;
426*795d594fSAndroid Build Coastguard Worker     bool can_move = true;
427*795d594fSAndroid Build Coastguard Worker     // Check users of the instruction.
428*795d594fSAndroid Build Coastguard Worker     for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
429*795d594fSAndroid Build Coastguard Worker       HInstruction* user = use.GetUser();
430*795d594fSAndroid Build Coastguard Worker       if (!post_dominated.IsBitSet(user->GetBlock()->GetBlockId()) &&
431*795d594fSAndroid Build Coastguard Worker           !instructions_that_can_move.IsBitSet(user->GetId())) {
432*795d594fSAndroid Build Coastguard Worker         all_users_in_post_dominated_blocks = false;
433*795d594fSAndroid Build Coastguard Worker         // If we've already processed this user, or the user cannot be moved, or
434*795d594fSAndroid Build Coastguard Worker         // is not dominating the post dominated blocks, bail.
435*795d594fSAndroid Build Coastguard Worker         // TODO(ngeoffray): The domination check is an approximation. We should
436*795d594fSAndroid Build Coastguard Worker         // instead check if the dominated blocks post dominate the user's block,
437*795d594fSAndroid Build Coastguard Worker         // but we do not have post dominance information here.
438*795d594fSAndroid Build Coastguard Worker         if (processed_instructions.IsBitSet(user->GetId()) ||
439*795d594fSAndroid Build Coastguard Worker             !IsInterestingInstruction(user) ||
440*795d594fSAndroid Build Coastguard Worker             !user->GetBlock()->Dominates(common_dominator)) {
441*795d594fSAndroid Build Coastguard Worker           can_move = false;
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     // Check environment users of the instruction. Some of these users require
448*795d594fSAndroid Build Coastguard Worker     // the instruction not to move.
449*795d594fSAndroid Build Coastguard Worker     if (all_users_in_post_dominated_blocks) {
450*795d594fSAndroid Build Coastguard Worker       for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
451*795d594fSAndroid Build Coastguard Worker         HEnvironment* environment = use.GetUser();
452*795d594fSAndroid Build Coastguard Worker         HInstruction* user = environment->GetHolder();
453*795d594fSAndroid Build Coastguard Worker         if (!post_dominated.IsBitSet(user->GetBlock()->GetBlockId())) {
454*795d594fSAndroid Build Coastguard Worker           if (graph_->IsDebuggable() ||
455*795d594fSAndroid Build Coastguard Worker               user->IsDeoptimize() ||
456*795d594fSAndroid Build Coastguard Worker               user->CanThrowIntoCatchBlock() ||
457*795d594fSAndroid Build Coastguard Worker               (user->IsSuspendCheck() && graph_->IsCompilingOsr())) {
458*795d594fSAndroid Build Coastguard Worker             can_move = false;
459*795d594fSAndroid Build Coastguard Worker             break;
460*795d594fSAndroid Build Coastguard Worker           }
461*795d594fSAndroid Build Coastguard Worker         }
462*795d594fSAndroid Build Coastguard Worker       }
463*795d594fSAndroid Build Coastguard Worker     }
464*795d594fSAndroid Build Coastguard Worker     if (!can_move) {
465*795d594fSAndroid Build Coastguard Worker       // Instruction cannot be moved, mark it as processed and remove it from the work
466*795d594fSAndroid Build Coastguard Worker       // list.
467*795d594fSAndroid Build Coastguard Worker       processed_instructions.SetBit(instruction->GetId());
468*795d594fSAndroid Build Coastguard Worker       worklist.pop_back();
469*795d594fSAndroid Build Coastguard Worker     } else if (all_users_in_post_dominated_blocks) {
470*795d594fSAndroid Build Coastguard Worker       // Instruction is a candidate for being sunk. Mark it as such, remove it from the
471*795d594fSAndroid Build Coastguard Worker       // work list, and add its inputs to the work list.
472*795d594fSAndroid Build Coastguard Worker       instructions_that_can_move.SetBit(instruction->GetId());
473*795d594fSAndroid Build Coastguard Worker       instructions_to_move[instruction->GetBlock()->GetBlockId()].push_back(instruction);
474*795d594fSAndroid Build Coastguard Worker       processed_instructions.SetBit(instruction->GetId());
475*795d594fSAndroid Build Coastguard Worker       worklist.pop_back();
476*795d594fSAndroid Build Coastguard Worker       AddInputs(instruction, processed_instructions, post_dominated, &worklist);
477*795d594fSAndroid Build Coastguard Worker       // Drop the environment use not in the list of post-dominated block. This is
478*795d594fSAndroid Build Coastguard Worker       // to help step (3) of this optimization, when we start moving instructions
479*795d594fSAndroid Build Coastguard Worker       // closer to their use.
480*795d594fSAndroid Build Coastguard Worker       for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
481*795d594fSAndroid Build Coastguard Worker         HEnvironment* environment = use.GetUser();
482*795d594fSAndroid Build Coastguard Worker         HInstruction* user = environment->GetHolder();
483*795d594fSAndroid Build Coastguard Worker         if (!post_dominated.IsBitSet(user->GetBlock()->GetBlockId())) {
484*795d594fSAndroid Build Coastguard Worker           environment->RemoveAsUserOfInput(use.GetIndex());
485*795d594fSAndroid Build Coastguard Worker           environment->SetRawEnvAt(use.GetIndex(), nullptr);
486*795d594fSAndroid Build Coastguard Worker         }
487*795d594fSAndroid Build Coastguard Worker       }
488*795d594fSAndroid Build Coastguard Worker     } else {
489*795d594fSAndroid Build Coastguard Worker       // The information we have on the users was not enough to decide whether the
490*795d594fSAndroid Build Coastguard Worker       // instruction could be moved.
491*795d594fSAndroid Build Coastguard Worker       // Add the users to the work list, and keep the instruction in the work list
492*795d594fSAndroid Build Coastguard Worker       // to process it again once all users have been processed.
493*795d594fSAndroid Build Coastguard Worker       for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
494*795d594fSAndroid Build Coastguard Worker         AddInstruction(use.GetUser(), processed_instructions, post_dominated, &worklist);
495*795d594fSAndroid Build Coastguard Worker       }
496*795d594fSAndroid Build Coastguard Worker     }
497*795d594fSAndroid Build Coastguard Worker   }
498*795d594fSAndroid Build Coastguard Worker 
499*795d594fSAndroid Build Coastguard Worker   // We want to process the instructions in reverse dominated order. This is required for heap
500*795d594fSAndroid Build Coastguard Worker   // stores. To guarantee this (including the transitivity of incomparability) we have some extra
501*795d594fSAndroid Build Coastguard Worker   // bookkeeping.
502*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HInstruction*> instructions_to_move_sorted(allocator.Adapter(kArenaAllocMisc));
503*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
504*795d594fSAndroid Build Coastguard Worker     const int block_id = block->GetBlockId();
505*795d594fSAndroid Build Coastguard Worker 
506*795d594fSAndroid Build Coastguard Worker     // Order the block itself first.
507*795d594fSAndroid Build Coastguard Worker     std::sort(instructions_to_move[block_id].begin(),
508*795d594fSAndroid Build Coastguard Worker               instructions_to_move[block_id].end(),
509*795d594fSAndroid Build Coastguard Worker               [&block](HInstruction* a, HInstruction* b) {
510*795d594fSAndroid Build Coastguard Worker                 return block->GetInstructions().FoundBefore(b, a);
511*795d594fSAndroid Build Coastguard Worker               });
512*795d594fSAndroid Build Coastguard Worker 
513*795d594fSAndroid Build Coastguard Worker     for (HInstruction* instruction : instructions_to_move[block_id]) {
514*795d594fSAndroid Build Coastguard Worker       instructions_to_move_sorted.push_back(instruction);
515*795d594fSAndroid Build Coastguard Worker     }
516*795d594fSAndroid Build Coastguard Worker   }
517*795d594fSAndroid Build Coastguard Worker 
518*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
519*795d594fSAndroid Build Coastguard Worker     // We should have ordered the instructions in reverse dominated order. This means that
520*795d594fSAndroid Build Coastguard Worker     // instructions shouldn't dominate instructions that come after it in the vector.
521*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < instructions_to_move_sorted.size(); ++i) {
522*795d594fSAndroid Build Coastguard Worker       for (size_t j = i + 1; j < instructions_to_move_sorted.size(); ++j) {
523*795d594fSAndroid Build Coastguard Worker         if (instructions_to_move_sorted[i]->StrictlyDominates(instructions_to_move_sorted[j])) {
524*795d594fSAndroid Build Coastguard Worker           std::stringstream ss;
525*795d594fSAndroid Build Coastguard Worker           graph_->Dump(ss, nullptr);
526*795d594fSAndroid Build Coastguard Worker           ss << "\n"
527*795d594fSAndroid Build Coastguard Worker              << "{";
528*795d594fSAndroid Build Coastguard Worker           for (HInstruction* instr : instructions_to_move_sorted) {
529*795d594fSAndroid Build Coastguard Worker             ss << *instr << " in block: " << instr->GetBlock() << ", ";
530*795d594fSAndroid Build Coastguard Worker           }
531*795d594fSAndroid Build Coastguard Worker           ss << "}\n";
532*795d594fSAndroid Build Coastguard Worker           ss << "i = " << i << " which is " << *instructions_to_move_sorted[i]
533*795d594fSAndroid Build Coastguard Worker              << "strictly dominates j = " << j << " which is " << *instructions_to_move_sorted[j]
534*795d594fSAndroid Build Coastguard Worker              << "\n";
535*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected ordering of code sinking instructions: " << ss.str();
536*795d594fSAndroid Build Coastguard Worker         }
537*795d594fSAndroid Build Coastguard Worker       }
538*795d594fSAndroid Build Coastguard Worker     }
539*795d594fSAndroid Build Coastguard Worker   }
540*795d594fSAndroid Build Coastguard Worker 
541*795d594fSAndroid Build Coastguard Worker   // Step (3): Try to move sinking candidates.
542*795d594fSAndroid Build Coastguard Worker   for (HInstruction* instruction : instructions_to_move_sorted) {
543*795d594fSAndroid Build Coastguard Worker     HInstruction* position = nullptr;
544*795d594fSAndroid Build Coastguard Worker     if (instruction->IsArraySet()
545*795d594fSAndroid Build Coastguard Worker             || instruction->IsInstanceFieldSet()
546*795d594fSAndroid Build Coastguard Worker             || instruction->IsConstructorFence()) {
547*795d594fSAndroid Build Coastguard Worker       if (!instructions_that_can_move.IsBitSet(instruction->InputAt(0)->GetId())) {
548*795d594fSAndroid Build Coastguard Worker         // A store can trivially move, but it can safely do so only if the heap
549*795d594fSAndroid Build Coastguard Worker         // location it stores to can also move.
550*795d594fSAndroid Build Coastguard Worker         // TODO(ngeoffray): Handle allocation/store cycles by pruning these instructions
551*795d594fSAndroid Build Coastguard Worker         // from the set and all their inputs.
552*795d594fSAndroid Build Coastguard Worker         continue;
553*795d594fSAndroid Build Coastguard Worker       }
554*795d594fSAndroid Build Coastguard Worker       // Find the position of the instruction we're storing into, filtering out this
555*795d594fSAndroid Build Coastguard Worker       // store and all other stores to that instruction.
556*795d594fSAndroid Build Coastguard Worker       position = FindIdealPosition(instruction->InputAt(0), post_dominated, /* filter= */ true);
557*795d594fSAndroid Build Coastguard Worker 
558*795d594fSAndroid Build Coastguard Worker       // The position needs to be dominated by the store, in order for the store to move there.
559*795d594fSAndroid Build Coastguard Worker       if (position == nullptr || !instruction->GetBlock()->Dominates(position->GetBlock())) {
560*795d594fSAndroid Build Coastguard Worker         continue;
561*795d594fSAndroid Build Coastguard Worker       }
562*795d594fSAndroid Build Coastguard Worker     } else {
563*795d594fSAndroid Build Coastguard Worker       // Find the ideal position within the post dominated blocks.
564*795d594fSAndroid Build Coastguard Worker       position = FindIdealPosition(instruction, post_dominated);
565*795d594fSAndroid Build Coastguard Worker       if (position == nullptr) {
566*795d594fSAndroid Build Coastguard Worker         continue;
567*795d594fSAndroid Build Coastguard Worker       }
568*795d594fSAndroid Build Coastguard Worker     }
569*795d594fSAndroid Build Coastguard Worker     // Bail if we could not find a position in the post dominated blocks (for example,
570*795d594fSAndroid Build Coastguard Worker     // if there are multiple users whose common dominator is not in the list of
571*795d594fSAndroid Build Coastguard Worker     // post dominated blocks).
572*795d594fSAndroid Build Coastguard Worker     if (!post_dominated.IsBitSet(position->GetBlock()->GetBlockId())) {
573*795d594fSAndroid Build Coastguard Worker       continue;
574*795d594fSAndroid Build Coastguard Worker     }
575*795d594fSAndroid Build Coastguard Worker     MaybeRecordStat(stats_, MethodCompilationStat::kInstructionSunk);
576*795d594fSAndroid Build Coastguard Worker     instruction->MoveBefore(position, /* do_checks= */ false);
577*795d594fSAndroid Build Coastguard Worker   }
578*795d594fSAndroid Build Coastguard Worker }
579*795d594fSAndroid Build Coastguard Worker 
ReturnSinking()580*795d594fSAndroid Build Coastguard Worker void CodeSinking::ReturnSinking() {
581*795d594fSAndroid Build Coastguard Worker   HBasicBlock* exit = graph_->GetExitBlock();
582*795d594fSAndroid Build Coastguard Worker   DCHECK(exit != nullptr);
583*795d594fSAndroid Build Coastguard Worker 
584*795d594fSAndroid Build Coastguard Worker   int number_of_returns = 0;
585*795d594fSAndroid Build Coastguard Worker   bool saw_return = false;
586*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* pred : exit->GetPredecessors()) {
587*795d594fSAndroid Build Coastguard Worker     // TODO(solanes): We might have Return/ReturnVoid->TryBoundary->Exit. We can theoretically
588*795d594fSAndroid Build Coastguard Worker     // handle them and move them out of the TryBoundary. However, it is a border case and it adds
589*795d594fSAndroid Build Coastguard Worker     // codebase complexity.
590*795d594fSAndroid Build Coastguard Worker     if (pred->GetLastInstruction()->IsReturn() || pred->GetLastInstruction()->IsReturnVoid()) {
591*795d594fSAndroid Build Coastguard Worker       saw_return |= pred->GetLastInstruction()->IsReturn();
592*795d594fSAndroid Build Coastguard Worker       ++number_of_returns;
593*795d594fSAndroid Build Coastguard Worker     }
594*795d594fSAndroid Build Coastguard Worker   }
595*795d594fSAndroid Build Coastguard Worker 
596*795d594fSAndroid Build Coastguard Worker   if (number_of_returns < 2) {
597*795d594fSAndroid Build Coastguard Worker     // Nothing to do.
598*795d594fSAndroid Build Coastguard Worker     return;
599*795d594fSAndroid Build Coastguard Worker   }
600*795d594fSAndroid Build Coastguard Worker 
601*795d594fSAndroid Build Coastguard Worker   // `new_block` will coalesce the Return instructions into Phi+Return, or the ReturnVoid
602*795d594fSAndroid Build Coastguard Worker   // instructions into a ReturnVoid.
603*795d594fSAndroid Build Coastguard Worker   HBasicBlock* new_block = new (graph_->GetAllocator()) HBasicBlock(graph_, exit->GetDexPc());
604*795d594fSAndroid Build Coastguard Worker   if (saw_return) {
605*795d594fSAndroid Build Coastguard Worker     HPhi* new_phi = nullptr;
606*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < exit->GetPredecessors().size(); /*++i in loop*/) {
607*795d594fSAndroid Build Coastguard Worker       HBasicBlock* pred = exit->GetPredecessors()[i];
608*795d594fSAndroid Build Coastguard Worker       if (!pred->GetLastInstruction()->IsReturn()) {
609*795d594fSAndroid Build Coastguard Worker         ++i;
610*795d594fSAndroid Build Coastguard Worker         continue;
611*795d594fSAndroid Build Coastguard Worker       }
612*795d594fSAndroid Build Coastguard Worker 
613*795d594fSAndroid Build Coastguard Worker       HReturn* ret = pred->GetLastInstruction()->AsReturn();
614*795d594fSAndroid Build Coastguard Worker       if (new_phi == nullptr) {
615*795d594fSAndroid Build Coastguard Worker         // Create the new_phi, if we haven't done so yet. We do it here since we need to know the
616*795d594fSAndroid Build Coastguard Worker         // type to assign to it.
617*795d594fSAndroid Build Coastguard Worker         new_phi = new (graph_->GetAllocator()) HPhi(graph_->GetAllocator(),
618*795d594fSAndroid Build Coastguard Worker                                                     kNoRegNumber,
619*795d594fSAndroid Build Coastguard Worker                                                     /*number_of_inputs=*/0,
620*795d594fSAndroid Build Coastguard Worker                                                     ret->InputAt(0)->GetType());
621*795d594fSAndroid Build Coastguard Worker         new_block->AddPhi(new_phi);
622*795d594fSAndroid Build Coastguard Worker       }
623*795d594fSAndroid Build Coastguard Worker       new_phi->AddInput(ret->InputAt(0));
624*795d594fSAndroid Build Coastguard Worker       pred->ReplaceAndRemoveInstructionWith(ret,
625*795d594fSAndroid Build Coastguard Worker                                             new (graph_->GetAllocator()) HGoto(ret->GetDexPc()));
626*795d594fSAndroid Build Coastguard Worker       pred->ReplaceSuccessor(exit, new_block);
627*795d594fSAndroid Build Coastguard Worker       // Since we are removing a predecessor, there's no need to increment `i`.
628*795d594fSAndroid Build Coastguard Worker     }
629*795d594fSAndroid Build Coastguard Worker     new_block->AddInstruction(new (graph_->GetAllocator()) HReturn(new_phi, exit->GetDexPc()));
630*795d594fSAndroid Build Coastguard Worker   } else {
631*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < exit->GetPredecessors().size(); /*++i in loop*/) {
632*795d594fSAndroid Build Coastguard Worker       HBasicBlock* pred = exit->GetPredecessors()[i];
633*795d594fSAndroid Build Coastguard Worker       if (!pred->GetLastInstruction()->IsReturnVoid()) {
634*795d594fSAndroid Build Coastguard Worker         ++i;
635*795d594fSAndroid Build Coastguard Worker         continue;
636*795d594fSAndroid Build Coastguard Worker       }
637*795d594fSAndroid Build Coastguard Worker 
638*795d594fSAndroid Build Coastguard Worker       HReturnVoid* ret = pred->GetLastInstruction()->AsReturnVoid();
639*795d594fSAndroid Build Coastguard Worker       pred->ReplaceAndRemoveInstructionWith(ret,
640*795d594fSAndroid Build Coastguard Worker                                             new (graph_->GetAllocator()) HGoto(ret->GetDexPc()));
641*795d594fSAndroid Build Coastguard Worker       pred->ReplaceSuccessor(exit, new_block);
642*795d594fSAndroid Build Coastguard Worker       // Since we are removing a predecessor, there's no need to increment `i`.
643*795d594fSAndroid Build Coastguard Worker     }
644*795d594fSAndroid Build Coastguard Worker     new_block->AddInstruction(new (graph_->GetAllocator()) HReturnVoid(exit->GetDexPc()));
645*795d594fSAndroid Build Coastguard Worker   }
646*795d594fSAndroid Build Coastguard Worker 
647*795d594fSAndroid Build Coastguard Worker   new_block->AddSuccessor(exit);
648*795d594fSAndroid Build Coastguard Worker   graph_->AddBlock(new_block);
649*795d594fSAndroid Build Coastguard Worker 
650*795d594fSAndroid Build Coastguard Worker   // Recompute dominance since we added a new block.
651*795d594fSAndroid Build Coastguard Worker   graph_->ClearDominanceInformation();
652*795d594fSAndroid Build Coastguard Worker   graph_->ComputeDominanceInformation();
653*795d594fSAndroid Build Coastguard Worker }
654*795d594fSAndroid Build Coastguard Worker 
655*795d594fSAndroid Build Coastguard Worker }  // namespace art
656