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