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