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 <iostream>
24 
25 namespace art {
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(!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 
230 //
231 // Local versions of CF calculation/adjustment routines.
232 //
233 
234 // TODO: merge with the original version in nodes.cc. The concern is that we don't want to affect
235 // the performance of the base version by checking the local set.
236 // TODO: this version works when updating the back edges info for natural loop-based local_set.
237 // Check which exactly types of subgraphs can be analysed or rename it to
238 // FindBackEdgesInTheNaturalLoop.
FindBackEdgesLocal(HBasicBlock * entry_block,ArenaBitVector * local_set)239 void SuperblockCloner::FindBackEdgesLocal(HBasicBlock* entry_block, ArenaBitVector* local_set) {
240   ArenaBitVector visited(arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
241   // "visited" must be empty on entry, it's an output argument for all visited (i.e. live) blocks.
242   DCHECK_EQ(visited.GetHighestBitSet(), -1);
243 
244   // Nodes that we're currently visiting, indexed by block id.
245   ArenaBitVector visiting(arena_, graph_->GetBlocks().size(), false, kArenaAllocGraphBuilder);
246   // Number of successors visited from a given node, indexed by block id.
247   ArenaVector<size_t> successors_visited(graph_->GetBlocks().size(),
248                                          0u,
249                                          arena_->Adapter(kArenaAllocGraphBuilder));
250   // Stack of nodes that we're currently visiting (same as marked in "visiting" above).
251   ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocGraphBuilder));
252   constexpr size_t kDefaultWorklistSize = 8;
253   worklist.reserve(kDefaultWorklistSize);
254 
255   visited.SetBit(entry_block->GetBlockId());
256   visiting.SetBit(entry_block->GetBlockId());
257   worklist.push_back(entry_block);
258 
259   while (!worklist.empty()) {
260     HBasicBlock* current = worklist.back();
261     uint32_t current_id = current->GetBlockId();
262     if (successors_visited[current_id] == current->GetSuccessors().size()) {
263       visiting.ClearBit(current_id);
264       worklist.pop_back();
265     } else {
266       HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
267       uint32_t successor_id = successor->GetBlockId();
268       if (!local_set->IsBitSet(successor_id)) {
269         continue;
270       }
271 
272       if (visiting.IsBitSet(successor_id)) {
273         DCHECK(ContainsElement(worklist, successor));
274         successor->AddBackEdgeWhileUpdating(current);
275       } else if (!visited.IsBitSet(successor_id)) {
276         visited.SetBit(successor_id);
277         visiting.SetBit(successor_id);
278         worklist.push_back(successor);
279       }
280     }
281   }
282 }
283 
RecalculateBackEdgesInfo(ArenaBitVector * outer_loop_bb_set)284 void SuperblockCloner::RecalculateBackEdgesInfo(ArenaBitVector* outer_loop_bb_set) {
285   HBasicBlock* block_entry = nullptr;
286 
287   if (outer_loop_ == nullptr) {
288     for (auto block : graph_->GetBlocks()) {
289       if (block != nullptr) {
290         outer_loop_bb_set->SetBit(block->GetBlockId());
291         HLoopInformation* info = block->GetLoopInformation();
292         if (info != nullptr) {
293           info->ResetBasicBlockData();
294         }
295       }
296     }
297     block_entry = graph_->GetEntryBlock();
298   } else {
299     outer_loop_bb_set->Copy(&outer_loop_bb_set_);
300     block_entry = outer_loop_->GetHeader();
301 
302     // Add newly created copy blocks.
303     for (auto entry : *bb_map_) {
304       outer_loop_bb_set->SetBit(entry.second->GetBlockId());
305     }
306 
307     // Clear loop_info for the whole outer loop.
308     for (uint32_t idx : outer_loop_bb_set->Indexes()) {
309       HBasicBlock* block = GetBlockById(idx);
310       HLoopInformation* info = block->GetLoopInformation();
311       if (info != nullptr) {
312         info->ResetBasicBlockData();
313       }
314     }
315   }
316 
317   FindBackEdgesLocal(block_entry, outer_loop_bb_set);
318 
319   for (uint32_t idx : outer_loop_bb_set->Indexes()) {
320     HBasicBlock* block = GetBlockById(idx);
321     HLoopInformation* info = block->GetLoopInformation();
322     // Reset LoopInformation for regular blocks and old headers which are no longer loop headers.
323     if (info != nullptr &&
324         (info->GetHeader() != block || info->NumberOfBackEdges() == 0)) {
325       block->SetLoopInformation(nullptr);
326     }
327   }
328 }
329 
330 // This is a modified version of HGraph::AnalyzeLoops.
AnalyzeLoopsLocally(ArenaBitVector * outer_loop_bb_set)331 GraphAnalysisResult SuperblockCloner::AnalyzeLoopsLocally(ArenaBitVector* outer_loop_bb_set) {
332   // We iterate post order to ensure we visit inner loops before outer loops.
333   // `PopulateRecursive` needs this guarantee to know whether a natural loop
334   // contains an irreducible loop.
335   for (HBasicBlock* block : graph_->GetPostOrder()) {
336     if (!outer_loop_bb_set->IsBitSet(block->GetBlockId())) {
337       continue;
338     }
339     if (block->IsLoopHeader()) {
340       if (block->IsCatchBlock()) {
341         // TODO: Dealing with exceptional back edges could be tricky because
342         //       they only approximate the real control flow. Bail out for now.
343         return kAnalysisFailThrowCatchLoop;
344       }
345       block->GetLoopInformation()->Populate();
346     }
347   }
348 
349   for (HBasicBlock* block : graph_->GetPostOrder()) {
350     if (!outer_loop_bb_set->IsBitSet(block->GetBlockId())) {
351       continue;
352     }
353     if (block->IsLoopHeader()) {
354       HLoopInformation* cur_loop = block->GetLoopInformation();
355       HLoopInformation* outer_loop = cur_loop->GetPreHeader()->GetLoopInformation();
356       if (outer_loop != nullptr) {
357         outer_loop->PopulateInnerLoopUpwards(cur_loop);
358       }
359     }
360   }
361 
362   return kAnalysisSuccess;
363 }
364 
CleanUpControlFlow()365 void SuperblockCloner::CleanUpControlFlow() {
366   // TODO: full control flow clean up for now, optimize it.
367   graph_->ClearDominanceInformation();
368 
369   ArenaBitVector outer_loop_bb_set(
370       arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
371   RecalculateBackEdgesInfo(&outer_loop_bb_set);
372 
373   // TODO: do it locally.
374   graph_->SimplifyCFG();
375   graph_->ComputeDominanceInformation();
376 
377   // AnalyzeLoopsLocally requires a correct post-ordering information which was calculated just
378   // before in ComputeDominanceInformation.
379   GraphAnalysisResult result = AnalyzeLoopsLocally(&outer_loop_bb_set);
380   DCHECK_EQ(result, kAnalysisSuccess);
381 
382   // TODO: do it locally
383   OrderLoopsHeadersPredecessors(graph_);
384 
385   graph_->ComputeTryBlockInformation();
386 }
387 
388 //
389 // Helpers for ResolveDataFlow
390 //
391 
ResolvePhi(HPhi * phi)392 void SuperblockCloner::ResolvePhi(HPhi* phi) {
393   HBasicBlock* phi_block = phi->GetBlock();
394   for (size_t i = 0, e = phi->InputCount(); i < e; i++) {
395     HInstruction* input = phi->InputAt(i);
396     HBasicBlock* input_block = input->GetBlock();
397 
398     // Originally defined outside the region.
399     if (!IsInOrigBBSet(input_block)) {
400       continue;
401     }
402     HBasicBlock* corresponding_block = phi_block->GetPredecessors()[i];
403     if (!IsInOrigBBSet(corresponding_block)) {
404       phi->ReplaceInput(GetInstrCopy(input), i);
405     }
406   }
407 }
408 
409 //
410 // Main algorithm methods.
411 //
412 
SearchForSubgraphExits(ArenaVector<HBasicBlock * > * exits) const413 void SuperblockCloner::SearchForSubgraphExits(ArenaVector<HBasicBlock*>* exits) const {
414   DCHECK(exits->empty());
415   for (uint32_t block_id : orig_bb_set_.Indexes()) {
416     HBasicBlock* block = GetBlockById(block_id);
417     for (HBasicBlock* succ : block->GetSuccessors()) {
418       if (!IsInOrigBBSet(succ)) {
419         exits->push_back(succ);
420       }
421     }
422   }
423 }
424 
FindAndSetLocalAreaForAdjustments()425 void SuperblockCloner::FindAndSetLocalAreaForAdjustments() {
426   DCHECK(outer_loop_ == nullptr);
427   ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
428   SearchForSubgraphExits(&exits);
429 
430   // For a reducible graph we need to update back-edges and dominance information only for
431   // the outermost loop which is affected by the transformation - it can be found by picking
432   // the common most outer loop of loops to which the subgraph exits blocks belong.
433   // Note: it can a loop or the whole graph (outer_loop_ will be nullptr in this case).
434   for (HBasicBlock* exit : exits) {
435     HLoopInformation* loop_exit_loop_info = exit->GetLoopInformation();
436     if (loop_exit_loop_info == nullptr) {
437       outer_loop_ = nullptr;
438       break;
439     }
440     if (outer_loop_ == nullptr) {
441       // We should not use the initial outer_loop_ value 'nullptr' when finding the most outer
442       // common loop.
443       outer_loop_ = loop_exit_loop_info;
444     }
445     outer_loop_ = FindCommonLoop(outer_loop_, loop_exit_loop_info);
446   }
447 
448   if (outer_loop_ != nullptr) {
449     // Save the loop population info as it will be changed later.
450     outer_loop_bb_set_.Copy(&outer_loop_->GetBlocks());
451   }
452 }
453 
RemapEdgesSuccessors()454 void SuperblockCloner::RemapEdgesSuccessors() {
455   // Redirect incoming edges.
456   for (HEdge e : *remap_incoming_) {
457     HBasicBlock* orig_block = GetBlockById(e.GetFrom());
458     HBasicBlock* orig_succ = GetBlockById(e.GetTo());
459     RemapOrigInternalOrIncomingEdge(orig_block, orig_succ);
460   }
461 
462   // Redirect internal edges.
463   for (uint32_t orig_block_id : orig_bb_set_.Indexes()) {
464     HBasicBlock* orig_block = GetBlockById(orig_block_id);
465 
466     for (HBasicBlock* orig_succ : orig_block->GetSuccessors()) {
467       uint32_t orig_succ_id = orig_succ->GetBlockId();
468 
469       // Check for outgoing edge.
470       if (!IsInOrigBBSet(orig_succ)) {
471         HBasicBlock* copy_block = GetBlockCopy(orig_block);
472         copy_block->AddSuccessor(orig_succ);
473         continue;
474       }
475 
476       auto orig_redir = remap_orig_internal_->find(HEdge(orig_block_id, orig_succ_id));
477       auto copy_redir = remap_copy_internal_->find(HEdge(orig_block_id, orig_succ_id));
478 
479       // Due to construction all successors of copied block were set to original.
480       if (copy_redir != remap_copy_internal_->end()) {
481         RemapCopyInternalEdge(orig_block, orig_succ);
482       } else {
483         AddCopyInternalEdge(orig_block, orig_succ);
484       }
485 
486       if (orig_redir != remap_orig_internal_->end()) {
487         RemapOrigInternalOrIncomingEdge(orig_block, orig_succ);
488       }
489     }
490   }
491 }
492 
AdjustControlFlowInfo()493 void SuperblockCloner::AdjustControlFlowInfo() {
494   ArenaBitVector outer_loop_bb_set(
495       arena_, graph_->GetBlocks().size(), false, kArenaAllocSuperblockCloner);
496   RecalculateBackEdgesInfo(&outer_loop_bb_set);
497 
498   graph_->ClearDominanceInformation();
499   // TODO: Do it locally.
500   graph_->ComputeDominanceInformation();
501 }
502 
503 // TODO: Current FastCase restriction guarantees that instructions' inputs are already mapped to
504 // the valid values; only phis' inputs must be adjusted.
ResolveDataFlow()505 void SuperblockCloner::ResolveDataFlow() {
506   for (auto entry : *bb_map_) {
507     HBasicBlock* orig_block = entry.first;
508 
509     for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
510       HPhi* orig_phi = it.Current()->AsPhi();
511       HPhi* copy_phi = GetInstrCopy(orig_phi)->AsPhi();
512       ResolvePhi(orig_phi);
513       ResolvePhi(copy_phi);
514     }
515     if (kIsDebugBuild) {
516       // Inputs of instruction copies must be already mapped to correspondent inputs copies.
517       for (HInstructionIterator it(orig_block->GetInstructions()); !it.Done(); it.Advance()) {
518         CheckInstructionInputsRemapping(it.Current());
519       }
520     }
521   }
522 }
523 
524 //
525 // Helpers for live-outs processing and Subgraph-closed SSA.
526 //
527 
CollectLiveOutsAndCheckClonable(HInstructionMap * live_outs) const528 bool SuperblockCloner::CollectLiveOutsAndCheckClonable(HInstructionMap* live_outs) const {
529   DCHECK(live_outs->empty());
530   for (uint32_t idx : orig_bb_set_.Indexes()) {
531     HBasicBlock* block = GetBlockById(idx);
532 
533     for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
534       HInstruction* instr = it.Current();
535       DCHECK(instr->IsClonable());
536 
537       if (IsUsedOutsideRegion(instr, orig_bb_set_)) {
538         live_outs->FindOrAdd(instr, instr);
539       }
540     }
541 
542     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
543       HInstruction* instr = it.Current();
544       if (!instr->IsClonable()) {
545         return false;
546       }
547 
548       if (IsUsedOutsideRegion(instr, orig_bb_set_)) {
549         // TODO: Investigate why HNewInstance, HCheckCast has a requirement for the input.
550         if (instr->IsLoadClass()) {
551           return false;
552         }
553         live_outs->FindOrAdd(instr, instr);
554       }
555     }
556   }
557   return true;
558 }
559 
UpdateInductionRangeInfoOf(HInstruction * user,HInstruction * old_instruction,HInstruction * replacement)560 void SuperblockCloner::UpdateInductionRangeInfoOf(
561       HInstruction* user, HInstruction* old_instruction, HInstruction* replacement) {
562   if (induction_range_ != nullptr) {
563     induction_range_->Replace(user, old_instruction, replacement);
564   }
565 }
566 
ConstructSubgraphClosedSSA()567 void SuperblockCloner::ConstructSubgraphClosedSSA() {
568   if (live_outs_.empty()) {
569     return;
570   }
571 
572   ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
573   SearchForSubgraphExits(&exits);
574   if (exits.empty()) {
575     DCHECK(live_outs_.empty());
576     return;
577   }
578 
579   DCHECK_EQ(exits.size(), 1u);
580   HBasicBlock* exit_block = exits[0];
581   // There should be no critical edges.
582   DCHECK_EQ(exit_block->GetPredecessors().size(), 1u);
583   DCHECK(exit_block->GetPhis().IsEmpty());
584 
585   // For each live-out value insert a phi into the loop exit and replace all the value's uses
586   // external to the loop with this phi. The phi will have the original value as its only input;
587   // after copying is done FixSubgraphClosedSSAAfterCloning will add a corresponding copy of the
588   // original value as the second input thus merging data flow from the original and copy parts of
589   // the subgraph. Also update the record in the live_outs_ map from (value, value) to
590   // (value, new_phi).
591   for (auto live_out_it = live_outs_.begin(); live_out_it != live_outs_.end(); ++live_out_it) {
592     HInstruction* value = live_out_it->first;
593     HPhi* phi = new (arena_) HPhi(arena_, kNoRegNumber, 0, value->GetType());
594 
595     if (value->GetType() == DataType::Type::kReference) {
596       phi->SetReferenceTypeInfo(value->GetReferenceTypeInfo());
597     }
598 
599     exit_block->AddPhi(phi);
600     live_out_it->second = phi;
601 
602     const HUseList<HInstruction*>& uses = value->GetUses();
603     for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) {
604       HInstruction* user = it->GetUser();
605       size_t index = it->GetIndex();
606       // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput().
607       ++it;
608       if (!IsInOrigBBSet(user->GetBlock())) {
609         user->ReplaceInput(phi, index);
610         UpdateInductionRangeInfoOf(user, value, phi);
611       }
612     }
613 
614     const HUseList<HEnvironment*>& env_uses = value->GetEnvUses();
615     for (auto it = env_uses.begin(), e = env_uses.end(); it != e; /* ++it below */) {
616       HEnvironment* env = it->GetUser();
617       size_t index = it->GetIndex();
618       ++it;
619       if (!IsInOrigBBSet(env->GetHolder()->GetBlock())) {
620         env->ReplaceInput(phi, index);
621       }
622     }
623 
624     phi->AddInput(value);
625   }
626 }
627 
FixSubgraphClosedSSAAfterCloning()628 void SuperblockCloner::FixSubgraphClosedSSAAfterCloning() {
629   for (auto it : live_outs_) {
630     DCHECK(it.first != it.second);
631     HInstruction* orig_value = it.first;
632     HPhi* phi = it.second->AsPhi();
633     HInstruction* copy_value = GetInstrCopy(orig_value);
634     // Copy edges are inserted after the original so we can just add new input to the phi.
635     phi->AddInput(copy_value);
636   }
637 }
638 
639 //
640 // Debug and logging methods.
641 //
642 
643 // Debug function to dump graph' BasicBlocks info.
DumpBB(HGraph * graph)644 void DumpBB(HGraph* graph) {
645   for (HBasicBlock* bb : graph->GetBlocks()) {
646     if (bb == nullptr) {
647       continue;
648     }
649     std::cout << bb->GetBlockId();
650     std::cout << " <- ";
651     for (HBasicBlock* pred : bb->GetPredecessors()) {
652       std::cout << pred->GetBlockId() << " ";
653     }
654     std::cout << " -> ";
655     for (HBasicBlock* succ : bb->GetSuccessors()) {
656       std::cout << succ->GetBlockId()  << " ";
657     }
658 
659     if (bb->GetDominator()) {
660       std::cout << " dom " << bb->GetDominator()->GetBlockId();
661     }
662 
663     if (bb->GetLoopInformation()) {
664       std::cout <<  "\tloop: " << bb->GetLoopInformation()->GetHeader()->GetBlockId();
665     }
666 
667     std::cout << std::endl;
668   }
669 }
670 
CheckInstructionInputsRemapping(HInstruction * orig_instr)671 void SuperblockCloner::CheckInstructionInputsRemapping(HInstruction* orig_instr) {
672   DCHECK(!orig_instr->IsPhi());
673   HInstruction* copy_instr = GetInstrCopy(orig_instr);
674   for (size_t i = 0, e = orig_instr->InputCount(); i < e; i++) {
675     HInstruction* orig_input = orig_instr->InputAt(i);
676     DCHECK(orig_input->GetBlock()->Dominates(orig_instr->GetBlock()));
677 
678     // If original input is defined outside the region then it will remain for both original
679     // instruction and the copy after the transformation.
680     if (!IsInOrigBBSet(orig_input->GetBlock())) {
681       continue;
682     }
683     HInstruction* copy_input = GetInstrCopy(orig_input);
684     DCHECK(copy_input->GetBlock()->Dominates(copy_instr->GetBlock()));
685   }
686 
687   // Resolve environment.
688   if (orig_instr->HasEnvironment()) {
689     HEnvironment* orig_env = orig_instr->GetEnvironment();
690 
691     for (size_t i = 0, e = orig_env->Size(); i < e; ++i) {
692       HInstruction* orig_input = orig_env->GetInstructionAt(i);
693 
694       // If original input is defined outside the region then it will remain for both original
695       // instruction and the copy after the transformation.
696       if (orig_input == nullptr || !IsInOrigBBSet(orig_input->GetBlock())) {
697         continue;
698       }
699 
700       HInstruction* copy_input = GetInstrCopy(orig_input);
701       DCHECK(copy_input->GetBlock()->Dominates(copy_instr->GetBlock()));
702     }
703   }
704 }
705 
CheckRemappingInfoIsValid()706 bool SuperblockCloner::CheckRemappingInfoIsValid() {
707   for (HEdge edge : *remap_orig_internal_) {
708     if (!IsEdgeValid(edge, graph_) ||
709         !IsInOrigBBSet(edge.GetFrom()) ||
710         !IsInOrigBBSet(edge.GetTo())) {
711       return false;
712     }
713   }
714 
715   for (auto edge : *remap_copy_internal_) {
716     if (!IsEdgeValid(edge, graph_) ||
717         !IsInOrigBBSet(edge.GetFrom()) ||
718         !IsInOrigBBSet(edge.GetTo())) {
719       return false;
720     }
721   }
722 
723   for (auto edge : *remap_incoming_) {
724     if (!IsEdgeValid(edge, graph_) ||
725         IsInOrigBBSet(edge.GetFrom()) ||
726         !IsInOrigBBSet(edge.GetTo())) {
727       return false;
728     }
729   }
730 
731   return true;
732 }
733 
VerifyGraph()734 void SuperblockCloner::VerifyGraph() {
735   for (auto it : *hir_map_) {
736     HInstruction* orig_instr = it.first;
737     HInstruction* copy_instr = it.second;
738     if (!orig_instr->IsPhi() && !orig_instr->IsSuspendCheck()) {
739       DCHECK(it.first->GetBlock() != nullptr);
740     }
741     if (!copy_instr->IsPhi() && !copy_instr->IsSuspendCheck()) {
742       DCHECK(it.second->GetBlock() != nullptr);
743     }
744   }
745 
746   GraphChecker checker(graph_);
747   checker.Run();
748   if (!checker.IsValid()) {
749     for (const std::string& error : checker.GetErrors()) {
750       std::cout << error << std::endl;
751     }
752     LOG(FATAL) << "GraphChecker failed: superblock cloner\n";
753   }
754 }
755 
DumpBBSet(const ArenaBitVector * set)756 void DumpBBSet(const ArenaBitVector* set) {
757   for (uint32_t idx : set->Indexes()) {
758     std::cout << idx << "\n";
759   }
760 }
761 
DumpInputSets()762 void SuperblockCloner::DumpInputSets() {
763   std::cout << "orig_bb_set:\n";
764   for (uint32_t idx : orig_bb_set_.Indexes()) {
765     std::cout << idx << "\n";
766   }
767   std::cout << "remap_orig_internal:\n";
768   for (HEdge e : *remap_orig_internal_) {
769     std::cout << e << "\n";
770   }
771   std::cout << "remap_copy_internal:\n";
772   for (auto e : *remap_copy_internal_) {
773     std::cout << e << "\n";
774   }
775   std::cout << "remap_incoming:\n";
776   for (auto e : *remap_incoming_) {
777     std::cout << e << "\n";
778   }
779 }
780 
781 //
782 // Public methods.
783 //
784 
SuperblockCloner(HGraph * graph,const HBasicBlockSet * orig_bb_set,HBasicBlockMap * bb_map,HInstructionMap * hir_map,InductionVarRange * induction_range)785 SuperblockCloner::SuperblockCloner(HGraph* graph,
786                                    const HBasicBlockSet* orig_bb_set,
787                                    HBasicBlockMap* bb_map,
788                                    HInstructionMap* hir_map,
789                                    InductionVarRange* induction_range)
790   : graph_(graph),
791     arena_(graph->GetAllocator()),
792     orig_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner),
793     remap_orig_internal_(nullptr),
794     remap_copy_internal_(nullptr),
795     remap_incoming_(nullptr),
796     bb_map_(bb_map),
797     hir_map_(hir_map),
798     induction_range_(induction_range),
799     outer_loop_(nullptr),
800     outer_loop_bb_set_(arena_, orig_bb_set->GetSizeOf(), true, kArenaAllocSuperblockCloner),
801     live_outs_(std::less<HInstruction*>(),
802         graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)) {
803   orig_bb_set_.Copy(orig_bb_set);
804 }
805 
SetSuccessorRemappingInfo(const HEdgeSet * remap_orig_internal,const HEdgeSet * remap_copy_internal,const HEdgeSet * remap_incoming)806 void SuperblockCloner::SetSuccessorRemappingInfo(const HEdgeSet* remap_orig_internal,
807                                                  const HEdgeSet* remap_copy_internal,
808                                                  const HEdgeSet* remap_incoming) {
809   remap_orig_internal_ = remap_orig_internal;
810   remap_copy_internal_ = remap_copy_internal;
811   remap_incoming_ = remap_incoming;
812   DCHECK(CheckRemappingInfoIsValid());
813 }
814 
IsSubgraphClonable() const815 bool SuperblockCloner::IsSubgraphClonable() const {
816   // TODO: Support irreducible graphs and graphs with try-catch.
817   if (graph_->HasIrreducibleLoops() || graph_->HasTryCatch()) {
818     return false;
819   }
820 
821   HInstructionMap live_outs(
822       std::less<HInstruction*>(), graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
823 
824   if (!CollectLiveOutsAndCheckClonable(&live_outs)) {
825     return false;
826   }
827 
828   ArenaVector<HBasicBlock*> exits(arena_->Adapter(kArenaAllocSuperblockCloner));
829   SearchForSubgraphExits(&exits);
830 
831   // The only loops with live-outs which are currently supported are loops with a single exit.
832   if (!live_outs.empty() && exits.size() != 1) {
833     return false;
834   }
835 
836   return true;
837 }
838 
IsFastCase() const839 bool SuperblockCloner::IsFastCase() const {
840   // Check that loop unrolling/loop peeling is being conducted.
841   // Check that all the basic blocks belong to the same loop.
842   bool flag = false;
843   HLoopInformation* common_loop_info = nullptr;
844   for (uint32_t idx : orig_bb_set_.Indexes()) {
845     HBasicBlock* block = GetBlockById(idx);
846     HLoopInformation* block_loop_info = block->GetLoopInformation();
847     if (!flag) {
848       common_loop_info = block_loop_info;
849     } else {
850       if (block_loop_info != common_loop_info) {
851         return false;
852       }
853     }
854   }
855 
856   // Check that orig_bb_set_ corresponds to loop peeling/unrolling.
857   if (common_loop_info == nullptr || !orig_bb_set_.SameBitsSet(&common_loop_info->GetBlocks())) {
858     return false;
859   }
860 
861   bool peeling_or_unrolling = false;
862   HEdgeSet remap_orig_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
863   HEdgeSet remap_copy_internal(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
864   HEdgeSet remap_incoming(graph_->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
865 
866 
867   // Check whether remapping info corresponds to loop unrolling.
868   CollectRemappingInfoForPeelUnroll(/* to_unroll*/ true,
869                                     common_loop_info,
870                                     &remap_orig_internal,
871                                     &remap_copy_internal,
872                                     &remap_incoming);
873 
874   peeling_or_unrolling |= EdgeHashSetsEqual(&remap_orig_internal, remap_orig_internal_) &&
875                           EdgeHashSetsEqual(&remap_copy_internal, remap_copy_internal_) &&
876                           EdgeHashSetsEqual(&remap_incoming, remap_incoming_);
877 
878   remap_orig_internal.clear();
879   remap_copy_internal.clear();
880   remap_incoming.clear();
881 
882   // Check whether remapping info corresponds to loop peeling.
883   CollectRemappingInfoForPeelUnroll(/* to_unroll*/ false,
884                                     common_loop_info,
885                                     &remap_orig_internal,
886                                     &remap_copy_internal,
887                                     &remap_incoming);
888 
889   peeling_or_unrolling |= EdgeHashSetsEqual(&remap_orig_internal, remap_orig_internal_) &&
890                           EdgeHashSetsEqual(&remap_copy_internal, remap_copy_internal_) &&
891                           EdgeHashSetsEqual(&remap_incoming, remap_incoming_);
892 
893   return peeling_or_unrolling;
894 }
895 
Run()896 void SuperblockCloner::Run() {
897   DCHECK(bb_map_ != nullptr);
898   DCHECK(hir_map_ != nullptr);
899   DCHECK(remap_orig_internal_ != nullptr &&
900          remap_copy_internal_ != nullptr &&
901          remap_incoming_ != nullptr);
902   DCHECK(IsSubgraphClonable());
903   DCHECK(IsFastCase());
904 
905   if (kSuperblockClonerLogging) {
906     DumpInputSets();
907   }
908 
909   CollectLiveOutsAndCheckClonable(&live_outs_);
910   // Find an area in the graph for which control flow information should be adjusted.
911   FindAndSetLocalAreaForAdjustments();
912   ConstructSubgraphClosedSSA();
913   // Clone the basic blocks from the orig_bb_set_; data flow is invalid after the call and is to be
914   // adjusted.
915   CloneBasicBlocks();
916   // Connect the blocks together/remap successors and fix phis which are directly affected my the
917   // remapping.
918   RemapEdgesSuccessors();
919 
920   // Check that the subgraph is connected.
921   if (kIsDebugBuild) {
922     HBasicBlockSet work_set(arena_, orig_bb_set_.GetSizeOf(), true, kArenaAllocSuperblockCloner);
923 
924     // Add original and copy blocks of the subgraph to the work set.
925     for (auto iter : *bb_map_) {
926       work_set.SetBit(iter.first->GetBlockId());   // Original block.
927       work_set.SetBit(iter.second->GetBlockId());  // Copy block.
928     }
929     CHECK(IsSubgraphConnected(&work_set, graph_));
930   }
931 
932   // Recalculate dominance and backedge information which is required by the next stage.
933   AdjustControlFlowInfo();
934   // Fix data flow of the graph.
935   ResolveDataFlow();
936   FixSubgraphClosedSSAAfterCloning();
937 }
938 
CleanUp()939 void SuperblockCloner::CleanUp() {
940   CleanUpControlFlow();
941 
942   // Remove phis which have all inputs being same.
943   // When a block has a single predecessor it must not have any phis. However after the
944   // transformation it could happen that there is such block with a phi with a single input.
945   // As this is needed to be processed we also simplify phis with multiple same inputs here.
946   for (auto entry : *bb_map_) {
947     HBasicBlock* orig_block = entry.first;
948     for (HInstructionIterator inst_it(orig_block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
949       HPhi* phi = inst_it.Current()->AsPhi();
950       if (ArePhiInputsTheSame(phi)) {
951         phi->ReplaceWith(phi->InputAt(0));
952         orig_block->RemovePhi(phi);
953       }
954     }
955 
956     HBasicBlock* copy_block = GetBlockCopy(orig_block);
957     for (HInstructionIterator inst_it(copy_block->GetPhis()); !inst_it.Done(); inst_it.Advance()) {
958       HPhi* phi = inst_it.Current()->AsPhi();
959       if (ArePhiInputsTheSame(phi)) {
960         phi->ReplaceWith(phi->InputAt(0));
961         copy_block->RemovePhi(phi);
962       }
963     }
964   }
965 
966   if (kIsDebugBuild) {
967     VerifyGraph();
968   }
969 }
970 
CloneBasicBlock(const HBasicBlock * orig_block)971 HBasicBlock* SuperblockCloner::CloneBasicBlock(const HBasicBlock* orig_block) {
972   HGraph* graph = orig_block->GetGraph();
973   HBasicBlock* copy_block = new (arena_) HBasicBlock(graph, orig_block->GetDexPc());
974   graph->AddBlock(copy_block);
975 
976   // Clone all the phis and add them to the map.
977   for (HInstructionIterator it(orig_block->GetPhis()); !it.Done(); it.Advance()) {
978     HInstruction* orig_instr = it.Current();
979     HInstruction* copy_instr = orig_instr->Clone(arena_);
980     copy_block->AddPhi(copy_instr->AsPhi());
981     copy_instr->AsPhi()->RemoveAllInputs();
982     DCHECK(!orig_instr->HasEnvironment());
983     hir_map_->Put(orig_instr, copy_instr);
984   }
985 
986   // Clone all the instructions and add them to the map.
987   for (HInstructionIterator it(orig_block->GetInstructions()); !it.Done(); it.Advance()) {
988     HInstruction* orig_instr = it.Current();
989     HInstruction* copy_instr = orig_instr->Clone(arena_);
990     ReplaceInputsWithCopies(copy_instr);
991     copy_block->AddInstruction(copy_instr);
992     if (orig_instr->HasEnvironment()) {
993       DeepCloneEnvironmentWithRemapping(copy_instr, orig_instr->GetEnvironment());
994     }
995     hir_map_->Put(orig_instr, copy_instr);
996   }
997 
998   return copy_block;
999 }
1000 
CloneBasicBlocks()1001 void SuperblockCloner::CloneBasicBlocks() {
1002   // By this time ReversePostOrder must be valid: in 'CloneBasicBlock' inputs of the copied
1003   // instructions might be replaced by copies of the original inputs (depending where those inputs
1004   // are defined). So the definitions of the original inputs must be visited before their original
1005   // uses. The property of the reducible graphs "if 'A' dom 'B' then rpo_num('A') >= rpo_num('B')"
1006   // guarantees that.
1007   for (HBasicBlock* orig_block : graph_->GetReversePostOrder()) {
1008     if (!IsInOrigBBSet(orig_block)) {
1009       continue;
1010     }
1011     HBasicBlock* copy_block = CloneBasicBlock(orig_block);
1012     bb_map_->Put(orig_block, copy_block);
1013     if (kSuperblockClonerLogging) {
1014       std::cout << "new block :" << copy_block->GetBlockId() << ": " << orig_block->GetBlockId() <<
1015                    std::endl;
1016     }
1017   }
1018 }
1019 
1020 //
1021 // Stand-alone methods.
1022 //
1023 
CollectRemappingInfoForPeelUnroll(bool to_unroll,HLoopInformation * loop_info,HEdgeSet * remap_orig_internal,HEdgeSet * remap_copy_internal,HEdgeSet * remap_incoming)1024 void CollectRemappingInfoForPeelUnroll(bool to_unroll,
1025                                        HLoopInformation* loop_info,
1026                                        HEdgeSet* remap_orig_internal,
1027                                        HEdgeSet* remap_copy_internal,
1028                                        HEdgeSet* remap_incoming) {
1029   DCHECK(loop_info != nullptr);
1030   HBasicBlock* loop_header = loop_info->GetHeader();
1031   // Set up remap_orig_internal edges set - set is empty.
1032   // Set up remap_copy_internal edges set.
1033   for (HBasicBlock* back_edge_block : loop_info->GetBackEdges()) {
1034     HEdge e = HEdge(back_edge_block, loop_header);
1035     if (to_unroll) {
1036       remap_orig_internal->insert(e);
1037       remap_copy_internal->insert(e);
1038     } else {
1039       remap_copy_internal->insert(e);
1040     }
1041   }
1042 
1043   // Set up remap_incoming edges set.
1044   if (!to_unroll) {
1045     remap_incoming->insert(HEdge(loop_info->GetPreHeader(), loop_header));
1046   }
1047 }
1048 
IsSubgraphConnected(SuperblockCloner::HBasicBlockSet * work_set,HGraph * graph)1049 bool IsSubgraphConnected(SuperblockCloner::HBasicBlockSet* work_set, HGraph* graph) {
1050   ArenaVector<HBasicBlock*> entry_blocks(
1051       graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1052 
1053   // Find subgraph entry blocks.
1054   for (uint32_t orig_block_id : work_set->Indexes()) {
1055     HBasicBlock* block = graph->GetBlocks()[orig_block_id];
1056     for (HBasicBlock* pred : block->GetPredecessors()) {
1057       if (!work_set->IsBitSet(pred->GetBlockId())) {
1058         entry_blocks.push_back(block);
1059         break;
1060       }
1061     }
1062   }
1063 
1064   for (HBasicBlock* entry_block : entry_blocks) {
1065     if (work_set->IsBitSet(entry_block->GetBlockId())) {
1066       TraverseSubgraphForConnectivity(entry_block, work_set);
1067     }
1068   }
1069 
1070   // Return whether there are unvisited - unreachable - blocks.
1071   return work_set->NumSetBits() == 0;
1072 }
1073 
FindCommonLoop(HLoopInformation * loop1,HLoopInformation * loop2)1074 HLoopInformation* FindCommonLoop(HLoopInformation* loop1, HLoopInformation* loop2) {
1075   if (loop1 == nullptr || loop2 == nullptr) {
1076     return nullptr;
1077   }
1078 
1079   if (loop1->IsIn(*loop2)) {
1080     return loop2;
1081   }
1082 
1083   HLoopInformation* current = loop1;
1084   while (current != nullptr && !loop2->IsIn(*current)) {
1085     current = current->GetPreHeader()->GetLoopInformation();
1086   }
1087 
1088   return current;
1089 }
1090 
IsLoopClonable(HLoopInformation * loop_info)1091 bool PeelUnrollHelper::IsLoopClonable(HLoopInformation* loop_info) {
1092   PeelUnrollHelper helper(
1093       loop_info, /* bb_map= */ nullptr, /* hir_map= */ nullptr, /* induction_range= */ nullptr);
1094   return helper.IsLoopClonable();
1095 }
1096 
DoPeelUnrollImpl(bool to_unroll)1097 HBasicBlock* PeelUnrollHelper::DoPeelUnrollImpl(bool to_unroll) {
1098   // For now do peeling only for natural loops.
1099   DCHECK(!loop_info_->IsIrreducible());
1100 
1101   HBasicBlock* loop_header = loop_info_->GetHeader();
1102   // Check that loop info is up-to-date.
1103   DCHECK(loop_info_ == loop_header->GetLoopInformation());
1104   HGraph* graph = loop_header->GetGraph();
1105 
1106   if (kSuperblockClonerLogging) {
1107     std::cout << "Method: " << graph->PrettyMethod() << std::endl;
1108     std::cout << "Scalar loop " << (to_unroll ? "unrolling" : "peeling") <<
1109                  " was applied to the loop <" << loop_header->GetBlockId() << ">." << std::endl;
1110   }
1111 
1112   ArenaAllocator allocator(graph->GetAllocator()->GetArenaPool());
1113 
1114   HEdgeSet remap_orig_internal(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1115   HEdgeSet remap_copy_internal(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1116   HEdgeSet remap_incoming(graph->GetAllocator()->Adapter(kArenaAllocSuperblockCloner));
1117 
1118   CollectRemappingInfoForPeelUnroll(to_unroll,
1119                                     loop_info_,
1120                                     &remap_orig_internal,
1121                                     &remap_copy_internal,
1122                                     &remap_incoming);
1123 
1124   cloner_.SetSuccessorRemappingInfo(&remap_orig_internal, &remap_copy_internal, &remap_incoming);
1125   cloner_.Run();
1126   cloner_.CleanUp();
1127 
1128   // Check that loop info is preserved.
1129   DCHECK(loop_info_ == loop_header->GetLoopInformation());
1130 
1131   return loop_header;
1132 }
1133 
PeelUnrollSimpleHelper(HLoopInformation * info,InductionVarRange * induction_range)1134 PeelUnrollSimpleHelper::PeelUnrollSimpleHelper(HLoopInformation* info,
1135                                                InductionVarRange* induction_range)
1136   : bb_map_(std::less<HBasicBlock*>(),
1137             info->GetHeader()->GetGraph()->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)),
1138     hir_map_(std::less<HInstruction*>(),
1139              info->GetHeader()->GetGraph()->GetAllocator()->Adapter(kArenaAllocSuperblockCloner)),
1140     helper_(info, &bb_map_, &hir_map_, induction_range) {}
1141 
1142 }  // namespace art
1143 
1144 namespace std {
1145 
operator <<(ostream & os,const art::HEdge & e)1146 ostream& operator<<(ostream& os, const art::HEdge& e) {
1147   e.Dump(os);
1148   return os;
1149 }
1150 
1151 }  // namespace std
1152