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