• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "graph.h"
17 #include "basicblock.h"
18 #include "inst.h"
19 #include "bytecode_optimizer/bytecode_encoder.h"
20 #include "compiler_logger.h"
21 #include "optimizer/analysis/alias_analysis.h"
22 #include "optimizer/analysis/bounds_analysis.h"
23 #include "optimizer/analysis/dominators_tree.h"
24 #include "optimizer/analysis/rpo.h"
25 #include "optimizer/analysis/linear_order.h"
26 #include "optimizer/analysis/loop_analyzer.h"
27 #if defined(PANDA_WITH_CODEGEN) && !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
28 #include "optimizer/code_generator/callconv.h"
29 #include "optimizer/code_generator/codegen.h"
30 #include "optimizer/code_generator/encode.h"
31 #include "optimizer/code_generator/registers_description.h"
32 #endif
33 
34 namespace ark::compiler {
MarkBlocksRec(Marker mrk,BasicBlock * block)35 static void MarkBlocksRec(Marker mrk, BasicBlock *block)
36 {
37     if (block->SetMarker(mrk)) {
38         return;
39     }
40     for (auto succ : block->GetSuccsBlocks()) {
41         MarkBlocksRec(mrk, succ);
42     }
43 }
44 
~Graph()45 Graph::~Graph()
46 {
47     if (encoder_ != nullptr) {
48         encoder_->~Encoder();
49     }
50 }
51 
RemoveUnreachableBlocks()52 void Graph::RemoveUnreachableBlocks()
53 {
54     Marker mrk = NewMarker();
55     MarkBlocksRec(mrk, GetStartBlock());
56     // Remove unreachable blocks
57     for (auto &bb : *this) {
58         if (bb == nullptr) {
59             continue;
60         }
61         if (bb->IsMarked(mrk)) {
62             continue;
63         }
64         RemovePredecessors(bb, false);
65         RemoveSuccessors(bb);
66         if (bb->IsTryBegin()) {
67             EraseTryBeginBlock(bb);
68             // Remove try_end mark from paired bb
69             if (!bb->IsEmpty()) {
70                 GetTryBeginInst(bb)->GetTryEndBlock()->SetTryEnd(false);
71             }
72         }
73         // Clear DF:
74         for (auto inst : bb->AllInsts()) {
75             inst->RemoveInputs();
76             if (IsInstThrowable(inst)) {
77                 RemoveThrowableInst(inst);
78             }
79         }
80         COMPILER_LOG(DEBUG, CLEANUP) << "Erase unreachable block " << bb->GetId();
81         EraseBlock(bb);
82     }
83     EraseMarker(mrk);
84 }
85 
AddConstInStartBlock(ConstantInst * constInst)86 void Graph::AddConstInStartBlock(ConstantInst *constInst)
87 {
88     GetStartBlock()->AppendInst(constInst);
89 }
90 
AddNewParameter(uint16_t argNumber)91 ParameterInst *Graph::AddNewParameter(uint16_t argNumber)
92 {
93     ParameterInst *param = CreateInstParameter(argNumber);
94     GetStartBlock()->AppendInst(param);
95     return param;
96 }
97 
FindParameter(uint16_t argNumber)98 ParameterInst *Graph::FindParameter(uint16_t argNumber)
99 {
100     for (auto inst : GetStartBlock()->AllInsts()) {
101         if (!inst->IsParameter()) {
102             continue;
103         }
104         auto paramInst = inst->CastToParameter();
105         if (paramInst->GetArgNumber() == argNumber) {
106             return paramInst;
107         }
108     }
109     return nullptr;
110 }
111 
GetOrCreateNullPtr()112 Inst *Graph::GetOrCreateNullPtr()
113 {
114     if (nullptrInst_ == nullptr) {
115         nullptrInst_ = CreateInstNullPtr(DataType::REFERENCE);
116         GetStartBlock()->AppendInst(nullptrInst_);
117     }
118     return nullptrInst_;
119 }
120 
GetOrCreateUniqueObjectInst()121 Inst *Graph::GetOrCreateUniqueObjectInst()
122 {
123     if (uniqueObjectInst_ == nullptr) {
124         uniqueObjectInst_ = CreateInstLoadUniqueObject(DataType::REFERENCE);
125         GetStartBlock()->AppendInst(uniqueObjectInst_);
126     }
127     return uniqueObjectInst_;
128 }
129 
RemoveConstFromList(ConstantInst * constInst)130 void Graph::RemoveConstFromList(ConstantInst *constInst)
131 {
132     if (constInst == firstConstInst_) {
133         firstConstInst_ = constInst->GetNextConst();
134         constInst->SetNextConst(nullptr);
135         return;
136     }
137     auto current = firstConstInst_;
138     auto next = current->GetNextConst();
139     while (next != nullptr && next != constInst) {
140         current = next;
141         next = next->GetNextConst();
142     }
143     ASSERT(next != nullptr);
144     ASSERT(next == constInst);
145     current->SetNextConst(constInst->GetNextConst());
146     constInst->SetNextConst(nullptr);
147 }
148 
InvalidateBlocksOrderAnalyzes(Graph * graph)149 void InvalidateBlocksOrderAnalyzes(Graph *graph)
150 {
151     graph->InvalidateAnalysis<Rpo>();
152     graph->InvalidateAnalysis<DominatorsTree>();
153     graph->InvalidateAnalysis<LinearOrder>();
154 }
155 
AddBlock(BasicBlock * block)156 void Graph::AddBlock(BasicBlock *block)
157 {
158     ASSERT(block != nullptr);
159     block->SetId(vectorBb_.size());
160     vectorBb_.push_back(block);
161     block->SetGraph(this);
162     InvalidateBlocksOrderAnalyzes(this);
163 }
164 
165 #ifndef NDEBUG
AddBlock(BasicBlock * block,uint32_t id)166 void Graph::AddBlock(BasicBlock *block, uint32_t id)
167 {
168     if (vectorBb_.size() <= id) {
169         // (id + 1) for adding a block with index 0
170         vectorBb_.resize((id + 1U) << 1U, nullptr);
171     }
172     ASSERT(vectorBb_[id] == nullptr);
173     block->SetId(id);
174     vectorBb_[id] = block;
175     InvalidateBlocksOrderAnalyzes(this);
176 }
177 #endif
178 
GetBoundsRangeInfo() const179 const BoundsRangeInfo *Graph::GetBoundsRangeInfo() const
180 {
181     return GetValidAnalysis<BoundsAnalysis>().GetBoundsRangeInfo();
182 }
183 
GetBlocksRPO() const184 const ArenaVector<BasicBlock *> &Graph::GetBlocksRPO() const
185 {
186     return GetValidAnalysis<Rpo>().GetBlocks();
187 }
188 
GetBlocksLinearOrder() const189 const ArenaVector<BasicBlock *> &Graph::GetBlocksLinearOrder() const
190 {
191     return GetValidAnalysis<LinearOrder>().GetBlocks();
192 }
193 
194 template <class Callback>
VisitAllInstructions(Callback callback)195 void Graph::VisitAllInstructions(Callback callback)
196 {
197     for (auto bb : GetBlocksRPO()) {
198         for (auto inst : bb->AllInsts()) {
199             callback(inst);
200         }
201     }
202 }
203 
CheckInstAlias(Inst * mem1,Inst * mem2)204 AliasType Graph::CheckInstAlias(Inst *mem1, Inst *mem2)
205 {
206     return GetValidAnalysis<AliasAnalysis>().CheckInstAlias(mem1, mem2);
207 }
208 
CreateEmptyBlock(uint32_t guestPc)209 BasicBlock *Graph::CreateEmptyBlock(uint32_t guestPc)
210 {
211     auto block = GetAllocator()->New<BasicBlock>(this, guestPc);
212     AddBlock(block);
213     return block;
214 }
215 
216 // Create empty block with base block's properties
CreateEmptyBlock(BasicBlock * baseBlock)217 BasicBlock *Graph::CreateEmptyBlock(BasicBlock *baseBlock)
218 {
219     ASSERT(baseBlock != nullptr);
220     auto block = CreateEmptyBlock();
221     ASSERT(block != nullptr);
222     block->SetGuestPc(baseBlock->GetGuestPc());
223     block->SetAllFields(baseBlock->GetAllFields());
224     block->SetTryId(baseBlock->GetTryId());
225     block->SetOsrEntry(false);
226     return block;
227 }
228 
229 #ifndef NDEBUG
CreateEmptyBlock(uint32_t id,uint32_t guestPc)230 BasicBlock *Graph::CreateEmptyBlock(uint32_t id, uint32_t guestPc)
231 {
232     auto block = GetAllocator()->New<BasicBlock>(this, guestPc);
233     AddBlock(block, id);
234     return block;
235 }
236 #endif
237 
CreateStartBlock()238 BasicBlock *Graph::CreateStartBlock()
239 {
240     auto block = CreateEmptyBlock(0U);
241     SetStartBlock(block);
242     return block;
243 }
244 
CreateEndBlock(uint32_t guestPc)245 BasicBlock *Graph::CreateEndBlock(uint32_t guestPc)
246 {
247     auto block = CreateEmptyBlock(guestPc);
248     SetEndBlock(block);
249     return block;
250 }
251 
RemovePredecessorUpdateDF(BasicBlock * block,BasicBlock * rmPred)252 void Graph::RemovePredecessorUpdateDF(BasicBlock *block, BasicBlock *rmPred)
253 {
254     constexpr auto IMM_2 = 2;
255     if (block->GetPredsBlocks().size() == IMM_2) {
256         for (auto phi : block->PhiInstsSafe()) {
257             auto rmIndex = phi->CastToPhi()->GetPredBlockIndex(rmPred);
258             auto remainingInst = phi->GetInput(1 - rmIndex).GetInst();
259             if (phi != remainingInst && remainingInst->GetBasicBlock() != nullptr) {
260                 phi->ReplaceUsers(remainingInst);
261             }
262             block->RemoveInst(phi);
263         }
264     } else if (block->GetPredsBlocks().size() > IMM_2) {
265         for (auto phi : block->PhiInstsSafe()) {
266             auto rmIndex = phi->CastToPhi()->GetPredBlockIndex(rmPred);
267             phi->CastToPhi()->RemoveInput(rmIndex);
268         }
269     } else {
270         ASSERT(block->GetPredsBlocks().size() == 1);
271     }
272     block->RemovePred(rmPred);
273     InvalidateBlocksOrderAnalyzes(block->GetGraph());
274 }
275 
276 /*
277  * Remove edges between `block` and its successors and
278  * update phi-instructions in successors blocks
279  */
RemoveSuccessors(BasicBlock * block)280 void Graph::RemoveSuccessors(BasicBlock *block)
281 {
282     for (auto succ : block->GetSuccsBlocks()) {
283         RemovePredecessorUpdateDF(succ, block);
284     }
285     block->GetSuccsBlocks().clear();
286 }
287 
288 /*
289  * Remove edges between `block` and its predecessors,
290  * update last instructions in predecessors blocks
291  */
RemovePredecessors(BasicBlock * block,bool removeLastInst)292 void Graph::RemovePredecessors(BasicBlock *block, bool removeLastInst)
293 {
294     for (auto pred : block->GetPredsBlocks()) {
295         if (removeLastInst && !pred->IsTryBegin() && !pred->IsTryEnd()) {
296             if (pred->GetSuccsBlocks().size() == 2U) {
297                 auto last = pred->GetLastInst();
298                 ASSERT(last->GetOpcode() == Opcode::If || last->GetOpcode() == Opcode::IfImm ||
299                        last->GetOpcode() == Opcode::AddOverflow || last->GetOpcode() == Opcode::SubOverflow ||
300                        last->GetOpcode() == Opcode::Throw);
301                 pred->RemoveInst(last);
302             } else {
303                 ASSERT(pred->GetSuccsBlocks().size() == 1 && pred->GetSuccessor(0) == block);
304             }
305         }
306         if (std::find(pred->GetSuccsBlocks().begin(), pred->GetSuccsBlocks().end(), block) !=
307             pred->GetSuccsBlocks().end()) {
308             pred->RemoveSucc(block);
309         }
310     }
311     block->GetPredsBlocks().clear();
312 }
313 
314 // Helper for the next 2 methods
FinishBlockRemoval(BasicBlock * block)315 static void FinishBlockRemoval(BasicBlock *block)
316 {
317     auto graph = block->GetGraph();
318     graph->GetAnalysis<DominatorsTree>().SetValid(true);
319     auto dominator = block->GetDominator();
320     if (dominator != nullptr) {
321         dominator->RemoveDominatedBlock(block);
322         for (auto domBlock : block->GetDominatedBlocks()) {
323             ASSERT(domBlock->GetDominator() == block);
324             dominator->AddDominatedBlock(domBlock);
325             domBlock->SetDominator(dominator);
326         }
327     }
328     block->SetDominator(nullptr);
329 
330     block->SetGraph(nullptr);
331     if (graph->GetAnalysis<Rpo>().IsValid()) {
332         graph->GetAnalysis<Rpo>().RemoveBasicBlock(block);
333     }
334 }
335 
336 /// @param block - a block which is disconnecting from the graph with clearing control-flow and data-flow
DisconnectBlock(BasicBlock * block,bool removeLastInst,bool fixDomTree)337 void Graph::DisconnectBlock(BasicBlock *block, bool removeLastInst, bool fixDomTree)
338 {
339     ASSERT(IsAnalysisValid<DominatorsTree>() || !fixDomTree);
340     RemovePredecessors(block, removeLastInst);
341     RemoveSuccessors(block);
342 
343     if (block->IsTryBegin()) {
344         EraseTryBeginBlock(block);
345     }
346 
347     // Remove all instructions from `block`
348     block->Clear();
349 
350     if (block->IsEndBlock()) {
351         SetEndBlock(nullptr);
352     }
353     if (fixDomTree) {
354         FinishBlockRemoval(block);
355     }
356     EraseBlock(block);
357     // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
358 }
359 
DisconnectBlockRec(BasicBlock * block,bool removeLastInst,bool fixDomTree)360 void Graph::DisconnectBlockRec(BasicBlock *block, bool removeLastInst, bool fixDomTree)
361 {
362     ASSERT(block != nullptr);
363     if (block->GetGraph() == nullptr) {
364         return;
365     }
366     bool loopFlag = false;
367     if (block->IsLoopHeader()) {
368         loopFlag = true;
369         auto loop = block->GetLoop();
370         for (auto pred : block->GetPredsBlocks()) {
371             loopFlag &= (std::find(loop->GetBackEdges().begin(), loop->GetBackEdges().end(), pred) !=
372                          loop->GetBackEdges().end());
373         }
374     }
375     if (block->GetPredsBlocks().empty() || loopFlag) {
376         BasicBlock::SuccsVector succs(block->GetSuccsBlocks());
377         DisconnectBlock(block, removeLastInst, fixDomTree);
378         for (auto succ : succs) {
379             DisconnectBlockRec(succ, removeLastInst, fixDomTree);
380         }
381     }
382 }
383 
EraseBlock(BasicBlock * block)384 void Graph::EraseBlock(BasicBlock *block)
385 {
386     vectorBb_[block->GetId()] = nullptr;
387     if (GetEndBlock() == block) {
388         SetEndBlock(nullptr);
389     }
390     ASSERT(GetStartBlock() != block);
391     block->SetGraph(nullptr);
392 }
393 
RestoreBlock(BasicBlock * block)394 void Graph::RestoreBlock(BasicBlock *block)
395 {
396     ASSERT(vectorBb_[block->GetId()] == nullptr);
397     vectorBb_[block->GetId()] = block;
398     block->SetGraph(this);
399     InvalidateBlocksOrderAnalyzes(this);
400 }
401 
402 /// @param block - same for block without instructions at all
RemoveEmptyBlock(BasicBlock * block)403 void Graph::RemoveEmptyBlock(BasicBlock *block)
404 {
405     ASSERT(IsAnalysisValid<DominatorsTree>());
406     ASSERT(block->GetLastInst() == nullptr);
407     ASSERT(block->GetPredsBlocks().empty());
408     ASSERT(block->GetSuccsBlocks().empty());
409 
410     FinishBlockRemoval(block);
411     EraseBlock(block);
412     // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
413 }
414 
415 /// @param block - same for block without instructions, may have Phi(s)
RemoveEmptyBlockWithPhis(BasicBlock * block,bool irrLoop)416 void Graph::RemoveEmptyBlockWithPhis(BasicBlock *block, bool irrLoop)
417 {
418     ASSERT(IsAnalysisValid<DominatorsTree>());
419     ASSERT(block->IsEmpty());
420 
421     ASSERT(!block->GetSuccsBlocks().empty());
422     ASSERT(!block->GetPredsBlocks().empty());
423     block->RemoveEmptyBlock(irrLoop);
424 
425     FinishBlockRemoval(block);
426     EraseBlock(block);
427 }
428 
FindConstant(DataType::Type type,uint64_t value)429 ConstantInst *Graph::FindConstant(DataType::Type type, uint64_t value)
430 {
431     for (auto constant = GetFirstConstInst(); constant != nullptr; constant = constant->GetNextConst()) {
432         if (constant->GetType() != type) {
433             continue;
434         }
435         if (IsBytecodeOptimizer() && IsInt32Bit(type) && (constant->GetInt32Value() == static_cast<uint32_t>(value))) {
436             return constant;
437         }
438         if (constant->IsEqualConst(type, value)) {
439             return constant;
440         }
441     }
442     return nullptr;
443 }
444 
FindOrAddConstant(ConstantInst * inst)445 ConstantInst *Graph::FindOrAddConstant(ConstantInst *inst)
446 {
447     auto existingConst = FindConstant(inst->GetType(), inst->GetRawValue());
448     if (existingConst != nullptr) {
449         return existingConst;
450     }
451     AddConstInStartBlock(inst);
452     inst->SetNextConst(firstConstInst_);
453     firstConstInst_ = inst;
454     return inst;
455 }
456 
GetEncoder()457 Encoder *Graph::GetEncoder()
458 {
459     if (encoder_ == nullptr) {
460         if (IsBytecodeOptimizer()) {
461             return encoder_ = GetAllocator()->New<bytecodeopt::BytecodeEncoder>(GetAllocator());
462         }
463 #if defined(PANDA_WITH_CODEGEN) && !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
464         encoder_ = Encoder::Create(GetAllocator(), GetArch(), g_options.IsCompilerEmitAsm(), IsDynamicMethod());
465 #endif
466     }
467     return encoder_;
468 }
469 
GetRegisters() const470 RegistersDescription *Graph::GetRegisters() const
471 {
472 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
473     return nullptr;
474 #else
475     if (registers_ == nullptr) {
476         registers_ = RegistersDescription::Create(GetAllocator(), GetArch());
477     }
478     return registers_;
479 #endif
480 }
481 
GetCallingConvention()482 CallingConvention *Graph::GetCallingConvention()
483 {
484 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
485     return nullptr;
486 #else
487     if (callconv_ == nullptr) {
488         // We use encoder_ instead of GetEncoder() because we use CallingConvention for ParameterInfo.
489         // This doesn't require an encoder, so we don't create one
490         bool isOptIrtoc = (mode_.IsInterpreter() || mode_.IsInterpreterEntry()) && IsIrtocPrologEpilogOptimized();
491         callconv_ = CallingConvention::Create(GetAllocator(), encoder_, GetRegisters(), GetArch(),
492                                               //   is_panda_abi,      is_osr,           is_dyn
493                                               mode_.SupportManagedCode(), IsOsrMode(),
494                                               IsDynamicMethod() && !GetMode().IsDynamicStub(), false, isOptIrtoc);
495     }
496     return callconv_;
497 #endif
498 }
499 
GetMethodProperties()500 const MethodProperties &Graph::GetMethodProperties()
501 {
502 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
503     UNREACHABLE();
504 #else
505     if (!methodProperties_) {
506         methodProperties_.emplace(this);
507     }
508 #endif
509     return methodProperties_.value();
510 }
511 
ResetParameterInfo()512 void Graph::ResetParameterInfo()
513 {
514 #if defined(PANDA_WITH_CODEGEN) && !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
515     auto callconv = GetCallingConvention();
516     if (callconv == nullptr) {
517         paramInfo_ = nullptr;
518         return;
519     }
520     auto regsReserve = 0;
521     if (GetMode().SupportManagedCode()) {
522         regsReserve++;
523         if (GetMode().IsDynamicMethod() && GetMode().IsDynamicStub()) {
524             regsReserve++;
525         }
526     }
527     paramInfo_ = callconv->GetParameterInfo(regsReserve);
528 #endif
529 }
530 
GetZeroReg() const531 Register Graph::GetZeroReg() const
532 {
533     auto regfile = GetRegisters();
534     if (regfile == nullptr) {
535         return GetInvalidReg();
536     }
537     auto reg = regfile->GetZeroReg();
538     if (reg == INVALID_REGISTER) {
539         return INVALID_REG;
540     }
541     return reg.GetId();
542 }
543 
GetArchTempReg() const544 Register Graph::GetArchTempReg() const
545 {
546     auto tempMask = Target(GetArch()).GetTempRegsMask();
547     for (ssize_t reg = static_cast<ssize_t>(RegMask::Size()) - 1; reg >= 0; reg--) {
548         if (tempMask[reg] && const_cast<Graph *>(this)->GetArchUsedRegs()[reg]) {
549             return reg;
550         }
551     }
552     return INVALID_REG;
553 }
554 
GetArchTempVReg() const555 Register Graph::GetArchTempVReg() const
556 {
557     auto regfile = GetRegisters();
558     if (regfile == nullptr) {
559         return INVALID_REG;
560     }
561     auto regId = regfile->GetTempVReg();
562     if (regId == INVALID_REG_ID) {
563         return INVALID_REG;
564     }
565     return regId;
566 }
567 
GetArchUsedRegs()568 RegMask Graph::GetArchUsedRegs()
569 {
570     auto regfile = GetRegisters();
571     if (regfile == nullptr && archUsedRegs_.None()) {
572         return RegMask();
573     }
574     if (archUsedRegs_.None()) {
575         archUsedRegs_ = regfile->GetRegMask();
576     }
577     return archUsedRegs_;
578 }
579 
SetArchUsedRegs(RegMask mask)580 void Graph::SetArchUsedRegs(RegMask mask)
581 {
582     archUsedRegs_ = mask;
583     auto regs = GetRegisters();
584     ASSERT(regs != nullptr);
585     regs->SetRegMask(mask);
586 }
587 
GetArchUsedVRegs()588 VRegMask Graph::GetArchUsedVRegs()
589 {
590     auto regfile = GetRegisters();
591     if (regfile == nullptr) {
592         return VRegMask();
593     }
594     return regfile->GetVRegMask();
595 }
596 
IsRegScalarMapped() const597 bool Graph::IsRegScalarMapped() const
598 {
599     auto regfile = GetRegisters();
600     if (regfile == nullptr) {
601         return false;
602     }
603     return regfile->SupportMapping(RegMapping::SCALAR_SCALAR);
604 }
605 
HasLoop() const606 bool Graph::HasLoop() const
607 {
608     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
609     return !GetRootLoop()->GetInnerLoops().empty();
610 }
611 
HasIrreducibleLoop() const612 bool Graph::HasIrreducibleLoop() const
613 {
614     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
615     return FlagIrredicibleLoop::Get(bitFields_);
616 }
617 
HasInfiniteLoop() const618 bool Graph::HasInfiniteLoop() const
619 {
620     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
621     return FlagInfiniteLoop::Get(bitFields_);
622 }
623 
HasFloatRegs() const624 bool Graph::HasFloatRegs() const
625 {
626     ASSERT(IsRegAllocApplied());
627     return FlagFloatRegs::Get(bitFields_);
628 }
629 
MarkSuccessBlocks(BasicBlock * block,Marker marker)630 static void MarkSuccessBlocks(BasicBlock *block, Marker marker)
631 {
632     auto loop = block->GetSuccessor(0)->GetLoop();
633     for (size_t i = 1; i < block->GetSuccsBlocks().size(); i++) {
634         if (loop != block->GetSuccessor(i)->GetLoop()) {
635             block->SetMarker(marker);
636         }
637     }
638 }
639 
640 /*
641  * Mark blocks, which have successor from external loop
642  */
MarkLoopExits(const Graph * graph,Marker marker)643 void MarkLoopExits(const Graph *graph, Marker marker)
644 {
645     for (auto block : graph->GetBlocksRPO()) {
646         if (block->GetSuccsBlocks().size() == MAX_SUCCS_NUM) {
647             auto thisLoop = block->GetLoop();
648             auto loop0 = block->GetSuccessor(0)->GetLoop();
649             auto loop1 = block->GetSuccessor(1)->GetLoop();
650             if (loop0 != thisLoop && !loop0->IsInside(thisLoop)) {
651                 block->SetMarker(marker);
652             }
653             if (loop1 != thisLoop && !loop1->IsInside(thisLoop)) {
654                 block->SetMarker(marker);
655             }
656         } else if (block->GetSuccsBlocks().size() > MAX_SUCCS_NUM) {
657             ASSERT(block->IsTryEnd() || block->IsTryBegin() || block->GetLastInst()->GetOpcode() == Opcode::Throw);
658             MarkSuccessBlocks(block, marker);
659         }
660     }
661 }
662 
GetMethodFullName(const Graph * graph,RuntimeInterface::MethodPtr method)663 std::string GetMethodFullName(const Graph *graph, RuntimeInterface::MethodPtr method)
664 {
665     std::stringstream sstream;
666     sstream << graph->GetRuntime()->GetClassNameFromMethod(method)
667             << "::" << graph->GetRuntime()->GetMethodName(method);
668     return sstream.str();
669 }
670 
GetDataForNativeParam(DataType::Type type)671 SpillFillData Graph::GetDataForNativeParam(DataType::Type type)
672 {
673 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
674     (void)type;
675     return {};
676 #else
677     // NOTE(pishin) change to ASSERT
678     if (paramInfo_ == nullptr) {
679         // NOTE(pishin) enable after fixing arch in tests - UNREACHABLE()
680         return {};
681     }
682 
683     auto param = paramInfo_->GetNativeParam(Codegen::ConvertDataType(type, GetArch()));
684     if (std::holds_alternative<Reg>(param)) {
685         auto reg = std::get<Reg>(param);
686         // NOTE! Vector parameter can be put to scalar register in aarch32
687         DataType::Type regType;
688         if (reg.IsFloat()) {
689             regType = DataType::FLOAT64;
690         } else if (reg.GetType() == INT64_TYPE) {
691             regType = DataType::UINT64;
692         } else {
693             regType = DataType::UINT32;
694         }
695         auto loc = reg.IsFloat() ? LocationType::FP_REGISTER : LocationType::REGISTER;
696         return SpillFillData(SpillFillData {loc, LocationType::INVALID, reg.GetId(), GetInvalidReg(), regType});
697     }
698     ASSERT(std::holds_alternative<uint8_t>(param));
699     auto slot = std::get<uint8_t>(param);
700     DataType::Type regType;
701     if (DataType::IsFloatType(type)) {
702         regType = type;
703     } else if (DataType::Is32Bits(type, GetArch())) {
704         regType = DataType::UINT32;
705     } else {
706         regType = DataType::UINT64;
707     }
708     return SpillFillData(
709         SpillFillData {LocationType::STACK_PARAMETER, LocationType::INVALID, slot, GetInvalidReg(), regType});
710 #endif
711 }
712 
713 // NOLINTNEXTLINE(readability-identifier-naming,-warnings-as-errors)
begin()714 Graph::ParameterList::Iterator Graph::ParameterList::begin()
715 {
716     auto startBb = graph_->GetStartBlock();
717     Iterator it(startBb->GetFirstInst());
718     if (*it != nullptr && it->GetOpcode() != Opcode::Parameter) {
719         ++it;
720     }
721     return it;
722 }
723 
RemoveThrowableInst(const Inst * inst)724 void Graph::RemoveThrowableInst(const Inst *inst)
725 {
726     ASSERT(IsInstThrowable(inst));
727     for (auto catchHandler : throwableInsts_.at(inst)) {
728         for (auto catchInst : catchHandler->AllInsts()) {
729             if (!catchInst->IsCatchPhi() || catchInst->CastToCatchPhi()->IsAcc()) {
730                 continue;
731             }
732             auto catchPhi = catchInst->CastToCatchPhi();
733             const auto &vregs = catchPhi->GetThrowableInsts();
734             if (vregs == nullptr || vregs->empty()) {
735                 continue;
736             }
737             auto it = std::find(vregs->begin(), vregs->end(), inst);
738             if (it != vregs->end()) {
739                 int index = std::distance(vregs->begin(), it);
740                 catchPhi->RemoveInput(index);
741             }
742         }
743     }
744     throwableInsts_.erase(inst);
745 }
746 
ReplaceThrowableInst(Inst * oldInst,Inst * newInst)747 void Graph::ReplaceThrowableInst(Inst *oldInst, Inst *newInst)
748 {
749     auto it = throwableInsts_.emplace(newInst, GetAllocator()->Adapter()).first;
750     it->second = std::move(throwableInsts_.at(oldInst));
751 
752     for (auto catchHandler : it->second) {
753         for (auto catchInst : catchHandler->AllInsts()) {
754             if (!catchInst->IsCatchPhi() || catchInst->CastToCatchPhi()->IsAcc()) {
755                 continue;
756             }
757             auto catchPhi = catchInst->CastToCatchPhi();
758             const auto &vregs = catchPhi->GetThrowableInsts();
759             auto iter = std::find(vregs->begin(), vregs->end(), oldInst);
760             if (iter != vregs->end()) {
761                 catchPhi->ReplaceThrowableInst(oldInst, newInst);
762             }
763         }
764     }
765     throwableInsts_.erase(oldInst);
766 }
767 
DumpThrowableInsts(std::ostream * out) const768 void Graph::DumpThrowableInsts(std::ostream *out) const
769 {
770     for (auto &[inst, handlers] : throwableInsts_) {
771         (*out) << "Throwable Inst";
772         inst->Dump(out);
773         (*out) << "Catch handlers:";
774         auto sep = " ";
775         for (auto bb : handlers) {
776             (*out) << sep << "BB " << bb->GetId();
777             sep = ", ";
778         }
779         (*out) << std::endl;
780     }
781 }
782 
InitDefaultLocations()783 void Graph::InitDefaultLocations()
784 {
785     if (IsDefaultLocationsInit()) {
786         return;
787     }
788     VisitAllInstructions([this](Inst *inst) {
789         if (!inst->IsOperandsDynamic() || inst->IsPhi()) {
790             return;
791         }
792         [[maybe_unused]] LocationsInfo *locations = GetAllocator()->New<LocationsInfo>(GetAllocator(), inst);
793         for (size_t i = 0; i < inst->GetInputsCount(); i++) {
794             if (inst->GetInputType(i) != DataType::NO_TYPE) {
795                 locations->SetLocation(i, Location::RequireRegister());
796             }
797         }
798     });
799     SetDefaultLocationsInit();
800 }
801 
GetBranchCounter(const BasicBlock * block,bool trueSucc)802 int64_t Graph::GetBranchCounter(const BasicBlock *block, bool trueSucc)
803 {
804     ASSERT(block->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
805     auto lastInst = block->GetLastInst();
806     ASSERT(lastInst != nullptr);
807     if (lastInst->GetPc() == 0) {
808         return 0;
809     }
810     RuntimeInterface::MethodPtr method;
811     if (lastInst->GetOpcode() == Opcode::IfImm) {
812         method = lastInst->CastToIfImm()->GetMethod();
813     } else if (lastInst->GetOpcode() == Opcode::If) {
814         method = lastInst->CastToIf()->GetMethod();
815     } else {
816         return 0;
817     }
818 
819     if (method == nullptr) {
820         // corresponded branch instruction was not present in bytecode, e.g. IfImmInst was created while inlining
821         return 0;
822     }
823 
824     return block->IsInverted() == trueSucc ? GetRuntime()->GetBranchNotTakenCounter(method, lastInst->GetPc())
825                                            : GetRuntime()->GetBranchTakenCounter(method, lastInst->GetPc());
826 }
827 
GetThrowCounter(const BasicBlock * block)828 int64_t Graph::GetThrowCounter(const BasicBlock *block)
829 {
830     auto lastInst = block->GetLastInst();
831     if (lastInst == nullptr || lastInst->GetOpcode() != Opcode::Throw || lastInst->GetPc() == INVALID_PC) {
832         return 0;
833     }
834 
835     auto method = lastInst->CastToThrow()->GetCallMethod();
836     if (method == nullptr) {
837         return 0;
838     }
839 
840     return GetRuntime()->GetThrowTakenCounter(method, lastInst->GetPc());
841 }
842 
GetParametersSlotsCount() const843 uint32_t Graph::GetParametersSlotsCount() const
844 {
845     uint32_t maxSlot = 0;
846     for (auto paramInst : GetParameters()) {
847         auto location = paramInst->CastToParameter()->GetLocationData().GetSrc();
848         if (location.IsStackParameter()) {
849             maxSlot = location.GetValue() + 1U;
850         }
851     }
852     return maxSlot;
853 }
854 
Dump(std::ostream & stm)855 void GraphMode::Dump(std::ostream &stm)
856 {
857     const char *sep = "";
858 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
859 #define DUMP_MODE(name)                                \
860     if (Is##name()) {                                  \
861         /* CC-OFFNXT(G.PRE.10) function scope macro */ \
862         stm << sep << #name;                           \
863         /* CC-OFFNXT(G.PRE.10) function scope macro */ \
864         sep = ", ";                                    \
865     }
866 
867     DUMP_MODE(Osr);
868     DUMP_MODE(BytecodeOpt);
869     DUMP_MODE(DynamicMethod);
870     DUMP_MODE(Native);
871     DUMP_MODE(FastPath);
872     DUMP_MODE(Boundary);
873     DUMP_MODE(Interpreter);
874     DUMP_MODE(InterpreterEntry);
875     DUMP_MODE(AbcKit);
876 
877 #undef DUMP_MODE
878 }
879 
GetObjectOffset(const Graph * graph,ObjectType objType,RuntimeInterface::FieldPtr field,uint32_t typeId)880 size_t GetObjectOffset(const Graph *graph, ObjectType objType, RuntimeInterface::FieldPtr field, uint32_t typeId)
881 {
882     switch (objType) {
883         case ObjectType::MEM_DYN_GLOBAL:
884             return graph->GetRuntime()->GetPropertyBoxOffset(graph->GetArch());
885         case ObjectType::MEM_DYN_ELEMENTS:
886             return graph->GetRuntime()->GetElementsOffset(graph->GetArch());
887         case ObjectType::MEM_DYN_PROPS:
888             return graph->GetRuntime()->GetPropertiesOffset(graph->GetArch());
889         case ObjectType::MEM_DYN_PROTO_HOLDER:
890             return graph->GetRuntime()->GetPrototypeHolderOffset(graph->GetArch());
891         case ObjectType::MEM_DYN_PROTO_CELL:
892             return graph->GetRuntime()->GetPrototypeCellOffset(graph->GetArch());
893         case ObjectType::MEM_DYN_CHANGE_FIELD:
894             return graph->GetRuntime()->GetIsChangeFieldOffset(graph->GetArch());
895         case ObjectType::MEM_DYN_ARRAY_LENGTH:
896             return graph->GetRuntime()->GetDynArrayLenthOffset(graph->GetArch());
897         case ObjectType::MEM_DYN_INLINED:
898             return typeId;
899         case ObjectType::MEM_DYN_CLASS:
900             return graph->GetRuntime()->GetObjClassOffset(graph->GetArch());
901         case ObjectType::MEM_DYN_METHOD:
902             return graph->GetRuntime()->GetFunctionTargetOffset(graph->GetArch());
903         case ObjectType::MEM_DYN_HCLASS:
904             return graph->GetRuntime()->GetHClassOffset(graph->GetArch());
905         default:
906             return graph->GetRuntime()->GetFieldOffset(field);
907     }
908 }
909 
910 }  // namespace ark::compiler
911