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