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