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