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