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