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