1 /*
2 * Copyright (c) 2021-2023 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 panda::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 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 pred->RemoveInst(last);
299 } else {
300 ASSERT(pred->GetSuccsBlocks().size() == 1 && pred->GetSuccessor(0) == block);
301 }
302 }
303 if (std::find(pred->GetSuccsBlocks().begin(), pred->GetSuccsBlocks().end(), block) !=
304 pred->GetSuccsBlocks().end()) {
305 pred->RemoveSucc(block);
306 }
307 }
308 block->GetPredsBlocks().clear();
309 }
310
311 // Helper for the next 2 methods
FinishBlockRemoval(BasicBlock * block)312 static void FinishBlockRemoval(BasicBlock *block)
313 {
314 auto graph = block->GetGraph();
315 graph->GetAnalysis<DominatorsTree>().SetValid(true);
316 auto dominator = block->GetDominator();
317 if (dominator != nullptr) {
318 dominator->RemoveDominatedBlock(block);
319 for (auto domBlock : block->GetDominatedBlocks()) {
320 ASSERT(domBlock->GetDominator() == block);
321 dominator->AddDominatedBlock(domBlock);
322 domBlock->SetDominator(dominator);
323 }
324 }
325 block->SetDominator(nullptr);
326
327 block->SetGraph(nullptr);
328 if (graph->GetAnalysis<Rpo>().IsValid()) {
329 graph->GetAnalysis<Rpo>().RemoveBasicBlock(block);
330 }
331 }
332
333 /// @param block - a block which is disconnecting from the graph with clearing control-flow and data-flow
DisconnectBlock(BasicBlock * block,bool removeLastInst,bool fixDomTree)334 void Graph::DisconnectBlock(BasicBlock *block, bool removeLastInst, bool fixDomTree)
335 {
336 ASSERT(IsAnalysisValid<DominatorsTree>() || !fixDomTree);
337 RemovePredecessors(block, removeLastInst);
338 RemoveSuccessors(block);
339
340 if (block->IsTryBegin()) {
341 EraseTryBeginBlock(block);
342 }
343
344 // Remove all instructions from `block`
345 block->Clear();
346
347 if (block->IsEndBlock()) {
348 SetEndBlock(nullptr);
349 }
350 if (fixDomTree) {
351 FinishBlockRemoval(block);
352 }
353 EraseBlock(block);
354 // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
355 }
356
DisconnectBlockRec(BasicBlock * block,bool removeLastInst,bool fixDomTree)357 void Graph::DisconnectBlockRec(BasicBlock *block, bool removeLastInst, bool fixDomTree)
358 {
359 if (block->GetGraph() == nullptr) {
360 return;
361 }
362 bool loopFlag = false;
363 if (block->IsLoopHeader()) {
364 loopFlag = true;
365 auto loop = block->GetLoop();
366 for (auto pred : block->GetPredsBlocks()) {
367 loopFlag &= (std::find(loop->GetBackEdges().begin(), loop->GetBackEdges().end(), pred) !=
368 loop->GetBackEdges().end());
369 }
370 }
371 if (block->GetPredsBlocks().empty() || loopFlag) {
372 ArenaVector<BasicBlock *> succs(block->GetSuccsBlocks(), GetLocalAllocator()->Adapter());
373 DisconnectBlock(block, removeLastInst, fixDomTree);
374 for (auto succ : succs) {
375 DisconnectBlockRec(succ, removeLastInst, fixDomTree);
376 }
377 }
378 }
379
EraseBlock(BasicBlock * block)380 void Graph::EraseBlock(BasicBlock *block)
381 {
382 vectorBb_[block->GetId()] = nullptr;
383 if (GetEndBlock() == block) {
384 SetEndBlock(nullptr);
385 }
386 ASSERT(GetStartBlock() != block);
387 block->SetGraph(nullptr);
388 }
389
RestoreBlock(BasicBlock * block)390 void Graph::RestoreBlock(BasicBlock *block)
391 {
392 ASSERT(vectorBb_[block->GetId()] == nullptr);
393 vectorBb_[block->GetId()] = block;
394 block->SetGraph(this);
395 InvalidateBlocksOrderAnalyzes(this);
396 }
397
398 /// @param block - same for block without instructions at all
RemoveEmptyBlock(BasicBlock * block)399 void Graph::RemoveEmptyBlock(BasicBlock *block)
400 {
401 ASSERT(IsAnalysisValid<DominatorsTree>());
402 ASSERT(block->GetLastInst() == nullptr);
403 ASSERT(block->GetPredsBlocks().empty());
404 ASSERT(block->GetSuccsBlocks().empty());
405
406 FinishBlockRemoval(block);
407 EraseBlock(block);
408 // NB! please do not forget to fix LoopAnalyzer or invalidate it after the end of the pass
409 }
410
411 /// @param block - same for block without instructions, may have Phi(s)
RemoveEmptyBlockWithPhis(BasicBlock * block,bool irrLoop)412 void Graph::RemoveEmptyBlockWithPhis(BasicBlock *block, bool irrLoop)
413 {
414 ASSERT(IsAnalysisValid<DominatorsTree>());
415 ASSERT(block->IsEmpty());
416
417 ASSERT(!block->GetSuccsBlocks().empty());
418 ASSERT(!block->GetPredsBlocks().empty());
419 block->RemoveEmptyBlock(irrLoop);
420
421 FinishBlockRemoval(block);
422 EraseBlock(block);
423 }
424
FindConstant(DataType::Type type,uint64_t value)425 ConstantInst *Graph::FindConstant(DataType::Type type, uint64_t value)
426 {
427 for (auto constant = GetFirstConstInst(); constant != nullptr; constant = constant->GetNextConst()) {
428 if (constant->GetType() != type) {
429 continue;
430 }
431 if (IsBytecodeOptimizer() && IsInt32Bit(type) && (constant->GetInt32Value() == static_cast<uint32_t>(value))) {
432 return constant;
433 }
434 if (constant->IsEqualConst(type, value)) {
435 return constant;
436 }
437 }
438 return nullptr;
439 }
440
FindOrAddConstant(ConstantInst * inst)441 ConstantInst *Graph::FindOrAddConstant(ConstantInst *inst)
442 {
443 auto existingConst = FindConstant(inst->GetType(), inst->GetRawValue());
444 if (existingConst != nullptr) {
445 return existingConst;
446 }
447 AddConstInStartBlock(inst);
448 inst->SetNextConst(firstConstInst_);
449 firstConstInst_ = inst;
450 return inst;
451 }
452
GetEncoder()453 Encoder *Graph::GetEncoder()
454 {
455 if (encoder_ == nullptr) {
456 if (IsBytecodeOptimizer()) {
457 return encoder_ = GetAllocator()->New<bytecodeopt::BytecodeEncoder>(GetAllocator());
458 }
459 #if defined(PANDA_WITH_CODEGEN) && !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
460 encoder_ = Encoder::Create(GetAllocator(), GetArch(), g_options.IsCompilerEmitAsm(), IsDynamicMethod());
461 #endif
462 }
463 return encoder_;
464 }
465
GetRegisters() const466 RegistersDescription *Graph::GetRegisters() const
467 {
468 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
469 return nullptr;
470 #else
471 if (registers_ == nullptr) {
472 registers_ = RegistersDescription::Create(GetAllocator(), GetArch());
473 }
474 return registers_;
475 #endif
476 }
477
GetCallingConvention()478 CallingConvention *Graph::GetCallingConvention()
479 {
480 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
481 return nullptr;
482 #else
483 if (callconv_ == nullptr) {
484 // We use encoder_ instead of GetEncoder() because we use CallingConvention for ParameterInfo.
485 // This doesn't require an encoder, so we don't create one
486 bool isOptIrtoc = (mode_.IsInterpreter() || mode_.IsInterpreterEntry()) && IsIrtocPrologEpilogOptimized();
487 callconv_ = CallingConvention::Create(GetAllocator(), encoder_, GetRegisters(), GetArch(),
488 // is_panda_abi, is_osr, is_dyn
489 mode_.SupportManagedCode(), IsOsrMode(),
490 IsDynamicMethod() && !GetMode().IsDynamicStub(), false, isOptIrtoc);
491 }
492 return callconv_;
493 #endif
494 }
495
GetMethodProperties()496 const MethodProperties &Graph::GetMethodProperties()
497 {
498 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
499 UNREACHABLE();
500 #else
501 if (!methodProperties_) {
502 methodProperties_.emplace(this);
503 }
504 #endif
505 return methodProperties_.value();
506 }
507
ResetParameterInfo()508 void Graph::ResetParameterInfo()
509 {
510 #if defined(PANDA_WITH_CODEGEN) && !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS)
511 auto callconv = GetCallingConvention();
512 if (callconv == nullptr) {
513 paramInfo_ = nullptr;
514 return;
515 }
516 auto regsReserve = 0;
517 if (GetMode().SupportManagedCode()) {
518 regsReserve++;
519 if (GetMode().IsDynamicMethod() && GetMode().IsDynamicStub()) {
520 regsReserve++;
521 }
522 }
523 paramInfo_ = callconv->GetParameterInfo(regsReserve);
524 #endif
525 }
526
GetZeroReg() const527 Register Graph::GetZeroReg() const
528 {
529 auto regfile = GetRegisters();
530 if (regfile == nullptr) {
531 return INVALID_REG;
532 }
533 auto reg = regfile->GetZeroReg();
534 if (reg == INVALID_REGISTER) {
535 return INVALID_REG;
536 }
537 return reg.GetId();
538 }
539
GetArchTempReg() const540 Register Graph::GetArchTempReg() const
541 {
542 auto tempMask = Target(GetArch()).GetTempRegsMask();
543 for (ssize_t reg = RegMask::Size() - 1; reg >= 0; reg--) {
544 if (tempMask[reg] && const_cast<Graph *>(this)->GetArchUsedRegs()[reg]) {
545 return reg;
546 }
547 }
548 return INVALID_REG;
549 }
550
GetArchTempVReg() const551 Register Graph::GetArchTempVReg() const
552 {
553 auto regfile = GetRegisters();
554 if (regfile == nullptr) {
555 return INVALID_REG;
556 }
557 auto regId = regfile->GetTempVReg();
558 if (regId == INVALID_REG_ID) {
559 return INVALID_REG;
560 }
561 return regId;
562 }
563
GetArchUsedRegs()564 RegMask Graph::GetArchUsedRegs()
565 {
566 auto regfile = GetRegisters();
567 if (regfile == nullptr && archUsedRegs_.None()) {
568 return RegMask();
569 }
570 if (archUsedRegs_.None()) {
571 archUsedRegs_ = regfile->GetRegMask();
572 }
573 return archUsedRegs_;
574 }
575
SetArchUsedRegs(RegMask mask)576 void Graph::SetArchUsedRegs(RegMask mask)
577 {
578 archUsedRegs_ = mask;
579 GetRegisters()->SetRegMask(mask);
580 }
581
GetArchUsedVRegs()582 VRegMask Graph::GetArchUsedVRegs()
583 {
584 auto regfile = GetRegisters();
585 if (regfile == nullptr) {
586 return VRegMask();
587 }
588 return regfile->GetVRegMask();
589 }
590
IsRegScalarMapped() const591 bool Graph::IsRegScalarMapped() const
592 {
593 auto regfile = GetRegisters();
594 if (regfile == nullptr) {
595 return false;
596 }
597 return regfile->SupportMapping(RegMapping::SCALAR_SCALAR);
598 }
599
HasLoop() const600 bool Graph::HasLoop() const
601 {
602 ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
603 return !GetRootLoop()->GetInnerLoops().empty();
604 }
605
HasIrreducibleLoop() const606 bool Graph::HasIrreducibleLoop() const
607 {
608 ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
609 return FlagIrredicibleLoop::Get(bitFields_);
610 }
611
HasInfiniteLoop() const612 bool Graph::HasInfiniteLoop() const
613 {
614 ASSERT(GetAnalysis<LoopAnalyzer>().IsValid());
615 return FlagInfiniteLoop::Get(bitFields_);
616 }
617
HasFloatRegs() const618 bool Graph::HasFloatRegs() const
619 {
620 ASSERT(IsRegAllocApplied());
621 return FlagFloatRegs::Get(bitFields_);
622 }
623
624 /*
625 * Mark blocks, which have successor from external loop
626 */
MarkLoopExits(const Graph * graph,Marker marker)627 void MarkLoopExits(const Graph *graph, Marker marker)
628 {
629 for (auto block : graph->GetBlocksRPO()) {
630 if (block->GetSuccsBlocks().size() == MAX_SUCCS_NUM) {
631 if (block->GetSuccessor(0)->GetLoop() != block->GetSuccessor(1)->GetLoop()) {
632 block->SetMarker(marker);
633 }
634 } else if (block->GetSuccsBlocks().size() > MAX_SUCCS_NUM) {
635 ASSERT(block->IsTryEnd() || block->IsTryBegin() || block->GetLastInst()->GetOpcode() == Opcode::Throw);
636 auto loop = block->GetSuccessor(0)->GetLoop();
637 for (size_t i = 1; i < block->GetSuccsBlocks().size(); i++) {
638 if (loop != block->GetSuccessor(i)->GetLoop()) {
639 block->SetMarker(marker);
640 }
641 }
642 }
643 }
644 }
645
GetMethodFullName(const Graph * graph,RuntimeInterface::MethodPtr method)646 std::string GetMethodFullName(const Graph *graph, RuntimeInterface::MethodPtr method)
647 {
648 std::stringstream sstream;
649 sstream << graph->GetRuntime()->GetClassNameFromMethod(method)
650 << "::" << graph->GetRuntime()->GetMethodName(method);
651 return sstream.str();
652 }
653
GetDataForNativeParam(DataType::Type type)654 SpillFillData Graph::GetDataForNativeParam(DataType::Type type)
655 {
656 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
657 (void)type;
658 return {};
659 #else
660 // NOTE(pishin) change to ASSERT
661 if (paramInfo_ == nullptr) {
662 // NOTE(pishin) enable after fixing arch in tests - UNREACHABLE()
663 return {};
664 }
665
666 auto param = paramInfo_->GetNativeParam(Codegen::ConvertDataType(type, GetArch()));
667 if (std::holds_alternative<Reg>(param)) {
668 auto reg = std::get<Reg>(param);
669 // NOTE! Vector parameter can be put to scalar register in aarch32
670 DataType::Type regType;
671 if (reg.IsFloat()) {
672 regType = DataType::FLOAT64;
673 } else if (reg.GetType() == INT64_TYPE) {
674 regType = DataType::UINT64;
675 } else {
676 regType = DataType::UINT32;
677 }
678 auto loc = reg.IsFloat() ? LocationType::FP_REGISTER : LocationType::REGISTER;
679 return SpillFillData(SpillFillData {loc, LocationType::INVALID, reg.GetId(), INVALID_REG, regType});
680 }
681 ASSERT(std::holds_alternative<uint8_t>(param));
682 auto slot = std::get<uint8_t>(param);
683 DataType::Type regType;
684 if (DataType::IsFloatType(type)) {
685 regType = type;
686 } else if (DataType::Is32Bits(type, GetArch())) {
687 regType = DataType::UINT32;
688 } else {
689 regType = DataType::UINT64;
690 }
691 return SpillFillData(
692 SpillFillData {LocationType::STACK_PARAMETER, LocationType::INVALID, slot, INVALID_REG, regType});
693 #endif
694 }
695
696 // NOLINTNEXTLINE(readability-identifier-naming,-warnings-as-errors)
begin()697 Graph::ParameterList::Iterator Graph::ParameterList::begin()
698 {
699 auto startBb = graph_->GetStartBlock();
700 Iterator it(startBb->GetFirstInst());
701 if (*it != nullptr && it->GetOpcode() != Opcode::Parameter) {
702 ++it;
703 }
704 return it;
705 }
706
RemoveThrowableInst(const Inst * inst)707 void Graph::RemoveThrowableInst(const Inst *inst)
708 {
709 ASSERT(IsInstThrowable(inst));
710 for (auto catchHandler : throwableInsts_.at(inst)) {
711 for (auto catchInst : catchHandler->AllInsts()) {
712 if (!catchInst->IsCatchPhi() || catchInst->CastToCatchPhi()->IsAcc()) {
713 continue;
714 }
715 auto catchPhi = catchInst->CastToCatchPhi();
716 const auto &vregs = catchPhi->GetThrowableInsts();
717 auto it = std::find(vregs->begin(), vregs->end(), inst);
718 if (it != vregs->end()) {
719 int index = std::distance(vregs->begin(), it);
720 catchPhi->RemoveInput(index);
721 }
722 }
723 }
724 throwableInsts_.erase(inst);
725 }
726
ReplaceThrowableInst(Inst * oldInst,Inst * newInst)727 void Graph::ReplaceThrowableInst(Inst *oldInst, Inst *newInst)
728 {
729 auto it = throwableInsts_.emplace(newInst, GetAllocator()->Adapter()).first;
730 it->second = std::move(throwableInsts_.at(oldInst));
731
732 for (auto catchHandler : it->second) {
733 for (auto catchInst : catchHandler->AllInsts()) {
734 if (!catchInst->IsCatchPhi() || catchInst->CastToCatchPhi()->IsAcc()) {
735 continue;
736 }
737 auto catchPhi = catchInst->CastToCatchPhi();
738 const auto &vregs = catchPhi->GetThrowableInsts();
739 auto iter = std::find(vregs->begin(), vregs->end(), oldInst);
740 if (iter != vregs->end()) {
741 catchPhi->ReplaceThrowableInst(oldInst, newInst);
742 }
743 }
744 }
745 throwableInsts_.erase(oldInst);
746 }
747
DumpThrowableInsts(std::ostream * out) const748 void Graph::DumpThrowableInsts(std::ostream *out) const
749 {
750 for (auto &[inst, handlers] : throwableInsts_) {
751 (*out) << "Throwable Inst";
752 inst->Dump(out);
753 (*out) << "Catch handlers:";
754 auto sep = " ";
755 for (auto bb : handlers) {
756 (*out) << sep << "BB " << bb->GetId();
757 sep = ", ";
758 }
759 (*out) << std::endl;
760 }
761 }
762
InitDefaultLocations()763 void Graph::InitDefaultLocations()
764 {
765 if (IsDefaultLocationsInit()) {
766 return;
767 }
768 VisitAllInstructions([this](Inst *inst) {
769 if (!inst->IsOperandsDynamic() || inst->IsPhi()) {
770 return;
771 }
772 [[maybe_unused]] LocationsInfo *locations = GetAllocator()->New<LocationsInfo>(GetAllocator(), inst);
773 for (size_t i = 0; i < inst->GetInputsCount(); i++) {
774 if (inst->GetInputType(i) != DataType::NO_TYPE) {
775 locations->SetLocation(i, Location::RequireRegister());
776 }
777 }
778 });
779 SetDefaultLocationsInit();
780 }
781
GetBranchCounter(const BasicBlock * block,bool trueSucc)782 int64_t Graph::GetBranchCounter(const BasicBlock *block, bool trueSucc)
783 {
784 ASSERT(block->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
785 auto lastInst = block->GetLastInst();
786 if (lastInst->GetPc() == 0) {
787 return 0;
788 }
789 RuntimeInterface::MethodPtr method;
790 if (lastInst->GetOpcode() == Opcode::IfImm) {
791 method = lastInst->CastToIfImm()->GetMethod();
792 } else if (lastInst->GetOpcode() == Opcode::If) {
793 method = lastInst->CastToIf()->GetMethod();
794 } else {
795 return 0;
796 }
797
798 if (method == nullptr) {
799 // corresponded branch instruction was not present in bytecode, e.g. IfImmInst was created while inlining
800 return 0;
801 }
802
803 return block->IsInverted() == trueSucc ? GetRuntime()->GetBranchNotTakenCounter(method, lastInst->GetPc())
804 : GetRuntime()->GetBranchTakenCounter(method, lastInst->GetPc());
805 }
806
GetThrowCounter(const BasicBlock * block)807 int64_t Graph::GetThrowCounter(const BasicBlock *block)
808 {
809 auto lastInst = block->GetLastInst();
810 if (lastInst == nullptr || lastInst->GetOpcode() != Opcode::Throw || lastInst->GetPc() == INVALID_PC) {
811 return 0;
812 }
813
814 auto method = lastInst->CastToThrow()->GetCallMethod();
815 if (method == nullptr) {
816 return 0;
817 }
818
819 return GetRuntime()->GetThrowTakenCounter(method, lastInst->GetPc());
820 }
821
GetParametersSlotsCount() const822 uint32_t Graph::GetParametersSlotsCount() const
823 {
824 uint32_t maxSlot = 0;
825 for (auto paramInst : GetParameters()) {
826 auto location = paramInst->CastToParameter()->GetLocationData().GetSrc();
827 if (location.IsStackParameter()) {
828 maxSlot = location.GetValue() + 1U;
829 }
830 }
831 return maxSlot;
832 }
833
Dump(std::ostream & stm)834 void GraphMode::Dump(std::ostream &stm)
835 {
836 const char *sep = "";
837 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
838 #define DUMP_MODE(name) \
839 if (Is##name()) { \
840 stm << sep << #name; \
841 sep = ", "; \
842 }
843
844 DUMP_MODE(Osr);
845 DUMP_MODE(BytecodeOpt);
846 DUMP_MODE(DynamicMethod);
847 DUMP_MODE(Native);
848 DUMP_MODE(FastPath);
849 DUMP_MODE(Boundary);
850 DUMP_MODE(Interpreter);
851 DUMP_MODE(InterpreterEntry);
852 }
853
GetObjectOffset(const Graph * graph,ObjectType objType,RuntimeInterface::FieldPtr field,uint32_t typeId)854 size_t GetObjectOffset(const Graph *graph, ObjectType objType, RuntimeInterface::FieldPtr field, uint32_t typeId)
855 {
856 switch (objType) {
857 case ObjectType::MEM_DYN_GLOBAL:
858 return graph->GetRuntime()->GetPropertyBoxOffset(graph->GetArch());
859 case ObjectType::MEM_DYN_ELEMENTS:
860 return graph->GetRuntime()->GetElementsOffset(graph->GetArch());
861 case ObjectType::MEM_DYN_PROPS:
862 return graph->GetRuntime()->GetPropertiesOffset(graph->GetArch());
863 case ObjectType::MEM_DYN_PROTO_HOLDER:
864 return graph->GetRuntime()->GetPrototypeHolderOffset(graph->GetArch());
865 case ObjectType::MEM_DYN_PROTO_CELL:
866 return graph->GetRuntime()->GetPrototypeCellOffset(graph->GetArch());
867 case ObjectType::MEM_DYN_CHANGE_FIELD:
868 return graph->GetRuntime()->GetIsChangeFieldOffset(graph->GetArch());
869 case ObjectType::MEM_DYN_ARRAY_LENGTH:
870 return graph->GetRuntime()->GetDynArrayLenthOffset(graph->GetArch());
871 case ObjectType::MEM_DYN_INLINED:
872 return typeId;
873 case ObjectType::MEM_DYN_CLASS:
874 return graph->GetRuntime()->GetObjClassOffset(graph->GetArch());
875 case ObjectType::MEM_DYN_METHOD:
876 return graph->GetRuntime()->GetFunctionTargetOffset(graph->GetArch());
877 case ObjectType::MEM_DYN_HCLASS:
878 return graph->GetRuntime()->GetHClassOffset(graph->GetArch());
879 default:
880 return graph->GetRuntime()->GetFieldOffset(field);
881 }
882 }
883 } // namespace panda::compiler
884