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 INVALID_REG;
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 if (block->GetSuccessor(0)->GetLoop() != block->GetSuccessor(1)->GetLoop()) {
643 block->SetMarker(marker);
644 }
645 } else if (block->GetSuccsBlocks().size() > MAX_SUCCS_NUM) {
646 ASSERT(block->IsTryEnd() || block->IsTryBegin() || block->GetLastInst()->GetOpcode() == Opcode::Throw);
647 MarkSuccessBlocks(block, marker);
648 }
649 }
650 }
651
GetMethodFullName(const Graph * graph,RuntimeInterface::MethodPtr method)652 std::string GetMethodFullName(const Graph *graph, RuntimeInterface::MethodPtr method)
653 {
654 std::stringstream sstream;
655 sstream << graph->GetRuntime()->GetClassNameFromMethod(method)
656 << "::" << graph->GetRuntime()->GetMethodName(method);
657 return sstream.str();
658 }
659
GetDataForNativeParam(DataType::Type type)660 SpillFillData Graph::GetDataForNativeParam(DataType::Type type)
661 {
662 #if !defined(PANDA_WITH_CODEGEN) || defined(PANDA_TARGET_WINDOWS) || defined(PANDA_TARGET_MACOS)
663 (void)type;
664 return {};
665 #else
666 // NOTE(pishin) change to ASSERT
667 if (paramInfo_ == nullptr) {
668 // NOTE(pishin) enable after fixing arch in tests - UNREACHABLE()
669 return {};
670 }
671
672 auto param = paramInfo_->GetNativeParam(Codegen::ConvertDataType(type, GetArch()));
673 if (std::holds_alternative<Reg>(param)) {
674 auto reg = std::get<Reg>(param);
675 // NOTE! Vector parameter can be put to scalar register in aarch32
676 DataType::Type regType;
677 if (reg.IsFloat()) {
678 regType = DataType::FLOAT64;
679 } else if (reg.GetType() == INT64_TYPE) {
680 regType = DataType::UINT64;
681 } else {
682 regType = DataType::UINT32;
683 }
684 auto loc = reg.IsFloat() ? LocationType::FP_REGISTER : LocationType::REGISTER;
685 return SpillFillData(SpillFillData {loc, LocationType::INVALID, reg.GetId(), INVALID_REG, regType});
686 }
687 ASSERT(std::holds_alternative<uint8_t>(param));
688 auto slot = std::get<uint8_t>(param);
689 DataType::Type regType;
690 if (DataType::IsFloatType(type)) {
691 regType = type;
692 } else if (DataType::Is32Bits(type, GetArch())) {
693 regType = DataType::UINT32;
694 } else {
695 regType = DataType::UINT64;
696 }
697 return SpillFillData(
698 SpillFillData {LocationType::STACK_PARAMETER, LocationType::INVALID, slot, INVALID_REG, regType});
699 #endif
700 }
701
702 // NOLINTNEXTLINE(readability-identifier-naming,-warnings-as-errors)
begin()703 Graph::ParameterList::Iterator Graph::ParameterList::begin()
704 {
705 auto startBb = graph_->GetStartBlock();
706 Iterator it(startBb->GetFirstInst());
707 if (*it != nullptr && it->GetOpcode() != Opcode::Parameter) {
708 ++it;
709 }
710 return it;
711 }
712
RemoveThrowableInst(const Inst * inst)713 void Graph::RemoveThrowableInst(const Inst *inst)
714 {
715 ASSERT(IsInstThrowable(inst));
716 for (auto catchHandler : throwableInsts_.at(inst)) {
717 for (auto catchInst : catchHandler->AllInsts()) {
718 if (!catchInst->IsCatchPhi() || catchInst->CastToCatchPhi()->IsAcc()) {
719 continue;
720 }
721 auto catchPhi = catchInst->CastToCatchPhi();
722 const auto &vregs = catchPhi->GetThrowableInsts();
723 if (vregs == nullptr || vregs->empty()) {
724 continue;
725 }
726 auto it = std::find(vregs->begin(), vregs->end(), inst);
727 if (it != vregs->end()) {
728 int index = std::distance(vregs->begin(), it);
729 catchPhi->RemoveInput(index);
730 }
731 }
732 }
733 throwableInsts_.erase(inst);
734 }
735
ReplaceThrowableInst(Inst * oldInst,Inst * newInst)736 void Graph::ReplaceThrowableInst(Inst *oldInst, Inst *newInst)
737 {
738 auto it = throwableInsts_.emplace(newInst, GetAllocator()->Adapter()).first;
739 it->second = std::move(throwableInsts_.at(oldInst));
740
741 for (auto catchHandler : it->second) {
742 for (auto catchInst : catchHandler->AllInsts()) {
743 if (!catchInst->IsCatchPhi() || catchInst->CastToCatchPhi()->IsAcc()) {
744 continue;
745 }
746 auto catchPhi = catchInst->CastToCatchPhi();
747 const auto &vregs = catchPhi->GetThrowableInsts();
748 auto iter = std::find(vregs->begin(), vregs->end(), oldInst);
749 if (iter != vregs->end()) {
750 catchPhi->ReplaceThrowableInst(oldInst, newInst);
751 }
752 }
753 }
754 throwableInsts_.erase(oldInst);
755 }
756
DumpThrowableInsts(std::ostream * out) const757 void Graph::DumpThrowableInsts(std::ostream *out) const
758 {
759 for (auto &[inst, handlers] : throwableInsts_) {
760 (*out) << "Throwable Inst";
761 inst->Dump(out);
762 (*out) << "Catch handlers:";
763 auto sep = " ";
764 for (auto bb : handlers) {
765 (*out) << sep << "BB " << bb->GetId();
766 sep = ", ";
767 }
768 (*out) << std::endl;
769 }
770 }
771
InitDefaultLocations()772 void Graph::InitDefaultLocations()
773 {
774 if (IsDefaultLocationsInit()) {
775 return;
776 }
777 VisitAllInstructions([this](Inst *inst) {
778 if (!inst->IsOperandsDynamic() || inst->IsPhi()) {
779 return;
780 }
781 [[maybe_unused]] LocationsInfo *locations = GetAllocator()->New<LocationsInfo>(GetAllocator(), inst);
782 for (size_t i = 0; i < inst->GetInputsCount(); i++) {
783 if (inst->GetInputType(i) != DataType::NO_TYPE) {
784 locations->SetLocation(i, Location::RequireRegister());
785 }
786 }
787 });
788 SetDefaultLocationsInit();
789 }
790
GetBranchCounter(const BasicBlock * block,bool trueSucc)791 int64_t Graph::GetBranchCounter(const BasicBlock *block, bool trueSucc)
792 {
793 ASSERT(block->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
794 auto lastInst = block->GetLastInst();
795 if (lastInst->GetPc() == 0) {
796 return 0;
797 }
798 RuntimeInterface::MethodPtr method;
799 if (lastInst->GetOpcode() == Opcode::IfImm) {
800 method = lastInst->CastToIfImm()->GetMethod();
801 } else if (lastInst->GetOpcode() == Opcode::If) {
802 method = lastInst->CastToIf()->GetMethod();
803 } else {
804 return 0;
805 }
806
807 if (method == nullptr) {
808 // corresponded branch instruction was not present in bytecode, e.g. IfImmInst was created while inlining
809 return 0;
810 }
811
812 return block->IsInverted() == trueSucc ? GetRuntime()->GetBranchNotTakenCounter(method, lastInst->GetPc())
813 : GetRuntime()->GetBranchTakenCounter(method, lastInst->GetPc());
814 }
815
GetThrowCounter(const BasicBlock * block)816 int64_t Graph::GetThrowCounter(const BasicBlock *block)
817 {
818 auto lastInst = block->GetLastInst();
819 if (lastInst == nullptr || lastInst->GetOpcode() != Opcode::Throw || lastInst->GetPc() == INVALID_PC) {
820 return 0;
821 }
822
823 auto method = lastInst->CastToThrow()->GetCallMethod();
824 if (method == nullptr) {
825 return 0;
826 }
827
828 return GetRuntime()->GetThrowTakenCounter(method, lastInst->GetPc());
829 }
830
GetParametersSlotsCount() const831 uint32_t Graph::GetParametersSlotsCount() const
832 {
833 uint32_t maxSlot = 0;
834 for (auto paramInst : GetParameters()) {
835 auto location = paramInst->CastToParameter()->GetLocationData().GetSrc();
836 if (location.IsStackParameter()) {
837 maxSlot = location.GetValue() + 1U;
838 }
839 }
840 return maxSlot;
841 }
842
Dump(std::ostream & stm)843 void GraphMode::Dump(std::ostream &stm)
844 {
845 const char *sep = "";
846 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
847 #define DUMP_MODE(name) \
848 if (Is##name()) { \
849 stm << sep << #name; \
850 sep = ", "; \
851 }
852
853 DUMP_MODE(Osr);
854 DUMP_MODE(BytecodeOpt);
855 DUMP_MODE(DynamicMethod);
856 DUMP_MODE(Native);
857 DUMP_MODE(FastPath);
858 DUMP_MODE(Boundary);
859 DUMP_MODE(Interpreter);
860 DUMP_MODE(InterpreterEntry);
861 }
862
GetObjectOffset(const Graph * graph,ObjectType objType,RuntimeInterface::FieldPtr field,uint32_t typeId)863 size_t GetObjectOffset(const Graph *graph, ObjectType objType, RuntimeInterface::FieldPtr field, uint32_t typeId)
864 {
865 switch (objType) {
866 case ObjectType::MEM_DYN_GLOBAL:
867 return graph->GetRuntime()->GetPropertyBoxOffset(graph->GetArch());
868 case ObjectType::MEM_DYN_ELEMENTS:
869 return graph->GetRuntime()->GetElementsOffset(graph->GetArch());
870 case ObjectType::MEM_DYN_PROPS:
871 return graph->GetRuntime()->GetPropertiesOffset(graph->GetArch());
872 case ObjectType::MEM_DYN_PROTO_HOLDER:
873 return graph->GetRuntime()->GetPrototypeHolderOffset(graph->GetArch());
874 case ObjectType::MEM_DYN_PROTO_CELL:
875 return graph->GetRuntime()->GetPrototypeCellOffset(graph->GetArch());
876 case ObjectType::MEM_DYN_CHANGE_FIELD:
877 return graph->GetRuntime()->GetIsChangeFieldOffset(graph->GetArch());
878 case ObjectType::MEM_DYN_ARRAY_LENGTH:
879 return graph->GetRuntime()->GetDynArrayLenthOffset(graph->GetArch());
880 case ObjectType::MEM_DYN_INLINED:
881 return typeId;
882 case ObjectType::MEM_DYN_CLASS:
883 return graph->GetRuntime()->GetObjClassOffset(graph->GetArch());
884 case ObjectType::MEM_DYN_METHOD:
885 return graph->GetRuntime()->GetFunctionTargetOffset(graph->GetArch());
886 case ObjectType::MEM_DYN_HCLASS:
887 return graph->GetRuntime()->GetHClassOffset(graph->GetArch());
888 default:
889 return graph->GetRuntime()->GetFieldOffset(field);
890 }
891 }
892
893 } // namespace ark::compiler
894