xref: /aosp_15_r20/art/compiler/optimizing/superblock_cloner.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 "superblock_cloner.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "common_dominator.h"
20*795d594fSAndroid Build Coastguard Worker #include "induction_var_range.h"
21*795d594fSAndroid Build Coastguard Worker #include "graph_checker.h"
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker #include <sstream>
24*795d594fSAndroid Build Coastguard Worker 
25*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker using HBasicBlockMap = SuperblockCloner::HBasicBlockMap;
28*795d594fSAndroid Build Coastguard Worker using HInstructionMap = SuperblockCloner::HInstructionMap;
29*795d594fSAndroid Build Coastguard Worker using HBasicBlockSet = SuperblockCloner::HBasicBlockSet;
30*795d594fSAndroid Build Coastguard Worker using HEdgeSet = SuperblockCloner::HEdgeSet;
31*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & stream) const32*795d594fSAndroid Build Coastguard Worker void HEdge::Dump(std::ostream& stream) const {
33*795d594fSAndroid Build Coastguard Worker   stream << "(" << from_ << "->" << to_ << ")";
34*795d594fSAndroid Build Coastguard Worker }
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker //
37*795d594fSAndroid Build Coastguard Worker // Static helper methods.
38*795d594fSAndroid Build Coastguard Worker //
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker // Returns whether instruction has any uses (regular or environmental) outside the region,
41*795d594fSAndroid Build Coastguard Worker // defined by basic block set.
IsUsedOutsideRegion(const HInstruction * instr,const HBasicBlockSet & bb_set)42*795d594fSAndroid Build Coastguard Worker static bool IsUsedOutsideRegion(const HInstruction* instr, const HBasicBlockSet& bb_set) {
43*795d594fSAndroid Build Coastguard Worker   auto& uses = instr->GetUses();
44*795d594fSAndroid Build Coastguard Worker   for (auto use_node = uses.begin(), e = uses.end(); use_node != e; ++use_node) {
45*795d594fSAndroid Build Coastguard Worker     HInstruction* user = use_node->GetUser();
46*795d594fSAndroid Build Coastguard Worker     if (!bb_set.IsBitSet(user->GetBlock()->GetBlockId())) {
47*795d594fSAndroid Build Coastguard Worker       return true;
48*795d594fSAndroid Build Coastguard Worker     }
49*795d594fSAndroid Build Coastguard Worker   }
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker   auto& env_uses = instr->GetEnvUses();
52*795d594fSAndroid Build Coastguard Worker   for (auto use_node = env_uses.begin(), e = env_uses.end(); use_node != e; ++use_node) {
53*795d594fSAndroid Build Coastguard Worker     HInstruction* user = use_node->GetUser()->GetHolder();
54*795d594fSAndroid Build Coastguard Worker     if (!bb_set.IsBitSet(user->GetBlock()->GetBlockId())) {
55*795d594fSAndroid Build Coastguard Worker       return true;
56*795d594fSAndroid Build Coastguard Worker     }
57*795d594fSAndroid Build Coastguard Worker   }
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker   return false;
60*795d594fSAndroid Build Coastguard Worker }
61*795d594fSAndroid Build Coastguard Worker 
62*795d594fSAndroid Build Coastguard Worker // Returns whether the phi's inputs are the same HInstruction.
ArePhiInputsTheSame(const HPhi * phi)63*795d594fSAndroid Build Coastguard Worker static bool ArePhiInputsTheSame(const HPhi* phi) {
64*795d594fSAndroid Build Coastguard Worker   HInstruction* first_input = phi->InputAt(0);
65*795d594fSAndroid Build Coastguard Worker   for (size_t i = 1, e = phi->InputCount(); i < e; i++) {
66*795d594fSAndroid Build Coastguard Worker     if (phi->InputAt(i) != first_input) {
67*795d594fSAndroid Build Coastguard Worker       return false;
68*795d594fSAndroid Build Coastguard Worker     }
69*795d594fSAndroid Build Coastguard Worker   }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker   return true;
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker // Returns whether two Edge sets are equal (ArenaHashSet doesn't have "Equal" method).
EdgeHashSetsEqual(const HEdgeSet * set1,const HEdgeSet * set2)75*795d594fSAndroid Build Coastguard Worker static bool EdgeHashSetsEqual(const HEdgeSet* set1, const HEdgeSet* set2) {
76*795d594fSAndroid Build Coastguard Worker   if (set1->size() != set2->size()) {
77*795d594fSAndroid Build Coastguard Worker     return false;
78*795d594fSAndroid Build Coastguard Worker   }
79*795d594fSAndroid Build Coastguard Worker 
80*795d594fSAndroid Build Coastguard Worker   for (auto e : *set1) {
81*795d594fSAndroid Build Coastguard Worker     if (set2->find(e) == set2->end()) {
82*795d594fSAndroid Build Coastguard Worker       return false;
83*795d594fSAndroid Build Coastguard Worker     }
84*795d594fSAndroid Build Coastguard Worker   }
85*795d594fSAndroid Build Coastguard Worker   return true;
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker 
88*795d594fSAndroid Build Coastguard Worker // Calls HGraph::OrderLoopHeaderPredecessors for each loop in the graph.
OrderLoopsHeadersPredecessors(HGraph * graph)89*795d594fSAndroid Build Coastguard Worker static void OrderLoopsHeadersPredecessors(HGraph* graph) {
90*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph->GetPostOrder()) {
91*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
92*795d594fSAndroid Build Coastguard Worker       graph->OrderLoopHeaderPredecessors(block);
93*795d594fSAndroid Build Coastguard Worker     }
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker }
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker // Performs DFS on the subgraph (specified by 'bb_set') starting from the specified block; while
98*795d594fSAndroid Build Coastguard Worker // traversing the function removes basic blocks from the bb_set (instead of traditional DFS
99*795d594fSAndroid Build Coastguard Worker // 'marking'). So what is left in the 'bb_set' after the traversal is not reachable from the start
100*795d594fSAndroid Build Coastguard Worker // block.
TraverseSubgraphForConnectivity(HBasicBlock * block,HBasicBlockSet * bb_set)101*795d594fSAndroid Build Coastguard Worker static void TraverseSubgraphForConnectivity(HBasicBlock* block, HBasicBlockSet* bb_set) {
102*795d594fSAndroid Build Coastguard Worker   DCHECK(bb_set->IsBitSet(block->GetBlockId()));
103*795d594fSAndroid Build Coastguard Worker   bb_set->ClearBit(block->GetBlockId());
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* succ : block->GetSuccessors()) {
106*795d594fSAndroid Build Coastguard Worker     if (bb_set->IsBitSet(succ->GetBlockId())) {
107*795d594fSAndroid Build Coastguard Worker       TraverseSubgraphForConnectivity(succ, bb_set);
108*795d594fSAndroid Build Coastguard Worker     }
109*795d594fSAndroid Build Coastguard Worker   }
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker 
112*795d594fSAndroid Build Coastguard Worker //
113*795d594fSAndroid Build Coastguard Worker // Helpers for CloneBasicBlock.
114*795d594fSAndroid Build Coastguard Worker //
115*795d594fSAndroid Build Coastguard Worker 
ReplaceInputsWithCopies(HInstruction * copy_instr)116*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ReplaceInputsWithCopies(HInstruction* copy_instr) {
117*795d594fSAndroid Build Coastguard Worker   DCHECK(!copy_instr->IsPhi());
118*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, e = copy_instr->InputCount(); i < e; i++) {
119*795d594fSAndroid Build Coastguard Worker     // Copy instruction holds the same input as the original instruction holds.
120*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_input = copy_instr->InputAt(i);
121*795d594fSAndroid Build Coastguard Worker     if (!IsInOrigBBSet(orig_input->GetBlock())) {
122*795d594fSAndroid Build Coastguard Worker       // Defined outside the subgraph.
123*795d594fSAndroid Build Coastguard Worker       continue;
124*795d594fSAndroid Build Coastguard Worker     }
125*795d594fSAndroid Build Coastguard Worker     HInstruction* copy_input = GetInstrCopy(orig_input);
126*795d594fSAndroid Build Coastguard Worker     // copy_instr will be registered as a user of copy_inputs after returning from this function:
127*795d594fSAndroid Build Coastguard Worker     // 'copy_block->AddInstruction(copy_instr)'.
128*795d594fSAndroid Build Coastguard Worker     copy_instr->SetRawInputAt(i, copy_input);
129*795d594fSAndroid Build Coastguard Worker   }
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker 
DeepCloneEnvironmentWithRemapping(HInstruction * copy_instr,const HEnvironment * orig_env)132*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::DeepCloneEnvironmentWithRemapping(HInstruction* copy_instr,
133*795d594fSAndroid Build Coastguard Worker                                                          const HEnvironment* orig_env) {
134*795d594fSAndroid Build Coastguard Worker   if (orig_env->GetParent() != nullptr) {
135*795d594fSAndroid Build Coastguard Worker     DeepCloneEnvironmentWithRemapping(copy_instr, orig_env->GetParent());
136*795d594fSAndroid Build Coastguard Worker   }
137*795d594fSAndroid Build Coastguard Worker   HEnvironment* copy_env = HEnvironment::Create(arena_, *orig_env, copy_instr);
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0; i < orig_env->Size(); i++) {
140*795d594fSAndroid Build Coastguard Worker     HInstruction* env_input = orig_env->GetInstructionAt(i);
141*795d594fSAndroid Build Coastguard Worker     if (env_input != nullptr && IsInOrigBBSet(env_input->GetBlock())) {
142*795d594fSAndroid Build Coastguard Worker       env_input = GetInstrCopy(env_input);
143*795d594fSAndroid Build Coastguard Worker       DCHECK(env_input != nullptr && env_input->GetBlock() != nullptr);
144*795d594fSAndroid Build Coastguard Worker     }
145*795d594fSAndroid Build Coastguard Worker     copy_env->SetRawEnvAt(i, env_input);
146*795d594fSAndroid Build Coastguard Worker     if (env_input != nullptr) {
147*795d594fSAndroid Build Coastguard Worker       env_input->AddEnvUseAt(copy_env, i);
148*795d594fSAndroid Build Coastguard Worker     }
149*795d594fSAndroid Build Coastguard Worker   }
150*795d594fSAndroid Build Coastguard Worker   // InsertRawEnvironment assumes that instruction already has an environment that's why we use
151*795d594fSAndroid Build Coastguard Worker   // SetRawEnvironment in the 'else' case.
152*795d594fSAndroid Build Coastguard Worker   // As this function calls itself recursively with the same copy_instr - this copy_instr may
153*795d594fSAndroid Build Coastguard Worker   // have partially copied chain of HEnvironments.
154*795d594fSAndroid Build Coastguard Worker   if (copy_instr->HasEnvironment()) {
155*795d594fSAndroid Build Coastguard Worker     copy_instr->InsertRawEnvironment(copy_env);
156*795d594fSAndroid Build Coastguard Worker   } else {
157*795d594fSAndroid Build Coastguard Worker     copy_instr->SetRawEnvironment(copy_env);
158*795d594fSAndroid Build Coastguard Worker   }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker 
161*795d594fSAndroid Build Coastguard Worker //
162*795d594fSAndroid Build Coastguard Worker // Helpers for RemapEdgesSuccessors.
163*795d594fSAndroid Build Coastguard Worker //
164*795d594fSAndroid Build Coastguard Worker 
RemapOrigInternalOrIncomingEdge(HBasicBlock * orig_block,HBasicBlock * orig_succ)165*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RemapOrigInternalOrIncomingEdge(HBasicBlock* orig_block,
166*795d594fSAndroid Build Coastguard Worker                                                        HBasicBlock* orig_succ) {
167*795d594fSAndroid Build Coastguard Worker   DCHECK(IsInOrigBBSet(orig_succ));
168*795d594fSAndroid Build Coastguard Worker   HBasicBlock* copy_succ = GetBlockCopy(orig_succ);
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker   size_t this_index = orig_succ->GetPredecessorIndexOf(orig_block);
171*795d594fSAndroid Build Coastguard Worker   size_t phi_input_count = 0;
172*795d594fSAndroid Build Coastguard Worker   // This flag reflects whether the original successor has at least one phi and this phi
173*795d594fSAndroid Build Coastguard Worker   // has been already processed in the loop. Used for validation purposes in DCHECK to check that
174*795d594fSAndroid Build Coastguard Worker   // in the end all of the phis in the copy successor have the same number of inputs - the number
175*795d594fSAndroid Build Coastguard Worker   // of copy successor's predecessors.
176*795d594fSAndroid Build Coastguard Worker   bool first_phi_met = false;
177*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(orig_succ->GetPhis()); !it.Done(); it.Advance()) {
178*795d594fSAndroid Build Coastguard Worker     HPhi* orig_phi = it.Current()->AsPhi();
179*795d594fSAndroid Build Coastguard Worker     HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
180*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_phi_input = orig_phi->InputAt(this_index);
181*795d594fSAndroid Build Coastguard Worker     // Remove corresponding input for original phi.
182*795d594fSAndroid Build Coastguard Worker     orig_phi->RemoveInputAt(this_index);
183*795d594fSAndroid Build Coastguard Worker     // Copy phi doesn't yet have either orig_block as predecessor or the input that corresponds
184*795d594fSAndroid Build Coastguard Worker     // to orig_block, so add the input at the end of the list.
185*795d594fSAndroid Build Coastguard Worker     copy_phi->AddInput(orig_phi_input);
186*795d594fSAndroid Build Coastguard Worker     if (!first_phi_met) {
187*795d594fSAndroid Build Coastguard Worker       phi_input_count = copy_phi->InputCount();
188*795d594fSAndroid Build Coastguard Worker       first_phi_met = true;
189*795d594fSAndroid Build Coastguard Worker     } else {
190*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(phi_input_count, copy_phi->InputCount());
191*795d594fSAndroid Build Coastguard Worker     }
192*795d594fSAndroid Build Coastguard Worker   }
193*795d594fSAndroid Build Coastguard Worker   // orig_block will be put at the end of the copy_succ's predecessors list; that corresponds
194*795d594fSAndroid Build Coastguard Worker   // to the previously added phi inputs position.
195*795d594fSAndroid Build Coastguard Worker   orig_block->ReplaceSuccessor(orig_succ, copy_succ);
196*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(first_phi_met, copy_succ->GetPredecessors().size() == phi_input_count);
197*795d594fSAndroid Build Coastguard Worker }
198*795d594fSAndroid Build Coastguard Worker 
AddCopyInternalEdge(HBasicBlock * orig_block,HBasicBlock * orig_succ)199*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::AddCopyInternalEdge(HBasicBlock* orig_block,
200*795d594fSAndroid Build Coastguard Worker                                            HBasicBlock* orig_succ) {
201*795d594fSAndroid Build Coastguard Worker   DCHECK(IsInOrigBBSet(orig_succ));
202*795d594fSAndroid Build Coastguard Worker   HBasicBlock* copy_block = GetBlockCopy(orig_block);
203*795d594fSAndroid Build Coastguard Worker   HBasicBlock* copy_succ = GetBlockCopy(orig_succ);
204*795d594fSAndroid Build Coastguard Worker   copy_block->AddSuccessor(copy_succ);
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker   size_t orig_index = orig_succ->GetPredecessorIndexOf(orig_block);
207*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(orig_succ->GetPhis()); !it.Done(); it.Advance()) {
208*795d594fSAndroid Build Coastguard Worker     HPhi* orig_phi = it.Current()->AsPhi();
209*795d594fSAndroid Build Coastguard Worker     HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
210*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_phi_input = orig_phi->InputAt(orig_index);
211*795d594fSAndroid Build Coastguard Worker     copy_phi->AddInput(orig_phi_input);
212*795d594fSAndroid Build Coastguard Worker   }
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker 
RemapCopyInternalEdge(HBasicBlock * orig_block,HBasicBlock * orig_succ)215*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RemapCopyInternalEdge(HBasicBlock* orig_block,
216*795d594fSAndroid Build Coastguard Worker                                              HBasicBlock* orig_succ) {
217*795d594fSAndroid Build Coastguard Worker   DCHECK(IsInOrigBBSet(orig_succ));
218*795d594fSAndroid Build Coastguard Worker   HBasicBlock* copy_block = GetBlockCopy(orig_block);
219*795d594fSAndroid Build Coastguard Worker   copy_block->AddSuccessor(orig_succ);
220*795d594fSAndroid Build Coastguard Worker   DCHECK(copy_block->HasSuccessor(orig_succ));
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker   size_t orig_index = orig_succ->GetPredecessorIndexOf(orig_block);
223*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(orig_succ->GetPhis()); !it.Done(); it.Advance()) {
224*795d594fSAndroid Build Coastguard Worker     HPhi* orig_phi = it.Current()->AsPhi();
225*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_phi_input = orig_phi->InputAt(orig_index);
226*795d594fSAndroid Build Coastguard Worker     orig_phi->AddInput(orig_phi_input);
227*795d594fSAndroid Build Coastguard Worker   }
228*795d594fSAndroid Build Coastguard Worker }
229*795d594fSAndroid Build Coastguard Worker 
IsRemapInfoForVersioning() const230*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::IsRemapInfoForVersioning() const {
231*795d594fSAndroid Build Coastguard Worker   return remap_incoming_->empty() &&
232*795d594fSAndroid Build Coastguard Worker          remap_orig_internal_->empty() &&
233*795d594fSAndroid Build Coastguard Worker          remap_copy_internal_->empty();
234*795d594fSAndroid Build Coastguard Worker }
235*795d594fSAndroid Build Coastguard Worker 
CopyIncomingEdgesForVersioning()236*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CopyIncomingEdgesForVersioning() {
237*795d594fSAndroid Build Coastguard Worker   for (uint32_t orig_block_id : orig_bb_set_.Indexes()) {
238*795d594fSAndroid Build Coastguard Worker     HBasicBlock* orig_block = GetBlockById(orig_block_id);
239*795d594fSAndroid Build Coastguard Worker     size_t incoming_edge_count = 0;
240*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* orig_pred : orig_block->GetPredecessors()) {
241*795d594fSAndroid Build Coastguard Worker       uint32_t orig_pred_id = orig_pred->GetBlockId();
242*795d594fSAndroid Build Coastguard Worker       if (IsInOrigBBSet(orig_pred_id)) {
243*795d594fSAndroid Build Coastguard Worker         continue;
244*795d594fSAndroid Build Coastguard Worker       }
245*795d594fSAndroid Build Coastguard Worker 
246*795d594fSAndroid Build Coastguard Worker       HBasicBlock* copy_block = GetBlockCopy(orig_block);
247*795d594fSAndroid Build Coastguard Worker       // This corresponds to the requirement on the order of predecessors: all the incoming
248*795d594fSAndroid Build Coastguard Worker       // edges must be seen before the internal ones. This is always true for natural loops.
249*795d594fSAndroid Build Coastguard Worker       // TODO: remove this requirement.
250*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(orig_block->GetPredecessorIndexOf(orig_pred), incoming_edge_count);
251*795d594fSAndroid Build Coastguard Worker       for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
252*795d594fSAndroid Build Coastguard Worker         HPhi* orig_phi = it.Current()->AsPhi();
253*795d594fSAndroid Build Coastguard Worker         HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
254*795d594fSAndroid Build Coastguard Worker         HInstruction* orig_phi_input = orig_phi->InputAt(incoming_edge_count);
255*795d594fSAndroid Build Coastguard Worker         // Add the corresponding input of the original phi to the copy one.
256*795d594fSAndroid Build Coastguard Worker         copy_phi->AddInput(orig_phi_input);
257*795d594fSAndroid Build Coastguard Worker       }
258*795d594fSAndroid Build Coastguard Worker       copy_block->AddPredecessor(orig_pred);
259*795d594fSAndroid Build Coastguard Worker       incoming_edge_count++;
260*795d594fSAndroid Build Coastguard Worker     }
261*795d594fSAndroid Build Coastguard Worker   }
262*795d594fSAndroid Build Coastguard Worker }
263*795d594fSAndroid Build Coastguard Worker 
264*795d594fSAndroid Build Coastguard Worker //
265*795d594fSAndroid Build Coastguard Worker // Local versions of CF calculation/adjustment routines.
266*795d594fSAndroid Build Coastguard Worker //
267*795d594fSAndroid Build Coastguard Worker 
268*795d594fSAndroid Build Coastguard Worker // TODO: merge with the original version in nodes.cc. The concern is that we don't want to affect
269*795d594fSAndroid Build Coastguard Worker // the performance of the base version by checking the local set.
270*795d594fSAndroid Build Coastguard Worker // TODO: this version works when updating the back edges info for natural loop-based local_set.
271*795d594fSAndroid Build Coastguard Worker // Check which exactly types of subgraphs can be analysed or rename it to
272*795d594fSAndroid Build Coastguard Worker // FindBackEdgesInTheNaturalLoop.
FindBackEdgesLocal(HBasicBlock * entry_block,ArenaBitVector * local_set)273*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::FindBackEdgesLocal(HBasicBlock* entry_block, ArenaBitVector* local_set) {
274*795d594fSAndroid Build Coastguard Worker   ArenaBitVector visited(arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
275*795d594fSAndroid Build Coastguard Worker 
276*795d594fSAndroid Build Coastguard Worker   // Nodes that we're currently visiting, indexed by block id.
277*795d594fSAndroid Build Coastguard Worker   ArenaBitVector visiting(arena_, graph_->GetBlocks().size(), false, kArenaAllocGraphBuilder);
278*795d594fSAndroid Build Coastguard Worker   // Number of successors visited from a given node, indexed by block id.
279*795d594fSAndroid Build Coastguard Worker   ArenaVector<size_t> successors_visited(graph_->GetBlocks().size(),
280*795d594fSAndroid Build Coastguard Worker                                          0u,
281*795d594fSAndroid Build Coastguard Worker                                          arena_->Adapter(kArenaAllocGraphBuilder));
282*795d594fSAndroid Build Coastguard Worker   // Stack of nodes that we're currently visiting (same as marked in "visiting" above).
283*795d594fSAndroid Build Coastguard Worker   ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocGraphBuilder));
284*795d594fSAndroid Build Coastguard Worker   constexpr size_t kDefaultWorklistSize = 8;
285*795d594fSAndroid Build Coastguard Worker   worklist.reserve(kDefaultWorklistSize);
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker   visited.SetBit(entry_block->GetBlockId());
288*795d594fSAndroid Build Coastguard Worker   visiting.SetBit(entry_block->GetBlockId());
289*795d594fSAndroid Build Coastguard Worker   worklist.push_back(entry_block);
290*795d594fSAndroid Build Coastguard Worker 
291*795d594fSAndroid Build Coastguard Worker   while (!worklist.empty()) {
292*795d594fSAndroid Build Coastguard Worker     HBasicBlock* current = worklist.back();
293*795d594fSAndroid Build Coastguard Worker     uint32_t current_id = current->GetBlockId();
294*795d594fSAndroid Build Coastguard Worker     if (successors_visited[current_id] == current->GetSuccessors().size()) {
295*795d594fSAndroid Build Coastguard Worker       visiting.ClearBit(current_id);
296*795d594fSAndroid Build Coastguard Worker       worklist.pop_back();
297*795d594fSAndroid Build Coastguard Worker     } else {
298*795d594fSAndroid Build Coastguard Worker       HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
299*795d594fSAndroid Build Coastguard Worker       uint32_t successor_id = successor->GetBlockId();
300*795d594fSAndroid Build Coastguard Worker       if (!local_set->IsBitSet(successor_id)) {
301*795d594fSAndroid Build Coastguard Worker         continue;
302*795d594fSAndroid Build Coastguard Worker       }
303*795d594fSAndroid Build Coastguard Worker 
304*795d594fSAndroid Build Coastguard Worker       if (visiting.IsBitSet(successor_id)) {
305*795d594fSAndroid Build Coastguard Worker         DCHECK(ContainsElement(worklist, successor));
306*795d594fSAndroid Build Coastguard Worker         successor->AddBackEdgeWhileUpdating(current);
307*795d594fSAndroid Build Coastguard Worker       } else if (!visited.IsBitSet(successor_id)) {
308*795d594fSAndroid Build Coastguard Worker         visited.SetBit(successor_id);
309*795d594fSAndroid Build Coastguard Worker         visiting.SetBit(successor_id);
310*795d594fSAndroid Build Coastguard Worker         worklist.push_back(successor);
311*795d594fSAndroid Build Coastguard Worker       }
312*795d594fSAndroid Build Coastguard Worker     }
313*795d594fSAndroid Build Coastguard Worker   }
314*795d594fSAndroid Build Coastguard Worker }
315*795d594fSAndroid Build Coastguard Worker 
RecalculateBackEdgesInfo(ArenaBitVector * outer_loop_bb_set)316*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RecalculateBackEdgesInfo(ArenaBitVector* outer_loop_bb_set) {
317*795d594fSAndroid Build Coastguard Worker   HBasicBlock* block_entry = nullptr;
318*795d594fSAndroid Build Coastguard Worker 
319*795d594fSAndroid Build Coastguard Worker   if (outer_loop_ == nullptr) {
320*795d594fSAndroid Build Coastguard Worker     for (auto block : graph_->GetBlocks()) {
321*795d594fSAndroid Build Coastguard Worker       if (block != nullptr) {
322*795d594fSAndroid Build Coastguard Worker         outer_loop_bb_set->SetBit(block->GetBlockId());
323*795d594fSAndroid Build Coastguard Worker         HLoopInformation* info = block->GetLoopInformation();
324*795d594fSAndroid Build Coastguard Worker         if (info != nullptr) {
325*795d594fSAndroid Build Coastguard Worker           info->ResetBasicBlockData();
326*795d594fSAndroid Build Coastguard Worker         }
327*795d594fSAndroid Build Coastguard Worker       }
328*795d594fSAndroid Build Coastguard Worker     }
329*795d594fSAndroid Build Coastguard Worker     block_entry = graph_->GetEntryBlock();
330*795d594fSAndroid Build Coastguard Worker   } else {
331*795d594fSAndroid Build Coastguard Worker     outer_loop_bb_set->Copy(&outer_loop_bb_set_);
332*795d594fSAndroid Build Coastguard Worker     block_entry = outer_loop_->GetHeader();
333*795d594fSAndroid Build Coastguard Worker 
334*795d594fSAndroid Build Coastguard Worker     // Add newly created copy blocks.
335*795d594fSAndroid Build Coastguard Worker     for (auto entry : *bb_map_) {
336*795d594fSAndroid Build Coastguard Worker       outer_loop_bb_set->SetBit(entry.second->GetBlockId());
337*795d594fSAndroid Build Coastguard Worker     }
338*795d594fSAndroid Build Coastguard Worker 
339*795d594fSAndroid Build Coastguard Worker     // Clear loop_info for the whole outer loop.
340*795d594fSAndroid Build Coastguard Worker     for (uint32_t idx : outer_loop_bb_set->Indexes()) {
341*795d594fSAndroid Build Coastguard Worker       HBasicBlock* block = GetBlockById(idx);
342*795d594fSAndroid Build Coastguard Worker       HLoopInformation* info = block->GetLoopInformation();
343*795d594fSAndroid Build Coastguard Worker       if (info != nullptr) {
344*795d594fSAndroid Build Coastguard Worker         info->ResetBasicBlockData();
345*795d594fSAndroid Build Coastguard Worker       }
346*795d594fSAndroid Build Coastguard Worker     }
347*795d594fSAndroid Build Coastguard Worker   }
348*795d594fSAndroid Build Coastguard Worker 
349*795d594fSAndroid Build Coastguard Worker   FindBackEdgesLocal(block_entry, outer_loop_bb_set);
350*795d594fSAndroid Build Coastguard Worker 
351*795d594fSAndroid Build Coastguard Worker   for (uint32_t idx : outer_loop_bb_set->Indexes()) {
352*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = GetBlockById(idx);
353*795d594fSAndroid Build Coastguard Worker     HLoopInformation* info = block->GetLoopInformation();
354*795d594fSAndroid Build Coastguard Worker     // Reset LoopInformation for regular blocks and old headers which are no longer loop headers.
355*795d594fSAndroid Build Coastguard Worker     if (info != nullptr &&
356*795d594fSAndroid Build Coastguard Worker         (info->GetHeader() != block || info->NumberOfBackEdges() == 0)) {
357*795d594fSAndroid Build Coastguard Worker       block->SetLoopInformation(nullptr);
358*795d594fSAndroid Build Coastguard Worker     }
359*795d594fSAndroid Build Coastguard Worker   }
360*795d594fSAndroid Build Coastguard Worker }
361*795d594fSAndroid Build Coastguard Worker 
362*795d594fSAndroid Build Coastguard Worker // This is a modified version of HGraph::AnalyzeLoops.
AnalyzeLoopsLocally(ArenaBitVector * outer_loop_bb_set)363*795d594fSAndroid Build Coastguard Worker GraphAnalysisResult SuperblockCloner::AnalyzeLoopsLocally(ArenaBitVector* outer_loop_bb_set) {
364*795d594fSAndroid Build Coastguard Worker   // We iterate post order to ensure we visit inner loops before outer loops.
365*795d594fSAndroid Build Coastguard Worker   // `PopulateRecursive` needs this guarantee to know whether a natural loop
366*795d594fSAndroid Build Coastguard Worker   // contains an irreducible loop.
367*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
368*795d594fSAndroid Build Coastguard Worker     if (!outer_loop_bb_set->IsBitSet(block->GetBlockId())) {
369*795d594fSAndroid Build Coastguard Worker       continue;
370*795d594fSAndroid Build Coastguard Worker     }
371*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
372*795d594fSAndroid Build Coastguard Worker       if (block->IsCatchBlock()) {
373*795d594fSAndroid Build Coastguard Worker         // TODO: Dealing with exceptional back edges could be tricky because
374*795d594fSAndroid Build Coastguard Worker         //       they only approximate the real control flow. Bail out for now.
375*795d594fSAndroid Build Coastguard Worker         return kAnalysisFailThrowCatchLoop;
376*795d594fSAndroid Build Coastguard Worker       }
377*795d594fSAndroid Build Coastguard Worker       block->GetLoopInformation()->Populate();
378*795d594fSAndroid Build Coastguard Worker     }
379*795d594fSAndroid Build Coastguard Worker   }
380*795d594fSAndroid Build Coastguard Worker 
381*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
382*795d594fSAndroid Build Coastguard Worker     if (!outer_loop_bb_set->IsBitSet(block->GetBlockId())) {
383*795d594fSAndroid Build Coastguard Worker       continue;
384*795d594fSAndroid Build Coastguard Worker     }
385*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
386*795d594fSAndroid Build Coastguard Worker       HLoopInformation* cur_loop = block->GetLoopInformation();
387*795d594fSAndroid Build Coastguard Worker       HLoopInformation* outer_loop = cur_loop->GetPreHeader()->GetLoopInformation();
388*795d594fSAndroid Build Coastguard Worker       if (outer_loop != nullptr) {
389*795d594fSAndroid Build Coastguard Worker         outer_loop->PopulateInnerLoopUpwards(cur_loop);
390*795d594fSAndroid Build Coastguard Worker       }
391*795d594fSAndroid Build Coastguard Worker     }
392*795d594fSAndroid Build Coastguard Worker   }
393*795d594fSAndroid Build Coastguard Worker 
394*795d594fSAndroid Build Coastguard Worker   return kAnalysisSuccess;
395*795d594fSAndroid Build Coastguard Worker }
396*795d594fSAndroid Build Coastguard Worker 
CleanUpControlFlow()397*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CleanUpControlFlow() {
398*795d594fSAndroid Build Coastguard Worker   // TODO: full control flow clean up for now, optimize it.
399*795d594fSAndroid Build Coastguard Worker   graph_->ClearDominanceInformation();
400*795d594fSAndroid Build Coastguard Worker 
401*795d594fSAndroid Build Coastguard Worker   ArenaBitVector outer_loop_bb_set(
402*795d594fSAndroid Build Coastguard Worker       arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
403*795d594fSAndroid Build Coastguard Worker   RecalculateBackEdgesInfo(&outer_loop_bb_set);
404*795d594fSAndroid Build Coastguard Worker 
405*795d594fSAndroid Build Coastguard Worker   // TODO: do it locally.
406*795d594fSAndroid Build Coastguard Worker   graph_->SimplifyCFG();
407*795d594fSAndroid Build Coastguard Worker   graph_->ComputeDominanceInformation();
408*795d594fSAndroid Build Coastguard Worker 
409*795d594fSAndroid Build Coastguard Worker   // AnalyzeLoopsLocally requires a correct post-ordering information which was calculated just
410*795d594fSAndroid Build Coastguard Worker   // before in ComputeDominanceInformation.
411*795d594fSAndroid Build Coastguard Worker   GraphAnalysisResult result = AnalyzeLoopsLocally(&outer_loop_bb_set);
412*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(result, kAnalysisSuccess);
413*795d594fSAndroid Build Coastguard Worker 
414*795d594fSAndroid Build Coastguard Worker   // TODO: do it locally
415*795d594fSAndroid Build Coastguard Worker   OrderLoopsHeadersPredecessors(graph_);
416*795d594fSAndroid Build Coastguard Worker 
417*795d594fSAndroid Build Coastguard Worker   graph_->ComputeTryBlockInformation();
418*795d594fSAndroid Build Coastguard Worker }
419*795d594fSAndroid Build Coastguard Worker 
420*795d594fSAndroid Build Coastguard Worker //
421*795d594fSAndroid Build Coastguard Worker // Helpers for ResolveDataFlow
422*795d594fSAndroid Build Coastguard Worker //
423*795d594fSAndroid Build Coastguard Worker 
ResolvePhi(HPhi * phi)424*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ResolvePhi(HPhi* phi) {
425*795d594fSAndroid Build Coastguard Worker   HBasicBlock* phi_block = phi->GetBlock();
426*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, e = phi->InputCount(); i < e; i++) {
427*795d594fSAndroid Build Coastguard Worker     HInstruction* input = phi->InputAt(i);
428*795d594fSAndroid Build Coastguard Worker     HBasicBlock* input_block = input->GetBlock();
429*795d594fSAndroid Build Coastguard Worker 
430*795d594fSAndroid Build Coastguard Worker     // Originally defined outside the region.
431*795d594fSAndroid Build Coastguard Worker     if (!IsInOrigBBSet(input_block)) {
432*795d594fSAndroid Build Coastguard Worker       continue;
433*795d594fSAndroid Build Coastguard Worker     }
434*795d594fSAndroid Build Coastguard Worker     HBasicBlock* corresponding_block = phi_block->GetPredecessors()[i];
435*795d594fSAndroid Build Coastguard Worker     if (!IsInOrigBBSet(corresponding_block)) {
436*795d594fSAndroid Build Coastguard Worker       phi->ReplaceInput(GetInstrCopy(input), i);
437*795d594fSAndroid Build Coastguard Worker     }
438*795d594fSAndroid Build Coastguard Worker   }
439*795d594fSAndroid Build Coastguard Worker }
440*795d594fSAndroid Build Coastguard Worker 
441*795d594fSAndroid Build Coastguard Worker //
442*795d594fSAndroid Build Coastguard Worker // Main algorithm methods.
443*795d594fSAndroid Build Coastguard Worker //
444*795d594fSAndroid Build Coastguard Worker 
SearchForSubgraphExits(ArenaVector<HBasicBlock * > * exits) const445*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::SearchForSubgraphExits(ArenaVector<HBasicBlock*>* exits) const {
446*795d594fSAndroid Build Coastguard Worker   DCHECK(exits->empty());
447*795d594fSAndroid Build Coastguard Worker   for (uint32_t block_id : orig_bb_set_.Indexes()) {
448*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = GetBlockById(block_id);
449*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* succ : block->GetSuccessors()) {
450*795d594fSAndroid Build Coastguard Worker       if (!IsInOrigBBSet(succ)) {
451*795d594fSAndroid Build Coastguard Worker         exits->push_back(succ);
452*795d594fSAndroid Build Coastguard Worker       }
453*795d594fSAndroid Build Coastguard Worker     }
454*795d594fSAndroid Build Coastguard Worker   }
455*795d594fSAndroid Build Coastguard Worker }
456*795d594fSAndroid Build Coastguard Worker 
FindAndSetLocalAreaForAdjustments()457*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::FindAndSetLocalAreaForAdjustments() {
458*795d594fSAndroid Build Coastguard Worker   DCHECK(outer_loop_ == nullptr);
459*795d594fSAndroid Build Coastguard Worker   ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
460*795d594fSAndroid Build Coastguard Worker   SearchForSubgraphExits(&exits);
461*795d594fSAndroid Build Coastguard Worker 
462*795d594fSAndroid Build Coastguard Worker   // For a reducible graph we need to update back-edges and dominance information only for
463*795d594fSAndroid Build Coastguard Worker   // the outermost loop which is affected by the transformation - it can be found by picking
464*795d594fSAndroid Build Coastguard Worker   // the common most outer loop of loops to which the subgraph exits blocks belong.
465*795d594fSAndroid Build Coastguard Worker   // Note: it can a loop or the whole graph (outer_loop_ will be nullptr in this case).
466*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* exit : exits) {
467*795d594fSAndroid Build Coastguard Worker     HLoopInformation* loop_exit_loop_info = exit->GetLoopInformation();
468*795d594fSAndroid Build Coastguard Worker     if (loop_exit_loop_info == nullptr) {
469*795d594fSAndroid Build Coastguard Worker       outer_loop_ = nullptr;
470*795d594fSAndroid Build Coastguard Worker       break;
471*795d594fSAndroid Build Coastguard Worker     }
472*795d594fSAndroid Build Coastguard Worker     if (outer_loop_ == nullptr) {
473*795d594fSAndroid Build Coastguard Worker       // We should not use the initial outer_loop_ value 'nullptr' when finding the most outer
474*795d594fSAndroid Build Coastguard Worker       // common loop.
475*795d594fSAndroid Build Coastguard Worker       outer_loop_ = loop_exit_loop_info;
476*795d594fSAndroid Build Coastguard Worker     }
477*795d594fSAndroid Build Coastguard Worker     outer_loop_ = FindCommonLoop(outer_loop_, loop_exit_loop_info);
478*795d594fSAndroid Build Coastguard Worker   }
479*795d594fSAndroid Build Coastguard Worker 
480*795d594fSAndroid Build Coastguard Worker   if (outer_loop_ != nullptr) {
481*795d594fSAndroid Build Coastguard Worker     // Save the loop population info as it will be changed later.
482*795d594fSAndroid Build Coastguard Worker     outer_loop_bb_set_.Copy(&outer_loop_->GetBlocks());
483*795d594fSAndroid Build Coastguard Worker   }
484*795d594fSAndroid Build Coastguard Worker }
485*795d594fSAndroid Build Coastguard Worker 
RemapEdgesSuccessors()486*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::RemapEdgesSuccessors() {
487*795d594fSAndroid Build Coastguard Worker   // By this stage all the blocks have been copied, copy phis - created with no inputs;
488*795d594fSAndroid Build Coastguard Worker   // no copy edges have been created so far.
489*795d594fSAndroid Build Coastguard Worker   if (IsRemapInfoForVersioning()) {
490*795d594fSAndroid Build Coastguard Worker     CopyIncomingEdgesForVersioning();
491*795d594fSAndroid Build Coastguard Worker   }
492*795d594fSAndroid Build Coastguard Worker 
493*795d594fSAndroid Build Coastguard Worker   // Redirect incoming edges.
494*795d594fSAndroid Build Coastguard Worker   for (HEdge e : *remap_incoming_) {
495*795d594fSAndroid Build Coastguard Worker     HBasicBlock* orig_block = GetBlockById(e.GetFrom());
496*795d594fSAndroid Build Coastguard Worker     HBasicBlock* orig_succ = GetBlockById(e.GetTo());
497*795d594fSAndroid Build Coastguard Worker     RemapOrigInternalOrIncomingEdge(orig_block, orig_succ);
498*795d594fSAndroid Build Coastguard Worker   }
499*795d594fSAndroid Build Coastguard Worker 
500*795d594fSAndroid Build Coastguard Worker   // Redirect internal edges.
501*795d594fSAndroid Build Coastguard Worker   for (uint32_t orig_block_id : orig_bb_set_.Indexes()) {
502*795d594fSAndroid Build Coastguard Worker     HBasicBlock* orig_block = GetBlockById(orig_block_id);
503*795d594fSAndroid Build Coastguard Worker 
504*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* orig_succ : orig_block->GetSuccessors()) {
505*795d594fSAndroid Build Coastguard Worker       uint32_t orig_succ_id = orig_succ->GetBlockId();
506*795d594fSAndroid Build Coastguard Worker 
507*795d594fSAndroid Build Coastguard Worker       // Check for outgoing edge.
508*795d594fSAndroid Build Coastguard Worker       if (!IsInOrigBBSet(orig_succ)) {
509*795d594fSAndroid Build Coastguard Worker         HBasicBlock* copy_block = GetBlockCopy(orig_block);
510*795d594fSAndroid Build Coastguard Worker         copy_block->AddSuccessor(orig_succ);
511*795d594fSAndroid Build Coastguard Worker         continue;
512*795d594fSAndroid Build Coastguard Worker       }
513*795d594fSAndroid Build Coastguard Worker 
514*795d594fSAndroid Build Coastguard Worker       auto orig_redir = remap_orig_internal_->find(HEdge(orig_block_id, orig_succ_id));
515*795d594fSAndroid Build Coastguard Worker       auto copy_redir = remap_copy_internal_->find(HEdge(orig_block_id, orig_succ_id));
516*795d594fSAndroid Build Coastguard Worker 
517*795d594fSAndroid Build Coastguard Worker       // Due to construction all successors of copied block were set to original.
518*795d594fSAndroid Build Coastguard Worker       if (copy_redir != remap_copy_internal_->end()) {
519*795d594fSAndroid Build Coastguard Worker         RemapCopyInternalEdge(orig_block, orig_succ);
520*795d594fSAndroid Build Coastguard Worker       } else {
521*795d594fSAndroid Build Coastguard Worker         AddCopyInternalEdge(orig_block, orig_succ);
522*795d594fSAndroid Build Coastguard Worker       }
523*795d594fSAndroid Build Coastguard Worker 
524*795d594fSAndroid Build Coastguard Worker       if (orig_redir != remap_orig_internal_->end()) {
525*795d594fSAndroid Build Coastguard Worker         RemapOrigInternalOrIncomingEdge(orig_block, orig_succ);
526*795d594fSAndroid Build Coastguard Worker       }
527*795d594fSAndroid Build Coastguard Worker     }
528*795d594fSAndroid Build Coastguard Worker   }
529*795d594fSAndroid Build Coastguard Worker }
530*795d594fSAndroid Build Coastguard Worker 
AdjustControlFlowInfo()531*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::AdjustControlFlowInfo() {
532*795d594fSAndroid Build Coastguard Worker   ArenaBitVector outer_loop_bb_set(
533*795d594fSAndroid Build Coastguard Worker       arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
534*795d594fSAndroid Build Coastguard Worker   RecalculateBackEdgesInfo(&outer_loop_bb_set);
535*795d594fSAndroid Build Coastguard Worker 
536*795d594fSAndroid Build Coastguard Worker   graph_->ClearDominanceInformation();
537*795d594fSAndroid Build Coastguard Worker   // TODO: Do it locally.
538*795d594fSAndroid Build Coastguard Worker   graph_->ComputeDominanceInformation();
539*795d594fSAndroid Build Coastguard Worker }
540*795d594fSAndroid Build Coastguard Worker 
541*795d594fSAndroid Build Coastguard Worker // TODO: Current FastCase restriction guarantees that instructions' inputs are already mapped to
542*795d594fSAndroid Build Coastguard Worker // the valid values; only phis' inputs must be adjusted.
ResolveDataFlow()543*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ResolveDataFlow() {
544*795d594fSAndroid Build Coastguard Worker   for (auto entry : *bb_map_) {
545*795d594fSAndroid Build Coastguard Worker     HBasicBlock* orig_block = entry.first;
546*795d594fSAndroid Build Coastguard Worker 
547*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
548*795d594fSAndroid Build Coastguard Worker       HPhi* orig_phi = it.Current()->AsPhi();
549*795d594fSAndroid Build Coastguard Worker       HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
550*795d594fSAndroid Build Coastguard Worker       ResolvePhi(orig_phi);
551*795d594fSAndroid Build Coastguard Worker       ResolvePhi(copy_phi);
552*795d594fSAndroid Build Coastguard Worker     }
553*795d594fSAndroid Build Coastguard Worker     if (kIsDebugBuild) {
554*795d594fSAndroid Build Coastguard Worker       // Inputs of instruction copies must be already mapped to correspondent inputs copies.
555*795d594fSAndroid Build Coastguard Worker       for (HInstructionIterator it(orig_block->GetInstructions()); !it.Done(); it.Advance()) {
556*795d594fSAndroid Build Coastguard Worker         CheckInstructionInputsRemapping(it.Current());
557*795d594fSAndroid Build Coastguard Worker       }
558*795d594fSAndroid Build Coastguard Worker     }
559*795d594fSAndroid Build Coastguard Worker   }
560*795d594fSAndroid Build Coastguard Worker }
561*795d594fSAndroid Build Coastguard Worker 
562*795d594fSAndroid Build Coastguard Worker //
563*795d594fSAndroid Build Coastguard Worker // Helpers for live-outs processing and Subgraph-closed SSA.
564*795d594fSAndroid Build Coastguard Worker //
565*795d594fSAndroid Build Coastguard Worker 
CollectLiveOutsAndCheckClonable(HInstructionMap * live_outs) const566*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::CollectLiveOutsAndCheckClonable(HInstructionMap* live_outs) const {
567*795d594fSAndroid Build Coastguard Worker   DCHECK(live_outs->empty());
568*795d594fSAndroid Build Coastguard Worker   for (uint32_t idx : orig_bb_set_.Indexes()) {
569*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = GetBlockById(idx);
570*795d594fSAndroid Build Coastguard Worker 
571*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
572*795d594fSAndroid Build Coastguard Worker       HInstruction* instr = it.Current();
573*795d594fSAndroid Build Coastguard Worker       DCHECK(instr->IsClonable());
574*795d594fSAndroid Build Coastguard Worker 
575*795d594fSAndroid Build Coastguard Worker       if (IsUsedOutsideRegion(instr, orig_bb_set_)) {
576*795d594fSAndroid Build Coastguard Worker         live_outs->FindOrAdd(instr, instr);
577*795d594fSAndroid Build Coastguard Worker       }
578*795d594fSAndroid Build Coastguard Worker     }
579*795d594fSAndroid Build Coastguard Worker 
580*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
581*795d594fSAndroid Build Coastguard Worker       HInstruction* instr = it.Current();
582*795d594fSAndroid Build Coastguard Worker       if (!instr->IsClonable()) {
583*795d594fSAndroid Build Coastguard Worker         return false;
584*795d594fSAndroid Build Coastguard Worker       }
585*795d594fSAndroid Build Coastguard Worker 
586*795d594fSAndroid Build Coastguard Worker       if (IsUsedOutsideRegion(instr, orig_bb_set_)) {
587*795d594fSAndroid Build Coastguard Worker         // TODO: Investigate why HNewInstance, HCheckCast has a requirement for the input.
588*795d594fSAndroid Build Coastguard Worker         if (instr->IsLoadClass()) {
589*795d594fSAndroid Build Coastguard Worker           return false;
590*795d594fSAndroid Build Coastguard Worker         }
591*795d594fSAndroid Build Coastguard Worker         live_outs->FindOrAdd(instr, instr);
592*795d594fSAndroid Build Coastguard Worker       }
593*795d594fSAndroid Build Coastguard Worker     }
594*795d594fSAndroid Build Coastguard Worker   }
595*795d594fSAndroid Build Coastguard Worker   return true;
596*795d594fSAndroid Build Coastguard Worker }
597*795d594fSAndroid Build Coastguard Worker 
UpdateInductionRangeInfoOf(HInstruction * user,HInstruction * old_instruction,HInstruction * replacement)598*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::UpdateInductionRangeInfoOf(
599*795d594fSAndroid Build Coastguard Worker       HInstruction* user, HInstruction* old_instruction, HInstruction* replacement) {
600*795d594fSAndroid Build Coastguard Worker   if (induction_range_ != nullptr) {
601*795d594fSAndroid Build Coastguard Worker     induction_range_->Replace(user, old_instruction, replacement);
602*795d594fSAndroid Build Coastguard Worker   }
603*795d594fSAndroid Build Coastguard Worker }
604*795d594fSAndroid Build Coastguard Worker 
ConstructSubgraphClosedSSA()605*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::ConstructSubgraphClosedSSA() {
606*795d594fSAndroid Build Coastguard Worker   if (live_outs_.empty()) {
607*795d594fSAndroid Build Coastguard Worker     return;
608*795d594fSAndroid Build Coastguard Worker   }
609*795d594fSAndroid Build Coastguard Worker 
610*795d594fSAndroid Build Coastguard Worker   ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
611*795d594fSAndroid Build Coastguard Worker   SearchForSubgraphExits(&exits);
612*795d594fSAndroid Build Coastguard Worker   if (exits.empty()) {
613*795d594fSAndroid Build Coastguard Worker     DCHECK(live_outs_.empty());
614*795d594fSAndroid Build Coastguard Worker     return;
615*795d594fSAndroid Build Coastguard Worker   }
616*795d594fSAndroid Build Coastguard Worker 
617*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(exits.size(), 1u);
618*795d594fSAndroid Build Coastguard Worker   HBasicBlock* exit_block = exits[0];
619*795d594fSAndroid Build Coastguard Worker   // There should be no critical edges.
620*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(exit_block->GetPredecessors().size(), 1u);
621*795d594fSAndroid Build Coastguard Worker   DCHECK(exit_block->GetPhis().IsEmpty());
622*795d594fSAndroid Build Coastguard Worker 
623*795d594fSAndroid Build Coastguard Worker   // For each live-out value insert a phi into the loop exit and replace all the value's uses
624*795d594fSAndroid Build Coastguard Worker   // external to the loop with this phi. The phi will have the original value as its only input;
625*795d594fSAndroid Build Coastguard Worker   // after copying is done FixSubgraphClosedSSAAfterCloning will add a corresponding copy of the
626*795d594fSAndroid Build Coastguard Worker   // original value as the second input thus merging data flow from the original and copy parts of
627*795d594fSAndroid Build Coastguard Worker   // the subgraph. Also update the record in the live_outs_ map from (value, value) to
628*795d594fSAndroid Build Coastguard Worker   // (value, new_phi).
629*795d594fSAndroid Build Coastguard Worker   for (auto live_out_it = live_outs_.begin(); live_out_it != live_outs_.end(); ++live_out_it) {
630*795d594fSAndroid Build Coastguard Worker     HInstruction* value = live_out_it->first;
631*795d594fSAndroid Build Coastguard Worker     HPhi* phi = new (arena_) HPhi(arena_, kNoRegNumber, 0, value->GetType());
632*795d594fSAndroid Build Coastguard Worker 
633*795d594fSAndroid Build Coastguard Worker     if (value->GetType() == DataType::Type::kReference) {
634*795d594fSAndroid Build Coastguard Worker       phi->SetReferenceTypeInfoIfValid(value->GetReferenceTypeInfo());
635*795d594fSAndroid Build Coastguard Worker     }
636*795d594fSAndroid Build Coastguard Worker 
637*795d594fSAndroid Build Coastguard Worker     exit_block->AddPhi(phi);
638*795d594fSAndroid Build Coastguard Worker     live_out_it->second = phi;
639*795d594fSAndroid Build Coastguard Worker 
640*795d594fSAndroid Build Coastguard Worker     const HUseList<HInstruction*>& uses = value->GetUses();
641*795d594fSAndroid Build Coastguard Worker     for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
642*795d594fSAndroid Build Coastguard Worker       HInstruction* user = it->GetUser();
643*795d594fSAndroid Build Coastguard Worker       size_t index = it->GetIndex();
644*795d594fSAndroid Build Coastguard Worker       // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
645*795d594fSAndroid Build Coastguard Worker       ++it;
646*795d594fSAndroid Build Coastguard Worker       if (!IsInOrigBBSet(user->GetBlock())) {
647*795d594fSAndroid Build Coastguard Worker         user->ReplaceInput(phi, index);
648*795d594fSAndroid Build Coastguard Worker         UpdateInductionRangeInfoOf(user, value, phi);
649*795d594fSAndroid Build Coastguard Worker       }
650*795d594fSAndroid Build Coastguard Worker     }
651*795d594fSAndroid Build Coastguard Worker 
652*795d594fSAndroid Build Coastguard Worker     const HUseList<HEnvironment*>& env_uses = value->GetEnvUses();
653*795d594fSAndroid Build Coastguard Worker     for (auto it = env_uses.begin(), e = env_uses.end(); it != e; /* ++it below */) {
654*795d594fSAndroid Build Coastguard Worker       HEnvironment* env = it->GetUser();
655*795d594fSAndroid Build Coastguard Worker       size_t index = it->GetIndex();
656*795d594fSAndroid Build Coastguard Worker       ++it;
657*795d594fSAndroid Build Coastguard Worker       if (!IsInOrigBBSet(env->GetHolder()->GetBlock())) {
658*795d594fSAndroid Build Coastguard Worker         env->ReplaceInput(phi, index);
659*795d594fSAndroid Build Coastguard Worker       }
660*795d594fSAndroid Build Coastguard Worker     }
661*795d594fSAndroid Build Coastguard Worker 
662*795d594fSAndroid Build Coastguard Worker     phi->AddInput(value);
663*795d594fSAndroid Build Coastguard Worker   }
664*795d594fSAndroid Build Coastguard Worker }
665*795d594fSAndroid Build Coastguard Worker 
FixSubgraphClosedSSAAfterCloning()666*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::FixSubgraphClosedSSAAfterCloning() {
667*795d594fSAndroid Build Coastguard Worker   for (auto it : live_outs_) {
668*795d594fSAndroid Build Coastguard Worker     DCHECK(it.first != it.second);
669*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_value = it.first;
670*795d594fSAndroid Build Coastguard Worker     HPhi* phi = it.second->AsPhi();
671*795d594fSAndroid Build Coastguard Worker     HInstruction* copy_value = GetInstrCopy(orig_value);
672*795d594fSAndroid Build Coastguard Worker     // Copy edges are inserted after the original so we can just add new input to the phi.
673*795d594fSAndroid Build Coastguard Worker     phi->AddInput(copy_value);
674*795d594fSAndroid Build Coastguard Worker   }
675*795d594fSAndroid Build Coastguard Worker }
676*795d594fSAndroid Build Coastguard Worker 
677*795d594fSAndroid Build Coastguard Worker //
678*795d594fSAndroid Build Coastguard Worker // Debug and logging methods.
679*795d594fSAndroid Build Coastguard Worker //
680*795d594fSAndroid Build Coastguard Worker 
681*795d594fSAndroid Build Coastguard Worker // Debug function to dump graph' BasicBlocks info.
DumpBB(HGraph * graph)682*795d594fSAndroid Build Coastguard Worker void DumpBB(HGraph* graph) {
683*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* bb : graph->GetBlocks()) {
684*795d594fSAndroid Build Coastguard Worker     if (bb == nullptr) {
685*795d594fSAndroid Build Coastguard Worker       continue;
686*795d594fSAndroid Build Coastguard Worker     }
687*795d594fSAndroid Build Coastguard Worker     std::ostringstream oss;
688*795d594fSAndroid Build Coastguard Worker     oss << bb->GetBlockId();
689*795d594fSAndroid Build Coastguard Worker     oss << " <- ";
690*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* pred : bb->GetPredecessors()) {
691*795d594fSAndroid Build Coastguard Worker       oss << pred->GetBlockId() << " ";
692*795d594fSAndroid Build Coastguard Worker     }
693*795d594fSAndroid Build Coastguard Worker     oss << " -> ";
694*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* succ : bb->GetSuccessors()) {
695*795d594fSAndroid Build Coastguard Worker       oss << succ->GetBlockId()  << " ";
696*795d594fSAndroid Build Coastguard Worker     }
697*795d594fSAndroid Build Coastguard Worker 
698*795d594fSAndroid Build Coastguard Worker     if (bb->GetDominator()) {
699*795d594fSAndroid Build Coastguard Worker       oss << " dom " << bb->GetDominator()->GetBlockId();
700*795d594fSAndroid Build Coastguard Worker     }
701*795d594fSAndroid Build Coastguard Worker 
702*795d594fSAndroid Build Coastguard Worker     if (bb->GetLoopInformation()) {
703*795d594fSAndroid Build Coastguard Worker       oss <<  "\tloop: " << bb->GetLoopInformation()->GetHeader()->GetBlockId();
704*795d594fSAndroid Build Coastguard Worker     }
705*795d594fSAndroid Build Coastguard Worker 
706*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << oss.str();
707*795d594fSAndroid Build Coastguard Worker   }
708*795d594fSAndroid Build Coastguard Worker }
709*795d594fSAndroid Build Coastguard Worker 
CheckInstructionInputsRemapping(HInstruction * orig_instr)710*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CheckInstructionInputsRemapping(HInstruction* orig_instr) {
711*795d594fSAndroid Build Coastguard Worker   DCHECK(!orig_instr->IsPhi());
712*795d594fSAndroid Build Coastguard Worker   HInstruction* copy_instr = GetInstrCopy(orig_instr);
713*795d594fSAndroid Build Coastguard Worker   for (size_t i = 0, e = orig_instr->InputCount(); i < e; i++) {
714*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_input = orig_instr->InputAt(i);
715*795d594fSAndroid Build Coastguard Worker     DCHECK(orig_input->GetBlock()->Dominates(orig_instr->GetBlock()));
716*795d594fSAndroid Build Coastguard Worker 
717*795d594fSAndroid Build Coastguard Worker     // If original input is defined outside the region then it will remain for both original
718*795d594fSAndroid Build Coastguard Worker     // instruction and the copy after the transformation.
719*795d594fSAndroid Build Coastguard Worker     if (!IsInOrigBBSet(orig_input->GetBlock())) {
720*795d594fSAndroid Build Coastguard Worker       continue;
721*795d594fSAndroid Build Coastguard Worker     }
722*795d594fSAndroid Build Coastguard Worker     HInstruction* copy_input = GetInstrCopy(orig_input);
723*795d594fSAndroid Build Coastguard Worker     DCHECK(copy_input->GetBlock()->Dominates(copy_instr->GetBlock()));
724*795d594fSAndroid Build Coastguard Worker   }
725*795d594fSAndroid Build Coastguard Worker 
726*795d594fSAndroid Build Coastguard Worker   // Resolve environment.
727*795d594fSAndroid Build Coastguard Worker   if (orig_instr->HasEnvironment()) {
728*795d594fSAndroid Build Coastguard Worker     HEnvironment* orig_env = orig_instr->GetEnvironment();
729*795d594fSAndroid Build Coastguard Worker 
730*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0, e = orig_env->Size(); i < e; ++i) {
731*795d594fSAndroid Build Coastguard Worker       HInstruction* orig_input = orig_env->GetInstructionAt(i);
732*795d594fSAndroid Build Coastguard Worker 
733*795d594fSAndroid Build Coastguard Worker       // If original input is defined outside the region then it will remain for both original
734*795d594fSAndroid Build Coastguard Worker       // instruction and the copy after the transformation.
735*795d594fSAndroid Build Coastguard Worker       if (orig_input == nullptr || !IsInOrigBBSet(orig_input->GetBlock())) {
736*795d594fSAndroid Build Coastguard Worker         continue;
737*795d594fSAndroid Build Coastguard Worker       }
738*795d594fSAndroid Build Coastguard Worker 
739*795d594fSAndroid Build Coastguard Worker       HInstruction* copy_input = GetInstrCopy(orig_input);
740*795d594fSAndroid Build Coastguard Worker       DCHECK(copy_input->GetBlock()->Dominates(copy_instr->GetBlock()));
741*795d594fSAndroid Build Coastguard Worker     }
742*795d594fSAndroid Build Coastguard Worker   }
743*795d594fSAndroid Build Coastguard Worker }
744*795d594fSAndroid Build Coastguard Worker 
CheckRemappingInfoIsValid()745*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::CheckRemappingInfoIsValid() {
746*795d594fSAndroid Build Coastguard Worker   for (HEdge edge : *remap_orig_internal_) {
747*795d594fSAndroid Build Coastguard Worker     if (!IsEdgeValid(edge, graph_) ||
748*795d594fSAndroid Build Coastguard Worker         !IsInOrigBBSet(edge.GetFrom()) ||
749*795d594fSAndroid Build Coastguard Worker         !IsInOrigBBSet(edge.GetTo())) {
750*795d594fSAndroid Build Coastguard Worker       return false;
751*795d594fSAndroid Build Coastguard Worker     }
752*795d594fSAndroid Build Coastguard Worker   }
753*795d594fSAndroid Build Coastguard Worker 
754*795d594fSAndroid Build Coastguard Worker   for (auto edge : *remap_copy_internal_) {
755*795d594fSAndroid Build Coastguard Worker     if (!IsEdgeValid(edge, graph_) ||
756*795d594fSAndroid Build Coastguard Worker         !IsInOrigBBSet(edge.GetFrom()) ||
757*795d594fSAndroid Build Coastguard Worker         !IsInOrigBBSet(edge.GetTo())) {
758*795d594fSAndroid Build Coastguard Worker       return false;
759*795d594fSAndroid Build Coastguard Worker     }
760*795d594fSAndroid Build Coastguard Worker   }
761*795d594fSAndroid Build Coastguard Worker 
762*795d594fSAndroid Build Coastguard Worker   for (auto edge : *remap_incoming_) {
763*795d594fSAndroid Build Coastguard Worker     if (!IsEdgeValid(edge, graph_) ||
764*795d594fSAndroid Build Coastguard Worker         IsInOrigBBSet(edge.GetFrom()) ||
765*795d594fSAndroid Build Coastguard Worker         !IsInOrigBBSet(edge.GetTo())) {
766*795d594fSAndroid Build Coastguard Worker       return false;
767*795d594fSAndroid Build Coastguard Worker     }
768*795d594fSAndroid Build Coastguard Worker   }
769*795d594fSAndroid Build Coastguard Worker 
770*795d594fSAndroid Build Coastguard Worker   return true;
771*795d594fSAndroid Build Coastguard Worker }
772*795d594fSAndroid Build Coastguard Worker 
VerifyGraph()773*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::VerifyGraph() {
774*795d594fSAndroid Build Coastguard Worker   for (auto it : *hir_map_) {
775*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_instr = it.first;
776*795d594fSAndroid Build Coastguard Worker     HInstruction* copy_instr = it.second;
777*795d594fSAndroid Build Coastguard Worker     if (!orig_instr->IsPhi() && !orig_instr->IsSuspendCheck()) {
778*795d594fSAndroid Build Coastguard Worker       DCHECK(it.first->GetBlock() != nullptr);
779*795d594fSAndroid Build Coastguard Worker     }
780*795d594fSAndroid Build Coastguard Worker     if (!copy_instr->IsPhi() && !copy_instr->IsSuspendCheck()) {
781*795d594fSAndroid Build Coastguard Worker       DCHECK(it.second->GetBlock() != nullptr);
782*795d594fSAndroid Build Coastguard Worker     }
783*795d594fSAndroid Build Coastguard Worker   }
784*795d594fSAndroid Build Coastguard Worker   if (kSuperblockClonerVerify) {
785*795d594fSAndroid Build Coastguard Worker     GraphChecker checker(graph_);
786*795d594fSAndroid Build Coastguard Worker     checker.Run();
787*795d594fSAndroid Build Coastguard Worker     if (!checker.IsValid()) {
788*795d594fSAndroid Build Coastguard Worker       for (const std::string& error : checker.GetErrors()) {
789*795d594fSAndroid Build Coastguard Worker         LOG(ERROR) << error;
790*795d594fSAndroid Build Coastguard Worker       }
791*795d594fSAndroid Build Coastguard Worker       LOG(FATAL) << "GraphChecker failed: superblock cloner";
792*795d594fSAndroid Build Coastguard Worker     }
793*795d594fSAndroid Build Coastguard Worker   }
794*795d594fSAndroid Build Coastguard Worker }
795*795d594fSAndroid Build Coastguard Worker 
DumpBBSet(const ArenaBitVector * set)796*795d594fSAndroid Build Coastguard Worker void DumpBBSet(const ArenaBitVector* set) {
797*795d594fSAndroid Build Coastguard Worker   for (uint32_t idx : set->Indexes()) {
798*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << idx;
799*795d594fSAndroid Build Coastguard Worker   }
800*795d594fSAndroid Build Coastguard Worker }
801*795d594fSAndroid Build Coastguard Worker 
DumpInputSets()802*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::DumpInputSets() {
803*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "orig_bb_set:";
804*795d594fSAndroid Build Coastguard Worker   for (uint32_t idx : orig_bb_set_.Indexes()) {
805*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << idx;
806*795d594fSAndroid Build Coastguard Worker   }
807*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "remap_orig_internal:";
808*795d594fSAndroid Build Coastguard Worker   for (HEdge e : *remap_orig_internal_) {
809*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << e;
810*795d594fSAndroid Build Coastguard Worker   }
811*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "remap_copy_internal:";
812*795d594fSAndroid Build Coastguard Worker   for (auto e : *remap_copy_internal_) {
813*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << e;
814*795d594fSAndroid Build Coastguard Worker   }
815*795d594fSAndroid Build Coastguard Worker   LOG(INFO) << "remap_incoming:";
816*795d594fSAndroid Build Coastguard Worker   for (auto e : *remap_incoming_) {
817*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << e;
818*795d594fSAndroid Build Coastguard Worker   }
819*795d594fSAndroid Build Coastguard Worker }
820*795d594fSAndroid Build Coastguard Worker 
821*795d594fSAndroid Build Coastguard Worker //
822*795d594fSAndroid Build Coastguard Worker // Public methods.
823*795d594fSAndroid Build Coastguard Worker //
824*795d594fSAndroid Build Coastguard Worker 
SuperblockCloner(HGraph * graph,const HBasicBlockSet * orig_bb_set,HBasicBlockMap * bb_map,HInstructionMap * hir_map,InductionVarRange * induction_range)825*795d594fSAndroid Build Coastguard Worker SuperblockCloner::SuperblockCloner(HGraph* graph,
826*795d594fSAndroid Build Coastguard Worker                                    const HBasicBlockSet* orig_bb_set,
827*795d594fSAndroid Build Coastguard Worker                                    HBasicBlockMap* bb_map,
828*795d594fSAndroid Build Coastguard Worker                                    HInstructionMap* hir_map,
829*795d594fSAndroid Build Coastguard Worker                                    InductionVarRange* induction_range)
830*795d594fSAndroid Build Coastguard Worker   : graph_(graph),
831*795d594fSAndroid Build Coastguard Worker     arena_(graph->GetAllocator()),
832*795d594fSAndroid Build Coastguard Worker     orig_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner),
833*795d594fSAndroid Build Coastguard Worker     remap_orig_internal_(nullptr),
834*795d594fSAndroid Build Coastguard Worker     remap_copy_internal_(nullptr),
835*795d594fSAndroid Build Coastguard Worker     remap_incoming_(nullptr),
836*795d594fSAndroid Build Coastguard Worker     bb_map_(bb_map),
837*795d594fSAndroid Build Coastguard Worker     hir_map_(hir_map),
838*795d594fSAndroid Build Coastguard Worker     induction_range_(induction_range),
839*795d594fSAndroid Build Coastguard Worker     outer_loop_(nullptr),
840*795d594fSAndroid Build Coastguard Worker     outer_loop_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner),
841*795d594fSAndroid Build Coastguard Worker     live_outs_(std::less<HInstruction*>(),
842*795d594fSAndroid Build Coastguard Worker         graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)) {
843*795d594fSAndroid Build Coastguard Worker   orig_bb_set_.Copy(orig_bb_set);
844*795d594fSAndroid Build Coastguard Worker }
845*795d594fSAndroid Build Coastguard Worker 
SetSuccessorRemappingInfo(const HEdgeSet * remap_orig_internal,const HEdgeSet * remap_copy_internal,const HEdgeSet * remap_incoming)846*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::SetSuccessorRemappingInfo(const HEdgeSet* remap_orig_internal,
847*795d594fSAndroid Build Coastguard Worker                                                  const HEdgeSet* remap_copy_internal,
848*795d594fSAndroid Build Coastguard Worker                                                  const HEdgeSet* remap_incoming) {
849*795d594fSAndroid Build Coastguard Worker   remap_orig_internal_ = remap_orig_internal;
850*795d594fSAndroid Build Coastguard Worker   remap_copy_internal_ = remap_copy_internal;
851*795d594fSAndroid Build Coastguard Worker   remap_incoming_ = remap_incoming;
852*795d594fSAndroid Build Coastguard Worker   DCHECK(CheckRemappingInfoIsValid());
853*795d594fSAndroid Build Coastguard Worker }
854*795d594fSAndroid Build Coastguard Worker 
IsSubgraphClonable() const855*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::IsSubgraphClonable() const {
856*795d594fSAndroid Build Coastguard Worker   // TODO: Support irreducible graphs and subgraphs with try-catch.
857*795d594fSAndroid Build Coastguard Worker   if (graph_->HasIrreducibleLoops()) {
858*795d594fSAndroid Build Coastguard Worker     return false;
859*795d594fSAndroid Build Coastguard Worker   }
860*795d594fSAndroid Build Coastguard Worker 
861*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
862*795d594fSAndroid Build Coastguard Worker     if (!IsInOrigBBSet(block)) {
863*795d594fSAndroid Build Coastguard Worker       continue;
864*795d594fSAndroid Build Coastguard Worker     }
865*795d594fSAndroid Build Coastguard Worker     if (block->GetTryCatchInformation() != nullptr) {
866*795d594fSAndroid Build Coastguard Worker       return false;
867*795d594fSAndroid Build Coastguard Worker     }
868*795d594fSAndroid Build Coastguard Worker   }
869*795d594fSAndroid Build Coastguard Worker 
870*795d594fSAndroid Build Coastguard Worker   HInstructionMap live_outs(
871*795d594fSAndroid Build Coastguard Worker       std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
872*795d594fSAndroid Build Coastguard Worker 
873*795d594fSAndroid Build Coastguard Worker   if (!CollectLiveOutsAndCheckClonable(&live_outs)) {
874*795d594fSAndroid Build Coastguard Worker     return false;
875*795d594fSAndroid Build Coastguard Worker   }
876*795d594fSAndroid Build Coastguard Worker 
877*795d594fSAndroid Build Coastguard Worker   ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
878*795d594fSAndroid Build Coastguard Worker   SearchForSubgraphExits(&exits);
879*795d594fSAndroid Build Coastguard Worker 
880*795d594fSAndroid Build Coastguard Worker   // The only loops with live-outs which are currently supported are loops with a single exit.
881*795d594fSAndroid Build Coastguard Worker   if (!live_outs.empty() && exits.size() != 1) {
882*795d594fSAndroid Build Coastguard Worker     return false;
883*795d594fSAndroid Build Coastguard Worker   }
884*795d594fSAndroid Build Coastguard Worker 
885*795d594fSAndroid Build Coastguard Worker   // The values in live_outs should be defined in a block that dominates exit_block.
886*795d594fSAndroid Build Coastguard Worker   for (const auto& live_out : live_outs) {
887*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(exits.size(), 1u);
888*795d594fSAndroid Build Coastguard Worker     HInstruction* value = live_out.first;
889*795d594fSAndroid Build Coastguard Worker     if (!value->GetBlock()->Dominates(exits[0])) {
890*795d594fSAndroid Build Coastguard Worker       // This case can only happen when `value` is used in a catch phi, so the graph must contain a
891*795d594fSAndroid Build Coastguard Worker       // catch block.
892*795d594fSAndroid Build Coastguard Worker       DCHECK(graph_->HasTryCatch());
893*795d594fSAndroid Build Coastguard Worker       return false;
894*795d594fSAndroid Build Coastguard Worker     }
895*795d594fSAndroid Build Coastguard Worker   }
896*795d594fSAndroid Build Coastguard Worker 
897*795d594fSAndroid Build Coastguard Worker   return true;
898*795d594fSAndroid Build Coastguard Worker }
899*795d594fSAndroid Build Coastguard Worker 
900*795d594fSAndroid Build Coastguard Worker // Checks that loop unrolling/peeling/versioning is being conducted.
IsFastCase() const901*795d594fSAndroid Build Coastguard Worker bool SuperblockCloner::IsFastCase() const {
902*795d594fSAndroid Build Coastguard Worker   // Check that all the basic blocks belong to the same loop.
903*795d594fSAndroid Build Coastguard Worker   bool flag = false;
904*795d594fSAndroid Build Coastguard Worker   HLoopInformation* common_loop_info = nullptr;
905*795d594fSAndroid Build Coastguard Worker   for (uint32_t idx : orig_bb_set_.Indexes()) {
906*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = GetBlockById(idx);
907*795d594fSAndroid Build Coastguard Worker     HLoopInformation* block_loop_info = block->GetLoopInformation();
908*795d594fSAndroid Build Coastguard Worker     if (!flag) {
909*795d594fSAndroid Build Coastguard Worker       common_loop_info = block_loop_info;
910*795d594fSAndroid Build Coastguard Worker     } else {
911*795d594fSAndroid Build Coastguard Worker       if (block_loop_info != common_loop_info) {
912*795d594fSAndroid Build Coastguard Worker         return false;
913*795d594fSAndroid Build Coastguard Worker       }
914*795d594fSAndroid Build Coastguard Worker     }
915*795d594fSAndroid Build Coastguard Worker   }
916*795d594fSAndroid Build Coastguard Worker 
917*795d594fSAndroid Build Coastguard Worker   // Check that orig_bb_set_ corresponds to loop peeling/unrolling/versioning.
918*795d594fSAndroid Build Coastguard Worker   if (common_loop_info == nullptr || !orig_bb_set_.SameBitsSet(&common_loop_info->GetBlocks())) {
919*795d594fSAndroid Build Coastguard Worker     return false;
920*795d594fSAndroid Build Coastguard Worker   }
921*795d594fSAndroid Build Coastguard Worker 
922*795d594fSAndroid Build Coastguard Worker   if (IsRemapInfoForVersioning()) {
923*795d594fSAndroid Build Coastguard Worker     return true;
924*795d594fSAndroid Build Coastguard Worker   }
925*795d594fSAndroid Build Coastguard Worker 
926*795d594fSAndroid Build Coastguard Worker   bool peeling_or_unrolling = false;
927*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_orig_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
928*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_copy_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
929*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_incoming(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
930*795d594fSAndroid Build Coastguard Worker 
931*795d594fSAndroid Build Coastguard Worker 
932*795d594fSAndroid Build Coastguard Worker   // Check whether remapping info corresponds to loop unrolling.
933*795d594fSAndroid Build Coastguard Worker   CollectRemappingInfoForPeelUnroll(/* to_unroll*/ true,
934*795d594fSAndroid Build Coastguard Worker                                     common_loop_info,
935*795d594fSAndroid Build Coastguard Worker                                     &remap_orig_internal,
936*795d594fSAndroid Build Coastguard Worker                                     &remap_copy_internal,
937*795d594fSAndroid Build Coastguard Worker                                     &remap_incoming);
938*795d594fSAndroid Build Coastguard Worker 
939*795d594fSAndroid Build Coastguard Worker   peeling_or_unrolling |= EdgeHashSetsEqual(&remap_orig_internal, remap_orig_internal_) &&
940*795d594fSAndroid Build Coastguard Worker                           EdgeHashSetsEqual(&remap_copy_internal, remap_copy_internal_) &&
941*795d594fSAndroid Build Coastguard Worker                           EdgeHashSetsEqual(&remap_incoming, remap_incoming_);
942*795d594fSAndroid Build Coastguard Worker 
943*795d594fSAndroid Build Coastguard Worker   remap_orig_internal.clear();
944*795d594fSAndroid Build Coastguard Worker   remap_copy_internal.clear();
945*795d594fSAndroid Build Coastguard Worker   remap_incoming.clear();
946*795d594fSAndroid Build Coastguard Worker 
947*795d594fSAndroid Build Coastguard Worker   // Check whether remapping info corresponds to loop peeling.
948*795d594fSAndroid Build Coastguard Worker   CollectRemappingInfoForPeelUnroll(/* to_unroll*/ false,
949*795d594fSAndroid Build Coastguard Worker                                     common_loop_info,
950*795d594fSAndroid Build Coastguard Worker                                     &remap_orig_internal,
951*795d594fSAndroid Build Coastguard Worker                                     &remap_copy_internal,
952*795d594fSAndroid Build Coastguard Worker                                     &remap_incoming);
953*795d594fSAndroid Build Coastguard Worker 
954*795d594fSAndroid Build Coastguard Worker   peeling_or_unrolling |= EdgeHashSetsEqual(&remap_orig_internal, remap_orig_internal_) &&
955*795d594fSAndroid Build Coastguard Worker                           EdgeHashSetsEqual(&remap_copy_internal, remap_copy_internal_) &&
956*795d594fSAndroid Build Coastguard Worker                           EdgeHashSetsEqual(&remap_incoming, remap_incoming_);
957*795d594fSAndroid Build Coastguard Worker 
958*795d594fSAndroid Build Coastguard Worker   return peeling_or_unrolling;
959*795d594fSAndroid Build Coastguard Worker }
960*795d594fSAndroid Build Coastguard Worker 
Run()961*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::Run() {
962*795d594fSAndroid Build Coastguard Worker   DCHECK(bb_map_ != nullptr);
963*795d594fSAndroid Build Coastguard Worker   DCHECK(hir_map_ != nullptr);
964*795d594fSAndroid Build Coastguard Worker   DCHECK(remap_orig_internal_ != nullptr &&
965*795d594fSAndroid Build Coastguard Worker          remap_copy_internal_ != nullptr &&
966*795d594fSAndroid Build Coastguard Worker          remap_incoming_ != nullptr);
967*795d594fSAndroid Build Coastguard Worker   DCHECK(IsSubgraphClonable());
968*795d594fSAndroid Build Coastguard Worker   DCHECK(IsFastCase());
969*795d594fSAndroid Build Coastguard Worker 
970*795d594fSAndroid Build Coastguard Worker   if (kSuperblockClonerLogging) {
971*795d594fSAndroid Build Coastguard Worker     DumpInputSets();
972*795d594fSAndroid Build Coastguard Worker   }
973*795d594fSAndroid Build Coastguard Worker 
974*795d594fSAndroid Build Coastguard Worker   bool result = CollectLiveOutsAndCheckClonable(&live_outs_);
975*795d594fSAndroid Build Coastguard Worker   DCHECK(result);
976*795d594fSAndroid Build Coastguard Worker   // Find an area in the graph for which control flow information should be adjusted.
977*795d594fSAndroid Build Coastguard Worker   FindAndSetLocalAreaForAdjustments();
978*795d594fSAndroid Build Coastguard Worker   ConstructSubgraphClosedSSA();
979*795d594fSAndroid Build Coastguard Worker   // Clone the basic blocks from the orig_bb_set_; data flow is invalid after the call and is to be
980*795d594fSAndroid Build Coastguard Worker   // adjusted.
981*795d594fSAndroid Build Coastguard Worker   CloneBasicBlocks();
982*795d594fSAndroid Build Coastguard Worker   // Connect the blocks together/remap successors and fix phis which are directly affected my the
983*795d594fSAndroid Build Coastguard Worker   // remapping.
984*795d594fSAndroid Build Coastguard Worker   RemapEdgesSuccessors();
985*795d594fSAndroid Build Coastguard Worker 
986*795d594fSAndroid Build Coastguard Worker   // Check that the subgraph is connected.
987*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
988*795d594fSAndroid Build Coastguard Worker     HBasicBlockSet work_set(arena_, orig_bb_set_.GetSizeOf(), true, kArenaAllocSuperblockCloner);
989*795d594fSAndroid Build Coastguard Worker 
990*795d594fSAndroid Build Coastguard Worker     // Add original and copy blocks of the subgraph to the work set.
991*795d594fSAndroid Build Coastguard Worker     for (auto iter : *bb_map_) {
992*795d594fSAndroid Build Coastguard Worker       work_set.SetBit(iter.first->GetBlockId());   // Original block.
993*795d594fSAndroid Build Coastguard Worker       work_set.SetBit(iter.second->GetBlockId());  // Copy block.
994*795d594fSAndroid Build Coastguard Worker     }
995*795d594fSAndroid Build Coastguard Worker     CHECK(IsSubgraphConnected(&work_set, graph_));
996*795d594fSAndroid Build Coastguard Worker   }
997*795d594fSAndroid Build Coastguard Worker 
998*795d594fSAndroid Build Coastguard Worker   // Recalculate dominance and backedge information which is required by the next stage.
999*795d594fSAndroid Build Coastguard Worker   AdjustControlFlowInfo();
1000*795d594fSAndroid Build Coastguard Worker   // Fix data flow of the graph.
1001*795d594fSAndroid Build Coastguard Worker   ResolveDataFlow();
1002*795d594fSAndroid Build Coastguard Worker   FixSubgraphClosedSSAAfterCloning();
1003*795d594fSAndroid Build Coastguard Worker }
1004*795d594fSAndroid Build Coastguard Worker 
CleanUp()1005*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CleanUp() {
1006*795d594fSAndroid Build Coastguard Worker   CleanUpControlFlow();
1007*795d594fSAndroid Build Coastguard Worker 
1008*795d594fSAndroid Build Coastguard Worker   // Remove phis which have all inputs being same.
1009*795d594fSAndroid Build Coastguard Worker   // When a block has a single predecessor it must not have any phis. However after the
1010*795d594fSAndroid Build Coastguard Worker   // transformation it could happen that there is such block with a phi with a single input.
1011*795d594fSAndroid Build Coastguard Worker   // As this is needed to be processed we also simplify phis with multiple same inputs here.
1012*795d594fSAndroid Build Coastguard Worker   for (auto entry : *bb_map_) {
1013*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* block : {entry.first, entry.second}) {
1014*795d594fSAndroid Build Coastguard Worker       for (HInstructionIterator inst_it(block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
1015*795d594fSAndroid Build Coastguard Worker         HPhi* phi = inst_it.Current()->AsPhi();
1016*795d594fSAndroid Build Coastguard Worker         if (ArePhiInputsTheSame(phi)) {
1017*795d594fSAndroid Build Coastguard Worker           phi->ReplaceWith(phi->InputAt(0));
1018*795d594fSAndroid Build Coastguard Worker           block->RemovePhi(phi);
1019*795d594fSAndroid Build Coastguard Worker         }
1020*795d594fSAndroid Build Coastguard Worker       }
1021*795d594fSAndroid Build Coastguard Worker     }
1022*795d594fSAndroid Build Coastguard Worker   }
1023*795d594fSAndroid Build Coastguard Worker 
1024*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
1025*795d594fSAndroid Build Coastguard Worker     VerifyGraph();
1026*795d594fSAndroid Build Coastguard Worker   }
1027*795d594fSAndroid Build Coastguard Worker }
1028*795d594fSAndroid Build Coastguard Worker 
CloneBasicBlock(const HBasicBlock * orig_block)1029*795d594fSAndroid Build Coastguard Worker HBasicBlock* SuperblockCloner::CloneBasicBlock(const HBasicBlock* orig_block) {
1030*795d594fSAndroid Build Coastguard Worker   HGraph* graph = orig_block->GetGraph();
1031*795d594fSAndroid Build Coastguard Worker   HBasicBlock* copy_block = new (arena_) HBasicBlock(graph, orig_block->GetDexPc());
1032*795d594fSAndroid Build Coastguard Worker   graph->AddBlock(copy_block);
1033*795d594fSAndroid Build Coastguard Worker 
1034*795d594fSAndroid Build Coastguard Worker   // Clone all the phis and add them to the map.
1035*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
1036*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_instr = it.Current();
1037*795d594fSAndroid Build Coastguard Worker     HInstruction* copy_instr = orig_instr->Clone(arena_);
1038*795d594fSAndroid Build Coastguard Worker     copy_block->AddPhi(copy_instr->AsPhi());
1039*795d594fSAndroid Build Coastguard Worker     copy_instr->AsPhi()->RemoveAllInputs();
1040*795d594fSAndroid Build Coastguard Worker     DCHECK(!orig_instr->HasEnvironment());
1041*795d594fSAndroid Build Coastguard Worker     hir_map_->Put(orig_instr, copy_instr);
1042*795d594fSAndroid Build Coastguard Worker   }
1043*795d594fSAndroid Build Coastguard Worker 
1044*795d594fSAndroid Build Coastguard Worker   // Clone all the instructions and add them to the map.
1045*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(orig_block->GetInstructions()); !it.Done(); it.Advance()) {
1046*795d594fSAndroid Build Coastguard Worker     HInstruction* orig_instr = it.Current();
1047*795d594fSAndroid Build Coastguard Worker     HInstruction* copy_instr = orig_instr->Clone(arena_);
1048*795d594fSAndroid Build Coastguard Worker     ReplaceInputsWithCopies(copy_instr);
1049*795d594fSAndroid Build Coastguard Worker     copy_block->AddInstruction(copy_instr);
1050*795d594fSAndroid Build Coastguard Worker     if (orig_instr->HasEnvironment()) {
1051*795d594fSAndroid Build Coastguard Worker       DeepCloneEnvironmentWithRemapping(copy_instr, orig_instr->GetEnvironment());
1052*795d594fSAndroid Build Coastguard Worker     }
1053*795d594fSAndroid Build Coastguard Worker     hir_map_->Put(orig_instr, copy_instr);
1054*795d594fSAndroid Build Coastguard Worker   }
1055*795d594fSAndroid Build Coastguard Worker 
1056*795d594fSAndroid Build Coastguard Worker   return copy_block;
1057*795d594fSAndroid Build Coastguard Worker }
1058*795d594fSAndroid Build Coastguard Worker 
CloneBasicBlocks()1059*795d594fSAndroid Build Coastguard Worker void SuperblockCloner::CloneBasicBlocks() {
1060*795d594fSAndroid Build Coastguard Worker   // By this time ReversePostOrder must be valid: in 'CloneBasicBlock' inputs of the copied
1061*795d594fSAndroid Build Coastguard Worker   // instructions might be replaced by copies of the original inputs (depending where those inputs
1062*795d594fSAndroid Build Coastguard Worker   // are defined). So the definitions of the original inputs must be visited before their original
1063*795d594fSAndroid Build Coastguard Worker   // uses. The property of the reducible graphs "if 'A' dom 'B' then rpo_num('A') >= rpo_num('B')"
1064*795d594fSAndroid Build Coastguard Worker   // guarantees that.
1065*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* orig_block : graph_->GetReversePostOrder()) {
1066*795d594fSAndroid Build Coastguard Worker     if (!IsInOrigBBSet(orig_block)) {
1067*795d594fSAndroid Build Coastguard Worker       continue;
1068*795d594fSAndroid Build Coastguard Worker     }
1069*795d594fSAndroid Build Coastguard Worker     HBasicBlock* copy_block = CloneBasicBlock(orig_block);
1070*795d594fSAndroid Build Coastguard Worker     bb_map_->Put(orig_block, copy_block);
1071*795d594fSAndroid Build Coastguard Worker     if (kSuperblockClonerLogging) {
1072*795d594fSAndroid Build Coastguard Worker       LOG(INFO) << "new block :" << copy_block->GetBlockId() << ": " << orig_block->GetBlockId();
1073*795d594fSAndroid Build Coastguard Worker     }
1074*795d594fSAndroid Build Coastguard Worker   }
1075*795d594fSAndroid Build Coastguard Worker }
1076*795d594fSAndroid Build Coastguard Worker 
1077*795d594fSAndroid Build Coastguard Worker //
1078*795d594fSAndroid Build Coastguard Worker // Stand-alone methods.
1079*795d594fSAndroid Build Coastguard Worker //
1080*795d594fSAndroid Build Coastguard Worker 
CollectRemappingInfoForPeelUnroll(bool to_unroll,HLoopInformation * loop_info,HEdgeSet * remap_orig_internal,HEdgeSet * remap_copy_internal,HEdgeSet * remap_incoming)1081*795d594fSAndroid Build Coastguard Worker void CollectRemappingInfoForPeelUnroll(bool to_unroll,
1082*795d594fSAndroid Build Coastguard Worker                                        HLoopInformation* loop_info,
1083*795d594fSAndroid Build Coastguard Worker                                        HEdgeSet* remap_orig_internal,
1084*795d594fSAndroid Build Coastguard Worker                                        HEdgeSet* remap_copy_internal,
1085*795d594fSAndroid Build Coastguard Worker                                        HEdgeSet* remap_incoming) {
1086*795d594fSAndroid Build Coastguard Worker   DCHECK(loop_info != nullptr);
1087*795d594fSAndroid Build Coastguard Worker   HBasicBlock* loop_header = loop_info->GetHeader();
1088*795d594fSAndroid Build Coastguard Worker   // Set up remap_orig_internal edges set - set is empty.
1089*795d594fSAndroid Build Coastguard Worker   // Set up remap_copy_internal edges set.
1090*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* back_edge_block : loop_info->GetBackEdges()) {
1091*795d594fSAndroid Build Coastguard Worker     HEdge e = HEdge(back_edge_block, loop_header);
1092*795d594fSAndroid Build Coastguard Worker     if (to_unroll) {
1093*795d594fSAndroid Build Coastguard Worker       remap_orig_internal->insert(e);
1094*795d594fSAndroid Build Coastguard Worker       remap_copy_internal->insert(e);
1095*795d594fSAndroid Build Coastguard Worker     } else {
1096*795d594fSAndroid Build Coastguard Worker       remap_copy_internal->insert(e);
1097*795d594fSAndroid Build Coastguard Worker     }
1098*795d594fSAndroid Build Coastguard Worker   }
1099*795d594fSAndroid Build Coastguard Worker 
1100*795d594fSAndroid Build Coastguard Worker   // Set up remap_incoming edges set.
1101*795d594fSAndroid Build Coastguard Worker   if (!to_unroll) {
1102*795d594fSAndroid Build Coastguard Worker     remap_incoming->insert(HEdge(loop_info->GetPreHeader(), loop_header));
1103*795d594fSAndroid Build Coastguard Worker   }
1104*795d594fSAndroid Build Coastguard Worker }
1105*795d594fSAndroid Build Coastguard Worker 
IsSubgraphConnected(SuperblockCloner::HBasicBlockSet * work_set,HGraph * graph)1106*795d594fSAndroid Build Coastguard Worker bool IsSubgraphConnected(SuperblockCloner::HBasicBlockSet* work_set, HGraph* graph) {
1107*795d594fSAndroid Build Coastguard Worker   ArenaVector<HBasicBlock*> entry_blocks(
1108*795d594fSAndroid Build Coastguard Worker       graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1109*795d594fSAndroid Build Coastguard Worker 
1110*795d594fSAndroid Build Coastguard Worker   // Find subgraph entry blocks.
1111*795d594fSAndroid Build Coastguard Worker   for (uint32_t orig_block_id : work_set->Indexes()) {
1112*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = graph->GetBlocks()[orig_block_id];
1113*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* pred : block->GetPredecessors()) {
1114*795d594fSAndroid Build Coastguard Worker       if (!work_set->IsBitSet(pred->GetBlockId())) {
1115*795d594fSAndroid Build Coastguard Worker         entry_blocks.push_back(block);
1116*795d594fSAndroid Build Coastguard Worker         break;
1117*795d594fSAndroid Build Coastguard Worker       }
1118*795d594fSAndroid Build Coastguard Worker     }
1119*795d594fSAndroid Build Coastguard Worker   }
1120*795d594fSAndroid Build Coastguard Worker 
1121*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* entry_block : entry_blocks) {
1122*795d594fSAndroid Build Coastguard Worker     if (work_set->IsBitSet(entry_block->GetBlockId())) {
1123*795d594fSAndroid Build Coastguard Worker       TraverseSubgraphForConnectivity(entry_block, work_set);
1124*795d594fSAndroid Build Coastguard Worker     }
1125*795d594fSAndroid Build Coastguard Worker   }
1126*795d594fSAndroid Build Coastguard Worker 
1127*795d594fSAndroid Build Coastguard Worker   // Return whether there are unvisited - unreachable - blocks.
1128*795d594fSAndroid Build Coastguard Worker   return work_set->NumSetBits() == 0;
1129*795d594fSAndroid Build Coastguard Worker }
1130*795d594fSAndroid Build Coastguard Worker 
FindCommonLoop(HLoopInformation * loop1,HLoopInformation * loop2)1131*795d594fSAndroid Build Coastguard Worker HLoopInformation* FindCommonLoop(HLoopInformation* loop1, HLoopInformation* loop2) {
1132*795d594fSAndroid Build Coastguard Worker   if (loop1 == nullptr || loop2 == nullptr) {
1133*795d594fSAndroid Build Coastguard Worker     return nullptr;
1134*795d594fSAndroid Build Coastguard Worker   }
1135*795d594fSAndroid Build Coastguard Worker 
1136*795d594fSAndroid Build Coastguard Worker   if (loop1->IsIn(*loop2)) {
1137*795d594fSAndroid Build Coastguard Worker     return loop2;
1138*795d594fSAndroid Build Coastguard Worker   }
1139*795d594fSAndroid Build Coastguard Worker 
1140*795d594fSAndroid Build Coastguard Worker   HLoopInformation* current = loop1;
1141*795d594fSAndroid Build Coastguard Worker   while (current != nullptr && !loop2->IsIn(*current)) {
1142*795d594fSAndroid Build Coastguard Worker     current = current->GetPreHeader()->GetLoopInformation();
1143*795d594fSAndroid Build Coastguard Worker   }
1144*795d594fSAndroid Build Coastguard Worker 
1145*795d594fSAndroid Build Coastguard Worker   return current;
1146*795d594fSAndroid Build Coastguard Worker }
1147*795d594fSAndroid Build Coastguard Worker 
IsLoopClonable(HLoopInformation * loop_info)1148*795d594fSAndroid Build Coastguard Worker bool LoopClonerHelper::IsLoopClonable(HLoopInformation* loop_info) {
1149*795d594fSAndroid Build Coastguard Worker   LoopClonerHelper helper(
1150*795d594fSAndroid Build Coastguard Worker       loop_info, /* bb_map= */ nullptr, /* hir_map= */ nullptr, /* induction_range= */ nullptr);
1151*795d594fSAndroid Build Coastguard Worker   return helper.IsLoopClonable();
1152*795d594fSAndroid Build Coastguard Worker }
1153*795d594fSAndroid Build Coastguard Worker 
DoLoopTransformationImpl(TransformationKind transformation)1154*795d594fSAndroid Build Coastguard Worker HBasicBlock* LoopClonerHelper::DoLoopTransformationImpl(TransformationKind transformation) {
1155*795d594fSAndroid Build Coastguard Worker   // For now do transformations only for natural loops.
1156*795d594fSAndroid Build Coastguard Worker   DCHECK(!loop_info_->IsIrreducible());
1157*795d594fSAndroid Build Coastguard Worker 
1158*795d594fSAndroid Build Coastguard Worker   HBasicBlock* loop_header = loop_info_->GetHeader();
1159*795d594fSAndroid Build Coastguard Worker   // Check that loop info is up-to-date.
1160*795d594fSAndroid Build Coastguard Worker   DCHECK(loop_info_ == loop_header->GetLoopInformation());
1161*795d594fSAndroid Build Coastguard Worker   HGraph* graph = loop_header->GetGraph();
1162*795d594fSAndroid Build Coastguard Worker 
1163*795d594fSAndroid Build Coastguard Worker   if (kSuperblockClonerLogging) {
1164*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "Method: " << graph->PrettyMethod();
1165*795d594fSAndroid Build Coastguard Worker     std::ostringstream oss;
1166*795d594fSAndroid Build Coastguard Worker     oss << "Scalar loop ";
1167*795d594fSAndroid Build Coastguard Worker     switch (transformation) {
1168*795d594fSAndroid Build Coastguard Worker       case TransformationKind::kPeeling:
1169*795d594fSAndroid Build Coastguard Worker         oss << "peeling";
1170*795d594fSAndroid Build Coastguard Worker         break;
1171*795d594fSAndroid Build Coastguard Worker       case TransformationKind::kUnrolling:
1172*795d594fSAndroid Build Coastguard Worker         oss<< "unrolling";
1173*795d594fSAndroid Build Coastguard Worker         break;
1174*795d594fSAndroid Build Coastguard Worker       case TransformationKind::kVersioning:
1175*795d594fSAndroid Build Coastguard Worker         oss << "versioning";
1176*795d594fSAndroid Build Coastguard Worker         break;
1177*795d594fSAndroid Build Coastguard Worker     }
1178*795d594fSAndroid Build Coastguard Worker     oss << " was applied to the loop <" << loop_header->GetBlockId() << ">.";
1179*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << oss.str();
1180*795d594fSAndroid Build Coastguard Worker   }
1181*795d594fSAndroid Build Coastguard Worker 
1182*795d594fSAndroid Build Coastguard Worker   ArenaAllocator allocator(graph->GetAllocator()->GetArenaPool());
1183*795d594fSAndroid Build Coastguard Worker 
1184*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_orig_internal(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1185*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_copy_internal(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1186*795d594fSAndroid Build Coastguard Worker   HEdgeSet remap_incoming(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1187*795d594fSAndroid Build Coastguard Worker 
1188*795d594fSAndroid Build Coastguard Worker   // No remapping needed for loop versioning.
1189*795d594fSAndroid Build Coastguard Worker   if (transformation != TransformationKind::kVersioning) {
1190*795d594fSAndroid Build Coastguard Worker     CollectRemappingInfoForPeelUnroll(transformation == TransformationKind::kUnrolling,
1191*795d594fSAndroid Build Coastguard Worker                                       loop_info_,
1192*795d594fSAndroid Build Coastguard Worker                                       &remap_orig_internal,
1193*795d594fSAndroid Build Coastguard Worker                                       &remap_copy_internal,
1194*795d594fSAndroid Build Coastguard Worker                                       &remap_incoming);
1195*795d594fSAndroid Build Coastguard Worker   }
1196*795d594fSAndroid Build Coastguard Worker 
1197*795d594fSAndroid Build Coastguard Worker   cloner_.SetSuccessorRemappingInfo(&remap_orig_internal, &remap_copy_internal, &remap_incoming);
1198*795d594fSAndroid Build Coastguard Worker   cloner_.Run();
1199*795d594fSAndroid Build Coastguard Worker   cloner_.CleanUp();
1200*795d594fSAndroid Build Coastguard Worker 
1201*795d594fSAndroid Build Coastguard Worker   // Check that loop info is preserved.
1202*795d594fSAndroid Build Coastguard Worker   DCHECK(loop_info_ == loop_header->GetLoopInformation());
1203*795d594fSAndroid Build Coastguard Worker 
1204*795d594fSAndroid Build Coastguard Worker   return loop_header;
1205*795d594fSAndroid Build Coastguard Worker }
1206*795d594fSAndroid Build Coastguard Worker 
LoopClonerSimpleHelper(HLoopInformation * info,InductionVarRange * induction_range)1207*795d594fSAndroid Build Coastguard Worker LoopClonerSimpleHelper::LoopClonerSimpleHelper(HLoopInformation* info,
1208*795d594fSAndroid Build Coastguard Worker                                                InductionVarRange* induction_range)
1209*795d594fSAndroid Build Coastguard Worker   : bb_map_(std::less<HBasicBlock*>(),
1210*795d594fSAndroid Build Coastguard Worker             info->GetHeader()->GetGraph()->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)),
1211*795d594fSAndroid Build Coastguard Worker     hir_map_(std::less<HInstruction*>(),
1212*795d594fSAndroid Build Coastguard Worker              info->GetHeader()->GetGraph()->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)),
1213*795d594fSAndroid Build Coastguard Worker     helper_(info, &bb_map_, &hir_map_, induction_range) {}
1214*795d594fSAndroid Build Coastguard Worker 
1215*795d594fSAndroid Build Coastguard Worker }  // namespace art
1216*795d594fSAndroid Build Coastguard Worker 
1217*795d594fSAndroid Build Coastguard Worker namespace std {
1218*795d594fSAndroid Build Coastguard Worker 
operator <<(ostream & os,const art::HEdge & e)1219*795d594fSAndroid Build Coastguard Worker ostream& operator<<(ostream& os, const art::HEdge& e) {
1220*795d594fSAndroid Build Coastguard Worker   e.Dump(os);
1221*795d594fSAndroid Build Coastguard Worker   return os;
1222*795d594fSAndroid Build Coastguard Worker }
1223*795d594fSAndroid Build Coastguard Worker 
1224*795d594fSAndroid Build Coastguard Worker }  // namespace std
1225