• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 "optimizer/analysis/alias_analysis.h"
21 #include "optimizer/analysis/bounds_analysis.h"
22 #include "optimizer/analysis/dominators_tree.h"
23 #include "optimizer/analysis/rpo.h"
24 #include "optimizer/analysis/linear_order.h"
25 #include "optimizer/analysis/loop_analyzer.h"
26 #if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
27 #include "optimizer/code_generator/callconv.h"
28 #include "optimizer/code_generator/codegen.h"
29 #include "optimizer/code_generator/encode.h"
30 #include "optimizer/code_generator/registers_description.h"
31 #endif
32 
33 namespace panda::compiler {
MarkBlocksRec(Marker mrk,BasicBlock * block)34 static void MarkBlocksRec(Marker mrk, BasicBlock *block)
35 {
36     if (block->SetMarker(mrk)) {
37         return;
38     }
39     for (auto succ : block->GetSuccsBlocks()) {
40         MarkBlocksRec(mrk, succ);
41     }
42 }
43 
~Graph()44 Graph::~Graph()
45 {
46     if (encoder_ != nullptr) {
47         encoder_->~Encoder();
48     }
49 }
50 
RemoveUnreachableBlocks()51 void Graph::RemoveUnreachableBlocks()
52 {
53     Marker mrk = NewMarker();
54     MarkBlocksRec(mrk, GetStartBlock());
55     // Remove unreachable blocks
56     for (auto &bb : *this) {
57         if (bb == nullptr) {
58             continue;
59         }
60         if (!bb->IsMarked(mrk)) {
61             RemovePredecessors(bb, false);
62             RemoveSuccessors(bb);
63             if (bb->IsTryBegin()) {
64                 EraseTryBeginBlock(bb);
65                 // Remove try_end mark from paired bb
66                 if (!bb->IsEmpty()) {
67                     GetTryBeginInst(bb)->GetTryEndBlock()->SetTryEnd(false);
68                 }
69             }
70             // Clear DF:
71             for (auto inst : bb->AllInsts()) {
72                 inst->RemoveInputs();
73                 if (IsInstThrowable(inst)) {
74                     RemoveThrowableInst(inst);
75                 }
76             }
77             EraseBlock(bb);
78         }
79     }
80     EraseMarker(mrk);
81 }
82 
AddConstInStartBlock(ConstantInst * const_inst)83 void Graph::AddConstInStartBlock(ConstantInst *const_inst)
84 {
85     GetStartBlock()->AppendInst(const_inst);
86 }
87 
AddNewParameter(uint16_t arg_number)88 ParameterInst *Graph::AddNewParameter(uint16_t arg_number)
89 {
90     ParameterInst *param = CreateInstParameter(arg_number);
91     GetStartBlock()->AppendInst(param);
92     return param;
93 }
94 
GetOrCreateNullPtr()95 Inst *Graph::GetOrCreateNullPtr()
96 {
97     if (nullptr_inst_ == nullptr) {
98         nullptr_inst_ = CreateInstNullPtr();
99         nullptr_inst_->SetType(DataType::REFERENCE);
100         GetStartBlock()->AppendInst(nullptr_inst_);
101     }
102     return nullptr_inst_;
103 }
104 
RemoveConstFromList(ConstantInst * const_inst)105 void Graph::RemoveConstFromList(ConstantInst *const_inst)
106 {
107     if (const_inst == first_const_inst_) {
108         first_const_inst_ = const_inst->GetNextConst();
109         const_inst->SetNextConst(nullptr);
110         return;
111     }
112     auto current = first_const_inst_;
113     auto next = current->GetNextConst();
114     while (next != nullptr && next != const_inst) {
115         current = next;
116         next = next->GetNextConst();
117     }
118     ASSERT(next != nullptr);
119     ASSERT(next == const_inst);
120     current->SetNextConst(const_inst->GetNextConst());
121     const_inst->SetNextConst(nullptr);
122 }
123 
InvalidateBlocksOrderAnalyzes(Graph * graph)124 void InvalidateBlocksOrderAnalyzes(Graph *graph)
125 {
126     graph->InvalidateAnalysis<Rpo>();
127     graph->InvalidateAnalysis<DominatorsTree>();
128     graph->InvalidateAnalysis<LinearOrder>();
129 }
130 
AddBlock(BasicBlock * block)131 void Graph::AddBlock(BasicBlock *block)
132 {
133     block->SetId(vector_bb_.size());
134     vector_bb_.push_back(block);
135     block->SetGraph(this);
136     InvalidateBlocksOrderAnalyzes(this);
137 }
138 
139 #ifndef NDEBUG
AddBlock(BasicBlock * block,uint32_t id)140 void Graph::AddBlock(BasicBlock *block, uint32_t id)
141 {
142     if (vector_bb_.size() <= id) {
143         // (id + 1) for adding a block with index 0
144         vector_bb_.resize((id + 1U) << 1U, nullptr);
145     }
146     ASSERT(vector_bb_[id] == nullptr);
147     block->SetId(id);
148     vector_bb_[id] = block;
149     InvalidateBlocksOrderAnalyzes(this);
150 }
151 #endif
152 
GetBoundsRangeInfo() const153 const BoundsRangeInfo *Graph::GetBoundsRangeInfo() const
154 {
155     return GetValidAnalysis<BoundsAnalysis>().GetBoundsRangeInfo();
156 }
157 
GetBlocksRPO() const158 const ArenaVector<BasicBlock *> &Graph::GetBlocksRPO() const
159 {
160     return GetValidAnalysis<Rpo>().GetBlocks();
161 }
162 
GetBlocksLinearOrder() const163 const ArenaVector<BasicBlock *> &Graph::GetBlocksLinearOrder() const
164 {
165     return GetValidAnalysis<LinearOrder>().GetBlocks();
166 }
167 
168 template <class Callback>
VisitAllInstructions(Callback callback)169 void Graph::VisitAllInstructions(Callback callback)
170 {
171     for (auto bb : GetBlocksRPO()) {
172         for (auto inst : bb->AllInsts()) {
173             callback(inst);
174         }
175     }
176 }
177 
CheckInstAlias(Inst * mem1,Inst * mem2)178 AliasType Graph::CheckInstAlias(Inst *mem1, Inst *mem2)
179 {
180     return GetValidAnalysis<AliasAnalysis>().CheckInstAlias(mem1, mem2);
181 }
182 
CreateEmptyBlock(uint32_t guest_pc)183 BasicBlock *Graph::CreateEmptyBlock(uint32_t guest_pc)
184 {
185     auto block = GetAllocator()->New<BasicBlock>(this, guest_pc);
186     AddBlock(block);
187     return block;
188 }
189 
190 // Create empty block with base block's properties
CreateEmptyBlock(BasicBlock * base_block)191 BasicBlock *Graph::CreateEmptyBlock(BasicBlock *base_block)
192 {
193     ASSERT(base_block != nullptr);
194     auto block = CreateEmptyBlock();
195     block->SetGuestPc(base_block->GetGuestPc());
196     block->SetAllFields(base_block->GetAllFields());
197     block->SetTryId(base_block->GetTryId());
198     return block;
199 }
200 
201 #ifndef NDEBUG
CreateEmptyBlock(uint32_t id,uint32_t guest_pc)202 BasicBlock *Graph::CreateEmptyBlock(uint32_t id, uint32_t guest_pc)
203 {
204     auto block = GetAllocator()->New<BasicBlock>(this, guest_pc);
205     AddBlock(block, id);
206     return block;
207 }
208 #endif
209 
CreateStartBlock()210 BasicBlock *Graph::CreateStartBlock()
211 {
212     auto block = CreateEmptyBlock(0U);
213     SetStartBlock(block);
214     return block;
215 }
216 
CreateEndBlock(uint32_t guest_pc)217 BasicBlock *Graph::CreateEndBlock(uint32_t guest_pc)
218 {
219     auto block = CreateEmptyBlock(guest_pc);
220     SetEndBlock(block);
221     return block;
222 }
223 
RemovePredecessorUpdateDF(BasicBlock * block,BasicBlock * rm_pred)224 void RemovePredecessorUpdateDF(BasicBlock *block, BasicBlock *rm_pred)
225 {
226     constexpr auto IMM_2 = 2;
227     if (block->GetPredsBlocks().size() == IMM_2) {
228         for (auto phi : block->PhiInstsSafe()) {
229             auto rm_index = phi->CastToPhi()->GetPredBlockIndex(rm_pred);
230             auto remaining_inst = phi->GetInput(1 - rm_index).GetInst();
231             if (phi != remaining_inst && remaining_inst->GetBasicBlock() != nullptr) {
232                 phi->ReplaceUsers(remaining_inst);
233             }
234             block->RemoveInst(phi);
235         }
236     } else if (block->GetPredsBlocks().size() > IMM_2) {
237         for (auto phi : block->PhiInstsSafe()) {
238             auto rm_index = phi->CastToPhi()->GetPredBlockIndex(rm_pred);
239             phi->CastToPhi()->RemoveInput(rm_index);
240         }
241     } else {
242         ASSERT(block->GetPredsBlocks().size() == 1);
243     }
244     block->RemovePred(rm_pred);
245     InvalidateBlocksOrderAnalyzes(block->GetGraph());
246 }
247 
248 /*
249  * Remove edges between `block` and its successors and
250  * update phi-instructions in successors blocks
251  */
RemoveSuccessors(BasicBlock * block)252 void Graph::RemoveSuccessors(BasicBlock *block)
253 {
254     for (auto succ : block->GetSuccsBlocks()) {
255         RemovePredecessorUpdateDF(succ, block);
256     }
257     block->GetSuccsBlocks().clear();
258 }
259 
260 /*
261  * Remove edges between `block` and its predecessors,
262  * update last instructions in predecessors blocks
263  */
RemovePredecessors(BasicBlock * block,bool remove_last_inst)264 void Graph::RemovePredecessors(BasicBlock *block, bool remove_last_inst)
265 {
266     for (auto pred : block->GetPredsBlocks()) {
267         if (remove_last_inst && !pred->IsTryBegin() && !pred->IsTryEnd()) {
268             if (pred->GetSuccsBlocks().size() == 2U) {
269                 auto last = pred->GetLastInst();
270                 ASSERT(last->GetOpcode() == Opcode::If || last->GetOpcode() == Opcode::IfImm ||
271                        last->GetOpcode() == Opcode::AddOverflow || last->GetOpcode() == Opcode::SubOverflow);
272                 pred->RemoveInst(last);
273             } else {
274                 ASSERT(pred->GetSuccsBlocks().size() == 1 && pred->GetSuccessor(0) == block);
275             }
276         }
277         if (std::find(pred->GetSuccsBlocks().begin(), pred->GetSuccsBlocks().end(), block) !=
278             pred->GetSuccsBlocks().end()) {
279             pred->RemoveSucc(block);
280         }
281     }
282     block->GetPredsBlocks().clear();
283 }
284 
285 // Helper for the next 2 methods
FinishBlockRemoval(BasicBlock * block)286 static void FinishBlockRemoval(BasicBlock *block)
287 {
288     auto graph = block->GetGraph();
289     graph->GetAnalysis<DominatorsTree>().SetValid(true);
290     auto dominator = block->GetDominator();
291     if (dominator != nullptr) {
292         dominator->RemoveDominatedBlock(block);
293         for (auto dom_block : block->GetDominatedBlocks()) {
294             ASSERT(dom_block->GetDominator() == block);
295             dominator->AddDominatedBlock(dom_block);
296             dom_block->SetDominator(dominator);
297         }
298     }
299     block->SetDominator(nullptr);
300 
301     block->SetGraph(nullptr);
302     if (graph->GetAnalysis<Rpo>().IsValid()) {
303         graph->GetAnalysis<Rpo>().RemoveBasicBlock(block);
304     }
305 }
306 
307 /**
308  * @param block - a block which is disconnecting from the graph with clearing control-flow and data-flow
309  */
DisconnectBlock(BasicBlock * block,bool remove_last_inst,bool fix_dom_tree)310 void Graph::DisconnectBlock(BasicBlock *block, bool remove_last_inst, bool fix_dom_tree)
311 {
312     ASSERT(IsAnalysisValid<DominatorsTree>() || !fix_dom_tree);
313     RemovePredecessors(block, remove_last_inst);
314     RemoveSuccessors(block);
315 
316     if (block->IsTryBegin()) {
317         EraseTryBeginBlock(block);
318     }
319 
320     // Remove all instructions from `block`
321     block->Clear();
322 
323     if (block->IsEndBlock()) {
324         SetEndBlock(nullptr);
325     }
326     if (fix_dom_tree) {
327         FinishBlockRemoval(block);
328     }
329     EraseBlock(block);
330     // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
331 }
332 
DisconnectBlockRec(BasicBlock * block,bool remove_last_inst,bool fix_dom_tree)333 void Graph::DisconnectBlockRec(BasicBlock *block, bool remove_last_inst, bool fix_dom_tree)
334 {
335     if (block->GetGraph() == nullptr) {
336         return;
337     }
338     bool loop_flag = false;
339     if (block->IsLoopHeader()) {
340         loop_flag = true;
341         auto loop = block->GetLoop();
342         for (auto pred : block->GetPredsBlocks()) {
343             loop_flag &= (std::find(loop->GetBackEdges().begin(), loop->GetBackEdges().end(), pred) !=
344                           loop->GetBackEdges().end());
345         }
346     }
347     if (block->GetPredsBlocks().empty() || loop_flag) {
348         ArenaVector<BasicBlock *> succs(block->GetSuccsBlocks(), GetLocalAllocator()->Adapter());
349         DisconnectBlock(block, remove_last_inst, fix_dom_tree);
350         for (auto succ : succs) {
351             DisconnectBlockRec(succ, remove_last_inst, fix_dom_tree);
352         }
353     }
354 }
355 
EraseBlock(BasicBlock * block)356 void Graph::EraseBlock(BasicBlock *block)
357 {
358     vector_bb_[block->GetId()] = nullptr;
359     if (GetEndBlock() == block) {
360         SetEndBlock(nullptr);
361     }
362     ASSERT(GetStartBlock() != block);
363     block->SetGraph(nullptr);
364 }
365 
RestoreBlock(BasicBlock * block)366 void Graph::RestoreBlock(BasicBlock *block)
367 {
368     ASSERT(vector_bb_[block->GetId()] == nullptr);
369     vector_bb_[block->GetId()] = block;
370     block->SetGraph(this);
371     InvalidateBlocksOrderAnalyzes(this);
372 }
373 
374 /**
375  * @param block - same for block without instructions at all
376  */
RemoveEmptyBlock(BasicBlock * block)377 void Graph::RemoveEmptyBlock(BasicBlock *block)
378 {
379     ASSERT(IsAnalysisValid<DominatorsTree>());
380     ASSERT(block->GetLastInst() == nullptr);
381     ASSERT(block->GetPredsBlocks().empty());
382     ASSERT(block->GetSuccsBlocks().empty());
383 
384     FinishBlockRemoval(block);
385     EraseBlock(block);
386     // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
387 }
388 
389 /**
390  * @param block - same for block without instructions, may have Phi(s)
391  */
RemoveEmptyBlockWithPhis(BasicBlock * block,bool irr_loop)392 void Graph::RemoveEmptyBlockWithPhis(BasicBlock *block, bool irr_loop)
393 {
394     ASSERT(IsAnalysisValid<DominatorsTree>());
395     ASSERT(block->IsEmpty());
396 
397     ASSERT(!block->GetSuccsBlocks().empty());
398     ASSERT(!block->GetPredsBlocks().empty());
399     block->RemoveEmptyBlock(irr_loop);
400 
401     FinishBlockRemoval(block);
402     EraseBlock(block);
403 }
404 
FindConstant(DataType::Type type,uint64_t value)405 ConstantInst *Graph::FindConstant(DataType::Type type, uint64_t value)
406 {
407     for (auto constant = GetFirstConstInst(); constant != nullptr; constant = constant->GetNextConst()) {
408         if (constant->GetType() != type) {
409             continue;
410         }
411         if (IsBytecodeOptimizer() && IsInt32Bit(type) && (constant->GetInt32Value() == static_cast<uint32_t>(value))) {
412             return constant;
413         }
414         if (constant->IsEqualConst(type, value)) {
415             return constant;
416         }
417     }
418     return nullptr;
419 }
420 
FindOrAddConstant(ConstantInst * inst)421 ConstantInst *Graph::FindOrAddConstant(ConstantInst *inst)
422 {
423     auto existing_const = FindConstant(inst->GetType(), inst->GetRawValue());
424     if (existing_const != nullptr) {
425         return existing_const;
426     }
427     AddConstInStartBlock(inst);
428     inst->SetNextConst(first_const_inst_);
429     first_const_inst_ = inst;
430     return inst;
431 }
432 
GetEncoder()433 Encoder *Graph::GetEncoder()
434 {
435     if (encoder_ == nullptr) {
436         if (IsBytecodeOptimizer()) {
437             return encoder_ = GetAllocator()->New<bytecodeopt::BytecodeEncoder>(GetAllocator());
438         }
439     }
440     return encoder_;
441 }
442 
GetRegisters() const443 RegistersDescription *Graph::GetRegisters() const
444 {
445     return registers_;
446 }
447 
GetCallingConvention()448 CallingConvention *Graph::GetCallingConvention()
449 {
450     return callconv_;
451 }
452 
GetMethodProperties()453 const MethodProperties &Graph::GetMethodProperties()
454 {
455     return method_properties_.value();
456 }
457 
ResetParameterInfo()458 void Graph::ResetParameterInfo()
459 {
460     param_info_ = nullptr;
461     return;
462 }
463 
GetZeroReg() const464 Register Graph::GetZeroReg() const
465 {
466     auto regfile = GetRegisters();
467     if (regfile == nullptr) {
468         return INVALID_REG;
469     }
470     auto reg = regfile->GetZeroReg();
471     if (reg == INVALID_REGISTER) {
472         return INVALID_REG;
473     }
474     return reg.GetId();
475 }
476 
GetArchTempReg() const477 Register Graph::GetArchTempReg() const
478 {
479     auto temp_mask = Target(GetArch()).GetTempRegsMask();
480     for (ssize_t reg = RegMask::Size() - 1; reg >= 0; reg--) {
481         if (temp_mask[reg] && const_cast<Graph *>(this)->GetArchUsedRegs()[reg]) {
482             return reg;
483         }
484     }
485     return INVALID_REG;
486 }
487 
GetArchTempVReg() const488 Register Graph::GetArchTempVReg() const
489 {
490     auto regfile = GetRegisters();
491     if (regfile == nullptr) {
492         return INVALID_REG;
493     }
494     auto reg_id = regfile->GetTempVReg();
495     if (reg_id == INVALID_REG_ID) {
496         return INVALID_REG;
497     }
498     return reg_id;
499 }
500 
GetArchUsedRegs()501 RegMask Graph::GetArchUsedRegs()
502 {
503     auto regfile = GetRegisters();
504     if (regfile == nullptr && arch_used_regs_.None()) {
505         return RegMask();
506     }
507     if (arch_used_regs_.None()) {
508         arch_used_regs_ = regfile->GetRegMask();
509     }
510     return arch_used_regs_;
511 }
512 
SetArchUsedRegs(RegMask mask)513 void Graph::SetArchUsedRegs(RegMask mask)
514 {
515     arch_used_regs_ = mask;
516     GetRegisters()->SetRegMask(mask);
517 }
518 
GetArchUsedVRegs()519 VRegMask Graph::GetArchUsedVRegs()
520 {
521     auto regfile = GetRegisters();
522     if (regfile == nullptr) {
523         return VRegMask();
524     }
525     return regfile->GetVRegMask();
526 }
527 
IsRegScalarMapped() const528 bool Graph::IsRegScalarMapped() const
529 {
530     auto regfile = GetRegisters();
531     if (regfile == nullptr) {
532         return false;
533     }
534     return regfile->SupportMapping(RegMapping::SCALAR_SCALAR);
535 }
536 
HasLoop() const537 bool Graph::HasLoop() const
538 {
539     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
540     return !GetRootLoop()->GetInnerLoops().empty();
541 }
542 
HasIrreducibleLoop() const543 bool Graph::HasIrreducibleLoop() const
544 {
545     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
546     return FlagIrredicibleLoop::Get(bit_fields_);
547 }
548 
HasInfiniteLoop() const549 bool Graph::HasInfiniteLoop() const
550 {
551     ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
552     return FlagInfiniteLoop::Get(bit_fields_);
553 }
554 
HasFloatRegs() const555 bool Graph::HasFloatRegs() const
556 {
557     ASSERT(IsRegAllocApplied());
558     return FlagFloatRegs::Get(bit_fields_);
559 }
560 
561 /*
562  * Mark blocks, which have successor from external loop
563  */
MarkLoopExits(const Graph * graph,Marker marker)564 void MarkLoopExits(const Graph *graph, Marker marker)
565 {
566     for (auto block : graph->GetBlocksRPO()) {
567         if (block->GetSuccsBlocks().size() == MAX_SUCCS_NUM) {
568             if (block->GetSuccessor(0)->GetLoop() != block->GetSuccessor(1)->GetLoop()) {
569                 block->SetMarker(marker);
570             }
571         } else if (block->GetSuccsBlocks().size() > MAX_SUCCS_NUM) {
572             ASSERT(block->IsTryEnd() || block->IsTryBegin() || block->GetLastInst()->GetOpcode() == Opcode::Throw);
573             auto loop = block->GetSuccessor(0)->GetLoop();
574             for (size_t i = 1; i < block->GetSuccsBlocks().size(); i++) {
575                 if (loop != block->GetSuccessor(i)->GetLoop()) {
576                     block->SetMarker(marker);
577                 }
578             }
579         }
580     }
581 }
582 
GetMethodFullName(const Graph * graph,RuntimeInterface::MethodPtr method)583 std::string GetMethodFullName(const Graph *graph, RuntimeInterface::MethodPtr method)
584 {
585     std::stringstream sstream;
586     sstream << graph->GetRuntime()->GetClassNameFromMethod(method)
587             << "::" << graph->GetRuntime()->GetMethodName(method);
588     return sstream.str();
589 }
590 
GetDataForNativeParam(DataType::Type type)591 SpillFillData Graph::GetDataForNativeParam(DataType::Type type)
592 {
593 #if defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
594     (void)type;
595     return {};
596 #else
597     // TODO(pishin) change to ASSERT
598     if (param_info_ == nullptr) {
599         // TODO(pishin) enable after fixing arch in tests - UNREACHABLE()
600         return {};
601     }
602 
603     auto param = param_info_->GetNativeParam(Codegen::ConvertDataType(type, GetArch()));
604 
605     if (std::holds_alternative<Reg>(param)) {
606         auto reg = std::get<Reg>(param);
607         // NOTE! Vector parameter can be put to scalar register in aarch32
608         DataType::Type reg_type;
609         if (reg.IsFloat()) {
610             reg_type = DataType::FLOAT64;
611         } else if (reg.GetType() == INT64_TYPE) {
612             reg_type = DataType::UINT64;
613         } else {
614             reg_type = DataType::UINT32;
615         }
616         auto loc = reg.IsFloat() ? LocationType::FP_REGISTER : LocationType::REGISTER;
617         return SpillFillData(SpillFillData {loc, LocationType::INVALID, reg.GetId(), INVALID_REG, reg_type});
618     }
619     ASSERT(std::holds_alternative<uint8_t>(param));
620     auto slot = std::get<uint8_t>(param);
621     DataType::Type reg_type;
622     if (DataType::IsFloatType(type)) {
623         reg_type = type;
624     } else if (DataType::Is32Bits(type, GetArch())) {
625         reg_type = DataType::UINT32;
626     } else {
627         reg_type = DataType::UINT64;
628     }
629     return SpillFillData(
630         SpillFillData {LocationType::STACK_PARAMETER, LocationType::INVALID, slot, INVALID_REG, reg_type});
631 #endif
632 }
633 
634 // NOLINTNEXTLINE(readability-identifier-naming,-warnings-as-errors)
begin()635 Graph::ParameterList::Iterator Graph::ParameterList::begin()
636 {
637     auto start_bb = graph_->GetStartBlock();
638     Iterator it(start_bb->GetFirstInst());
639     if (*it != nullptr && it->GetOpcode() != Opcode::Parameter) {
640         ++it;
641     }
642     return it;
643 }
644 
RemoveThrowableInst(const Inst * inst)645 void Graph::RemoveThrowableInst(const Inst *inst)
646 {
647     ASSERT(IsInstThrowable(inst));
648     for (auto catch_handler : throwable_insts_.at(inst)) {
649         for (auto catch_inst : catch_handler->AllInsts()) {
650             if (!catch_inst->IsCatchPhi() || catch_inst->CastToCatchPhi()->IsAcc()) {
651                 continue;
652             }
653             auto catch_phi = catch_inst->CastToCatchPhi();
654             const auto &vregs = catch_phi->GetThrowableInsts();
655             auto it = std::find(vregs->begin(), vregs->end(), inst);
656             if (it != vregs->end()) {
657                 int index = std::distance(vregs->begin(), it);
658                 catch_phi->RemoveInput(index);
659             }
660         }
661     }
662     throwable_insts_.erase(inst);
663 }
664 
ReplaceThrowableInst(Inst * old_inst,Inst * new_inst)665 void Graph::ReplaceThrowableInst(Inst *old_inst, Inst *new_inst)
666 {
667     auto it = throwable_insts_.emplace(new_inst, GetAllocator()->Adapter()).first;
668     it->second = std::move(throwable_insts_.at(old_inst));
669 
670     for (auto catch_handler : it->second) {
671         for (auto catch_inst : catch_handler->AllInsts()) {
672             if (!catch_inst->IsCatchPhi() || catch_inst->CastToCatchPhi()->IsAcc()) {
673                 continue;
674             }
675             auto catch_phi = catch_inst->CastToCatchPhi();
676             const auto &vregs = catch_phi->GetThrowableInsts();
677             auto iter = std::find(vregs->begin(), vregs->end(), old_inst);
678             if (iter != vregs->end()) {
679                 catch_phi->ReplaceThrowableInst(old_inst, new_inst);
680             }
681         }
682     }
683     throwable_insts_.erase(old_inst);
684 }
685 
DumpThrowableInsts(std::ostream * out) const686 void Graph::DumpThrowableInsts(std::ostream *out) const
687 {
688     for (auto &[inst, handlers] : throwable_insts_) {
689         (*out) << "Throwable Inst";
690         inst->Dump(out);
691         (*out) << "Catch handlers:";
692         auto sep = " ";
693         for (auto bb : handlers) {
694             (*out) << sep << "BB " << bb->GetId();
695             sep = ", ";
696         }
697         (*out) << std::endl;
698     }
699 }
700 
InitDefaultLocations()701 void Graph::InitDefaultLocations()
702 {
703     if (IsDefaultLocationsInit()) {
704         return;
705     }
706     VisitAllInstructions([this](Inst *inst) {
707         if (!inst->IsOperandsDynamic() || inst->IsPhi()) {
708             return;
709         }
710         [[maybe_unused]] LocationsInfo *locations = GetAllocator()->New<LocationsInfo>(GetAllocator(), inst);
711         for (size_t i = 0; i < inst->GetInputsCount(); i++) {
712             if (inst->GetInputType(i) != DataType::NO_TYPE) {
713                 locations->SetLocation(i, Location::RequireRegister());
714             }
715         }
716     });
717     SetDefaultLocationsInit();
718 }
719 
GetBranchCounter(const BasicBlock * block,bool true_succ)720 int64_t Graph::GetBranchCounter(const BasicBlock *block, bool true_succ)
721 {
722     ASSERT(block->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
723     auto last_inst = block->GetLastInst();
724     RuntimeInterface::MethodPtr method;
725     if (last_inst->GetOpcode() == Opcode::IfImm) {
726         method = last_inst->CastToIfImm()->GetMethod();
727     } else if (last_inst->GetOpcode() == Opcode::If) {
728         method = last_inst->CastToIf()->GetMethod();
729     } else {
730         return 0;
731     }
732 
733     if (method == nullptr) {
734         // corresponded branch instruction was not present in bytecode, e.g. IfImmInst was created while inlining
735         return 0;
736     }
737 
738     return block->IsInverted() == true_succ ? GetRuntime()->GetBranchNotTakenCounter(method, last_inst->GetPc())
739                                             : GetRuntime()->GetBranchTakenCounter(method, last_inst->GetPc());
740 }
741 
GetParametersSlotsCount() const742 uint32_t Graph::GetParametersSlotsCount() const
743 {
744     uint32_t max_slot = 0;
745     for (auto param_inst : GetParameters()) {
746         auto location = param_inst->CastToParameter()->GetLocationData().GetSrc();
747         if (location.IsStackParameter()) {
748             max_slot = location.GetValue() + 1U;
749         }
750     }
751     return max_slot;
752 }
753 
Dump(std::ostream & stm)754 void GraphMode::Dump(std::ostream &stm)
755 {
756     const char *sep = "";
757 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
758 #define DUMP_MODE(name)      \
759     if (Is##name()) {        \
760         stm << sep << #name; \
761         sep = ", ";          \
762     }
763 
764     DUMP_MODE(Osr);
765     DUMP_MODE(BytecodeOpt);
766     DUMP_MODE(DynamicMethod);
767     DUMP_MODE(Native);
768     DUMP_MODE(FastPath);
769     DUMP_MODE(Boundary);
770     DUMP_MODE(Interpreter);
771     DUMP_MODE(InterpreterEntry);
772 }
773 
774 }  // namespace panda::compiler
775