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