• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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