1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "compiler_logger.h"
17 #include "inst.h"
18 #include "optimizer/analysis/dominators_tree.h"
19 #include "optimizer/analysis/loop_analyzer.h"
20 #include "optimizer/analysis/linear_order.h"
21 #include "optimizer/ir/graph.h"
22 #include "optimizer/ir/graph_cloner.h"
23
24 namespace ark::compiler {
GraphCloner(Graph * graph,ArenaAllocator * allocator,ArenaAllocator * localAllocator)25 GraphCloner::GraphCloner(Graph *graph, ArenaAllocator *allocator, ArenaAllocator *localAllocator)
26 : graph_(graph),
27 allocator_(allocator),
28 localAllocator_(localAllocator),
29 cloneBlocks_(allocator->Adapter()),
30 cloneInstructions_(allocator->Adapter()),
31 cloneInstMap_(allocator->Adapter())
32 {
33 }
34
35 /// Clone the whole graph
CloneGraph()36 Graph *GraphCloner::CloneGraph()
37 {
38 auto newGraph = allocator_->New<Graph>(Graph::GraphArgs {allocator_, localAllocator_, GetGraph()->GetArch(),
39 GetGraph()->GetMethod(), GetGraph()->GetRuntime()},
40 GetGraph()->GetParentGraph(), GetGraph()->GetMode());
41 newGraph->SetCurrentInstructionId(GetGraph()->GetCurrentInstructionId());
42 newGraph->SetAotData(GetGraph()->GetAotData());
43 CloneBlocksAndInstructions<InstCloneType::CLONE_ALL, false>(GetGraph()->GetVectorBlocks(), newGraph);
44 BuildControlFlow();
45 BuildTryCatchLogic(newGraph);
46 BuildDataFlow();
47 CloneConstantsInfo(newGraph);
48 newGraph->GetPassManager()->SetCheckMode(GetGraph()->GetPassManager()->IsCheckMode());
49 // Clone all flags
50 newGraph->SetBitFields(GetGraph()->GetBitFields());
51 newGraph->InitUsedRegs<DataType::INT64>(GetGraph()->GetUsedRegs<DataType::INT64>());
52 newGraph->InitUsedRegs<DataType::FLOAT64>(GetGraph()->GetUsedRegs<DataType::FLOAT64>());
53 #ifdef COMPILER_DEBUG_CHECKS
54 CloneAnalyses(newGraph);
55 #endif
56 return newGraph;
57 }
58
CloneAnalyses(Graph * newGraph)59 void GraphCloner::CloneAnalyses(Graph *newGraph)
60 {
61 // Clone dominators if analysis is valid to check dom-tree
62 ASSERT(!newGraph->IsAnalysisValid<DominatorsTree>());
63 if (GetGraph()->IsAnalysisValid<DominatorsTree>()) {
64 newGraph->GetAnalysis<DominatorsTree>().SetValid(true);
65 for (auto block : GetGraph()->GetBlocksRPO()) {
66 auto clone = GetClone(block);
67 if (block->GetDominator() != nullptr) {
68 auto cloneDom = GetClone(block->GetDominator());
69 clone->SetDominator(cloneDom);
70 }
71 for (auto domBlocks : block->GetDominatedBlocks()) {
72 clone->AddDominatedBlock(GetClone(domBlocks));
73 }
74 }
75 }
76
77 // Clone loops if analysis is valid to check loop-tree
78 ASSERT(!newGraph->IsAnalysisValid<LoopAnalyzer>());
79 if (GetGraph()->IsAnalysisValid<LoopAnalyzer>()) {
80 auto &clonedLa = newGraph->GetAnalysis<LoopAnalyzer>();
81 clonedLa.SetValid(true);
82 clonedLa.CreateRootLoop();
83 CopyLoop(GetGraph()->GetRootLoop(), newGraph->GetRootLoop());
84 newGraph->SetHasIrreducibleLoop(GetGraph()->HasIrreducibleLoop());
85 newGraph->SetHasInfiniteLoop(GetGraph()->HasInfiniteLoop());
86 }
87
88 ASSERT(!newGraph->IsAnalysisValid<LinearOrder>());
89 if (GetGraph()->IsAnalysisValid<LinearOrder>()) {
90 newGraph->GetAnalysis<LinearOrder>().SetValid(true);
91 CloneLinearOrder(newGraph);
92 }
93 }
94
CopyLoop(Loop * loop,Loop * clonedLoop)95 void GraphCloner::CopyLoop(Loop *loop, Loop *clonedLoop)
96 {
97 if (!loop->IsRoot() && !loop->IsIrreducible() && !loop->IsTryCatchLoop()) {
98 ASSERT(GetClone(loop->GetHeader()) == clonedLoop->GetHeader());
99 clonedLoop->SetPreHeader(GetClone(loop->GetPreHeader()));
100 }
101 for (auto block : loop->GetBlocks()) {
102 if (block->IsLoopHeader()) {
103 continue;
104 }
105 clonedLoop->AppendBlock(GetClone(block));
106 }
107
108 for (auto backEdge : loop->GetBackEdges()) {
109 clonedLoop->AppendBackEdge(GetClone(backEdge));
110 }
111 clonedLoop->SetIsIrreducible(loop->IsIrreducible());
112 clonedLoop->SetIsInfinite(loop->IsInfinite());
113
114 // clone inner loops
115 for (const auto &innerLoop : loop->GetInnerLoops()) {
116 auto clonedHeader = GetClone(innerLoop->GetHeader());
117 auto &clonedLa = clonedHeader->GetGraph()->GetAnalysis<LoopAnalyzer>();
118 auto clonedInnerLoop = clonedLa.CreateNewLoop(clonedHeader);
119 clonedInnerLoop->SetOuterLoop(clonedLoop);
120 clonedLoop->AppendInnerLoop(clonedInnerLoop);
121 CopyLoop(innerLoop, clonedInnerLoop);
122 }
123 }
124
CloneLinearOrder(Graph * newGraph)125 void GraphCloner::CloneLinearOrder([[maybe_unused]] Graph *newGraph)
126 {
127 ASSERT(newGraph != nullptr);
128 ASSERT(GetGraph()->IsAnalysisValid<LinearOrder>());
129 auto &cloneLinearBlocks = newGraph->GetAnalysis<LinearOrder>().GetBlocks();
130 cloneLinearBlocks.reserve(GetGraph()->GetBlocksLinearOrder().size());
131 for (auto block : GetGraph()->GetBlocksLinearOrder()) {
132 cloneLinearBlocks.push_back(GetClone(block));
133 }
134 }
135
136 /// Clone the whole graph control-flow
BuildControlFlow()137 void GraphCloner::BuildControlFlow()
138 {
139 for (const auto &block : GetGraph()->GetVectorBlocks()) {
140 if (block == nullptr) {
141 continue;
142 }
143 CloneEdges<CloneEdgeType::EDGE_PRED>(block);
144 CloneEdges<CloneEdgeType::EDGE_SUCC>(block);
145 }
146 }
147
CloneThrowableInstHandlers(Graph * newGraph)148 void GraphCloner::CloneThrowableInstHandlers(Graph *newGraph)
149 {
150 for (auto *block : GetGraph()->GetVectorBlocks()) {
151 if (block == nullptr) {
152 continue;
153 }
154 for (auto *inst : block->AllInsts()) {
155 if (!GetGraph()->IsInstThrowable(inst)) {
156 continue;
157 }
158
159 auto *clonedInst = GetClone(inst);
160 for (auto *catchBlock : GetGraph()->GetThrowableInstHandlers(inst)) {
161 auto *clonedCatchBlock = GetClone(catchBlock);
162 newGraph->AppendThrowableInst(clonedInst, clonedCatchBlock);
163 }
164 }
165 }
166 }
167
BuildTryCatchLogic(Graph * newGraph)168 void GraphCloner::BuildTryCatchLogic(Graph *newGraph)
169 {
170 // Connect every tryInst to corresponding tryEndBlock
171 for (auto *tryBegin : newGraph->GetTryBeginBlocks()) {
172 TryInst *tryInst = GetTryBeginInst(tryBegin);
173 ASSERT(tryInst != nullptr);
174 for (auto block : newGraph->GetBlocksRPO()) {
175 if (block->IsTryEnd() && (block->GetTryId() == tryBegin->GetTryId())) {
176 tryInst->SetTryEndBlock(block);
177 }
178 }
179 }
180
181 CloneThrowableInstHandlers(newGraph);
182
183 auto fixThrowables = [this](const CatchPhiInst *originalInst, CatchPhiInst *clonedInst) {
184 if (originalInst->GetThrowableInsts() != nullptr) {
185 for (int i = 0, j = originalInst->GetThrowableInsts()->size(); i < j; ++i) {
186 auto *clonedThrowable = cloneInstMap_[originalInst->GetThrowableInst(i)];
187 clonedInst->AppendThrowableInst(clonedThrowable);
188 }
189 }
190 };
191
192 // Restore catchPhi's and throwables
193 for (BasicBlock *clone : cloneBlocks_) {
194 // Skip nullptrs and non-catch blocks
195 if (clone == nullptr || !clone->IsCatch()) {
196 continue;
197 }
198 Inst *inst = clone->GetFirstInst();
199 while (inst != nullptr) {
200 if (inst->IsCatchPhi() && !inst->CastToCatchPhi()->IsAcc()) {
201 fixThrowables(cloneInstMap_[inst]->CastToCatchPhi(), inst->CastToCatchPhi());
202 }
203 inst = inst->GetNext();
204 }
205 }
206 }
207
208 /// Clone the whole graph data-flow
BuildDataFlow()209 void GraphCloner::BuildDataFlow()
210 {
211 for (const auto &block : GetGraph()->GetVectorBlocks()) {
212 if (block == nullptr) {
213 continue;
214 }
215 auto blockClone = GetClone(block);
216 for (const auto &inst : block->Insts()) {
217 SetCloneInputs<false>(inst);
218 GetClone(inst)->SetId(inst->GetId());
219 UpdateCaller(inst);
220 }
221 for (const auto &inst : block->PhiInsts()) {
222 auto phi = inst->CastToPhi();
223 auto instClone = GetClone(inst);
224 instClone->SetId(inst->GetId());
225 for (const auto &clonePredBlock : blockClone->GetPredsBlocks()) {
226 auto it = std::find(cloneBlocks_.begin(), cloneBlocks_.end(), clonePredBlock);
227 ASSERT(it != cloneBlocks_.end());
228 size_t index = std::distance(cloneBlocks_.begin(), it);
229 ASSERT(GetGraph()->GetVectorBlocks().size() > index);
230 auto predBlock = GetGraph()->GetVectorBlocks()[index];
231 instClone->AppendInput(GetClone(phi->GetPhiInput(predBlock)));
232 }
233 }
234 }
235 }
236
CloneConstantsInfo(Graph * newGraph)237 void GraphCloner::CloneConstantsInfo(Graph *newGraph)
238 {
239 // Restore firstConstInst_ logic
240 BasicBlock *startBB = newGraph->GetStartBlock();
241 Inst *inst = startBB->GetFirstInst();
242 // Find first const if any
243 while (inst != nullptr) {
244 if (inst->IsConst()) {
245 newGraph->SetFirstConstInst(inst->CastToConstant());
246 break;
247 }
248 inst = inst->GetNext();
249 }
250 if (inst == nullptr) {
251 return;
252 }
253 // Put another constants in chain if any
254 ConstantInst *constInst = inst->CastToConstant();
255 ASSERT(constInst->GetBasicBlock() == startBB);
256 while ((inst = inst->GetNext()) != nullptr) {
257 if (inst->IsConst()) {
258 constInst->SetNextConst(inst->CastToConstant());
259 constInst = inst->CastToConstant();
260 }
261 }
262 }
263
PopulateResolverBlock(Loop * loop,BasicBlock * resolver,Inst * inst)264 void PopulateResolverBlock(Loop *loop, BasicBlock *resolver, Inst *inst)
265 {
266 Inst *phiResolver = nullptr;
267 auto userIt = inst->GetUsers().begin();
268 while (userIt != inst->GetUsers().end()) {
269 auto user = userIt->GetInst();
270 auto inputIdx = userIt->GetIndex();
271 ++userIt;
272 ASSERT(user->GetBasicBlock() != nullptr);
273 if (user->GetBasicBlock()->GetLoop() != loop) {
274 if (phiResolver == nullptr) {
275 phiResolver = inst->GetBasicBlock()->GetGraph()->CreateInstPhi(inst->GetType(), inst->GetPc());
276 phiResolver->AppendInput(inst);
277 resolver->AppendPhi(phiResolver);
278 }
279 user->SetInput(inputIdx, phiResolver);
280 }
281 }
282 }
283
284 /*
285 * Create resolver-block - common successor for all loop side-exits
286 */
CreateResolverBlock(Loop * loop,BasicBlock * backEdge)287 BasicBlock *GraphCloner::CreateResolverBlock(Loop *loop, BasicBlock *backEdge)
288 {
289 auto outsideSucc = GetLoopOutsideSuccessor(loop);
290 auto resolver = backEdge->InsertNewBlockToSuccEdge(outsideSucc);
291 backEdge->GetLoop()->GetOuterLoop()->AppendBlock(resolver);
292 // Populate resolver-block with phis for each instruction which has outside-loop user
293 for (auto block : loop->GetBlocks()) {
294 for (auto inst : block->AllInsts()) {
295 PopulateResolverBlock(loop, resolver, inst);
296 }
297 }
298 return resolver;
299 }
300
GetCompareInst(Inst * ifimm)301 Inst *GraphCloner::GetCompareInst(Inst *ifimm)
302 {
303 auto compare = ifimm->GetInput(0).GetInst();
304 ASSERT(compare->GetOpcode() == Opcode::Compare);
305 // If there are intructions between `Compare` and `IfImm`, clone `Compare` and insert before `IfImm`
306 if (ifimm->GetPrev() != compare || !compare->HasSingleUser()) {
307 auto newCmp = compare->Clone(compare->GetBasicBlock()->GetGraph());
308 newCmp->SetInput(0, compare->GetInput(0).GetInst());
309 newCmp->SetInput(1, compare->GetInput(1).GetInst());
310 ifimm->InsertBefore(newCmp);
311 ifimm->SetInput(0, newCmp);
312 compare = newCmp;
313 }
314 return compare;
315 }
316
317 /*
318 * Split back-edge for cloning without side exits - in order not to clone `Compare` and `IfImm` instructions
319 */
SplitBackEdge(LoopUnrollData * unrollData,Loop * loop,BasicBlock * backEdge)320 BasicBlock *GraphCloner::SplitBackEdge(LoopUnrollData *unrollData, Loop *loop, BasicBlock *backEdge)
321 {
322 auto *ifimm = backEdge->GetLastInst();
323 ASSERT(ifimm->GetOpcode() == Opcode::IfImm);
324 auto *compare = GetCompareInst(ifimm);
325 if (compare->GetPrev() != nullptr) {
326 auto backEdgeSplit = backEdge->SplitBlockAfterInstruction(compare->GetPrev(), true);
327 loop->ReplaceBackEdge(backEdge, backEdgeSplit);
328 backEdge = backEdgeSplit;
329 } else {
330 ASSERT(backEdge->GetPredsBlocks().size() == 1);
331 auto it = std::find(unrollData->blocks->begin(), unrollData->blocks->end(), backEdge);
332 ASSERT(it != unrollData->blocks->end());
333 unrollData->blocks->erase(it);
334 unrollData->exitBlock = backEdge->GetPredBlockByIndex(0);
335 }
336 [[maybe_unused]] static constexpr auto BACK_EDGE_INST_COUNT = 2;
337 ASSERT(std::distance(backEdge->AllInsts().begin(), backEdge->AllInsts().end()) == BACK_EDGE_INST_COUNT);
338 return backEdge;
339 }
340
341 /**
342 * - Split loop-header into two blocks, header phis will not be cloned:
343 * [phi-insts]
344 * -----------
345 * [all-insts]
346 *
347 * - If loop is cloing with side-exits create common successor for them;
348 * - Otherwise split back-edge to cut `Compare` and `IfImm` instructions and not clone them;
349 */
PrepareLoopToUnroll(Loop * loop,bool cloneSideExits)350 GraphCloner::LoopUnrollData *GraphCloner::PrepareLoopToUnroll(Loop *loop, bool cloneSideExits)
351 {
352 ASSERT(loop != nullptr);
353 // Populate `LoopUnrollData`
354 auto allocator = loop->GetHeader()->GetGraph()->GetLocalAllocator();
355 auto unrollData = allocator->New<LoopUnrollData>();
356 unrollData->blocks = allocator->New<ArenaVector<BasicBlock *>>(allocator->Adapter());
357 unrollData->blocks->resize(loop->GetBlocks().size());
358 std::copy(loop->GetBlocks().begin(), loop->GetBlocks().end(), unrollData->blocks->begin());
359 // Split loop-header
360 ASSERT(loop->GetBackEdges().size() == 1U);
361 auto backEdge = loop->GetBackEdges()[0];
362 ASSERT(backEdge != nullptr);
363 auto headerBlock = loop->GetHeader();
364 ASSERT(!headerBlock->IsEmpty());
365 if (headerBlock->HasPhi()) {
366 auto lastPhi = headerBlock->GetFirstInst()->GetPrev();
367 ASSERT(lastPhi != nullptr && lastPhi->IsPhi());
368 auto headerSplit = headerBlock->SplitBlockAfterInstruction(lastPhi, true);
369 ASSERT(loop->GetBlocks().front() == headerBlock);
370 unrollData->blocks->at(0) = headerSplit;
371
372 if (backEdge == headerBlock) {
373 loop->ReplaceBackEdge(headerBlock, headerSplit);
374 backEdge = headerSplit;
375 }
376 }
377 unrollData->exitBlock = backEdge;
378 if (cloneSideExits) {
379 unrollData->outer = CreateResolverBlock(loop, backEdge);
380 } else {
381 backEdge = SplitBackEdge(unrollData, loop, backEdge);
382 }
383 // Save replaceable phi inputs
384
385 unrollData->phiUpdateInputs = allocator->New<InstVector>(allocator->Adapter());
386 for (auto phi : headerBlock->PhiInsts()) {
387 unrollData->phiUpdateInputs->push_back(phi->CastToPhi()->GetPhiInput(backEdge));
388 }
389 unrollData->header = headerBlock;
390 unrollData->backedge = backEdge;
391 return unrollData;
392 }
393
394 /// Update data-flow after unrolling without side-exits
UpdateUsersAfterNoSideExitsUnroll(const LoopUnrollData * unrollData)395 void GraphCloner::UpdateUsersAfterNoSideExitsUnroll(const LoopUnrollData *unrollData)
396 {
397 auto loop = unrollData->header->GetLoop();
398 // Update outloop users: replace inputs located in the original loop by theirs clones
399 auto compare = unrollData->backedge->GetLastInst()->GetPrev();
400 ASSERT(compare->GetOpcode() == Opcode::Compare);
401 for (size_t i = 0; i < compare->GetInputsCount(); i++) {
402 auto input = compare->GetInput(i).GetInst();
403 if (HasClone(input)) {
404 compare->SetInput(i, GetClone(input));
405 }
406 }
407 // update outloop users
408 for (auto block : *unrollData->blocks) {
409 for (auto inst : block->AllInsts()) {
410 UpdateOutloopUsers(loop, inst);
411 }
412 }
413
414 // All header-phi's outloop users are placed in the outer_bb after cloning the original loop
415 // So it's enough to to iterate outer_bb's phis and repalce header-phi by its backedge input
416 auto outerIdx = 1U - unrollData->backedge->GetSuccBlockIndex(unrollData->header);
417 auto outerBb = unrollData->backedge->GetSuccessor(outerIdx);
418 for (auto outerPhi : outerBb->PhiInsts()) {
419 auto headerPhi = outerPhi->CastToPhi()->GetPhiInput(unrollData->backedge);
420 if (headerPhi->IsPhi() && headerPhi->GetBasicBlock() == unrollData->header) {
421 outerPhi->ReplaceInput(headerPhi, headerPhi->CastToPhi()->GetPhiInput(unrollData->backedge));
422 }
423 }
424 }
425
UpdateOutloopUsers(Loop * loop,Inst * inst)426 void GraphCloner::UpdateOutloopUsers(Loop *loop, Inst *inst)
427 {
428 auto userIt = inst->GetUsers().begin();
429 while (userIt != inst->GetUsers().end()) {
430 auto user = userIt->GetInst();
431 auto inputIdx = userIt->GetIndex();
432 ++userIt;
433 ASSERT(user->GetBasicBlock() != nullptr);
434 if (user->GetBasicBlock()->GetLoop() != loop) {
435 user->SetInput(inputIdx, GetClone(inst));
436 }
437 }
438 }
439
440 /**
441 * Link cloned blocks with each other and insert them to the graph between the last-block and the output-block
442 *
443 * - No-side-exits case:
444 * /---->[header]
445 * | |
446 * | v
447 * | [loop-body] << last-block << exit-block
448 * | |
449 * | v
450 * \-----[backedge]----> ...
451 *
452 * New control-flow:
453 * /---->[header]
454 * | |
455 * | v
456 * | [loop-body] << exit-block
457 * | |
458 * | v
459 * | [loop-body-clone] << last-block
460 * | |
461 * | v
462 * \-----[backedge]----> ...
463 *
464 *
465 * Side-exits case:
466 * /---->[header]
467 * | |
468 * | v
469 * | [loop-body]
470 * | |
471 * | v
472 * \-----[backedge] << last-block << exit-block
473 * |
474 * v
475 * [outer]-----> ...
476 *
477 * New control-flow:
478 * /---->[header]
479 * | |
480 * | v
481 * | [loop-body]
482 * | |
483 * | v
484 * | [backedge]------------\ << exit-block
485 * | | |
486 * | v |
487 * | [loop-body-clone] |
488 * | | |
489 * | v |
490 * \-----[backedge-clone]----->| << last-block
491 * |
492 * v
493 * [outer]-----> ...
494 */
BuildLoopUnrollControlFlow(LoopUnrollData * unrollData)495 void GraphCloner::BuildLoopUnrollControlFlow(LoopUnrollData *unrollData)
496 {
497 auto frontBlock = unrollData->blocks->front();
498 auto loop = frontBlock->GetLoop();
499
500 // Copy 'blocks' control-flow to the 'clones'
501 for (auto block : *unrollData->blocks) {
502 ASSERT(block->GetLoop() == loop);
503 loop->AppendBlock(GetClone(block));
504
505 if (block != frontBlock) {
506 CloneEdges<CloneEdgeType::EDGE_PRED>(block);
507 }
508 if (block != unrollData->exitBlock) {
509 CloneEdges<CloneEdgeType::EDGE_SUCC>(block);
510 }
511 }
512
513 auto frontClone = GetClone(frontBlock);
514 auto exitClone = GetClone(unrollData->exitBlock);
515 if (unrollData->outer == nullptr) {
516 ASSERT(unrollData->backedge->GetPredsBlocks().size() == 1);
517 auto lastBlock = unrollData->backedge->GetPredsBlocks()[0];
518 lastBlock->ReplaceSucc(unrollData->backedge, frontClone);
519 unrollData->backedge->ReplacePred(lastBlock, exitClone);
520 } else {
521 ASSERT(!unrollData->outer->GetPredsBlocks().empty());
522 auto lastBlock = unrollData->outer->GetPredsBlocks().back();
523 lastBlock->ReplaceSucc(unrollData->header, frontClone);
524 unrollData->header->ReplacePred(lastBlock, exitClone);
525
526 exitClone->AddSucc(unrollData->outer);
527 if (exitClone->GetSuccBlockIndex(unrollData->outer) != lastBlock->GetSuccBlockIndex(unrollData->outer)) {
528 exitClone->SwapTrueFalseSuccessors();
529 }
530 auto newBackedge = GetClone(unrollData->exitBlock);
531 loop->ReplaceBackEdge(unrollData->backedge, newBackedge);
532 unrollData->backedge = newBackedge;
533 }
534 }
535
536 /**
537 * Construct dataflow for the cloned instructions
538 * if input of the original instruction is front-block phi - insert replaceable input of this phi
539 */
BuildLoopUnrollDataFlow(LoopUnrollData * unrollData)540 void GraphCloner::BuildLoopUnrollDataFlow(LoopUnrollData *unrollData)
541 {
542 for (auto block : *unrollData->blocks) {
543 for (auto inst : block->AllInsts()) {
544 if (inst->IsMarked(cloneMarker_)) {
545 SetCloneInputs<true>(inst, unrollData->backedge);
546 UpdateCaller(inst);
547 }
548 }
549 }
550
551 // Append input to the phi-resolver from outer block, it holds all instructions which have outside loop users
552 auto loop = unrollData->blocks->front()->GetLoop();
553 if (unrollData->outer != nullptr) {
554 for (auto phi : unrollData->outer->PhiInsts()) {
555 auto inst = phi->GetInput(0).GetInst();
556 if (IsInstLoopHeaderPhi(inst, loop)) {
557 auto update = inst->CastToPhi()->GetPhiInput(unrollData->backedge);
558 phi->AppendInput(update);
559 } else {
560 phi->AppendInput(GetClone(inst));
561 }
562 }
563 }
564
565 // NOTE (a.popov) use temp container after if would be possible to reset local allocator
566 if (unrollData->phiReplacedInputs == nullptr) {
567 unrollData->phiReplacedInputs = allocator_->New<PhiInputsMap>(allocator_->Adapter());
568 } else {
569 unrollData->phiReplacedInputs->clear();
570 }
571
572 // Set new update inputs for header phis
573 size_t phiCount = 0;
574 for (auto phi : loop->GetHeader()->PhiInsts()) {
575 auto input = unrollData->phiUpdateInputs->at(phiCount);
576 if (HasClone(input)) {
577 input = GetClone(input);
578 } else if (input->IsPhi() && input->GetBasicBlock()->GetLoop() == loop) {
579 if (phi->IsDominate(input)) {
580 input = input->CastToPhi()->GetPhiInput(unrollData->backedge);
581 } else {
582 // phi should be visited and its input should be added to the map
583 ASSERT(unrollData->phiReplacedInputs->count(input) == 1);
584 input = unrollData->phiReplacedInputs->at(input);
585 }
586 }
587
588 auto phiUpdateInputIdx = phi->CastToPhi()->GetPredBlockIndex(unrollData->backedge);
589 unrollData->phiReplacedInputs->emplace(phi, phi->GetInput(phiUpdateInputIdx).GetInst());
590 phi->SetInput(phiUpdateInputIdx, input);
591 phiCount++;
592 }
593 }
594
RemoveLoopBackEdge(const LoopUnrollData * unrollData)595 void GraphCloner::RemoveLoopBackEdge(const LoopUnrollData *unrollData)
596 {
597 auto lastBlock = unrollData->backedge;
598 ASSERT(unrollData->outer == nullptr || lastBlock == unrollData->outer->GetPredsBlocks().back());
599
600 // Erase control-flow instruction
601 auto ifimm = lastBlock->GetLastInst();
602 ASSERT(ifimm->GetOpcode() == Opcode::IfImm);
603 lastBlock->RemoveInst(ifimm);
604 // Remove back-edge
605 auto header = unrollData->header;
606 // Clear header block, it should only contain phi
607 ASSERT(header->GetFirstInst() == nullptr);
608 for (auto phi : header->PhiInstsSafe()) {
609 auto remainingInst = phi->CastToPhi()->GetPhiInput(header->GetLoop()->GetPreHeader());
610 phi->ReplaceUsers(remainingInst);
611 header->RemoveInst(phi);
612 }
613
614 lastBlock->RemoveSucc(header);
615 header->RemovePred(lastBlock);
616
617 // Clear outer phis if it has single predecessor
618 if (unrollData->outer != nullptr && unrollData->outer->GetPredsBlocks().size() == 1U) {
619 for (auto phi : unrollData->outer->PhiInstsSafe()) {
620 auto remainingInst = phi->GetInput(0).GetInst();
621 phi->ReplaceUsers(remainingInst);
622 unrollData->outer->RemoveInst(phi);
623 }
624 }
625 }
626
RemoveLoopPreHeader(const LoopUnrollData * unrollData)627 void GraphCloner::RemoveLoopPreHeader(const LoopUnrollData *unrollData)
628 {
629 ASSERT(unrollData->header->GetPredsBlocks().size() == 1);
630 // Loop::GetPreHeader may be invalid here
631 auto preHeader = unrollData->header->GetPredBlockByIndex(0);
632 auto ifimm = preHeader->GetLastInst();
633 ASSERT(ifimm->GetOpcode() == Opcode::IfImm);
634 preHeader->RemoveInst(ifimm);
635
636 // Loop header should be removed from backedge successors before call to this function
637 ASSERT(unrollData->backedge->GetSuccsBlocks().size() == 1);
638 auto removedSucc = unrollData->backedge->GetSuccessor(0);
639
640 for (auto phi : removedSucc->PhiInstsSafe()) {
641 if (removedSucc->GetPredsBlocks().size() == 2U) {
642 auto remainingInst = phi->CastToPhi()->GetPhiInput(unrollData->backedge);
643 phi->ReplaceUsers(remainingInst);
644 removedSucc->RemoveInst(phi);
645 } else {
646 phi->RemoveInput(phi->CastToPhi()->GetPredBlockIndex(preHeader));
647 }
648 }
649
650 preHeader->RemoveSucc(removedSucc);
651 removedSucc->RemovePred(preHeader);
652 }
653
BuildClonedLoopHeaderDataFlow(const BasicBlock & block,BasicBlock * resolver,BasicBlock * clone)654 void GraphCloner::BuildClonedLoopHeaderDataFlow(const BasicBlock &block, BasicBlock *resolver, BasicBlock *clone)
655 {
656 for (auto inst : block.Insts()) {
657 if (inst->IsMarked(cloneMarker_)) {
658 SetCloneInputs<true>(inst, clone);
659 UpdateUsersForClonedLoopHeader(inst, resolver);
660 UpdateCaller(inst);
661 }
662 }
663 for (auto phi : block.PhiInsts()) {
664 ASSERT(phi->GetInputsCount() == 2U);
665 auto preloopInput = phi->CastToPhi()->GetPhiInput(clone);
666 // Create phi instruction in the `resolver` block with two inputs: current phi and phi's preloop_input
667 auto resolverPhi = GetGraph()->CreateInstPhi(phi->GetType(), phi->GetPc());
668 for (auto userIt = phi->GetUsers().begin(); userIt != phi->GetUsers().end();) {
669 auto user = userIt->GetInst();
670 auto inputIndex = userIt->GetIndex();
671 ++userIt;
672 ASSERT(user->GetBasicBlock() != nullptr);
673 auto userLoop = user->GetBasicBlock()->GetLoop();
674 if (userLoop != block.GetLoop() && !userLoop->IsInside(block.GetLoop())) {
675 user->SetInput(inputIndex, resolverPhi);
676 }
677 }
678 if (resolverPhi->HasUsers()) {
679 resolverPhi->AppendInput(phi);
680 resolverPhi->AppendInput(preloopInput);
681 resolver->AppendPhi(resolverPhi);
682 }
683 }
684 }
685
686 /**
687 * Used by Loop peeling to clone loop-header and insert this clone before loop-header.
688 * Created block-resolved - common succesor for loop-header and its clone
689 *
690 * [replaceable_pred]
691 * |
692 * v
693 * ... --->[block]--------\
694 * | |
695 * v v
696 * ... [outer]
697 *
698 *
699 * [replaceable_pred]
700 * |
701 * v
702 * [clone_block]---------\
703 * | |
704 * v |
705 * ... --->[block]--------\ |
706 * | | |
707 * v v v
708 * ... [resolver]
709 * |
710 * v
711 * [outer]
712 */
CloneLoopHeader(BasicBlock * block,BasicBlock * outer,BasicBlock * replaceablePred)713 BasicBlock *GraphCloner::CloneLoopHeader(BasicBlock *block, BasicBlock *outer, BasicBlock *replaceablePred)
714 {
715 ASSERT(GetGraph()->IsAnalysisValid<DominatorsTree>());
716 ASSERT(cloneMarker_ == UNDEF_MARKER);
717 auto markerHolder = MarkerHolder(GetGraph());
718 cloneMarker_ = markerHolder.GetMarker();
719 cloneInstructions_.clear();
720 size_t instCount = 0;
721 // Build control-flow
722 auto resolver = block->InsertNewBlockToSuccEdge(outer);
723 outer->GetLoop()->AppendBlock(resolver);
724 if (outer->GetLoop()->HasBackEdge(block)) {
725 outer->GetLoop()->ReplaceBackEdge(block, resolver);
726 }
727 auto cloneBlock = replaceablePred->InsertNewBlockToSuccEdge(block);
728 ASSERT(block->GetLoop()->GetPreHeader() == replaceablePred);
729 block->GetLoop()->SetPreHeader(cloneBlock);
730 ASSERT(replaceablePred->GetNextLoop() == nullptr);
731 replaceablePred->GetLoop()->AppendBlock(cloneBlock);
732 cloneBlock->AddSucc(resolver);
733 // Check the order of true-false successors
734 if (cloneBlock->GetSuccBlockIndex(resolver) != block->GetSuccBlockIndex(resolver)) {
735 cloneBlock->SwapTrueFalseSuccessors();
736 }
737 // Fix Dominators info
738 auto &domTree = GetGraph()->GetAnalysis<DominatorsTree>();
739 domTree.SetValid(true);
740 ASSERT(block->GetDominator() == replaceablePred);
741 replaceablePred->RemoveDominatedBlock(block);
742 domTree.SetDomPair(cloneBlock, block);
743 domTree.SetDomPair(replaceablePred, cloneBlock);
744 domTree.SetDomPair(cloneBlock, resolver);
745 if (outer->GetDominator() == block) {
746 block->RemoveDominatedBlock(outer);
747 domTree.SetDomPair(resolver, outer);
748 }
749 CloneInstructions<InstCloneType::CLONE_INSTS, true>(block, cloneBlock, &instCount);
750 BuildClonedLoopHeaderDataFlow(*block, resolver, cloneBlock);
751 cloneBlock->SetAllFields(block->GetAllFields());
752 return cloneBlock;
753 }
754
755 /**
756 * Use the following logic cloning the users:
757 * - replace inputs of all users, placed OUTSIDE cloneable loop, by the new `phi_out` instruction
758 * - `phi_out` is appended to the outer-block
759 * - replace inputs of all users, placed INSIDE cloneable loop, but not cloned, by the new `phi_in` instruction
760 * - `phi_in` is appended to the `inst` basic block
761 * - `phi_in\phi_out` have `inst` and its clone as inputs
762 */
UpdateUsersForClonedLoopHeader(Inst * inst,BasicBlock * outerBlock)763 void GraphCloner::UpdateUsersForClonedLoopHeader(Inst *inst, BasicBlock *outerBlock)
764 {
765 if (!inst->HasUsers()) {
766 return;
767 }
768 auto instBlock = inst->GetBasicBlock();
769 auto clone = GetClone(inst);
770 auto cloneBlock = clone->GetBasicBlock();
771 ASSERT(cloneBlock != nullptr);
772 // phi for inside users
773 auto phiIn = GetGraph()->CreateInstPhi(inst->GetType(), inst->GetPc());
774 // phi for outside users
775 auto phiOut = GetGraph()->CreateInstPhi(inst->GetType(), inst->GetPc());
776 auto userIt = inst->GetUsers().begin();
777 while (userIt != inst->GetUsers().end()) {
778 auto user = userIt->GetInst();
779 auto inputIdx = userIt->GetIndex();
780 ++userIt;
781 ASSERT(user->GetBasicBlock() != nullptr);
782 auto userLoop = user->GetBasicBlock()->GetLoop();
783 if (userLoop == instBlock->GetLoop() || userLoop->IsInside(instBlock->GetLoop())) {
784 // user inside loop
785 // skip users that will be moved to the loop-exit block
786 if (user->GetBasicBlock() == instBlock && !user->IsPhi()) {
787 continue;
788 }
789 user->SetInput(inputIdx, phiIn);
790 } else {
791 // user outside loop
792 user->SetInput(inputIdx, phiOut);
793 }
794 }
795
796 if (phiIn->HasUsers()) {
797 auto cloneIndex {instBlock->GetPredBlockIndex(cloneBlock)};
798 phiIn->AppendInput(clone);
799 phiIn->AppendInput(inst);
800 phiIn->CastToPhi()->SetPhiInputBbNum(0, cloneIndex);
801 phiIn->CastToPhi()->SetPhiInputBbNum(1, 1 - cloneIndex);
802
803 auto firstPhi = instBlock->GetFirstPhi();
804 if (firstPhi == nullptr) {
805 instBlock->AppendPhi(phiIn);
806 } else {
807 instBlock->InsertBefore(phiIn, firstPhi);
808 }
809 }
810
811 if (phiOut->HasUsers()) {
812 phiOut->AppendInput(inst);
813 phiOut->AppendInput(clone);
814 outerBlock->AppendPhi(phiOut);
815 }
816 }
817
IsInstLoopHeaderPhi(Inst * inst,Loop * loop)818 bool GraphCloner::IsInstLoopHeaderPhi(Inst *inst, Loop *loop)
819 {
820 return inst->IsPhi() && inst->GetBasicBlock() == loop->GetHeader();
821 }
822
823 /**
824 * Create clone of loop and insert it after original loop:
825 *
826 * /----[pre-loop]
827 * | |
828 * | v
829 * | [loop-body]<----\
830 * | | | |
831 * | | \-------/
832 * | |
833 * | v
834 * \--->[outside-block]
835 * |
836 * v
837 * /----[pre-loop']
838 * | |
839 * | v
840 * | [loop-body']<----\
841 * | | | |
842 * | | \-------/
843 * | |
844 * | v
845 * \--->[outside-block']
846 */
CloneLoop(Loop * loop)847 Loop *GraphCloner::CloneLoop(Loop *loop)
848 {
849 ASSERT(loop != nullptr && !loop->IsRoot());
850 ASSERT_PRINT(IsLoopSingleBackEdgeExitPoint(loop), "Cloning blocks doesn't have single entry/exit point");
851 ASSERT(loop->GetPreHeader() != nullptr);
852 ASSERT(cloneMarker_ == UNDEF_MARKER);
853
854 auto markerHolder = MarkerHolder(GetGraph());
855 cloneMarker_ = markerHolder.GetMarker();
856 SplitPreHeader(loop);
857 auto unrollData = PrepareLoopToClone(loop);
858
859 CloneBlocksAndInstructions<InstCloneType::CLONE_ALL, true>(*unrollData->blocks, GetGraph());
860 BuildLoopCloneControlFlow(unrollData);
861 BuildLoopCloneDataFlow(unrollData);
862 MakeLoopCloneInfo(unrollData);
863 GetGraph()->RunPass<DominatorsTree>();
864
865 auto cloneLoop = GetClone(loop->GetHeader())->GetLoop();
866 ASSERT(cloneLoop != loop && cloneLoop->GetOuterLoop() == loop->GetOuterLoop());
867 COMPILER_LOG(DEBUG, GRAPH_CLONER) << "Loop " << loop->GetId() << " is copied";
868 COMPILER_LOG(DEBUG, GRAPH_CLONER) << "Created new loop, id = " << cloneLoop->GetId();
869 return cloneLoop;
870 }
871
CreateNewOutsideSucc(BasicBlock * outsideSucc,BasicBlock * backEdge,BasicBlock * preHeader)872 BasicBlock *GraphCloner::CreateNewOutsideSucc(BasicBlock *outsideSucc, BasicBlock *backEdge, BasicBlock *preHeader)
873 {
874 auto backEdgeIdx = outsideSucc->GetPredBlockIndex(backEdge);
875 auto preHeaderIdx = outsideSucc->GetPredBlockIndex(preHeader);
876 auto rmIdxMax = std::max(backEdgeIdx, preHeaderIdx);
877 auto rmIdxMin = std::min(backEdgeIdx, preHeaderIdx);
878 auto newOutsideSucc = GetGraph()->CreateEmptyBlock();
879 outsideSucc->GetLoop()->AppendBlock(newOutsideSucc);
880 backEdge->ReplaceSucc(outsideSucc, newOutsideSucc);
881 preHeader->ReplaceSucc(outsideSucc, newOutsideSucc);
882 newOutsideSucc->AddSucc(outsideSucc);
883 for (auto phi : outsideSucc->PhiInsts()) {
884 auto newPhi = GetGraph()->CreateInstPhi(phi->GetType(), phi->GetPc());
885 newPhi->AppendInput(phi->CastToPhi()->GetPhiInput(backEdge));
886 newPhi->AppendInput(phi->CastToPhi()->GetPhiInput(preHeader));
887 phi->AppendInput(newPhi);
888 auto phiBackEdgeIdx {phi->CastToPhi()->GetPredBlockIndex(backEdge)};
889 auto phiPreHeaderIdx {phi->CastToPhi()->GetPredBlockIndex(preHeader)};
890 phi->RemoveInput(rmIdxMax == backEdgeIdx ? phiBackEdgeIdx : phiPreHeaderIdx);
891 phi->RemoveInput(rmIdxMin == preHeaderIdx ? phiPreHeaderIdx : phiBackEdgeIdx);
892 newOutsideSucc->AppendPhi(newPhi);
893 }
894 outsideSucc->RemovePred(rmIdxMax);
895 outsideSucc->RemovePred(rmIdxMin);
896
897 COMPILER_LOG(DEBUG, GRAPH_CLONER) << "New loop outside block created: " << newOutsideSucc->GetId();
898 return newOutsideSucc;
899 }
900
PopulateLoopClonerData(Loop * loop,BasicBlock * preHeader,BasicBlock * outsideSucc)901 GraphCloner::LoopClonerData *GraphCloner::PopulateLoopClonerData(Loop *loop, BasicBlock *preHeader,
902 BasicBlock *outsideSucc)
903 {
904 auto allocator = GetGraph()->GetLocalAllocator();
905 auto clonerData = allocator->New<LoopClonerData>();
906 clonerData->blocks = allocator->New<ArenaVector<BasicBlock *>>(allocator->Adapter());
907 clonerData->blocks->resize(loop->GetBlocks().size() + 1);
908 clonerData->blocks->at(0) = preHeader;
909 std::copy(loop->GetBlocks().begin(), loop->GetBlocks().end(), clonerData->blocks->begin() + 1);
910 clonerData->blocks->push_back(outsideSucc);
911 clonerData->outer = outsideSucc;
912 clonerData->header = loop->GetHeader();
913 clonerData->preHeader = loop->GetPreHeader();
914 return clonerData;
915 }
916
917 // Split pre-header to contain `Compare` and `IfImm` instructions only;
SplitPreHeader(Loop * loop)918 void GraphCloner::SplitPreHeader(Loop *loop)
919 {
920 ASSERT(loop != nullptr);
921 auto preHeader = loop->GetPreHeader();
922 auto *ifimm = preHeader->GetLastInst();
923 ASSERT(ifimm != nullptr && ifimm->GetOpcode() == Opcode::IfImm);
924 auto *compare = GetCompareInst(ifimm);
925 if (compare->GetPrev() != nullptr) {
926 auto newPreHeader = preHeader->SplitBlockAfterInstruction(compare->GetPrev(), true);
927 loop->SetPreHeader(newPreHeader);
928 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
929 preHeader = newPreHeader;
930 }
931 [[maybe_unused]] static constexpr auto PRE_HEADER_INST_COUNT = 2;
932 ASSERT(std::distance(preHeader->AllInsts().begin(), preHeader->AllInsts().end()) == PRE_HEADER_INST_COUNT);
933 }
934
935 /**
936 * - Make sure `outsideSucc` has 2 predecessors only: loop header and back-edge;
937 * - Split `outsideSucc` to contain phi-instructions only;
938 */
PrepareLoopToClone(Loop * loop)939 GraphCloner::LoopClonerData *GraphCloner::PrepareLoopToClone(Loop *loop)
940 {
941 // If `outsideSucc` has more than 2 predecessors, create a new one
942 // with loop header and back-edge predecessors only and insert it before `outsideSucc`
943 auto preHeader = loop->GetPreHeader();
944 auto outsideSucc = GetLoopOutsideSuccessor(loop);
945 constexpr auto PREDS_NUM = 2;
946 if (outsideSucc->GetPredsBlocks().size() > PREDS_NUM) {
947 auto backEdge = loop->GetBackEdges()[0];
948 outsideSucc = CreateNewOutsideSucc(outsideSucc, backEdge, preHeader);
949 }
950 // Split outside succ after last phi
951 // create empty block before outside succ if outside succ don't contain phi insts
952 if (outsideSucc->HasPhi() && outsideSucc->GetFirstInst() != nullptr) {
953 auto lastPhi = outsideSucc->GetFirstInst()->GetPrev();
954 auto block = outsideSucc->SplitBlockAfterInstruction(lastPhi, true);
955 // if `outsideSucc` is pre-header replace it by `block`
956 for (auto inLoop : loop->GetOuterLoop()->GetInnerLoops()) {
957 if (inLoop->GetPreHeader() == outsideSucc) {
958 inLoop->SetPreHeader(block);
959 }
960 }
961 } else if (outsideSucc->GetFirstInst() != nullptr) {
962 auto block = outsideSucc->InsertEmptyBlockBefore();
963 outsideSucc->GetLoop()->AppendBlock(block);
964 outsideSucc = block;
965 }
966 // Populate `LoopClonerData`
967 return PopulateLoopClonerData(loop, preHeader, outsideSucc);
968 }
969
970 /// Create new loop, populate it with cloned blocks and build conrlow-flow
BuildLoopCloneControlFlow(LoopClonerData * unrollData)971 void GraphCloner::BuildLoopCloneControlFlow(LoopClonerData *unrollData)
972 {
973 ASSERT(unrollData != nullptr);
974 auto outerClone = GetClone(unrollData->outer);
975 auto preHeaderClone = GetClone(unrollData->preHeader);
976
977 while (!unrollData->outer->GetSuccsBlocks().empty()) {
978 auto succ = unrollData->outer->GetSuccsBlocks().front();
979 succ->ReplacePred(unrollData->outer, outerClone);
980 unrollData->outer->RemoveSucc(succ);
981 }
982 unrollData->outer->AddSucc(preHeaderClone);
983
984 for (auto &block : *unrollData->blocks) {
985 if (block != unrollData->preHeader) {
986 CloneEdges<CloneEdgeType::EDGE_PRED>(block);
987 }
988 if (block != unrollData->outer) {
989 CloneEdges<CloneEdgeType::EDGE_SUCC>(block);
990 }
991 }
992 ASSERT(unrollData->outer->GetPredBlockIndex(unrollData->preHeader) ==
993 outerClone->GetPredBlockIndex(preHeaderClone));
994 ASSERT(unrollData->header->GetPredBlockIndex(unrollData->preHeader) ==
995 GetClone(unrollData->header)->GetPredBlockIndex(preHeaderClone));
996 }
997
998 /// Insert cloned loop into loop-tree and populated with cloned blocks
MakeLoopCloneInfo(LoopClonerData * unrollData)999 void GraphCloner::MakeLoopCloneInfo(LoopClonerData *unrollData)
1000 {
1001 ASSERT(unrollData != nullptr);
1002 // Update loop tree
1003 auto loop = unrollData->header->GetLoop();
1004 auto headerClone = GetClone(loop->GetHeader());
1005 auto cloneLoop = GetGraph()->GetAnalysis<LoopAnalyzer>().CreateNewLoop(headerClone);
1006 auto outerLoop = loop->GetOuterLoop();
1007 outerLoop->AppendInnerLoop(cloneLoop);
1008 cloneLoop->SetOuterLoop(outerLoop);
1009
1010 // Populate cloned loop
1011 auto preLoopClone = GetClone(unrollData->preHeader);
1012 auto outsideSuccClone = GetClone(unrollData->outer);
1013 cloneLoop->SetPreHeader(preLoopClone);
1014 outerLoop->AppendBlock(preLoopClone);
1015 outerLoop->AppendBlock(outsideSuccClone);
1016 for (auto &block : loop->GetBlocks()) {
1017 if (!block->IsLoopHeader()) {
1018 cloneLoop->AppendBlock(GetClone(block));
1019 }
1020 }
1021 for (auto backEdge : loop->GetBackEdges()) {
1022 cloneLoop->AppendBackEdge(GetClone(backEdge));
1023 }
1024 }
1025
1026 /// Find or create phi in the outside_succ block with the same inputs as `check_phi`
GetPhiResolver(Inst * checkPhi,BasicBlock * outsideSucc,BasicBlock * preHeader)1027 Inst *GetPhiResolver(Inst *checkPhi, BasicBlock *outsideSucc, BasicBlock *preHeader)
1028 {
1029 [[maybe_unused]] constexpr auto MAX_PREDS_NUM = 2;
1030 ASSERT(outsideSucc->GetPredsBlocks().size() == MAX_PREDS_NUM);
1031 ASSERT(checkPhi->GetBasicBlock()->IsLoopHeader());
1032 auto initIdx = checkPhi->CastToPhi()->GetPredBlockIndex(preHeader);
1033 auto initInput = checkPhi->GetInput(initIdx).GetInst();
1034 auto updateInput = checkPhi->GetInput(1 - initIdx).GetInst();
1035
1036 for (auto phi : outsideSucc->PhiInsts()) {
1037 auto idx {phi->CastToPhi()->GetPredBlockIndex(preHeader)};
1038 if (phi->GetInput(idx).GetInst() == initInput && phi->GetInput(1 - idx).GetInst() == updateInput) {
1039 return phi;
1040 }
1041 }
1042
1043 auto phiResolver = outsideSucc->GetGraph()->CreateInstPhi(checkPhi->GetType(), checkPhi->GetPc());
1044 auto outInitIdx = outsideSucc->GetPredBlockIndex(preHeader);
1045 phiResolver->AppendInput(initInput);
1046 phiResolver->AppendInput(updateInput);
1047 phiResolver->SetPhiInputBbNum(0, outInitIdx);
1048 phiResolver->SetPhiInputBbNum(1, 1 - outInitIdx);
1049
1050 outsideSucc->AppendPhi(phiResolver);
1051 return phiResolver;
1052 }
1053
ProcessMarkedInsts(LoopClonerData * data)1054 void GraphCloner::ProcessMarkedInsts(LoopClonerData *data)
1055 {
1056 for (const auto &block : *data->blocks) {
1057 for (const auto &inst : block->AllInsts()) {
1058 if (inst->GetOpcode() == Opcode::NOP) {
1059 continue;
1060 }
1061 if (inst->IsMarked(cloneMarker_)) {
1062 SetCloneInputs<false>(inst);
1063 UpdateCaller(inst);
1064 }
1065 }
1066 }
1067 }
1068
1069 /// Build data-flow for cloned instructions
BuildLoopCloneDataFlow(LoopClonerData * unrollData)1070 void GraphCloner::BuildLoopCloneDataFlow(LoopClonerData *unrollData)
1071 {
1072 ASSERT(unrollData != nullptr);
1073 ProcessMarkedInsts(unrollData);
1074
1075 auto preLoopClone = GetClone(unrollData->preHeader);
1076 for (auto phi : unrollData->outer->PhiInsts()) {
1077 auto phiClone = GetClone(phi);
1078 phi->ReplaceUsers(phiClone);
1079 auto idx = phiClone->CastToPhi()->GetPredBlockIndex(preLoopClone);
1080 phiClone->SetInput(idx, phi);
1081 }
1082
1083 auto compare = preLoopClone->GetFirstInst();
1084 auto exitBlock = unrollData->outer->GetPredBlockByIndex(0);
1085 if (exitBlock == unrollData->preHeader) {
1086 exitBlock = unrollData->outer->GetPredBlockByIndex(1);
1087 } else {
1088 ASSERT(unrollData->outer->GetPredBlockByIndex(1) == unrollData->preHeader);
1089 }
1090 auto backEdgeCompare = exitBlock->GetLastInst()->GetInput(0).GetInst();
1091 ASSERT(compare->GetOpcode() == Opcode::Compare);
1092 ASSERT(backEdgeCompare->GetOpcode() == Opcode::Compare);
1093 for (auto phi : unrollData->header->PhiInsts()) {
1094 auto initIdx = phi->CastToPhi()->GetPredBlockIndex(unrollData->preHeader);
1095 ASSERT(GetClone(phi)->CastToPhi()->GetPredBlockIndex(preLoopClone) == initIdx);
1096
1097 auto init = phi->GetInput(initIdx).GetInst();
1098 auto update = phi->GetInput(1 - initIdx).GetInst();
1099 auto resolverPhi = GetPhiResolver(phi, unrollData->outer, unrollData->preHeader);
1100 auto clonePhi = GetClone(phi);
1101 ASSERT(clonePhi->GetInput(initIdx).GetInst() == init);
1102 clonePhi->SetInput(initIdx, resolverPhi);
1103 for (size_t i = 0; i < compare->GetInputsCount(); i++) {
1104 if (compare->GetInput(i).GetInst() == init && backEdgeCompare->GetInput(i).GetInst() == update) {
1105 compare->SetInput(i, resolverPhi);
1106 break;
1107 }
1108 }
1109 }
1110 }
1111
UpdateCaller(Inst * inst)1112 void GraphCloner::UpdateCaller(Inst *inst)
1113 {
1114 if (inst->IsSaveState()) {
1115 auto caller = static_cast<SaveStateInst *>(inst)->GetCallerInst();
1116 if (caller != nullptr && caller->IsInlined() && HasClone(caller)) {
1117 auto ssClone = GetClone(inst);
1118 auto callerClone = GetClone(caller);
1119 static_cast<SaveStateInst *>(ssClone)->SetCallerInst(static_cast<CallInst *>(callerClone));
1120 }
1121 }
1122 }
1123 } // namespace ark::compiler
1124