• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /*
17 Codegen Hi-Level implementation
18 */
19 #include "operands.h"
20 #include "codegen.h"
21 #include "compiler_options.h"
22 #include "lib_call_inst.h"
23 #include "relocations.h"
24 #include "include/compiler_interface.h"
25 #include "ir-dyn-base-types.h"
26 #include "runtime/include/coretypes/string.h"
27 #include "compiler/optimizer/ir/analysis.h"
28 #include "compiler/optimizer/ir/locations.h"
29 #include "compiler/optimizer/analysis/liveness_analyzer.h"
30 #include "optimizer/code_generator/method_properties.h"
31 #include "events/events.h"
32 #include "libpandabase/utils/tsan_interface.h"
33 #include "libpandabase/utils/utils.h"
34 #include <iomanip>
35 
36 namespace panda::compiler {
37 
38 class OsrEntryStub {
FixIntervals(Codegen * codegen,Encoder * encoder)39     void FixIntervals(Codegen *codegen, Encoder *encoder)
40     {
41         auto &la = codegen->GetGraph()->GetAnalysis<LivenessAnalyzer>();
42         la.EnumerateLiveIntervalsForInst(saveState_, [this, codegen, encoder](const auto &li) {
43             auto inst = li->GetInst();
44             auto location = li->GetLocation();
45             // Skip live registers that are already in the input list of the OsrSaveState
46             const auto &ssInputs = saveState_->GetInputs();
47             if (std::find_if(ssInputs.begin(), ssInputs.end(),
48                              [inst](auto &input) { return input.GetInst() == inst; }) != ssInputs.end()) {
49                 return;
50             }
51             // Only constants allowed
52             switch (inst->GetOpcode()) {
53                 case Opcode::LoadAndInitClass: {
54                     auto klass = reinterpret_cast<uintptr_t>(inst->CastToLoadAndInitClass()->GetClass());
55                     encoder->EncodeMov(codegen->ConvertRegister(inst->GetDstReg(), inst->GetType()),
56                                        Imm(reinterpret_cast<uintptr_t>(klass)));
57                     break;
58                 }
59                 case Opcode::Constant: {
60                     if (location.IsFixedRegister()) {
61                         EncodeConstantMove(li, encoder);
62                     } else if (location.IsStack()) {
63                         auto slot = location.GetValue();
64                         encoder->EncodeSti(
65                             bit_cast<int64_t>(inst->CastToConstant()->GetRawValue()), DOUBLE_WORD_SIZE_BYTES,
66                             MemRef(codegen->SpReg(), codegen->GetFrameLayout().GetSpillOffsetFromSpInBytes(slot)));
67                     } else {
68                         ASSERT(location.IsConstant());
69                     }
70                     break;
71                 }
72                 // NOTE (ekudriashov): UnresolvedLoadAndInitClass
73                 default:
74                     break;
75             }
76         });
77     }
78 
EncodeConstantMove(const LifeIntervals * li,Encoder * encoder)79     static void EncodeConstantMove(const LifeIntervals *li, Encoder *encoder)
80     {
81         auto inst = li->GetInst();
82         switch (li->GetType()) {
83             case DataType::FLOAT64:
84                 encoder->EncodeMov(Reg(li->GetReg(), FLOAT64_TYPE),
85                                    Imm(bit_cast<double>(inst->CastToConstant()->GetDoubleValue())));
86                 break;
87             case DataType::FLOAT32:
88                 encoder->EncodeMov(Reg(li->GetReg(), FLOAT32_TYPE),
89                                    Imm(bit_cast<float>(inst->CastToConstant()->GetFloatValue())));
90                 break;
91             case DataType::UINT32:
92                 encoder->EncodeMov(Reg(li->GetReg(), INT32_TYPE), Imm(inst->CastToConstant()->GetRawValue()));
93                 break;
94             case DataType::UINT64:
95                 encoder->EncodeMov(Reg(li->GetReg(), INT64_TYPE), Imm(inst->CastToConstant()->GetRawValue()));
96                 break;
97             default:
98                 UNREACHABLE();
99         }
100     }
101 
102 public:
OsrEntryStub(Codegen * codegen,SaveStateInst * inst)103     OsrEntryStub(Codegen *codegen, SaveStateInst *inst) : label_(codegen->GetEncoder()->CreateLabel()), saveState_(inst)
104     {
105     }
106 
107     DEFAULT_MOVE_SEMANTIC(OsrEntryStub);
108     DEFAULT_COPY_SEMANTIC(OsrEntryStub);
109     ~OsrEntryStub() = default;
110 
Generate(Codegen * codegen)111     void Generate(Codegen *codegen)
112     {
113         auto encoder = codegen->GetEncoder();
114         auto lr = codegen->GetTarget().GetLinkReg();
115         auto fl = codegen->GetFrameLayout();
116         codegen->CreateStackMap(saveState_->CastToSaveStateOsr());
117         ssize_t slot = CFrameLayout::LOCALS_START_SLOT + CFrameLayout::GetLocalsCount() - 1;
118         encoder->EncodeStp(
119             codegen->FpReg(), lr,
120             MemRef(codegen->FpReg(),
121                    -fl.GetOffset<CFrameLayout::OffsetOrigin::FP, CFrameLayout::OffsetUnit::BYTES>(slot)));
122 
123         FixIntervals(codegen, encoder);
124         encoder->EncodeJump(label_);
125     }
126 
GetInst()127     SaveStateInst *GetInst()
128     {
129         return saveState_;
130     }
131 
GetLabel()132     auto &GetLabel()
133     {
134         return label_;
135     }
136 
137 private:
138     LabelHolder::LabelId label_;
139     SaveStateInst *saveState_ {nullptr};
140 };
141 
Codegen(Graph * graph)142 Codegen::Codegen(Graph *graph)
143     : Optimization(graph),
144       allocator_(graph->GetAllocator()),
145       localAllocator_(graph->GetLocalAllocator()),
146       codeBuilder_(allocator_->New<CodeInfoBuilder>(graph->GetArch(), allocator_)),
147       slowPaths_(graph->GetLocalAllocator()->Adapter()),
148       slowPathsMap_(graph->GetLocalAllocator()->Adapter()),
149       frameLayout_(CFrameLayout(graph->GetArch(), graph->GetStackSlotsCount())),
150       osrEntries_(graph->GetLocalAllocator()->Adapter()),
151       vregIndices_(GetAllocator()->Adapter()),
152       runtime_(graph->GetRuntime()),
153       target_(graph->GetArch()),
154       liveOuts_(graph->GetLocalAllocator()->Adapter()),
155       disasm_(this),
156       spillFillsResolver_(graph)
157 {
158     graph->SetCodeBuilder(codeBuilder_);
159     regfile_ = graph->GetRegisters();
160     if (regfile_ != nullptr) {
161         ASSERT(regfile_->IsValid());
162         ArenaVector<Reg> regsUsage(allocator_->Adapter());
163         Convert(&regsUsage, graph->GetUsedRegs<DataType::INT64>(), INT64_TYPE);
164         Convert(&regsUsage, graph->GetUsedRegs<DataType::FLOAT64>(), FLOAT64_TYPE);
165         regfile_->SetUsedRegs(regsUsage);
166 #ifndef NDEBUG
167         COMPILER_LOG(DEBUG, CODEGEN) << "Regalloc used registers scalar " << graph->GetUsedRegs<DataType::INT64>();
168         COMPILER_LOG(DEBUG, CODEGEN) << "Regalloc used registers vector " << graph->GetUsedRegs<DataType::FLOAT64>();
169 #endif
170     }
171 
172     enc_ = graph->GetEncoder();
173     ASSERT(enc_ != nullptr && enc_->IsValid());
174     enc_->SetRegfile(regfile_);
175     if (enc_->InitMasm()) {
176         enc_->SetFrameLayout(GetFrameLayout());
177     }
178 
179     callconv_ = graph->GetCallingConvention();
180     if (callconv_ != nullptr) {
181         ASSERT(callconv_->IsValid());
182         if (callconv_->GetEncoder() == nullptr) {
183             callconv_->SetEncoder(enc_);
184         }
185     }
186 
187     auto method = graph->GetMethod();
188     // workaround for test
189     if (method != nullptr) {
190         methodId_ = graph->GetRuntime()->GetMethodId(method);
191     }
192     GetDisasm()->Init();
193     GetDisasm()->SetEncoder(GetEncoder());
194 }
195 
GetPassName() const196 const char *Codegen::GetPassName() const
197 {
198     return "Codegen";
199 }
200 
AbortIfFailed() const201 bool Codegen::AbortIfFailed() const
202 {
203     return true;
204 }
205 
CreateFrameInfo()206 void Codegen::CreateFrameInfo()
207 {
208     // Create FrameInfo for CFrame
209     auto &fl = GetFrameLayout();
210     auto frame = GetGraph()->GetLocalAllocator()->New<FrameInfo>(
211         FrameInfo::PositionedCallers::Encode(true) | FrameInfo::PositionedCallees::Encode(true) |
212         FrameInfo::CallersRelativeFp::Encode(false) | FrameInfo::CalleesRelativeFp::Encode(true));
213     frame->SetFrameSize(fl.GetFrameSize<CFrameLayout::OffsetUnit::BYTES>());
214     frame->SetSpillsCount(fl.GetSpillsCount());
215 
216     frame->SetCallersOffset(fl.GetOffset<CFrameLayout::OffsetOrigin::SP, CFrameLayout::OffsetUnit::SLOTS>(
217         fl.GetStackStartSlot() + fl.GetCallerLastSlot(false)));
218     frame->SetFpCallersOffset(fl.GetOffset<CFrameLayout::OffsetOrigin::SP, CFrameLayout::OffsetUnit::SLOTS>(
219         fl.GetStackStartSlot() + fl.GetCallerLastSlot(true)));
220     frame->SetCalleesOffset(-fl.GetOffset<CFrameLayout::OffsetOrigin::FP, CFrameLayout::OffsetUnit::SLOTS>(
221         fl.GetStackStartSlot() + fl.GetCalleeLastSlot(false)));
222     frame->SetFpCalleesOffset(-fl.GetOffset<CFrameLayout::OffsetOrigin::FP, CFrameLayout::OffsetUnit::SLOTS>(
223         fl.GetStackStartSlot() + fl.GetCalleeLastSlot(true)));
224 
225     frame->SetSetupFrame(true);
226     frame->SetSaveFrameAndLinkRegs(true);
227     frame->SetSaveUnusedCalleeRegs(!GetGraph()->GetMethodProperties().GetCompactPrologueAllowed());
228     frame->SetAdjustSpReg(true);
229     frame->SetHasFloatRegs(GetGraph()->HasFloatRegs());
230 
231     GetCodeBuilder()->SetHasFloatRegs(GetGraph()->HasFloatRegs());
232 
233     SetFrameInfo(frame);
234 }
235 
FillOnlyParameters(RegMask * liveRegs,uint32_t numParams,bool isFastpath) const236 void Codegen::FillOnlyParameters(RegMask *liveRegs, uint32_t numParams, bool isFastpath) const
237 {
238     ASSERT(numParams <= 6U);
239     if (GetArch() == Arch::AARCH64 && !isFastpath) {
240         numParams = AlignUp(numParams, 2U);
241     }
242     *liveRegs &= GetTarget().GetParamRegsMask(numParams);
243 }
244 
Convert(ArenaVector<Reg> * regsUsage,const ArenaVector<bool> * mask,TypeInfo typeInfo)245 void Codegen::Convert(ArenaVector<Reg> *regsUsage, const ArenaVector<bool> *mask, TypeInfo typeInfo)
246 {
247     ASSERT(regsUsage != nullptr);
248     // There are no used registers
249     if (mask == nullptr) {
250         return;
251     }
252     ASSERT(mask->size() == MAX_NUM_REGS);
253     for (uint32_t i = 0; i < MAX_NUM_REGS; ++i) {
254         if ((*mask)[i]) {
255             regsUsage->emplace_back(i, typeInfo);
256         }
257     }
258 }
259 
260 #ifdef INTRINSIC_SLOW_PATH_ENTRY_ENABLED
CreateIrtocIntrinsic(IntrinsicInst * inst,Reg dst,SRCREGS src)261 void Codegen::CreateIrtocIntrinsic(IntrinsicInst *inst, [[maybe_unused]] Reg dst, [[maybe_unused]] SRCREGS src)
262 {
263     switch (inst->GetIntrinsicId()) {
264         case RuntimeInterface::IntrinsicId::INTRINSIC_SLOW_PATH_ENTRY:
265             IntrinsicSlowPathEntry(inst);
266             break;
267         case RuntimeInterface::IntrinsicId::INTRINSIC_UNREACHABLE:
268             GetEncoder()->EncodeAbort();
269             break;
270         case RuntimeInterface::IntrinsicId::INTRINSIC_SAVE_REGISTERS_EP:
271             IntrinsicSaveRegisters(inst);
272             break;
273         case RuntimeInterface::IntrinsicId::INTRINSIC_RESTORE_REGISTERS_EP:
274             IntrinsicRestoreRegisters(inst);
275             break;
276         case RuntimeInterface::IntrinsicId::INTRINSIC_TAIL_CALL:
277             IntrinsicTailCall(inst);
278             break;
279         case RuntimeInterface::IntrinsicId::INTRINSIC_INTERPRETER_RETURN:
280             GetCallingConvention()->GenerateNativeEpilogue(*GetFrameInfo(), []() {});
281             break;
282         case RuntimeInterface::IntrinsicId::INTRINSIC_LOAD_ACQUIRE_MARK_WORD_EXCLUSIVE:
283             ASSERT(GetRuntime()->GetObjMarkWordOffset(GetArch()) == 0);
284             GetEncoder()->EncodeLdrExclusive(dst, src[0], true);
285             break;
286         case RuntimeInterface::IntrinsicId::INTRINSIC_STORE_RELEASE_MARK_WORD_EXCLUSIVE:
287             ASSERT(GetRuntime()->GetObjMarkWordOffset(GetArch()) == 0);
288             GetEncoder()->EncodeStrExclusive(dst, src[SECOND_OPERAND], src[0], true);
289             break;
290         case RuntimeInterface::IntrinsicId::INTRINSIC_COMPARE_AND_SET_MARK_WORD:
291             ASSERT(GetRuntime()->GetObjMarkWordOffset(GetArch()) == 0);
292             GetEncoder()->EncodeCompareAndSwap(dst, src[0], src[SECOND_OPERAND], src[THIRD_OPERAND]);
293             break;
294         case RuntimeInterface::IntrinsicId::INTRINSIC_DATA_MEMORY_BARRIER_FULL:
295             GetEncoder()->EncodeMemoryBarrier(memory_order::FULL);
296             break;
297         case RuntimeInterface::IntrinsicId::INTRINSIC_COMPRESS_EIGHT_UTF16_TO_UTF8_CHARS_USING_SIMD:
298             GetEncoder()->EncodeCompressEightUtf16ToUtf8CharsUsingSimd(src[FIRST_OPERAND], src[SECOND_OPERAND]);
299             break;
300         case RuntimeInterface::IntrinsicId::INTRINSIC_COMPRESS_SIXTEEN_UTF16_TO_UTF8_CHARS_USING_SIMD:
301             GetEncoder()->EncodeCompressSixteenUtf16ToUtf8CharsUsingSimd(src[FIRST_OPERAND], src[SECOND_OPERAND]);
302             break;
303         default:
304             UNREACHABLE();
305             break;
306     }
307 }
308 #endif
309 
BeginMethod()310 bool Codegen::BeginMethod()
311 {
312     // Do not try to encode too large graph
313     auto instSize = GetGraph()->GetCurrentInstructionId();
314     auto instsPerByte = GetEncoder()->MaxArchInstPerEncoded();
315     auto maxBitsInInst = GetInstructionSizeBits(GetArch());
316     instSize += slowPaths_.size() * INST_IN_SLOW_PATH;
317     if ((instSize * instsPerByte * maxBitsInInst) > g_options.GetCompilerMaxGenCodeSize()) {
318         return false;
319     }
320     // After this - encoder aborted, if allocated too much size.
321     GetEncoder()->SetMaxAllocatedBytes(g_options.GetCompilerMaxGenCodeSize());
322 
323     if (GetGraph()->IsAotMode()) {
324         GetEncoder()->SetCodeOffset(GetGraph()->GetAotData()->GetCodeOffset() + CodeInfo::GetCodeOffset(GetArch()));
325     } else {
326         GetEncoder()->SetCodeOffset(0);
327     }
328 
329     codeBuilder_->BeginMethod(GetFrameLayout().GetFrameSize<CFrameLayout::OffsetUnit::BYTES>(),
330                               GetGraph()->GetVRegsCount() + GetGraph()->GetEnvCount());
331 
332     GetEncoder()->BindLabel(GetLabelEntry());
333     SetStartCodeOffset(GetEncoder()->GetCursorOffset());
334 
335     GeneratePrologue();
336 
337     return GetEncoder()->GetResult();
338 }
339 
GeneratePrologue()340 void Codegen::GeneratePrologue()
341 {
342     SCOPED_DISASM_STR(this, "Method Prologue");
343 
344     GetCallingConvention()->GeneratePrologue(*frameInfo_);
345 
346     if (!GetGraph()->GetMode().IsNative()) {
347         GetEncoder()->EncodeSti(1, 1, MemRef(ThreadReg(), GetRuntime()->GetTlsFrameKindOffset(GetArch())));
348     }
349     if (!GetGraph()->GetMode().IsNative()) {
350         // Create stack overflow check
351         GetEncoder()->EncodeStackOverflowCheck(-GetRuntime()->GetStackOverflowCheckOffset());
352         // Create empty stackmap for the stack overflow check
353         GetCodeBuilder()->BeginStackMap(0, 0, nullptr, 0, false, false);
354         GetCodeBuilder()->EndStackMap();
355     }
356 
357 #if defined(EVENT_METHOD_ENTER_ENABLED) && EVENT_METHOD_ENTER_ENABLED != 0
358     if (GetGraph()->IsAotMode()) {
359         SCOPED_DISASM_STR(this, "LoadMethod for trace");
360         ScopedTmpReg method_reg(GetEncoder());
361         LoadMethod(method_reg);
362         InsertTrace(Imm(static_cast<size_t>(TraceId::METHOD_ENTER)), method_reg,
363                     Imm(static_cast<size_t>(events::MethodEnterKind::COMPILED)));
364     } else {
365         InsertTrace(Imm(static_cast<size_t>(TraceId::METHOD_ENTER)),
366                     Imm(reinterpret_cast<size_t>(GetGraph()->GetMethod())),
367                     Imm(static_cast<size_t>(events::MethodEnterKind::COMPILED)));
368     }
369 #endif
370 }
371 
GenerateEpilogue()372 void Codegen::GenerateEpilogue()
373 {
374     SCOPED_DISASM_STR(this, "Method Epilogue");
375 
376 #if defined(EVENT_METHOD_EXIT_ENABLED) && EVENT_METHOD_EXIT_ENABLED != 0
377     GetCallingConvention()->GenerateEpilogue(*frame_info_, [this]() {
378         if (GetGraph()->IsAotMode()) {
379             ScopedTmpReg method_reg(GetEncoder());
380             LoadMethod(method_reg);
381             InsertTrace(Imm(static_cast<size_t>(TraceId::METHOD_EXIT)), method_reg,
382                         Imm(static_cast<size_t>(events::MethodExitKind::COMPILED)));
383         } else {
384             InsertTrace(Imm(static_cast<size_t>(TraceId::METHOD_EXIT)),
385                         Imm(reinterpret_cast<size_t>(GetGraph()->GetMethod())),
386                         Imm(static_cast<size_t>(events::MethodExitKind::COMPILED)));
387         }
388     });
389 #else
390     GetCallingConvention()->GenerateEpilogue(*frameInfo_, []() {});
391 #endif
392 }
393 
VisitGraph()394 bool Codegen::VisitGraph()
395 {
396     EncodeVisitor visitor(this);
397     visitor_ = &visitor;
398 
399     const auto &blocks = GetGraph()->GetBlocksLinearOrder();
400 
401     for (auto bb : blocks) {
402         GetEncoder()->BindLabel(bb->GetId());
403         for (auto inst : bb->AllInsts()) {
404             SCOPED_DISASM_INST(this, inst);
405 
406 #ifdef PANDA_COMPILER_DEBUG_INFO
407             auto debugInfo = inst->GetDebugInfo();
408             if (GetGraph()->IsLineDebugInfoEnabled() && debugInfo != nullptr) {
409                 debugInfo->SetOffset(GetEncoder()->GetCursorOffset());
410             }
411 #endif
412             visitor.VisitInstruction(inst);
413             if (!visitor.GetResult()) {
414                 COMPILER_LOG(DEBUG, CODEGEN)
415                     << "Can't encode instruction: " << GetOpcodeString(inst->GetOpcode()) << *inst;
416                 break;
417             }
418         }
419 
420         if (bb->NeedsJump()) {
421             EmitJump(bb);
422         }
423 
424         if (!visitor.GetResult()) {
425             return false;
426         }
427     }
428 
429     auto instsPerByte = GetEncoder()->MaxArchInstPerEncoded();
430     auto maxBitsInInst = GetInstructionSizeBits(GetArch());
431     auto instSize = GetGraph()->GetCurrentInstructionId() + slowPaths_.size() * INST_IN_SLOW_PATH;
432     if ((instSize * instsPerByte * maxBitsInInst) > g_options.GetCompilerMaxGenCodeSize()) {
433         return false;
434     }
435 
436     EmitSlowPaths();
437     visitor_ = nullptr;
438 
439     return true;
440 }
441 
EmitJump(const BasicBlock * bb)442 void Codegen::EmitJump(const BasicBlock *bb)
443 {
444     BasicBlock *sucBb = nullptr;
445 
446     if (bb->GetLastInst() == nullptr) {
447         ASSERT(bb->IsEmpty());
448         sucBb = bb->GetSuccsBlocks()[0];
449     } else {
450         switch (bb->GetLastInst()->GetOpcode()) {
451             case Opcode::If:
452             case Opcode::IfImm:
453                 ASSERT(bb->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
454                 sucBb = bb->GetFalseSuccessor();
455                 break;
456             default:
457                 sucBb = bb->GetSuccsBlocks()[0];
458                 break;
459         }
460     }
461     SCOPED_DISASM_STR(this, std::string("Jump from  BB_") + std::to_string(bb->GetId()) + " to BB_" +
462                                 std::to_string(sucBb->GetId()));
463 
464     auto label = sucBb->GetId();
465     GetEncoder()->EncodeJump(label);
466 }
467 
EndMethod()468 void Codegen::EndMethod()
469 {
470     for (auto &osrStub : osrEntries_) {
471         SCOPED_DISASM_STR(this,
472                           std::string("Osr stub for OsrStateStump ") + std::to_string(osrStub->GetInst()->GetId()));
473         osrStub->Generate(this);
474     }
475 
476     GetEncoder()->Finalize();
477 }
478 
479 // Allocates memory, copies generated code to it, sets the code to the graph's codegen data. Also this function
480 // encodes the code info and sets it to the graph.
CopyToCodeCache()481 bool Codegen::CopyToCodeCache()
482 {
483     auto codeEntry = reinterpret_cast<void *>(GetEncoder()->GetLabelAddress(GetLabelEntry()));
484     auto codeSize = GetEncoder()->GetCursorOffset();
485     bool saveAllCalleeRegisters = !GetGraph()->GetMethodProperties().GetCompactPrologueAllowed();
486 
487     auto code = reinterpret_cast<uint8_t *>(GetAllocator()->Alloc(codeSize));
488     if (code == nullptr) {
489         return false;
490     }
491     memcpy_s(code, codeSize, codeEntry, codeSize);
492     GetGraph()->SetCode(EncodeDataType(code, codeSize));
493 
494     RegMask calleeRegs;
495     VRegMask calleeVregs;
496     GetRegfile()->FillUsedCalleeSavedRegisters(&calleeRegs, &calleeVregs, saveAllCalleeRegisters);
497     constexpr size_t MAX_NUM_REGISTERS = 32;
498     static_assert(MAX_NUM_REGS <= MAX_NUM_REGISTERS && MAX_NUM_VREGS <= MAX_NUM_REGISTERS);
499     codeBuilder_->SetSavedCalleeRegsMask(static_cast<uint32_t>(calleeRegs.to_ulong()),
500                                          static_cast<uint32_t>(calleeVregs.to_ulong()));
501 
502     ArenaVector<uint8_t> codeInfoData(GetGraph()->GetAllocator()->Adapter());
503     codeBuilder_->Encode(&codeInfoData);
504     GetGraph()->SetCodeInfo(Span(codeInfoData));
505 
506     return true;
507 }
508 
IssueDisasm()509 void Codegen::IssueDisasm()
510 {
511     if (GetGraph()->GetMode().SupportManagedCode() && g_options.IsCompilerDisasmDumpCodeInfo()) {
512         GetDisasm()->PrintCodeInfo(this);
513     }
514     GetDisasm()->PrintCodeStatistics(this);
515     auto &stream = GetDisasm()->GetStream();
516     for (auto &item : GetDisasm()->GetItems()) {
517         if (std::holds_alternative<CodeItem>(item)) {
518             auto &code = std::get<CodeItem>(item);
519             for (size_t pc = code.GetPosition(); pc < code.GetCursorOffset();) {
520                 stream << GetDisasm()->GetIndent(code.GetDepth());
521                 auto newPc = GetEncoder()->DisasmInstr(stream, pc, 0);
522                 stream << "\n";
523                 pc = newPc;
524             }
525         } else if (std::holds_alternative<std::string>(item)) {
526             stream << (std::get<std::string>(item));
527         }
528     }
529 }
530 
RunImpl()531 bool Codegen::RunImpl()
532 {
533     Initialize();
534 
535     auto encoder = GetEncoder();
536     encoder->GetLabels()->CreateLabels(GetGraph()->GetVectorBlocks().size());
537     labelEntry_ = encoder->CreateLabel();
538     labelExit_ = encoder->CreateLabel();
539 
540 #ifndef NDEBUG
541     if (g_options.IsCompilerNonOptimizing()) {
542         // In case of non-optimizing compiler lowering pass is not run but low-level instructions may
543         // also appear on codegen so, to satisfy GraphChecker, the flag should be raised.
544         GetGraph()->SetLowLevelInstructionsEnabled();
545     }
546 #endif  // NDEBUG
547 
548     if ((GetCallingConvention() == nullptr) || (GetEncoder() == nullptr)) {
549         return false;
550     }
551 
552     if (GetCallingConvention()->IsDynCallMode()) {
553         auto numExpectedArgs = GetRuntime()->GetMethodTotalArgumentsCount(GetGraph()->GetMethod());
554         if (numExpectedArgs > GetRuntime()->GetDynamicNumFixedArgs()) {
555             CallConvDynInfo dynInfo(numExpectedArgs,
556                                     GetRuntime()->GetEntrypointTlsOffset(
557                                         GetArch(), RuntimeInterface::EntrypointId::EXPAND_COMPILED_CODE_ARGS_DYN));
558             GetCallingConvention()->SetDynInfo(dynInfo);
559             frameInfo_->SetSaveFrameAndLinkRegs(true);
560         } else {
561             GetCallingConvention()->SetDynInfo(CallConvDynInfo());
562         }
563     }
564 
565     if (!GetEncoder()->GetResult()) {
566         return false;
567     }
568 
569     // Remove registers from the temp registers, if they are in the regalloc mask, i.e. available for regalloc.
570     auto usedRegs = ~GetGraph()->GetArchUsedRegs();
571     auto forbiddenTemps = usedRegs & GetTarget().GetTempRegsMask();
572     if (forbiddenTemps.Any()) {
573         for (size_t i = forbiddenTemps.GetMinRegister(); i <= forbiddenTemps.GetMaxRegister(); i++) {
574             if (forbiddenTemps[i] && encoder->IsScratchRegisterReleased(Reg(i, INT64_TYPE))) {
575                 encoder->AcquireScratchRegister(Reg(i, INT64_TYPE));
576             }
577         }
578     }
579 
580     return Finalize();
581 }
582 
Initialize()583 void Codegen::Initialize()
584 {
585     CreateFrameInfo();
586 
587     GetRegfile()->SetCalleeSaved(GetRegfile()->GetCalleeSaved());
588 
589     if (!GetGraph()->SupportManagedCode()) {
590         for (auto inst : GetGraph()->GetStartBlock()->AllInsts()) {
591             if (inst->GetOpcode() == Opcode::LiveIn && GetTarget().GetTempRegsMask().Test(inst->GetDstReg())) {
592                 GetEncoder()->AcquireScratchRegister(Reg(inst->GetDstReg(), INT64_TYPE));
593             }
594         }
595     }
596 
597     bool hasCalls = false;
598 
599     for (auto bb : GetGraph()->GetBlocksLinearOrder()) {
600         // Calls may be in the middle of method
601         for (auto inst : bb->Insts()) {
602             // For throw instruction need jump2runtime same way
603             if (inst->IsCall() || inst->GetOpcode() == Opcode::Throw) {
604                 hasCalls = true;
605                 break;
606             }
607         }
608         if (hasCalls) {
609             break;
610         }
611     }
612 
613     /* Convert Graph::GetUsedRegs(), which is std::vector<bool>, to simple
614      * RegMask and save it in the Codegen. These masks are used to determine
615      * which registers we need to save in prologue.
616      *
617      * NB! It's related to IRTOC specific prologue generation (see CodegenFastPath etc.).
618      * Arch specific CallingConvention::GenerateProlog() relies on reg usage information
619      * prepared in the Codegen constructor (before Initialize() is called).
620      */
621     auto fillMask = [](RegMask *mask, auto *vector) {
622         if (vector == nullptr) {
623             return;
624         }
625         ASSERT(mask->size() >= vector->size());
626         mask->reset();
627         for (size_t i = 0; i < mask->size(); i++) {
628             if ((*vector)[i]) {
629                 mask->set(i);
630             }
631         }
632     };
633     fillMask(&usedRegs_, GetGraph()->GetUsedRegs<DataType::INT64>());
634     fillMask(&usedVregs_, GetGraph()->GetUsedRegs<DataType::FLOAT64>());
635     usedVregs_ &= GetTarget().GetAvailableVRegsMask();
636     usedRegs_ &= GetTarget().GetAvailableRegsMask();
637     usedRegs_ &= ~GetGraph()->GetArchUsedRegs();
638     usedVregs_ &= ~GetGraph()->GetArchUsedVRegs();
639 
640     /* Remove used registers from Encoder's scratch registers */
641     RegMask usedTemps = usedRegs_ & GetTarget().GetTempRegsMask();
642     if (usedTemps.any()) {
643         for (size_t i = 0; i < usedTemps.size(); i++) {
644             if (usedTemps[i]) {
645                 GetEncoder()->AcquireScratchRegister(Reg(i, INT64_TYPE));
646             }
647         }
648     }
649 }
650 
Finalize()651 bool Codegen::Finalize()
652 {
653     if (GetDisasm()->IsEnabled()) {
654         GetDisasm()->PrintMethodEntry(this);
655     }
656 
657     if (!BeginMethod()) {
658         return false;
659     }
660 
661     if (!VisitGraph()) {
662         return false;
663     }
664     EndMethod();
665 
666     if (!CopyToCodeCache()) {
667         return false;
668     }
669 
670     if (GetDisasm()->IsEnabled()) {
671         IssueDisasm();
672     }
673 
674     return true;
675 }
676 
ConvertRegister(Register r,DataType::Type type)677 Reg Codegen::ConvertRegister(Register r, DataType::Type type)
678 {
679     switch (type) {
680         case DataType::BOOL:
681         case DataType::UINT8:
682         case DataType::INT8: {
683             return Reg(r, INT8_TYPE);
684         }
685         case DataType::UINT16:
686         case DataType::INT16: {
687             return Reg(r, INT16_TYPE);
688         }
689         case DataType::UINT32:
690         case DataType::INT32: {
691             return Reg(r, INT32_TYPE);
692         }
693         case DataType::UINT64:
694         case DataType::INT64:
695         case DataType::ANY: {
696             return Reg(r, INT64_TYPE);
697         }
698         case DataType::FLOAT32: {
699             return Reg(r, FLOAT32_TYPE);
700         }
701         case DataType::FLOAT64: {
702             return Reg(r, FLOAT64_TYPE);
703         }
704         case DataType::REFERENCE: {
705             return ConvertRegister(r, DataType::GetIntTypeForReference(GetArch()));
706         }
707         case DataType::POINTER: {
708             return Reg(r, ConvertDataType(DataType::POINTER, GetArch()));
709         }
710         default:
711             // Invalid converted register
712             return INVALID_REGISTER;
713     }
714 }
715 
716 // Panda don't support types less then 32, so we need sign or zero extended to 32
ConvertImmWithExtend(uint64_t imm,DataType::Type type)717 Imm Codegen::ConvertImmWithExtend(uint64_t imm, DataType::Type type)
718 {
719     switch (type) {
720         case DataType::BOOL:
721         case DataType::UINT8:
722             return Imm(static_cast<uint32_t>(static_cast<uint8_t>(imm)));
723         case DataType::INT8:
724             return Imm(static_cast<int32_t>(bit_cast<int8_t, uint8_t>(imm)));
725         case DataType::UINT16:
726             return Imm(static_cast<uint32_t>(static_cast<uint16_t>(imm)));
727         case DataType::INT16:
728             return Imm(static_cast<int32_t>(bit_cast<int16_t, uint16_t>(imm)));
729         // NOLINTNEXTLINE(bugprone-branch-clone)
730         case DataType::UINT32:
731             return Imm(bit_cast<int32_t, uint32_t>(imm));
732         case DataType::INT32:
733             return Imm(bit_cast<int32_t, uint32_t>(imm));
734         // NOLINTNEXTLINE(bugprone-branch-clone)
735         case DataType::UINT64:
736             return Imm(bit_cast<int64_t, uint64_t>(imm));
737         case DataType::INT64:
738             return Imm(bit_cast<int64_t, uint64_t>(imm));
739         case DataType::FLOAT32:
740             return Imm(bit_cast<float, uint32_t>(static_cast<uint32_t>(imm)));
741         case DataType::FLOAT64:
742             return Imm(bit_cast<double, uint64_t>(imm));
743         case DataType::ANY:
744             return Imm(bit_cast<uint64_t, uint64_t>(imm));
745         case DataType::REFERENCE:
746             if (imm == 0) {
747                 return Imm(0);
748             }
749             [[fallthrough]]; /* fall-through */
750         default:
751             // Invalid converted immediate
752             UNREACHABLE();
753     }
754     return Imm(0);
755 }
756 
ConvertCc(ConditionCode cc)757 Condition Codegen::ConvertCc(ConditionCode cc)
758 {
759     switch (cc) {
760         case CC_EQ:
761             return Condition::EQ;
762         case CC_NE:
763             return Condition::NE;
764         case CC_LT:
765             return Condition::LT;
766         case CC_LE:
767             return Condition::LE;
768         case CC_GT:
769             return Condition::GT;
770         case CC_GE:
771             return Condition::GE;
772         case CC_B:
773             return Condition::LO;
774         case CC_BE:
775             return Condition::LS;
776         case CC_A:
777             return Condition::HI;
778         case CC_AE:
779             return Condition::HS;
780         case CC_TST_EQ:
781             return Condition::TST_EQ;
782         case CC_TST_NE:
783             return Condition::TST_NE;
784         default:
785             UNREACHABLE();
786             return Condition::EQ;
787     }
788     return Condition::EQ;
789 }
790 
ConvertCcOverflow(ConditionCode cc)791 Condition Codegen::ConvertCcOverflow(ConditionCode cc)
792 {
793     switch (cc) {
794         case CC_EQ:
795             return Condition::VS;
796         case CC_NE:
797             return Condition::VC;
798         default:
799             UNREACHABLE();
800             return Condition::VS;
801     }
802     return Condition::VS;
803 }
804 
EmitSlowPaths()805 void Codegen::EmitSlowPaths()
806 {
807     for (auto slowPath : slowPaths_) {
808         slowPath->Generate(this);
809     }
810 }
811 
CreateStackMap(Inst * inst,Inst * user)812 void Codegen::CreateStackMap(Inst *inst, Inst *user)
813 {
814     SaveStateInst *saveState = nullptr;
815     if (inst->IsSaveState()) {
816         saveState = static_cast<SaveStateInst *>(inst);
817     } else {
818         saveState = inst->GetSaveState();
819     }
820     ASSERT(saveState != nullptr);
821 
822     bool requireVregMap = inst->RequireRegMap();
823     uint32_t outerBpc = inst->GetPc();
824     for (auto callInst = saveState->GetCallerInst(); callInst != nullptr;
825          callInst = callInst->GetSaveState()->GetCallerInst()) {
826         outerBpc = callInst->GetPc();
827     }
828     codeBuilder_->BeginStackMap(outerBpc, GetEncoder()->GetCursorOffset(), saveState->GetRootsStackMask(),
829                                 saveState->GetRootsRegsMask().to_ulong(), requireVregMap,
830                                 saveState->GetOpcode() == Opcode::SaveStateOsr);
831     if (user == nullptr) {
832         user = inst;
833         if (inst == saveState && inst->HasUsers()) {
834             auto users = inst->GetUsers();
835             auto it = std::find_if(users.begin(), users.end(),
836                                    [](auto &u) { return u.GetInst()->GetOpcode() != Opcode::ReturnInlined; });
837             user = it->GetInst();
838         }
839     }
840     CreateStackMapRec(saveState, requireVregMap, user);
841 
842     codeBuilder_->EndStackMap();
843     if (GetDisasm()->IsEnabled()) {
844         GetDisasm()->PrintStackMap(this);
845     }
846 }
847 
CreateStackMapRec(SaveStateInst * saveState,bool requireVregMap,Inst * targetSite)848 void Codegen::CreateStackMapRec(SaveStateInst *saveState, bool requireVregMap, Inst *targetSite)
849 {
850     bool hasInlineInfo = saveState->GetCallerInst() != nullptr;
851     size_t vregsCount = 0;
852     if (requireVregMap) {
853         auto runtime = GetRuntime();
854         if (auto caller = saveState->GetCallerInst()) {
855             vregsCount = runtime->GetMethodRegistersCount(caller->GetCallMethod()) +
856                          runtime->GetMethodArgumentsCount(caller->GetCallMethod());
857         } else {
858             vregsCount = runtime->GetMethodRegistersCount(saveState->GetMethod()) +
859                          runtime->GetMethodArgumentsCount(saveState->GetMethod());
860         }
861         ASSERT(!GetGraph()->IsBytecodeOptimizer());
862         // 1 for acc, number of env regs for dynamic method
863         vregsCount += 1U + GetGraph()->GetEnvCount();
864 #ifndef NDEBUG
865         ASSERT_PRINT(!saveState->GetInputsWereDeleted(), "Some vregs were deleted from the save state");
866 #endif
867     }
868 
869     if (auto callInst = saveState->GetCallerInst()) {
870         CreateStackMapRec(callInst->GetSaveState(), requireVregMap, targetSite);
871         auto method = GetGraph()->IsAotMode() ? nullptr : callInst->GetCallMethod();
872         codeBuilder_->BeginInlineInfo(method, GetRuntime()->GetMethodId(callInst->GetCallMethod()), saveState->GetPc(),
873                                       vregsCount);
874     }
875 
876     if (requireVregMap) {
877         CreateVRegMap(saveState, vregsCount, targetSite);
878     }
879 
880     if (hasInlineInfo) {
881         codeBuilder_->EndInlineInfo();
882     }
883 }
884 
CreateVRegMap(SaveStateInst * saveState,size_t vregsCount,Inst * targetSite)885 void Codegen::CreateVRegMap(SaveStateInst *saveState, size_t vregsCount, Inst *targetSite)
886 {
887     vregIndices_.clear();
888     vregIndices_.resize(vregsCount, {-1, -1});
889     FillVregIndices(saveState);
890 
891     ASSERT(GetGraph()->IsAnalysisValid<LivenessAnalyzer>());
892     auto &la = GetGraph()->GetAnalysis<LivenessAnalyzer>();
893     auto targetLifeNumber = la.GetInstLifeIntervals(targetSite)->GetBegin();
894 
895     for (auto &inputIndex : vregIndices_) {
896         if (inputIndex.first == -1 && inputIndex.second == -1) {
897             codeBuilder_->AddVReg(VRegInfo());
898             continue;
899         }
900         if (inputIndex.second != -1) {
901             auto imm = saveState->GetImmediate(inputIndex.second);
902             codeBuilder_->AddConstant(imm.value, IrTypeToMetainfoType(imm.type), imm.vregType);
903             continue;
904         }
905         ASSERT(inputIndex.first != -1);
906         auto vreg = saveState->GetVirtualRegister(inputIndex.first);
907         auto inputInst = saveState->GetDataFlowInput(inputIndex.first);
908         auto interval = la.GetInstLifeIntervals(inputInst)->FindSiblingAt(targetLifeNumber);
909         ASSERT(interval != nullptr);
910         CreateVreg(interval->GetLocation(), inputInst, vreg);
911     }
912 }
913 
CreateVreg(const Location & location,Inst * inst,const VirtualRegister & vreg)914 void Codegen::CreateVreg(const Location &location, Inst *inst, const VirtualRegister &vreg)
915 {
916     switch (location.GetKind()) {
917         case LocationType::FP_REGISTER:
918         case LocationType::REGISTER: {
919             CreateVRegForRegister(location, inst, vreg);
920             break;
921         }
922         case LocationType::STACK_PARAMETER: {
923             auto slot = location.GetValue();
924             codeBuilder_->AddVReg(VRegInfo(GetFrameLayout().GetStackArgsStartSlot() - slot - CFrameSlots::Start(),
925                                            VRegInfo::Location::SLOT, IrTypeToMetainfoType(inst->GetType()),
926                                            vreg.GetVRegType()));
927             break;
928         }
929         case LocationType::STACK: {
930             auto slot = location.GetValue();
931             if (!Is64BitsArch(GetArch())) {
932                 slot = ((location.GetValue() << 1U) + 1);
933             }
934             codeBuilder_->AddVReg(VRegInfo(GetFrameLayout().GetFirstSpillSlot() + slot, VRegInfo::Location::SLOT,
935                                            IrTypeToMetainfoType(inst->GetType()), vreg.GetVRegType()));
936             break;
937         }
938         case LocationType::IMMEDIATE: {
939             ASSERT(inst->IsConst());
940             auto type = inst->GetType();
941             // There are no int64 type for dynamic methods.
942             if (GetGraph()->IsDynamicMethod() && type == DataType::INT64) {
943                 type = DataType::INT32;
944             }
945             codeBuilder_->AddConstant(inst->CastToConstant()->GetRawValue(), IrTypeToMetainfoType(type),
946                                       vreg.GetVRegType());
947             break;
948         }
949         default:
950             // Reg-to-reg spill fill must not occurs within SaveState
951             UNREACHABLE();
952     }
953 }
954 
FillVregIndices(SaveStateInst * saveState)955 void Codegen::FillVregIndices(SaveStateInst *saveState)
956 {
957     for (size_t i = 0; i < saveState->GetInputsCount(); ++i) {
958         size_t vregIndex = saveState->GetVirtualRegister(i).Value();
959         if (vregIndex == VirtualRegister::BRIDGE) {
960             continue;
961         }
962         ASSERT(vregIndex < vregIndices_.size());
963         vregIndices_[vregIndex].first = i;
964     }
965     for (size_t i = 0; i < saveState->GetImmediatesCount(); i++) {
966         auto vregImm = saveState->GetImmediate(i);
967         if (vregImm.vreg == VirtualRegister::BRIDGE) {
968             continue;
969         }
970         ASSERT(vregImm.vreg < vregIndices_.size());
971         ASSERT(vregIndices_[vregImm.vreg].first == -1);
972         vregIndices_[vregImm.vreg].second = i;
973     }
974 }
975 
CreateVRegForRegister(const Location & location,Inst * inst,const VirtualRegister & vreg)976 void Codegen::CreateVRegForRegister(const Location &location, Inst *inst, const VirtualRegister &vreg)
977 {
978     bool isOsr = GetGraph()->IsOsrMode();
979     bool isFp = (location.GetKind() == LocationType::FP_REGISTER);
980     auto regNum = location.GetValue();
981     auto reg = Reg(regNum, isFp ? FLOAT64_TYPE : INT64_TYPE);
982     if (!isOsr && GetRegfile()->GetZeroReg() == reg) {
983         codeBuilder_->AddConstant(0, IrTypeToMetainfoType(inst->GetType()), vreg.GetVRegType());
984     } else if (isOsr || GetRegfile()->IsCalleeRegister(reg)) {
985         if (isFp) {
986             ASSERT(inst->GetType() != DataType::REFERENCE);
987             ASSERT(isOsr || regNum >= GetFirstCalleeReg(GetArch(), true));
988             codeBuilder_->AddVReg(VRegInfo(regNum, VRegInfo::Location::FP_REGISTER,
989                                            IrTypeToMetainfoType(inst->GetType()), vreg.GetVRegType()));
990         } else {
991             ASSERT(isOsr || regNum >= GetFirstCalleeReg(GetArch(), false));
992             codeBuilder_->AddVReg(VRegInfo(regNum, VRegInfo::Location::REGISTER, IrTypeToMetainfoType(inst->GetType()),
993                                            vreg.GetVRegType()));
994         }
995     } else {
996         ASSERT(regNum >= GetFirstCallerReg(GetArch(), isFp));
997         auto lastSlot = GetFrameLayout().GetCallerLastSlot(isFp);
998         regNum -= GetFirstCallerReg(GetArch(), isFp);
999         codeBuilder_->AddVReg(VRegInfo(lastSlot - regNum, VRegInfo::Location::SLOT,
1000                                        IrTypeToMetainfoType(inst->GetType()), vreg.GetVRegType()));
1001     }
1002 }
1003 
CreateOsrEntry(SaveStateInst * saveState)1004 void Codegen::CreateOsrEntry(SaveStateInst *saveState)
1005 {
1006     auto &stub = osrEntries_.emplace_back(GetAllocator()->New<OsrEntryStub>(this, saveState));
1007     GetEncoder()->BindLabel(stub->GetLabel());
1008 }
1009 
CallIntrinsic(Inst * inst,RuntimeInterface::IntrinsicId id)1010 void Codegen::CallIntrinsic(Inst *inst, RuntimeInterface::IntrinsicId id)
1011 {
1012     SCOPED_DISASM_STR(this, "CallIntrinsic");
1013     // Call intrinsics isn't supported for IrToc, because we don't know address of intrinsics during IRToc compilation.
1014     // We store adresses of intrinsics in aot file in AOT mode.
1015     ASSERT(GetGraph()->SupportManagedCode());
1016     if (GetGraph()->IsAotMode()) {
1017         auto aotData = GetGraph()->GetAotData();
1018         intptr_t offset = aotData->GetEntrypointOffset(GetEncoder()->GetCursorOffset(), static_cast<int32_t>(id));
1019         GetEncoder()->MakeCallAot(offset);
1020     } else {
1021         GetEncoder()->MakeCall(reinterpret_cast<const void *>(GetRuntime()->GetIntrinsicAddress(
1022             inst->IsRuntimeCall(), GetRuntime()->GetMethodSourceLanguage(GetGraph()->GetMethod()), id)));
1023     }
1024 }
1025 
EmitCallRuntimeCode(Inst * inst,std::variant<EntrypointId,Reg> entrypoint)1026 bool Codegen::EmitCallRuntimeCode(Inst *inst, std::variant<EntrypointId, Reg> entrypoint)
1027 {
1028     auto encoder = GetEncoder();
1029     if (std::holds_alternative<Reg>(entrypoint)) {
1030         auto reg = std::get<Reg>(entrypoint);
1031         ASSERT(reg.IsValid());
1032         encoder->MakeCall(reg);
1033     } else {
1034         auto id = std::get<EntrypointId>(entrypoint);
1035         MemRef entry(ThreadReg(), GetRuntime()->GetEntrypointTlsOffset(GetArch(), id));
1036         encoder->MakeCall(entry);
1037     }
1038 
1039     SaveStateInst *saveState =
1040         (inst == nullptr || inst->IsSaveState()) ? static_cast<SaveStateInst *>(inst) : inst->GetSaveState();
1041     // StackMap should follow the call as the bridge function expects retaddr points to the stackmap
1042     if (saveState != nullptr) {
1043         CreateStackMap(inst);
1044     }
1045 
1046     if (std::holds_alternative<EntrypointId>(entrypoint) &&
1047         GetRuntime()->IsEntrypointNoreturn(std::get<EntrypointId>(entrypoint))) {
1048         if constexpr (DEBUG_BUILD) {  // NOLINT
1049             encoder->EncodeAbort();
1050         }
1051         return false;
1052     }
1053     ASSERT(saveState == nullptr || inst->IsRuntimeCall());
1054 
1055     return true;
1056 }
1057 
SaveRegistersForImplicitRuntime(Inst * inst,RegMask * paramsMask,RegMask * mask)1058 void Codegen::SaveRegistersForImplicitRuntime(Inst *inst, RegMask *paramsMask, RegMask *mask)
1059 {
1060     auto &rootsMask = inst->GetSaveState()->GetRootsRegsMask();
1061     for (auto i = 0U; i < inst->GetInputsCount(); i++) {
1062         auto input = inst->GetDataFlowInput(i);
1063         if (!input->IsMovableObject()) {
1064             continue;
1065         }
1066         auto location = inst->GetLocation(i);
1067         if (location.IsRegister() && location.IsRegisterValid()) {
1068             auto val = location.GetValue();
1069             auto reg = Reg(val, INT64_TYPE);
1070             GetEncoder()->SetRegister(mask, nullptr, reg, true);
1071             if (DataType::IsReference(inst->GetInputType(i)) && !rootsMask.test(val)) {
1072                 paramsMask->set(val);
1073                 rootsMask.set(val);
1074             }
1075         }
1076     }
1077 }
1078 
CreateCheckForTLABWithConstSize(Inst * inst,Reg regTlabStart,Reg regTlabSize,size_t size,LabelHolder::LabelId label)1079 void Codegen::CreateCheckForTLABWithConstSize([[maybe_unused]] Inst *inst, Reg regTlabStart, Reg regTlabSize,
1080                                               size_t size, LabelHolder::LabelId label)
1081 {
1082     SCOPED_DISASM_STR(this, "CreateCheckForTLABWithConstSize");
1083     auto encoder = GetEncoder();
1084     if (encoder->CanEncodeImmAddSubCmp(size, WORD_SIZE, false)) {
1085         encoder->EncodeJump(label, regTlabSize, Imm(size), Condition::LO);
1086         // Change pointer to start free memory
1087         encoder->EncodeAdd(regTlabSize, regTlabStart, Imm(size));
1088     } else {
1089         ScopedTmpReg sizeReg(encoder);
1090         encoder->EncodeMov(sizeReg, Imm(size));
1091         encoder->EncodeJump(label, regTlabSize, sizeReg, Condition::LO);
1092         encoder->EncodeAdd(regTlabSize, regTlabStart, sizeReg);
1093     }
1094 }
1095 
CreateDebugRuntimeCallsForNewObject(Inst * inst,Reg regTlabStart,size_t allocSize,RegMask preserved)1096 void Codegen::CreateDebugRuntimeCallsForNewObject(Inst *inst, [[maybe_unused]] Reg regTlabStart, size_t allocSize,
1097                                                   RegMask preserved)
1098 {
1099 #if defined(PANDA_ASAN_ON) || defined(PANDA_TSAN_ON)
1100     CallRuntime(inst, EntrypointId::ANNOTATE_SANITIZERS, INVALID_REGISTER, preserved, regTlabStart,
1101                 TypedImm(allocSize));
1102 #endif
1103     if (GetRuntime()->IsTrackTlabAlloc()) {
1104         CallRuntime(inst, EntrypointId::WRITE_TLAB_STATS, INVALID_REGISTER, preserved, regTlabStart,
1105                     TypedImm(allocSize));
1106     }
1107 }
1108 
CreateNewObjCall(NewObjectInst * newObj)1109 void Codegen::CreateNewObjCall(NewObjectInst *newObj)
1110 {
1111     auto dst = ConvertRegister(newObj->GetDstReg(), newObj->GetType());
1112     auto src = ConvertRegister(newObj->GetSrcReg(0), newObj->GetInputType(0));
1113     auto initClass = newObj->GetInput(0).GetInst();
1114     auto srcClass = ConvertRegister(newObj->GetSrcReg(0), DataType::POINTER);
1115     auto runtime = GetRuntime();
1116 
1117     auto maxTlabSize = runtime->GetTLABMaxSize();
1118     if (maxTlabSize == 0 ||
1119         (initClass->GetOpcode() != Opcode::LoadAndInitClass && initClass->GetOpcode() != Opcode::LoadImmediate)) {
1120         CallRuntime(newObj, EntrypointId::CREATE_OBJECT_BY_CLASS, dst, RegMask::GetZeroMask(), src);
1121         return;
1122     }
1123     RuntimeInterface::ClassPtr klass;
1124     if (initClass->GetOpcode() == Opcode::LoadAndInitClass) {
1125         klass = initClass->CastToLoadAndInitClass()->GetClass();
1126     } else {
1127         ASSERT(initClass->GetOpcode() == Opcode::LoadImmediate);
1128         klass = initClass->CastToLoadImmediate()->GetClass();
1129     }
1130     if (klass == nullptr || !runtime->CanUseTlabForClass(klass)) {
1131         CallRuntime(newObj, EntrypointId::CREATE_OBJECT_BY_CLASS, dst, RegMask::GetZeroMask(), src);
1132         return;
1133     }
1134     auto classSize = runtime->GetClassSize(klass);
1135     auto alignment = runtime->GetTLABAlignment();
1136 
1137     classSize = (classSize & ~(alignment - 1U)) + ((classSize % alignment) != 0U ? alignment : 0U);
1138     if (classSize > maxTlabSize) {
1139         CallRuntime(newObj, EntrypointId::CREATE_OBJECT_BY_CLASS, dst, RegMask::GetZeroMask(), src);
1140         return;
1141     }
1142     CallFastPath(newObj, EntrypointId::ALLOCATE_OBJECT_TLAB, dst, RegMask::GetZeroMask(), srcClass,
1143                  TypedImm(classSize));
1144 }
1145 
CreateNewObjCallOld(NewObjectInst * newObj)1146 void Codegen::CreateNewObjCallOld(NewObjectInst *newObj)
1147 {
1148     auto dst = ConvertRegister(newObj->GetDstReg(), newObj->GetType());
1149     auto src = ConvertRegister(newObj->GetSrcReg(0), newObj->GetInputType(0));
1150     auto initClass = newObj->GetInput(0).GetInst();
1151     auto runtime = GetRuntime();
1152     auto maxTlabSize = runtime->GetTLABMaxSize();
1153     auto encoder = GetEncoder();
1154 
1155     if (maxTlabSize == 0 ||
1156         (initClass->GetOpcode() != Opcode::LoadAndInitClass && initClass->GetOpcode() != Opcode::LoadImmediate)) {
1157         CallRuntime(newObj, EntrypointId::CREATE_OBJECT_BY_CLASS, dst, RegMask::GetZeroMask(), src);
1158         return;
1159     }
1160     RuntimeInterface::ClassPtr klass;
1161     if (initClass->GetOpcode() == Opcode::LoadAndInitClass) {
1162         klass = initClass->CastToLoadAndInitClass()->GetClass();
1163     } else {
1164         ASSERT(initClass->GetOpcode() == Opcode::LoadImmediate);
1165         klass = initClass->CastToLoadImmediate()->GetClass();
1166     }
1167     if (klass == nullptr || !runtime->CanUseTlabForClass(klass)) {
1168         CallRuntime(newObj, EntrypointId::CREATE_OBJECT_BY_CLASS, dst, RegMask::GetZeroMask(), src);
1169         return;
1170     }
1171     auto classSize = runtime->GetClassSize(klass);
1172     auto alignment = runtime->GetTLABAlignment();
1173 
1174     classSize = (classSize & ~(alignment - 1U)) + ((classSize % alignment) != 0U ? alignment : 0U);
1175     if (classSize > maxTlabSize) {
1176         CallRuntime(newObj, EntrypointId::CREATE_OBJECT_BY_CLASS, dst, RegMask::GetZeroMask(), src);
1177         return;
1178     }
1179     ScopedLiveTmpReg regTlabStart(encoder);
1180     ScopedLiveTmpReg regTlabSize(encoder);
1181 
1182     auto slowPath = CreateSlowPath<SlowPathEntrypoint>(newObj, EntrypointId::CREATE_OBJECT_BY_CLASS);
1183     CreateLoadTLABInformation(regTlabStart, regTlabSize);
1184     CreateCheckForTLABWithConstSize(newObj, regTlabStart, regTlabSize, classSize, slowPath->GetLabel());
1185 
1186     RegMask preservedRegs;
1187     encoder->SetRegister(&preservedRegs, nullptr, src);
1188     CreateDebugRuntimeCallsForNewObject(newObj, regTlabStart, reinterpret_cast<size_t>(classSize), preservedRegs);
1189 
1190     ScopedTmpReg tlabReg(encoder);
1191     // Load pointer to tlab
1192     encoder->EncodeLdr(tlabReg, false, MemRef(ThreadReg(), runtime->GetCurrentTLABOffset(GetArch())));
1193 
1194     // Store pointer to the class
1195     encoder->EncodeStr(src, MemRef(regTlabStart, runtime->GetObjClassOffset(GetArch())));
1196     encoder->EncodeMov(dst, regTlabStart);
1197     regTlabStart.Release();
1198     // Store new pointer to start free memory in TLAB
1199     encoder->EncodeStrRelease(regTlabSize, MemRef(tlabReg, runtime->GetTLABFreePointerOffset(GetArch())));
1200     slowPath->BindBackLabel(encoder);
1201 }
1202 
LoadClassFromObject(Reg classReg,Reg objReg)1203 void Codegen::LoadClassFromObject(Reg classReg, Reg objReg)
1204 {
1205     Reg reg = ConvertRegister(classReg.GetId(), DataType::REFERENCE);
1206     GetEncoder()->EncodeLdr(reg, false, MemRef(objReg, GetRuntime()->GetObjClassOffset(GetArch())));
1207 }
1208 
CreateMultiArrayCall(CallInst * callInst)1209 void Codegen::CreateMultiArrayCall(CallInst *callInst)
1210 {
1211     SCOPED_DISASM_STR(this, "Create Call for MultiArray");
1212 
1213     auto dstReg = ConvertRegister(callInst->GetDstReg(), callInst->GetType());
1214     auto numArgs = callInst->GetInputsCount() - 2U;  // first is class, last is save_state
1215 
1216     ScopedTmpReg classReg(GetEncoder());
1217     auto classType = ConvertDataType(DataType::REFERENCE, GetArch());
1218     Reg classOrig = classReg.GetReg().As(classType);
1219     auto location = callInst->GetLocation(0);
1220     ASSERT(location.IsFixedRegister() && location.IsRegisterValid());
1221 
1222     GetEncoder()->EncodeMov(classOrig, ConvertRegister(location.GetValue(), DataType::INT32));
1223     CallRuntime(callInst, EntrypointId::CREATE_MULTI_ARRAY, dstReg, RegMask::GetZeroMask(), classReg, TypedImm(numArgs),
1224                 SpReg());
1225     if (callInst->GetFlag(inst_flags::MEM_BARRIER)) {
1226         GetEncoder()->EncodeMemoryBarrier(memory_order::RELEASE);
1227     }
1228 }
1229 
CreateJumpToClassResolverPltShared(Inst * inst,Reg tmpReg,RuntimeInterface::EntrypointId id)1230 void Codegen::CreateJumpToClassResolverPltShared(Inst *inst, Reg tmpReg, RuntimeInterface::EntrypointId id)
1231 {
1232     auto encoder = GetEncoder();
1233     auto graph = GetGraph();
1234     auto aotData = graph->GetAotData();
1235     auto offset = aotData->GetSharedSlowPathOffset(id, encoder->GetCursorOffset());
1236     if (offset == 0 || !encoder->CanMakeCallByOffset(offset)) {
1237         SlowPathShared *slowPath;
1238         auto search = slowPathsMap_.find(id);
1239         if (search != slowPathsMap_.end()) {
1240             slowPath = search->second;
1241             ASSERT(slowPath->GetTmpReg().GetId() == tmpReg.GetId());
1242         } else {
1243             slowPath = CreateSlowPath<SlowPathShared>(inst, id);
1244             slowPath->SetTmpReg(tmpReg);
1245             slowPathsMap_[id] = slowPath;
1246         }
1247         encoder->MakeCall(slowPath->GetLabel());
1248     } else {
1249         encoder->MakeCallByOffset(offset);
1250     }
1251     CreateStackMap(inst);
1252 }
1253 
CreateLoadClassFromPLT(Inst * inst,Reg tmpReg,Reg dst,size_t classId)1254 void Codegen::CreateLoadClassFromPLT(Inst *inst, Reg tmpReg, Reg dst, size_t classId)
1255 {
1256     auto encoder = GetEncoder();
1257     auto graph = GetGraph();
1258     auto aotData = graph->GetAotData();
1259     intptr_t offset = aotData->GetClassSlotOffset(encoder->GetCursorOffset(), classId, false);
1260     auto label = encoder->CreateLabel();
1261     ASSERT(tmpReg.GetId() != dst.GetId());
1262     ASSERT(inst->IsRuntimeCall());
1263     encoder->MakeLoadAotTableAddr(offset, tmpReg, dst);
1264     encoder->EncodeJump(label, dst, Condition::NE);
1265 
1266     // PLT Class Resolver has special calling convention:
1267     // First encoder temporary (tmp_reg) works as parameter and return value
1268     CHECK_EQ(tmpReg.GetId(), encoder->GetTarget().GetTempRegsMask().GetMinRegister());
1269 
1270     CreateJumpToClassResolverPltShared(inst, tmpReg, EntrypointId::CLASS_RESOLVER);
1271 
1272     encoder->EncodeMov(dst, tmpReg);
1273     encoder->BindLabel(label);
1274 }
1275 
CreateLoadTLABInformation(Reg regTlabStart,Reg regTlabSize)1276 void Codegen::CreateLoadTLABInformation(Reg regTlabStart, Reg regTlabSize)
1277 {
1278     SCOPED_DISASM_STR(this, "LoadTLABInformation");
1279     auto runtime = GetRuntime();
1280     // Load pointer to tlab
1281     GetEncoder()->EncodeLdr(regTlabSize, false, MemRef(ThreadReg(), runtime->GetCurrentTLABOffset(GetArch())));
1282     // Load pointer to start free memory in TLAB
1283     GetEncoder()->EncodeLdr(regTlabStart, false, MemRef(regTlabSize, runtime->GetTLABFreePointerOffset(GetArch())));
1284     // Load pointer to end free memory in TLAB
1285     GetEncoder()->EncodeLdr(regTlabSize, false, MemRef(regTlabSize, runtime->GetTLABEndPointerOffset(GetArch())));
1286     // Calculate size of the free memory
1287     GetEncoder()->EncodeSub(regTlabSize, regTlabSize, regTlabStart);
1288 }
1289 
1290 // The function alignment up the value from alignment_reg using tmp_reg.
CreateAlignmentValue(Reg alignmentReg,Reg tmpReg,size_t alignment)1291 void Codegen::CreateAlignmentValue(Reg alignmentReg, Reg tmpReg, size_t alignment)
1292 {
1293     auto andVal = ~(alignment - 1U);
1294     // zeroed lower bits
1295     GetEncoder()->EncodeAnd(tmpReg, alignmentReg, Imm(andVal));
1296     GetEncoder()->EncodeSub(alignmentReg, alignmentReg, tmpReg);
1297 
1298     auto endLabel = GetEncoder()->CreateLabel();
1299 
1300     // if zeroed value is different, add alignment
1301     GetEncoder()->EncodeJump(endLabel, alignmentReg, Condition::EQ);
1302     GetEncoder()->EncodeAdd(tmpReg, tmpReg, Imm(alignment));
1303 
1304     GetEncoder()->BindLabel(endLabel);
1305     GetEncoder()->EncodeMov(alignmentReg, tmpReg);
1306 }
1307 
GetObjectReg(Codegen * codegen,Inst * inst)1308 inline Reg GetObjectReg(Codegen *codegen, Inst *inst)
1309 {
1310     ASSERT(inst->IsCall() || inst->GetOpcode() == Opcode::ResolveVirtual);
1311     auto location = inst->GetLocation(0);
1312     ASSERT(location.IsFixedRegister() && location.IsRegisterValid());
1313     auto objReg = codegen->ConvertRegister(location.GetValue(), inst->GetInputType(0));
1314     ASSERT(objReg != INVALID_REGISTER);
1315     return objReg;
1316 }
1317 
CreateCallIntrinsic(IntrinsicInst * inst)1318 void Codegen::CreateCallIntrinsic(IntrinsicInst *inst)
1319 {
1320     if (inst->HasArgumentsOnStack()) {
1321         // Since for some intrinsics(f.e. TimedWaitNanos) we need SaveState instruction and
1322         // more than two arguments, we need to place arguments on the stack, but in same time we need to
1323         // create boundary frame
1324         LOG(WARNING, COMPILER) << "Intrinsics with arguments on stack are not supported";
1325         GetEncoder()->SetFalseResult();
1326         return;
1327     }
1328 
1329     ASSERT(!HasLiveCallerSavedRegs(inst));
1330     if (inst->HasImms() && GetGraph()->SupportManagedCode()) {
1331         EncodeImms(inst->GetImms(), (inst->HasIdInput() || inst->IsMethodFirstInput()));
1332     }
1333 
1334     size_t explicitArgs;
1335     if (IsStackRangeIntrinsic(inst->GetIntrinsicId(), &explicitArgs)) {
1336         auto paramInfo = GetCallingConvention()->GetParameterInfo(explicitArgs);
1337         auto rangePtrReg =
1338             ConvertRegister(paramInfo->GetNextLocation(DataType::POINTER).GetRegister(), DataType::POINTER);
1339         if (inst->GetInputsCount() > explicitArgs + (inst->RequireState() ? 1U : 0U)) {
1340             auto rangeSpOffs = GetStackOffset(inst->GetLocation(explicitArgs));
1341             GetEncoder()->EncodeAdd(rangePtrReg, GetTarget().GetStackReg(), Imm(rangeSpOffs));
1342         }
1343     }
1344     if (inst->IsMethodFirstInput()) {
1345         Reg param0 = GetTarget().GetParamReg(0);
1346         if (GetGraph()->IsAotMode()) {
1347             LoadMethod(param0);
1348         } else {
1349             GetEncoder()->EncodeMov(param0, Imm(reinterpret_cast<uintptr_t>(inst->GetMethod())));
1350         }
1351     }
1352     CallIntrinsic(inst, inst->GetIntrinsicId());
1353 
1354     if (inst->GetSaveState() != nullptr) {
1355         // StackMap should follow the call as the bridge function expects retaddr points to the stackmap
1356         CreateStackMap(inst);
1357     }
1358 
1359     if (inst->GetType() != DataType::VOID) {
1360         auto arch = GetArch();
1361         auto returnType = inst->GetType();
1362         auto dstReg = ConvertRegister(inst->GetDstReg(), inst->GetType());
1363         auto returnReg = GetTarget().GetReturnReg(dstReg.GetType());
1364         // We must:
1365         //  sign extended INT8 and INT16 to INT32
1366         //  zero extended UINT8 and UINT16 to UINT32
1367         if (DataType::ShiftByType(returnType, arch) < DataType::ShiftByType(DataType::INT32, arch)) {
1368             bool isSigned = DataType::IsTypeSigned(returnType);
1369             GetEncoder()->EncodeCast(dstReg, isSigned, Reg(returnReg.GetId(), INT32_TYPE), isSigned);
1370         } else {
1371             GetEncoder()->EncodeMov(dstReg, returnReg);
1372         }
1373     }
1374 }
1375 
IntfInlineCachePass(ResolveVirtualInst * resolver,Reg methodReg,Reg tmpReg,Reg objReg)1376 void Codegen::IntfInlineCachePass(ResolveVirtualInst *resolver, Reg methodReg, Reg tmpReg, Reg objReg)
1377 {
1378     // Cache structure:(offset addr)/(class addr) 32bit/32bit
1379     // -----------------------------------------------
1380     // (.aot_got)
1381     //     ...
1382     //     cache:offset/class   <----------|
1383     //     ...                             |
1384     // (.text)                             |
1385     // interface call start                |
1386     // call runtime irtoc function
1387     // if call class == cache.class <------|
1388     //    use cache.offset(method)  <------|
1389     // else                                |
1390     //    call RESOLVE_VIRTUAL_CALL_AOT    |
1391     //    save method‘s offset to cache >--|
1392     // return to (.text)
1393     // call method
1394     // -----------------------------------------------
1395     auto aotData = GetGraph()->GetAotData();
1396     uint64_t intfInlineCacheIndex = aotData->GetIntfInlineCacheIndex();
1397     // NOTE(liyiming): do LoadMethod in irtoc to reduce use tmp reg
1398     if (objReg.GetId() != tmpReg.GetId()) {
1399         auto regTmp64 = tmpReg.As(INT64_TYPE);
1400         uint64_t offset = aotData->GetInfInlineCacheSlotOffset(GetEncoder()->GetCursorOffset(), intfInlineCacheIndex);
1401         GetEncoder()->MakeLoadAotTableAddr(offset, regTmp64, INVALID_REGISTER);
1402         LoadMethod(methodReg);
1403         CallFastPath(resolver, EntrypointId::INTF_INLINE_CACHE, methodReg, {}, methodReg, objReg,
1404                      TypedImm(resolver->GetCallMethodId()), regTmp64);
1405     } else {
1406         // we don't have tmp reg here, so use x3 directly
1407         Reg reg3 = Reg(3U, INT64_TYPE);
1408         ScopedTmpRegF64 vtmp(GetEncoder());
1409         GetEncoder()->EncodeMov(vtmp, reg3);
1410         uint64_t offset = aotData->GetInfInlineCacheSlotOffset(GetEncoder()->GetCursorOffset(), intfInlineCacheIndex);
1411         GetEncoder()->MakeLoadAotTableAddr(offset, reg3, INVALID_REGISTER);
1412         LoadMethod(methodReg);
1413         CallFastPath(resolver, EntrypointId::INTF_INLINE_CACHE, methodReg, {}, methodReg, objReg,
1414                      TypedImm(resolver->GetCallMethodId()), reg3);
1415         GetEncoder()->EncodeMov(reg3, vtmp);
1416     }
1417 
1418     intfInlineCacheIndex++;
1419     aotData->SetIntfInlineCacheIndex(intfInlineCacheIndex);
1420 }
1421 
1422 /**
1423  * Returns a pointer to a caller of a virtual/static resolver.
1424  *
1425  * InstBuilder uses UnresolvedTypesInterface::AddTableSlot(method_ptr, ...) to allocate cache slots
1426  * for unresolved methods. The codegen uses UnresolvedTypesInterface::GetTableSlot(method_ptr, ...)
1427  * to get corresponding slots for unresolved methods.
1428  *
1429  * Since there is no valid method_ptr for an unresolved method at the point of IR construction
1430  * InstBuilder::BuildCallInst uses the pointer to the caller (GetGraph()->GetMethod()) as an argument
1431  * of UnresolvedTypesInterface::AddTableSlot. So the codegen has to deduce the pointer to the caller
1432  * and pass it to UnresolvedTypesInterface::GetTableSlot. If the caller was not inlined then
1433  * GetGraph()->GetMethod() works just fine, otherwise it is done by means of SaveState,
1434  * which is capable of remebering the corresponding caller instruction.
1435  *
1436  * To clarify the details let's consider the following sequence of calls:
1437  *
1438  * main() -> foo() -> bar()
1439  *
1440  * Suppose that foo() is a static method and bar() is an unresolved virtual method.
1441  *
1442  * 1) foo() is going to be inlined
1443  *
1444  * To inline foo() the inlining pass creates its IR by means of IRBuilder(..., caller_inst),
1445  * where caller_inst (the third argument) represents "CallStatic foo" instruction.
1446  * The caller_inst gets remembered in the corresponding SaveState created for bar's resolver
1447  * (see InstBuilder::CreateSaveState for the details).
1448  * At the same time "CallStatic foo" instruction contains a valid method pointer to foo()
1449  * (it can not be nullptr because we do not inline Unresolved).
1450  *
1451  * So we go through the following chain: bar's resolver->SaveState->caller_inst->pointer to the method.
1452  *
1453  * 2) foo() is not inlined
1454  *
1455  * In this case SaveState.caller_inst_ == nullptr (because foo() is not inlined).
1456  * Thus we just use plain GetGraph()->GetMethod().
1457  */
1458 template <typename T>
GetCallerOfUnresolvedMethod(T * resolver)1459 RuntimeInterface::MethodPtr Codegen::GetCallerOfUnresolvedMethod(T *resolver)
1460 {
1461     ASSERT(resolver->GetCallMethod() == nullptr);
1462     auto saveState = resolver->GetSaveState();
1463     ASSERT(saveState != nullptr);
1464     auto caller = saveState->GetCallerInst();
1465     auto method = (caller == nullptr ? GetGraph()->GetMethod() : caller->GetCallMethod());
1466     ASSERT(method != nullptr);
1467     return method;
1468 }
1469 
EmitResolveUnknownVirtual(ResolveVirtualInst * resolver,Reg methodReg)1470 void Codegen::EmitResolveUnknownVirtual(ResolveVirtualInst *resolver, Reg methodReg)
1471 {
1472     SCOPED_DISASM_STR(this, "Create runtime call to resolve an unknown virtual method");
1473     ASSERT(resolver->GetOpcode() == Opcode::ResolveVirtual);
1474     auto method = GetCallerOfUnresolvedMethod(resolver);
1475     ScopedTmpReg tmpReg(GetEncoder(), ConvertDataType(DataType::REFERENCE, GetArch()));
1476     Reg objReg = GetObjectReg(this, resolver);
1477     if (GetGraph()->IsAotMode()) {
1478         LoadMethod(methodReg);
1479         CallRuntime(resolver, EntrypointId::RESOLVE_VIRTUAL_CALL_AOT, methodReg, {}, methodReg, objReg,
1480                     TypedImm(resolver->GetCallMethodId()), TypedImm(0));
1481     } else {
1482         auto runtime = GetRuntime();
1483         auto utypes = runtime->GetUnresolvedTypes();
1484         auto skind = UnresolvedTypesInterface::SlotKind::VIRTUAL_METHOD;
1485         // Try to load vtable index
1486         auto methodSlotAddr = utypes->GetTableSlot(method, resolver->GetCallMethodId(), skind);
1487         GetEncoder()->EncodeMov(methodReg, Imm(methodSlotAddr));
1488         GetEncoder()->EncodeLdr(methodReg, false, MemRef(methodReg));
1489         // 0 means the virtual call is uninitialized or it is an interface call
1490         auto entrypoint = EntrypointId::RESOLVE_UNKNOWN_VIRTUAL_CALL;
1491         auto slowPath = CreateSlowPath<SlowPathUnresolved>(resolver, entrypoint);
1492         slowPath->SetUnresolvedType(method, resolver->GetCallMethodId());
1493         slowPath->SetDstReg(methodReg);
1494         slowPath->SetArgReg(objReg);
1495         slowPath->SetSlotAddr(methodSlotAddr);
1496         GetEncoder()->EncodeJump(slowPath->GetLabel(), methodReg, Condition::EQ);
1497         // Load klass into tmp_reg
1498         LoadClassFromObject(tmpReg, objReg);
1499         // Load from VTable, address = (klass + (index << shift)) + vtable_offset
1500         auto tmpReg64 = Reg(tmpReg.GetReg().GetId(), INT64_TYPE);
1501         GetEncoder()->EncodeAdd(tmpReg64, tmpReg, Shift(methodReg, GetVtableShift()));
1502         GetEncoder()->EncodeLdr(methodReg, false,
1503                                 MemRef(tmpReg64, runtime->GetVTableOffset(GetArch()) - (1U << GetVtableShift())));
1504         slowPath->BindBackLabel(GetEncoder());
1505     }
1506 }
1507 
EmitResolveVirtualAot(ResolveVirtualInst * resolver,Reg methodReg)1508 void Codegen::EmitResolveVirtualAot(ResolveVirtualInst *resolver, Reg methodReg)
1509 {
1510     SCOPED_DISASM_STR(this, "AOT ResolveVirtual using PLT-GOT");
1511     ASSERT(resolver->IsRuntimeCall());
1512     ScopedTmpReg tmpReg(GetEncoder(), ConvertDataType(DataType::REFERENCE, GetArch()));
1513     auto methodReg64 = Reg(methodReg.GetId(), INT64_TYPE);
1514     auto tmpReg64 = Reg(tmpReg.GetReg().GetId(), INT64_TYPE);
1515     auto aotData = GetGraph()->GetAotData();
1516     intptr_t offset = aotData->GetVirtIndexSlotOffset(GetEncoder()->GetCursorOffset(), resolver->GetCallMethodId());
1517     GetEncoder()->MakeLoadAotTableAddr(offset, tmpReg64, methodReg64);
1518     auto label = GetEncoder()->CreateLabel();
1519     GetEncoder()->EncodeJump(label, methodReg, Condition::NE);
1520     GetEncoder()->EncodeMov(methodReg64, tmpReg64);
1521     // PLT CallVirtual Resolver has a very special calling convention:
1522     //   First encoder temporary (method_reg) works as a parameter and return value
1523     CHECK_EQ(methodReg64.GetId(), GetTarget().GetTempRegsMask().GetMinRegister());
1524     MemRef entry(ThreadReg(), GetRuntime()->GetEntrypointTlsOffset(GetArch(), EntrypointId::CALL_VIRTUAL_RESOLVER));
1525     GetEncoder()->MakeCall(entry);
1526     // Need a stackmap to build correct boundary frame
1527     CreateStackMap(resolver);
1528     GetEncoder()->BindLabel(label);
1529     // Load class into method_reg
1530     Reg objReg = GetObjectReg(this, resolver);
1531     LoadClassFromObject(tmpReg, objReg);
1532     // Load from VTable, address = (klass + (index << shift)) + vtable_offset
1533     GetEncoder()->EncodeAdd(methodReg, tmpReg64, Shift(methodReg, GetVtableShift()));
1534     GetEncoder()->EncodeLdr(methodReg, false,
1535                             MemRef(methodReg, GetRuntime()->GetVTableOffset(GetArch()) - (1U << GetVtableShift())));
1536 }
1537 
EmitResolveVirtual(ResolveVirtualInst * resolver)1538 void Codegen::EmitResolveVirtual(ResolveVirtualInst *resolver)
1539 {
1540     auto methodReg = ConvertRegister(resolver->GetDstReg(), resolver->GetType());
1541     auto objectReg = ConvertRegister(resolver->GetSrcReg(0), DataType::REFERENCE);
1542     ScopedTmpReg tmpMethodReg(GetEncoder());
1543     if (resolver->GetCallMethod() == nullptr) {
1544         EmitResolveUnknownVirtual(resolver, tmpMethodReg);
1545         GetEncoder()->EncodeMov(methodReg, tmpMethodReg);
1546     } else if (GetRuntime()->IsInterfaceMethod(resolver->GetCallMethod())) {
1547         SCOPED_DISASM_STR(this, "Create runtime call to resolve a known virtual call");
1548         if (GetGraph()->IsAotMode()) {
1549             if (GetArch() == Arch::AARCH64) {
1550                 ScopedTmpReg tmpReg(GetEncoder(), ConvertDataType(DataType::REFERENCE, GetArch()));
1551                 IntfInlineCachePass(resolver, tmpMethodReg, tmpReg, objectReg);
1552             } else {
1553                 LoadMethod(tmpMethodReg);
1554                 CallRuntime(resolver, EntrypointId::RESOLVE_VIRTUAL_CALL_AOT, tmpMethodReg, {}, tmpMethodReg, objectReg,
1555                             TypedImm(resolver->GetCallMethodId()), TypedImm(0));
1556             }
1557         } else {
1558             CallRuntime(resolver, EntrypointId::RESOLVE_VIRTUAL_CALL, tmpMethodReg, {},
1559                         TypedImm(reinterpret_cast<size_t>(resolver->GetCallMethod())), objectReg);
1560         }
1561         GetEncoder()->EncodeMov(methodReg, tmpMethodReg);
1562     } else if (GetGraph()->IsAotNoChaMode()) {
1563         // ResolveVirtualAot requires method_reg to be the first tmp register.
1564         EmitResolveVirtualAot(resolver, tmpMethodReg);
1565         GetEncoder()->EncodeMov(methodReg, tmpMethodReg);
1566     } else {
1567         UNREACHABLE();
1568     }
1569 }
1570 
EmitCallResolvedVirtual(CallInst * call)1571 void Codegen::EmitCallResolvedVirtual(CallInst *call)
1572 {
1573     SCOPED_DISASM_STR(this, "Create a call to resolved virtual method");
1574     ASSERT(call->GetOpcode() == Opcode::CallResolvedVirtual);
1575     if (call->GetSaveState() != nullptr && call->IsInlined()) {
1576 #if defined(EVENT_METHOD_ENTER_ENABLED) && EVENT_METHOD_ENTER_ENABLED != 0
1577         if (!GetGraph()->IsAotMode()) {
1578             InsertTrace({Imm(static_cast<size_t>(TraceId::METHOD_ENTER)),
1579                          Imm(reinterpret_cast<size_t>(call->GetCallMethod())),
1580                          Imm(static_cast<size_t>(events::MethodEnterKind::INLINED))});
1581         }
1582 #endif
1583         return;
1584     }
1585     ASSERT(!HasLiveCallerSavedRegs(call));
1586     ASSERT(call->GetCallMethod() == nullptr || GetGraph()->GetRuntime()->IsInterfaceMethod(call->GetCallMethod()) ||
1587            GetGraph()->IsAotNoChaMode());
1588     Reg methodReg = ConvertRegister(call->GetSrcReg(0), DataType::POINTER);
1589     Reg param0 = GetTarget().GetParamReg(0);
1590     // Set method
1591     GetEncoder()->EncodeMov(param0, methodReg);
1592     GetEncoder()->MakeCall(MemRef(param0, GetRuntime()->GetCompiledEntryPointOffset(GetArch())));
1593     FinalizeCall(call);
1594 }
1595 
EmitCallVirtual(CallInst * call)1596 void Codegen::EmitCallVirtual(CallInst *call)
1597 {
1598     SCOPED_DISASM_STR(this, "Create a call to virtual method");
1599     ASSERT(call->GetOpcode() == Opcode::CallVirtual);
1600     if (call->GetSaveState() != nullptr && call->IsInlined()) {
1601 #if defined(EVENT_METHOD_ENTER_ENABLED) && EVENT_METHOD_ENTER_ENABLED != 0
1602         if (!GetGraph()->IsAotMode()) {
1603             InsertTrace({Imm(static_cast<size_t>(TraceId::METHOD_ENTER)),
1604                          Imm(reinterpret_cast<size_t>(call->GetCallMethod())),
1605                          Imm(static_cast<size_t>(events::MethodEnterKind::INLINED))});
1606         }
1607 #endif
1608         return;
1609     }
1610     auto runtime = GetRuntime();
1611     auto method = call->GetCallMethod();
1612     ASSERT(!HasLiveCallerSavedRegs(call));
1613     ASSERT(!call->IsUnresolved() && !runtime->IsInterfaceMethod(method) && !GetGraph()->IsAotNoChaMode());
1614     Reg methodReg = GetTarget().GetParamReg(0);
1615     ASSERT(!RegisterKeepCallArgument(call, methodReg));
1616     LoadClassFromObject(methodReg, GetObjectReg(this, call));
1617     // Get index
1618     auto vtableIndex = runtime->GetVTableIndex(method);
1619     // Load from VTable, address = klass + ((index << shift) + vtable_offset)
1620     auto totalOffset = runtime->GetVTableOffset(GetArch()) + (vtableIndex << GetVtableShift());
1621     // Class ref was loaded to method_reg
1622     GetEncoder()->EncodeLdr(methodReg, false, MemRef(methodReg, totalOffset));
1623     // Set method
1624     GetEncoder()->MakeCall(MemRef(methodReg, runtime->GetCompiledEntryPointOffset(GetArch())));
1625     FinalizeCall(call);
1626 }
1627 
EnsureParamsFitIn32Bit(std::initializer_list<std::variant<Reg,TypedImm>> params)1628 [[maybe_unused]] bool Codegen::EnsureParamsFitIn32Bit(std::initializer_list<std::variant<Reg, TypedImm>> params)
1629 {
1630     for (auto &param : params) {
1631         if (std::holds_alternative<Reg>(param)) {
1632             auto reg = std::get<Reg>(param);
1633             if (reg.GetSize() > WORD_SIZE) {
1634                 return false;
1635             }
1636         } else {
1637             auto immType = std::get<TypedImm>(param).GetType();
1638             if (immType.GetSize() > WORD_SIZE) {
1639                 return false;
1640             }
1641         }
1642     }
1643     return true;
1644 }
1645 
EmitResolveStatic(ResolveStaticInst * resolver)1646 void Codegen::EmitResolveStatic(ResolveStaticInst *resolver)
1647 {
1648     auto methodReg = ConvertRegister(resolver->GetDstReg(), resolver->GetType());
1649     if (GetGraph()->IsAotMode()) {
1650         LoadMethod(methodReg);
1651         CallRuntime(resolver, EntrypointId::GET_UNKNOWN_CALLEE_METHOD, methodReg, RegMask::GetZeroMask(), methodReg,
1652                     TypedImm(resolver->GetCallMethodId()), TypedImm(0));
1653         return;
1654     }
1655     auto method = GetCallerOfUnresolvedMethod(resolver);
1656     ScopedTmpReg tmp(GetEncoder());
1657     auto utypes = GetRuntime()->GetUnresolvedTypes();
1658     auto skind = UnresolvedTypesInterface::SlotKind::METHOD;
1659     auto methodAddr = utypes->GetTableSlot(method, resolver->GetCallMethodId(), skind);
1660     GetEncoder()->EncodeMov(tmp.GetReg(), Imm(methodAddr));
1661     GetEncoder()->EncodeLdr(tmp.GetReg(), false, MemRef(tmp.GetReg()));
1662     auto slowPath = CreateSlowPath<SlowPathUnresolved>(resolver, EntrypointId::GET_UNKNOWN_CALLEE_METHOD);
1663     slowPath->SetUnresolvedType(method, resolver->GetCallMethodId());
1664     slowPath->SetDstReg(tmp.GetReg());
1665     slowPath->SetSlotAddr(methodAddr);
1666     GetEncoder()->EncodeJump(slowPath->GetLabel(), tmp.GetReg(), Condition::EQ);
1667     slowPath->BindBackLabel(GetEncoder());
1668     GetEncoder()->EncodeMov(methodReg, tmp.GetReg());
1669 }
1670 
EmitCallResolvedStatic(CallInst * call)1671 void Codegen::EmitCallResolvedStatic(CallInst *call)
1672 {
1673     ASSERT(call->GetOpcode() == Opcode::CallResolvedStatic && call->GetCallMethod() == nullptr);
1674     Reg methodReg = ConvertRegister(call->GetSrcReg(0), DataType::POINTER);
1675     Reg param0 = GetTarget().GetParamReg(0);
1676     GetEncoder()->EncodeMov(param0, methodReg);
1677     GetEncoder()->MakeCall(MemRef(param0, GetRuntime()->GetCompiledEntryPointOffset(GetArch())));
1678     FinalizeCall(call);
1679 }
1680 
EmitCallStatic(CallInst * call)1681 void Codegen::EmitCallStatic(CallInst *call)
1682 {
1683     ASSERT(call->IsStaticCall() && !call->IsUnresolved());
1684     if (call->GetSaveState() != nullptr && call->IsInlined()) {
1685 #if defined(EVENT_METHOD_ENTER_ENABLED) && EVENT_METHOD_ENTER_ENABLED != 0
1686         if (!GetGraph()->IsAotMode()) {
1687             InsertTrace({Imm(static_cast<size_t>(TraceId::METHOD_ENTER)),
1688                          Imm(reinterpret_cast<size_t>(call->GetCallMethod())),
1689                          Imm(static_cast<size_t>(events::MethodEnterKind::INLINED))});
1690         }
1691 #endif
1692         return;
1693     }
1694     SCOPED_DISASM_STR(this, "Create a call to static");
1695     ASSERT(!HasLiveCallerSavedRegs(call));
1696     // Now MakeCallByOffset is not supported in Arch32Encoder (support ADR instruction)
1697     Reg param0 = GetTarget().GetParamReg(0);
1698     if (call->GetCallMethod() == GetGraph()->GetMethod() && GetArch() != Arch::AARCH32 && !GetGraph()->IsOsrMode() &&
1699         !GetGraph()->GetMethodProperties().GetHasDeopt()) {
1700         if (GetGraph()->IsAotMode()) {
1701             LoadMethod(param0);
1702         } else {
1703             GetEncoder()->EncodeMov(param0, Imm(reinterpret_cast<size_t>(GetGraph()->GetMethod())));
1704         }
1705         GetEncoder()->MakeCallByOffset(GetStartCodeOffset() - GetEncoder()->GetCursorOffset());
1706     } else {
1707         if (GetGraph()->IsAotMode()) {
1708             auto aotData = GetGraph()->GetAotData();
1709             intptr_t offset = aotData->GetPltSlotOffset(GetEncoder()->GetCursorOffset(), call->GetCallMethodId());
1710             // PLT CallStatic Resolver transparently uses param_0 (Method) register
1711             GetEncoder()->MakeLoadAotTable(offset, param0);
1712         } else {  // usual JIT case
1713             auto method = call->GetCallMethod();
1714             GetEncoder()->EncodeMov(param0, Imm(reinterpret_cast<size_t>(method)));
1715         }
1716         GetEncoder()->MakeCall(MemRef(param0, GetRuntime()->GetCompiledEntryPointOffset(GetArch())));
1717     }
1718     FinalizeCall(call);
1719 }
1720 
EmitCallDynamic(CallInst * call)1721 void Codegen::EmitCallDynamic(CallInst *call)
1722 {
1723     SCOPED_DISASM_STR(this, "Create a dynamic call");
1724     if (call->GetSaveState() != nullptr && call->IsInlined()) {
1725 #if defined(EVENT_METHOD_ENTER_ENABLED) && EVENT_METHOD_ENTER_ENABLED != 0
1726         if (!GetGraph()->IsAotMode()) {
1727             InsertTrace(Imm(static_cast<size_t>(TraceId::METHOD_ENTER)),
1728                         Imm(reinterpret_cast<size_t>(call->GetCallMethod())),
1729                         Imm(static_cast<size_t>(events::MethodEnterKind::INLINED)));
1730         }
1731 #endif
1732         return;
1733     }
1734     RuntimeInterface *runtime = GetRuntime();
1735     Encoder *encoder = GetEncoder();
1736 
1737     auto dstReg = ConvertRegister(call->GetDstReg(), call->GetType());
1738     Reg methodParamReg = GetTarget().GetParamReg(CallConvDynInfo::REG_METHOD).As(GetPtrRegType());
1739     Reg numArgsParamReg = GetTarget().GetParamReg(CallConvDynInfo::REG_NUM_ARGS);
1740     auto paramFuncObjLoc = Location::MakeStackArgument(CallConvDynInfo::SLOT_CALLEE);
1741 
1742     ASSERT(!HasLiveCallerSavedRegs(call));
1743 
1744     // Load method from callee object
1745     static_assert(coretypes::TaggedValue::TAG_OBJECT == 0);
1746     encoder->EncodeLdr(methodParamReg, false, MemRef(SpReg(), GetStackOffset(paramFuncObjLoc)));
1747     encoder->EncodeLdr(methodParamReg, false, MemRef(methodParamReg, runtime->GetFunctionTargetOffset(GetArch())));
1748 
1749     ASSERT(call->GetInputsCount() > 1);
1750     auto numArgs = static_cast<uint32_t>(call->GetInputsCount() - 1);  // '-1' means 1 for spill fill input
1751     encoder->EncodeMov(numArgsParamReg, Imm(numArgs));
1752 
1753     size_t entryPointOffset = runtime->GetCompiledEntryPointOffset(GetArch());
1754     encoder->MakeCall(MemRef(methodParamReg, entryPointOffset));
1755 
1756     CreateStackMap(call);
1757     // Dynamic callee may have moved sp if there was insufficient num_actual_args
1758     encoder->EncodeSub(
1759         SpReg(), FpReg(),
1760         Imm(GetFrameLayout().GetOffset<CFrameLayout::OffsetOrigin::SP, CFrameLayout::OffsetUnit::BYTES>(0)));
1761 
1762     if (dstReg.IsValid()) {
1763         Reg retReg = GetTarget().GetReturnReg(dstReg.GetType());
1764         encoder->EncodeMov(dstReg, retReg);
1765     }
1766 }
1767 
FinalizeCall(CallInst * call)1768 void Codegen::FinalizeCall(CallInst *call)
1769 {
1770     ASSERT(!call->IsDynamicCall());
1771     CreateStackMap(call);
1772     auto returnType = call->GetType();
1773     auto dstReg = ConvertRegister(call->GetDstReg(), returnType);
1774     // Restore frame pointer in the TLS
1775     GetEncoder()->EncodeStr(FpReg(), MemRef(ThreadReg(), GetRuntime()->GetTlsFrameOffset(GetArch())));
1776     // Sign/Zero extend return_reg if necessary
1777     if (dstReg.IsValid()) {
1778         auto arch = GetArch();
1779         auto returnReg = GetTarget().GetReturnReg(dstReg.GetType());
1780         //  INT8  and INT16  must be sign extended to INT32
1781         //  UINT8 and UINT16 must be zero extended to UINT32
1782         if (DataType::ShiftByType(returnType, arch) < DataType::ShiftByType(DataType::INT32, arch)) {
1783             bool isSigned = DataType::IsTypeSigned(returnType);
1784             GetEncoder()->EncodeCast(dstReg, isSigned, Reg(returnReg.GetId(), INT32_TYPE), isSigned);
1785         } else {
1786             GetEncoder()->EncodeMov(dstReg, returnReg);
1787         }
1788     }
1789 }
1790 
1791 template <typename T>
GetBarrierOperandValue(RuntimeInterface * runtime,panda::mem::BarrierPosition position,std::string_view name)1792 static T GetBarrierOperandValue(RuntimeInterface *runtime, panda::mem::BarrierPosition position, std::string_view name)
1793 {
1794     auto operand = runtime->GetBarrierOperand(position, name);
1795     return std::get<T>(operand.GetValue());
1796 }
1797 
1798 template <bool IS_CLASS>
CreatePreWRB(Inst * inst,MemRef mem,RegMask preserved,bool storePair)1799 void Codegen::CreatePreWRB(Inst *inst, MemRef mem, RegMask preserved, bool storePair)
1800 {
1801     auto runtime = GetRuntime();
1802     auto *enc = GetEncoder();
1803 
1804     SCOPED_DISASM_STR(this, "Pre WRB");
1805     ScopedTmpReg entrypointReg(enc, enc->IsLrAsTempRegEnabledAndReleased());
1806     GetEncoder()->EncodeLdr(entrypointReg, false,
1807                             MemRef(ThreadReg(), runtime->GetTlsPreWrbEntrypointOffset(GetArch())));
1808 
1809     // Check entrypoint address
1810     auto label = GetEncoder()->CreateLabel();
1811     enc->EncodeJump(label, entrypointReg, Condition::EQ);
1812     auto refType =
1813         inst->GetType() == DataType::REFERENCE ? DataType::GetIntTypeForReference(enc->GetArch()) : DataType::INT64;
1814     ScopedTmpReg tmpRef(enc, ConvertDataType(refType, GetArch()));
1815     auto prevOffset = enc->GetCursorOffset();
1816     // Load old value
1817     if (IsVolatileMemInst(inst)) {
1818         enc->EncodeLdrAcquire(tmpRef, false, mem);
1819     } else {
1820         enc->EncodeLdr(tmpRef, false, mem);
1821     }
1822     TryInsertImplicitNullCheck(inst, prevOffset);
1823     if constexpr (IS_CLASS) {
1824         enc->EncodeLdr(tmpRef, false, MemRef(tmpRef, runtime->GetManagedClassOffset(GetArch())));
1825     } else {
1826         CheckObject(tmpRef, label);
1827     }
1828     auto [liveRegs, liveVregs] = GetLiveRegisters<true>(inst);
1829     liveRegs |= preserved;
1830     CallBarrier(liveRegs, liveVregs, entrypointReg.GetReg(), tmpRef);
1831 
1832     if (storePair) {
1833         // store pair doesn't support index and scalar
1834         ASSERT(!mem.HasIndex() && !mem.HasScale());
1835         // calculate offset for second store
1836         auto secondOffset = 1U << DataType::ShiftByType(DataType::REFERENCE, enc->GetArch());
1837         if (mem.HasDisp()) {
1838             secondOffset += mem.GetDisp();
1839         }
1840         // Load old value
1841         if (IsVolatileMemInst(inst)) {
1842             enc->EncodeLdrAcquire(tmpRef, false, MemRef(mem.GetBase(), secondOffset));
1843         } else {
1844             enc->EncodeLdr(tmpRef, false, MemRef(mem.GetBase(), secondOffset));
1845         }
1846         CheckObject(tmpRef, label);
1847         CallBarrier(liveRegs, liveVregs, entrypointReg.GetReg(), tmpRef);
1848     }
1849     enc->BindLabel(label);
1850 }
1851 
EncodePostWRB(Inst * inst,MemRef mem,Reg reg1,Reg reg2,bool checkObject)1852 void Codegen::EncodePostWRB(Inst *inst, MemRef mem, Reg reg1, Reg reg2, bool checkObject)
1853 {
1854     auto refType {TypeInfo::FromDataType(DataType::REFERENCE, GetArch())};
1855     ASSERT(reg1.IsValid());
1856     reg1 = reg1.As(refType);
1857     if (reg2.IsValid()) {
1858         reg2 = reg2.As(refType);
1859     }
1860 
1861     if (GetGraph()->SupportsIrtocBarriers()) {
1862         if (GetGraph()->IsOfflineCompilationMode()) {
1863             CreateOfflineIrtocPostWrb(inst, mem, reg1, reg2);
1864         } else {
1865             CreateOnlineIrtocPostWrb(inst, mem, reg1, reg2, checkObject);
1866         }
1867         return;
1868     }
1869 
1870     auto barrierType {GetRuntime()->GetPostType()};
1871     ASSERT(barrierType == panda::mem::BarrierType::POST_INTERGENERATIONAL_BARRIER ||
1872            barrierType == panda::mem::BarrierType::POST_INTERREGION_BARRIER);
1873 
1874     if (barrierType == panda::mem::BarrierType::POST_INTERREGION_BARRIER) {
1875         CreatePostInterRegionBarrier(inst, mem, reg1, reg2, checkObject);
1876     } else {
1877         auto base {mem.GetBase().As(refType)};
1878         CreatePostInterGenerationalBarrier(base);
1879     }
1880 }
1881 
CreatePostWRBForDynamic(Inst * inst,MemRef mem,Reg reg1,Reg reg2)1882 void Codegen::CreatePostWRBForDynamic(Inst *inst, MemRef mem, Reg reg1, Reg reg2)
1883 {
1884     int storeIndex;
1885     if (reg2 == INVALID_REGISTER) {
1886         if (inst->GetOpcode() == Opcode::StoreObject || inst->GetOpcode() == Opcode::StoreI ||
1887             inst->GetOpcode() == Opcode::StoreArrayI) {
1888             storeIndex = 1_I;
1889         } else {
1890             ASSERT(inst->GetOpcode() == Opcode::StoreArray || inst->GetOpcode() == Opcode::Store);
1891             storeIndex = 2_I;
1892         }
1893         if (StoreValueCanBeObject(inst->GetDataFlowInput(storeIndex))) {
1894             EncodePostWRB(inst, mem, reg1, reg2, true);
1895         }
1896     } else {
1897         if (inst->GetOpcode() == Opcode::StoreArrayPairI) {
1898             storeIndex = 1_I;
1899         } else {
1900             ASSERT(inst->GetOpcode() == Opcode::StoreArrayPair);
1901             storeIndex = 2_I;
1902         }
1903         bool firstIsObject = StoreValueCanBeObject(inst->GetDataFlowInput(storeIndex));
1904         bool secondIsObject = StoreValueCanBeObject(inst->GetDataFlowInput(storeIndex + 1));
1905         if (firstIsObject || secondIsObject) {
1906             if (firstIsObject && !secondIsObject) {
1907                 reg2 = INVALID_REGISTER;
1908             } else if (!firstIsObject && secondIsObject) {
1909                 reg1 = reg2;
1910                 reg2 = INVALID_REGISTER;
1911             }
1912             EncodePostWRB(inst, mem, reg1, reg2, true);
1913         }
1914     }
1915 }
1916 
CreatePostWRB(Inst * inst,MemRef mem,Reg reg1,Reg reg2)1917 void Codegen::CreatePostWRB(Inst *inst, MemRef mem, Reg reg1, Reg reg2)
1918 {
1919     ASSERT(reg1 != INVALID_REGISTER);
1920 
1921     if (!GetGraph()->SupportsIrtocBarriers() || !GetGraph()->IsOfflineCompilationMode()) {
1922         auto barrierType = GetRuntime()->GetPostType();
1923         if (barrierType == panda::mem::BarrierType::POST_WRB_NONE) {
1924             return;
1925         }
1926         ASSERT(barrierType == panda::mem::BarrierType::POST_INTERGENERATIONAL_BARRIER ||
1927                barrierType == panda::mem::BarrierType::POST_INTERREGION_BARRIER);
1928     }
1929 
1930     // For dynamic methods, another check
1931     if (GetGraph()->IsDynamicMethod()) {
1932         CreatePostWRBForDynamic(inst, mem, reg1, reg2);
1933         return;
1934     }
1935     Inst *secondValue;
1936     Inst *val = InstStoredValue(inst, &secondValue);
1937     ASSERT(secondValue == nullptr || reg2 != INVALID_REGISTER);
1938     if (val->GetOpcode() == Opcode::NullPtr) {
1939         // We can don't encode Post barrier for nullptr
1940         if (secondValue == nullptr || secondValue->GetOpcode() == Opcode::NullPtr) {
1941             return;
1942         }
1943         // CallPostWRB only for second reg
1944         EncodePostWRB(inst, mem, reg2, INVALID_REGISTER, !IsInstNotNull(secondValue));
1945         return;
1946     }
1947     // Create PostWRB only for first value
1948     if (secondValue != nullptr && secondValue->GetOpcode() == Opcode::NullPtr) {
1949         reg2 = INVALID_REGISTER;
1950     }
1951     bool checkObject = true;
1952     if (reg2 == INVALID_REGISTER) {
1953         if (IsInstNotNull(val)) {
1954             checkObject = false;
1955         }
1956     } else {
1957         if (IsInstNotNull(val) && IsInstNotNull(secondValue)) {
1958             checkObject = false;
1959         }
1960     }
1961     EncodePostWRB(inst, mem, reg1, reg2, checkObject);
1962 }
1963 
CheckObject(Reg reg,LabelHolder::LabelId label)1964 void Codegen::CheckObject(Reg reg, LabelHolder::LabelId label)
1965 {
1966     auto graph = GetGraph();
1967     auto *enc = GetEncoder();
1968 
1969     // interpreter use x20 in IrToc and we don't have enough temporary registers
1970     // remove after PR 98 or PR 47
1971     if (graph->IsDynamicMethod()) {
1972         ASSERT(reg.IsScalar());
1973         reg = reg.As(INT64_TYPE);
1974         auto tagMask = graph->GetRuntime()->GetTaggedTagMask();
1975         // Check that the value is object(not int and not double)
1976         enc->EncodeJumpTest(label, reg, Imm(tagMask), Condition::TST_NE);
1977         auto specialMask = graph->GetRuntime()->GetTaggedSpecialMask();
1978         // Check that the value is not special value
1979         enc->EncodeJumpTest(label, reg, Imm(~specialMask), Condition::TST_EQ);
1980     } else {
1981         enc->EncodeJump(label, reg, Condition::EQ);
1982     }
1983 }
1984 
CreateOfflineIrtocPostWrb(Inst * inst,MemRef mem,Reg reg1,Reg reg2)1985 void Codegen::CreateOfflineIrtocPostWrb(Inst *inst, MemRef mem, Reg reg1, Reg reg2)
1986 {
1987     ASSERT(reg1.IsValid());
1988 
1989     bool hasObj2 {reg2.IsValid() && reg1 != reg2};
1990 
1991     auto paramRegs {GetTarget().GetParamRegsMask(hasObj2 ? 4U : 3U) & GetLiveRegisters(inst).first};
1992     SaveCallerRegisters(paramRegs, VRegMask(), false);
1993 
1994     if (hasObj2) {
1995         FillPostWrbCallParams(mem, reg1, reg2);
1996     } else {
1997         FillPostWrbCallParams(mem, reg1);
1998     }
1999 
2000     // load function pointer from tls field
2001     auto offset {hasObj2 ? cross_values::GetManagedThreadPostWrbTwoObjectsOffset(GetArch())
2002                          : cross_values::GetManagedThreadPostWrbOneObjectOffset(GetArch())};
2003     MemRef entry(ThreadReg(), offset);
2004     GetEncoder()->MakeCall(entry);
2005 
2006     LoadCallerRegisters(paramRegs, VRegMask(), false);
2007 }
2008 
CheckObj(Encoder * enc,Codegen * cg,Reg base,Reg reg1,LabelHolder::LabelId skipLabel,bool checkNull)2009 void CheckObj(Encoder *enc, Codegen *cg, Reg base, Reg reg1, LabelHolder::LabelId skipLabel, bool checkNull)
2010 {
2011     if (checkNull) {
2012         // Fast null check in-place for one register
2013         enc->EncodeJump(skipLabel, reg1, Condition::EQ);
2014     }
2015 
2016     ScopedTmpReg tmp(enc, cg->ConvertDataType(DataType::REFERENCE, cg->GetArch()));
2017     auto regionSizeBit = GetBarrierOperandValue<uint8_t>(
2018         cg->GetRuntime(), panda::mem::BarrierPosition::BARRIER_POSITION_POST, "REGION_SIZE_BITS");
2019     enc->EncodeXor(tmp, base, reg1);
2020     enc->EncodeShr(tmp, tmp, Imm(regionSizeBit));
2021     enc->EncodeJump(skipLabel, tmp, Condition::EQ);
2022 }
2023 
WrapOneArg(Encoder * enc,Reg param,Reg base,MemRef mem,size_t additionalOffset=0)2024 void WrapOneArg(Encoder *enc, Reg param, Reg base, MemRef mem, size_t additionalOffset = 0)
2025 {
2026     if (mem.HasIndex()) {
2027         ASSERT(mem.GetScale() == 0 && !mem.HasDisp());
2028         enc->EncodeAdd(param, base, mem.GetIndex());
2029         if (additionalOffset != 0) {
2030             enc->EncodeAdd(param, param, Imm(additionalOffset));
2031         }
2032     } else if (mem.HasDisp()) {
2033         ASSERT(!mem.HasIndex());
2034         enc->EncodeAdd(param, base, Imm(mem.GetDisp() + additionalOffset));
2035     } else {
2036         enc->EncodeAdd(param, base, Imm(additionalOffset));
2037     }
2038 }
2039 
2040 /**
2041  * Post-write barrier for StorePair case.
2042  * The code below may mark 0, 1 or 2 cards. The idea is following:
2043  *  if (the second object isn't null and is allocated in other from base object's region)
2044  *      MarkOneCard(CardOfSecondField(mem))
2045  *      if (address of the second field isn't aligned at the size of a card)
2046  *          # i.e. each of store address (fields of the base objects) are related to the same card
2047  *          goto Done
2048  *
2049  *  if (the first object isn't null and is allocated in other from base object's region)
2050  *      MarkOneCard(CardOfFirstField(mem))
2051  *
2052  *  label: Done
2053  */
CreateOnlineIrtocPostWrbRegionTwoRegs(Inst * inst,MemRef mem,Reg reg1,Reg reg2,bool checkObject)2054 void Codegen::CreateOnlineIrtocPostWrbRegionTwoRegs(Inst *inst, MemRef mem, Reg reg1, Reg reg2, bool checkObject)
2055 {
2056     auto entrypointId {EntrypointId::POST_INTER_REGION_BARRIER_SLOW};
2057     auto enc {GetEncoder()};
2058     auto base {mem.GetBase().As(TypeInfo::FromDataType(DataType::REFERENCE, GetArch()))};
2059     auto paramReg0 = enc->GetTarget().GetParamReg(0);
2060     MemRef entry(ThreadReg(), GetRuntime()->GetEntrypointTlsOffset(GetArch(), entrypointId));
2061     constexpr size_t PARAMS_NUM = 1U;
2062     auto paramRegs {GetTarget().GetParamRegsMask(PARAMS_NUM) & GetLiveRegisters(inst).first};
2063 
2064     auto lblMarkCardAndExit = enc->CreateLabel();
2065     auto lblCheck1Obj = enc->CreateLabel();
2066     auto done = enc->CreateLabel();
2067 
2068     CheckObj(enc, this, base, reg2, lblCheck1Obj, checkObject);
2069     SaveCallerRegisters(paramRegs, VRegMask(), false);
2070     WrapOneArg(enc, paramReg0, base, mem, reg1.GetSize() / BITS_PER_BYTE);
2071     {
2072         ScopedTmpReg tmp(enc, ConvertDataType(DataType::REFERENCE, GetArch()));
2073         enc->EncodeAnd(tmp, paramReg0, Imm(cross_values::GetCardAlignmentMask(GetArch())));
2074         enc->EncodeJump(lblMarkCardAndExit, tmp, Condition::NE);
2075     }
2076 
2077     enc->MakeCall(entry);
2078     LoadCallerRegisters(paramRegs, VRegMask(), false);
2079 
2080     enc->BindLabel(lblCheck1Obj);
2081     CheckObj(enc, this, base, reg1, done, checkObject);
2082     SaveCallerRegisters(paramRegs, VRegMask(), false);
2083     WrapOneArg(enc, paramReg0, base, mem);
2084     enc->BindLabel(lblMarkCardAndExit);
2085     enc->MakeCall(entry);
2086     LoadCallerRegisters(paramRegs, VRegMask(), false);
2087     enc->BindLabel(done);
2088 }
2089 
CreateOnlineIrtocPostWrbRegionOneReg(Inst * inst,MemRef mem,Reg reg1,bool checkObject)2090 void Codegen::CreateOnlineIrtocPostWrbRegionOneReg(Inst *inst, MemRef mem, Reg reg1, bool checkObject)
2091 {
2092     auto entrypointId {EntrypointId::POST_INTER_REGION_BARRIER_SLOW};
2093     auto enc {GetEncoder()};
2094     auto base {mem.GetBase().As(TypeInfo::FromDataType(DataType::REFERENCE, GetArch()))};
2095     auto paramReg0 = enc->GetTarget().GetParamReg(0);
2096     MemRef entry(ThreadReg(), GetRuntime()->GetEntrypointTlsOffset(GetArch(), entrypointId));
2097     constexpr size_t PARAMS_NUM = 1;
2098     auto paramRegs {GetTarget().GetParamRegsMask(PARAMS_NUM) & GetLiveRegisters(inst).first};
2099 
2100     auto skip = enc->CreateLabel();
2101 
2102     CheckObj(enc, this, base, reg1, skip, checkObject);
2103     SaveCallerRegisters(paramRegs, VRegMask(), false);
2104     WrapOneArg(enc, paramReg0, base, mem);
2105     enc->MakeCall(entry);
2106     LoadCallerRegisters(paramRegs, VRegMask(), false);
2107     enc->BindLabel(skip);
2108 }
2109 
CreateOnlineIrtocPostWrb(Inst * inst,MemRef mem,Reg reg1,Reg reg2,bool checkObject)2110 void Codegen::CreateOnlineIrtocPostWrb(Inst *inst, MemRef mem, Reg reg1, Reg reg2, bool checkObject)
2111 {
2112     SCOPED_DISASM_STR(this, "Post Online Irtoc-WRB");
2113     ASSERT(reg1.IsValid());
2114 
2115     auto enc {GetEncoder()};
2116 
2117     bool hasObj2 {reg2.IsValid() && reg1 != reg2};
2118     if (GetRuntime()->GetPostType() == panda::mem::BarrierType::POST_INTERREGION_BARRIER) {
2119         if (hasObj2) {
2120             CreateOnlineIrtocPostWrbRegionTwoRegs(inst, mem, reg1, reg2, checkObject);
2121         } else {
2122             CreateOnlineIrtocPostWrbRegionOneReg(inst, mem, reg1, checkObject);
2123         }
2124     } else {
2125         auto entrypointId {EntrypointId::POST_INTER_GENERATIONAL_BARRIER0};
2126         auto base {mem.GetBase().As(TypeInfo::FromDataType(DataType::REFERENCE, GetArch()))};
2127         constexpr size_t PARAMS_NUM = 1;
2128         auto paramRegs {GetTarget().GetParamRegsMask(PARAMS_NUM) & GetLiveRegisters(inst).first};
2129 
2130         SaveCallerRegisters(paramRegs, VRegMask(), false);
2131         auto paramReg0 = enc->GetTarget().GetParamReg(0);
2132         enc->EncodeMov(paramReg0, base);
2133         MemRef entry(ThreadReg(), GetRuntime()->GetEntrypointTlsOffset(GetArch(), entrypointId));
2134         enc->MakeCall(entry);
2135         LoadCallerRegisters(paramRegs, VRegMask(), false);
2136     }
2137 }
2138 
CreatePostInterRegionBarrier(Inst * inst,MemRef mem,Reg reg1,Reg reg2,bool checkObject)2139 void Codegen::CreatePostInterRegionBarrier(Inst *inst, MemRef mem, Reg reg1, Reg reg2, bool checkObject)
2140 {
2141     SCOPED_DISASM_STR(this, "Post IR-WRB");
2142     auto *enc = GetEncoder();
2143     ASSERT(GetRuntime()->GetPostType() == panda::mem::BarrierType::POST_INTERREGION_BARRIER);
2144     ASSERT(reg1 != INVALID_REGISTER);
2145 
2146     auto label = GetEncoder()->CreateLabel();
2147 
2148     if (checkObject) {
2149         CheckObject(reg1, label);
2150     }
2151 
2152     auto regionSizeBit = GetBarrierOperandValue<uint8_t>(
2153         GetRuntime(), panda::mem::BarrierPosition::BARRIER_POSITION_POST, "REGION_SIZE_BITS");
2154 
2155     auto base {mem.GetBase().As(TypeInfo::FromDataType(DataType::REFERENCE, GetArch()))};
2156     ScopedTmpReg tmp(enc, ConvertDataType(DataType::REFERENCE, GetArch()));
2157     // Compare first store value with mem
2158     enc->EncodeXor(tmp, base, reg1);
2159     enc->EncodeShr(tmp, tmp, Imm(regionSizeBit));
2160 
2161     enc->EncodeJump(label, tmp, Condition::EQ);
2162     auto [liveRegs, liveVregs] = GetLiveRegisters<true>(inst);
2163 
2164     if (mem.HasIndex()) {
2165         ASSERT(mem.GetScale() == 0 && !mem.HasDisp());
2166         enc->EncodeAdd(tmp, base, mem.GetIndex());
2167         CallBarrier(liveRegs, liveVregs, EntrypointId::POST_WRB_UPDATE_CARD_FUNC_NO_BRIDGE, tmp, reg1);
2168     } else if (mem.HasDisp()) {
2169         ASSERT(!mem.HasIndex());
2170         enc->EncodeAdd(tmp, base, Imm(mem.GetDisp()));
2171         CallBarrier(liveRegs, liveVregs, EntrypointId::POST_WRB_UPDATE_CARD_FUNC_NO_BRIDGE, tmp, reg1);
2172     } else {
2173         CallBarrier(liveRegs, liveVregs, EntrypointId::POST_WRB_UPDATE_CARD_FUNC_NO_BRIDGE, base, reg1);
2174     }
2175     enc->BindLabel(label);
2176 
2177     if (reg2.IsValid() && reg1 != reg2) {
2178         auto label1 = GetEncoder()->CreateLabel();
2179         if (checkObject) {
2180             CheckObject(reg2, label1);
2181         }
2182 
2183         // Compare second store value with mem
2184         enc->EncodeXor(tmp, base, reg2);
2185         enc->EncodeShr(tmp, tmp, Imm(regionSizeBit));
2186         enc->EncodeJump(label1, tmp, Condition::EQ);
2187 
2188         enc->EncodeAdd(tmp, base, Imm(reg1.GetSize() / BITS_PER_BYTE));
2189         if (mem.HasIndex()) {
2190             ASSERT(mem.GetScale() == 0 && !mem.HasDisp());
2191             enc->EncodeAdd(tmp, tmp, mem.GetIndex());
2192         } else if (mem.HasDisp()) {
2193             ASSERT(!mem.HasIndex());
2194             enc->EncodeAdd(tmp, tmp, Imm(mem.GetDisp()));
2195         }
2196         CallBarrier(liveRegs, liveVregs, EntrypointId::POST_WRB_UPDATE_CARD_FUNC_NO_BRIDGE, tmp, reg2);
2197         enc->BindLabel(label1);
2198     }
2199 }
2200 
CalculateCardIndex(Reg baseReg,ScopedTmpReg * tmp,ScopedTmpReg * tmp1)2201 void Codegen::CalculateCardIndex(Reg baseReg, ScopedTmpReg *tmp, ScopedTmpReg *tmp1)
2202 {
2203     auto tmpType = tmp->GetReg().GetType();
2204     auto tmp1Type = tmp1->GetReg().GetType();
2205     auto *enc = GetEncoder();
2206     auto cardBits =
2207         GetBarrierOperandValue<uint8_t>(GetRuntime(), panda::mem::BarrierPosition::BARRIER_POSITION_POST, "CARD_BITS");
2208 
2209     ASSERT(baseReg != INVALID_REGISTER);
2210     if (baseReg.GetSize() < Reg(*tmp).GetSize()) {
2211         tmp->ChangeType(baseReg.GetType());
2212         tmp1->ChangeType(baseReg.GetType());
2213     }
2214     enc->EncodeSub(*tmp, baseReg, *tmp);
2215     enc->EncodeShr(*tmp, *tmp, Imm(cardBits));
2216     tmp->ChangeType(tmpType);
2217     tmp1->ChangeType(tmp1Type);
2218 }
2219 
CreatePostInterGenerationalBarrier(Reg base)2220 void Codegen::CreatePostInterGenerationalBarrier(Reg base)
2221 {
2222     SCOPED_DISASM_STR(this, "Post IG-WRB");
2223     auto runtime = GetRuntime();
2224     auto *enc = GetEncoder();
2225     ASSERT(runtime->GetPostType() == panda::mem::BarrierType::POST_INTERGENERATIONAL_BARRIER);
2226     ScopedTmpReg tmp(enc);
2227     ScopedTmpReg tmp1(enc);
2228     // * load AddressOf(MIN_ADDR) -> min_addr
2229     if (GetGraph()->IsOfflineCompilationMode()) {
2230         GetEncoder()->EncodeLdr(tmp, false, MemRef(ThreadReg(), runtime->GetTlsCardTableMinAddrOffset(GetArch())));
2231     } else {
2232         auto minAddress = reinterpret_cast<uintptr_t>(
2233             GetBarrierOperandValue<void *>(runtime, panda::mem::BarrierPosition::BARRIER_POSITION_POST, "MIN_ADDR"));
2234         enc->EncodeMov(tmp, Imm(minAddress));
2235     }
2236     // * card_index = (AddressOf(obj.field) - min_addr) >> CARD_BITS   // shift right
2237     CalculateCardIndex(base, &tmp, &tmp1);
2238     // * load AddressOf(CARD_TABLE_ADDR) -> card_table_addr
2239     if (GetGraph()->IsOfflineCompilationMode()) {
2240         GetEncoder()->EncodeLdr(tmp1.GetReg().As(INT64_TYPE), false,
2241                                 MemRef(ThreadReg(), runtime->GetTlsCardTableAddrOffset(GetArch())));
2242     } else {
2243         auto cardTableAddr = reinterpret_cast<uintptr_t>(GetBarrierOperandValue<uint8_t *>(
2244             runtime, panda::mem::BarrierPosition::BARRIER_POSITION_POST, "CARD_TABLE_ADDR"));
2245         enc->EncodeMov(tmp1, Imm(cardTableAddr));
2246     }
2247     // * card_addr = card_table_addr + card_index
2248     enc->EncodeAdd(tmp, tmp1, tmp);
2249     // * store card_addr <- DIRTY_VAL
2250     auto dirtyVal =
2251         GetBarrierOperandValue<uint8_t>(runtime, panda::mem::BarrierPosition::BARRIER_POSITION_POST, "DIRTY_VAL");
2252 
2253     auto tmp1B = ConvertRegister(tmp1.GetReg().GetId(), DataType::INT8);
2254     enc->EncodeMov(tmp1B, Imm(dirtyVal));
2255     enc->EncodeStr(tmp1B, MemRef(tmp));
2256 }
2257 
HasLiveCallerSavedRegs(Inst * inst)2258 bool Codegen::HasLiveCallerSavedRegs(Inst *inst)
2259 {
2260     auto [liveRegs, liveFpRegs] = GetLiveRegisters<false>(inst);
2261     liveRegs &= GetCallerRegsMask(GetArch(), false);
2262     liveFpRegs &= GetCallerRegsMask(GetArch(), true);
2263     return liveRegs.Any() || liveFpRegs.Any();
2264 }
2265 
SaveCallerRegisters(RegMask liveRegs,VRegMask liveVregs,bool adjustRegs)2266 void Codegen::SaveCallerRegisters(RegMask liveRegs, VRegMask liveVregs, bool adjustRegs)
2267 {
2268     SCOPED_DISASM_STR(this, "Save caller saved regs");
2269     auto base = GetFrameInfo()->GetCallersRelativeFp() ? GetTarget().GetFrameReg() : GetTarget().GetStackReg();
2270     liveRegs &= ~GetEncoder()->GetAvailableScratchRegisters();
2271     liveVregs &= ~GetEncoder()->GetAvailableScratchFpRegisters();
2272     if (adjustRegs) {
2273         liveRegs &= GetRegfile()->GetCallerSavedRegMask();
2274         liveVregs &= GetRegfile()->GetCallerSavedVRegMask();
2275     } else {
2276         liveRegs &= GetCallerRegsMask(GetArch(), false);
2277         liveVregs &= GetCallerRegsMask(GetArch(), true);
2278     }
2279     if (GetFrameInfo()->GetPushCallers()) {
2280         GetEncoder()->PushRegisters(liveRegs, liveVregs);
2281     } else {
2282         GetEncoder()->SaveRegisters(liveRegs, false, GetFrameInfo()->GetCallersOffset(), base,
2283                                     GetCallerRegsMask(GetArch(), false));
2284         GetEncoder()->SaveRegisters(liveVregs, true, GetFrameInfo()->GetFpCallersOffset(), base,
2285                                     GetFrameInfo()->GetPositionedCallers() ? GetCallerRegsMask(GetArch(), true)
2286                                                                            : RegMask());
2287     }
2288 }
2289 
LoadCallerRegisters(RegMask liveRegs,VRegMask liveVregs,bool adjustRegs)2290 void Codegen::LoadCallerRegisters(RegMask liveRegs, VRegMask liveVregs, bool adjustRegs)
2291 {
2292     SCOPED_DISASM_STR(this, "Restore caller saved regs");
2293     auto base = GetFrameInfo()->GetCallersRelativeFp() ? GetTarget().GetFrameReg() : GetTarget().GetStackReg();
2294     liveRegs &= ~GetEncoder()->GetAvailableScratchRegisters();
2295     liveVregs &= ~GetEncoder()->GetAvailableScratchFpRegisters();
2296     if (adjustRegs) {
2297         liveRegs &= GetRegfile()->GetCallerSavedRegMask();
2298         liveVregs &= GetRegfile()->GetCallerSavedVRegMask();
2299     } else {
2300         liveRegs &= GetCallerRegsMask(GetArch(), false);
2301         liveVregs &= GetCallerRegsMask(GetArch(), true);
2302     }
2303     if (GetFrameInfo()->GetPushCallers()) {
2304         GetEncoder()->PopRegisters(liveRegs, liveVregs);
2305     } else {
2306         GetEncoder()->LoadRegisters(liveRegs, false, GetFrameInfo()->GetCallersOffset(), base,
2307                                     GetCallerRegsMask(GetArch(), false));
2308         GetEncoder()->LoadRegisters(liveVregs, true, GetFrameInfo()->GetFpCallersOffset(), base,
2309                                     GetCallerRegsMask(GetArch(), true));
2310     }
2311 }
2312 
RegisterKeepCallArgument(CallInst * callInst,Reg reg)2313 bool Codegen::RegisterKeepCallArgument(CallInst *callInst, Reg reg)
2314 {
2315     for (auto i = 0U; i < callInst->GetInputsCount(); i++) {
2316         auto location = callInst->GetLocation(i);
2317         if (location.IsRegister() && location.GetValue() == reg.GetId()) {
2318             return true;
2319         }
2320     }
2321     return false;
2322 }
2323 
LoadMethod(Reg dst)2324 void Codegen::LoadMethod(Reg dst)
2325 {
2326     ASSERT((CFrameMethod::GetOffsetFromSpInBytes(GetFrameLayout()) -
2327             (GetFrameLayout().GetMethodOffset<CFrameLayout::OffsetOrigin::SP, CFrameLayout::OffsetUnit::BYTES>())) ==
2328            0);
2329     auto spOffset = CFrameMethod::GetOffsetFromSpInBytes(GetFrameLayout());
2330     auto mem = MemRef(SpReg(), spOffset);
2331     GetEncoder()->EncodeLdr(dst, false, mem);
2332 }
2333 
StoreFreeSlot(Reg src)2334 void Codegen::StoreFreeSlot(Reg src)
2335 {
2336     ASSERT(src.GetSize() <= (GetFrameLayout().GetSlotSize() << 3U));
2337     auto spOffset =
2338         GetFrameLayout().GetFreeSlotOffset<CFrameLayout::OffsetOrigin::SP, CFrameLayout::OffsetUnit::BYTES>();
2339     auto mem = MemRef(SpReg(), spOffset);
2340     GetEncoder()->EncodeStr(src, mem);
2341 }
2342 
LoadFreeSlot(Reg dst)2343 void Codegen::LoadFreeSlot(Reg dst)
2344 {
2345     ASSERT(dst.GetSize() <= (GetFrameLayout().GetSlotSize() << 3U));
2346     auto spOffset =
2347         GetFrameLayout().GetFreeSlotOffset<CFrameLayout::OffsetOrigin::SP, CFrameLayout::OffsetUnit::BYTES>();
2348     auto mem = MemRef(SpReg(), spOffset);
2349     GetEncoder()->EncodeLdr(dst, false, mem);
2350 }
2351 
CreateReturn(const Inst * inst)2352 void Codegen::CreateReturn(const Inst *inst)
2353 {
2354     if (GetGraph()->GetMethodProperties().GetLastReturn() == inst) {
2355         GetEncoder()->BindLabel(GetLabelExit());
2356         GenerateEpilogue();
2357     } else {
2358         GetEncoder()->EncodeJump(GetLabelExit());
2359     }
2360 }
2361 
EncodeDynamicCast(Inst * inst,Reg dst,bool dstSigned,Reg src)2362 void Codegen::EncodeDynamicCast(Inst *inst, Reg dst, bool dstSigned, Reg src)
2363 {
2364     CHECK_EQ(src.GetSize(), BITS_PER_UINT64);
2365     CHECK_GE(dst.GetSize(), BITS_PER_UINT32);
2366 
2367     bool isDst64 {dst.GetSize() == BITS_PER_UINT64};
2368     dst = dst.As(INT32_TYPE);
2369 
2370     auto enc {GetEncoder()};
2371     if (g_options.IsCpuFeatureEnabled(CpuFeature::JSCVT)) {
2372         // no slow path intended
2373         enc->EncodeFastPathDynamicCast(dst, src, LabelHolder::INVALID_LABEL);
2374     } else {
2375         auto slowPath {CreateSlowPath<SlowPathJsCastDoubleToInt32>(inst)};
2376         slowPath->SetDstReg(dst);
2377         slowPath->SetSrcReg(src);
2378 
2379         enc->EncodeFastPathDynamicCast(dst, src, slowPath->GetLabel());
2380         slowPath->BindBackLabel(enc);
2381     }
2382 
2383     if (isDst64) {
2384         enc->EncodeCast(dst.As(INT64_TYPE), dstSigned, dst, dstSigned);
2385     }
2386 }
2387 
2388 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2389 #define UNARY_OPERATION(opc)                                                      \
2390     void EncodeVisitor::Visit##opc(GraphVisitor *visitor, Inst *inst)             \
2391     {                                                                             \
2392         EncodeVisitor *enc = static_cast<EncodeVisitor *>(visitor);               \
2393         auto type = inst->GetType();                                              \
2394         auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);   \
2395         auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type); \
2396         enc->GetEncoder()->Encode##opc(dst, src0);                                \
2397     }
2398 
2399 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2400 #define BINARY_OPERATION(opc)                                                     \
2401     void EncodeVisitor::Visit##opc(GraphVisitor *visitor, Inst *inst)             \
2402     {                                                                             \
2403         auto type = inst->GetType();                                              \
2404         EncodeVisitor *enc = static_cast<EncodeVisitor *>(visitor);               \
2405         auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);   \
2406         auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type); \
2407         auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type); \
2408         enc->GetEncoder()->Encode##opc(dst, src0, src1);                          \
2409     }
2410 
2411 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2412 #define BINARY_SHIFTED_REGISTER_OPERATION(opc)                                               \
2413     void EncodeVisitor::Visit##opc##SR(GraphVisitor *visitor, Inst *inst)                    \
2414     {                                                                                        \
2415         auto type = inst->GetType();                                                         \
2416         EncodeVisitor *enc = static_cast<EncodeVisitor *>(visitor);                          \
2417         auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);              \
2418         auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);            \
2419         auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);            \
2420         auto immShiftInst = static_cast<BinaryShiftedRegisterOperation *>(inst);             \
2421         auto immValue = static_cast<uint32_t>(immShiftInst->GetImm()) & (dst.GetSize() - 1); \
2422         auto shift = Shift(src1, immShiftInst->GetShiftType(), immValue);                    \
2423         enc->GetEncoder()->Encode##opc(dst, src0, shift);                                    \
2424     }
2425 
2426 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2427 #define INST_DEF(OPCODE, TYPE) TYPE(OPCODE)
2428 
2429 ENCODE_MATH_LIST(INST_DEF)
ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF)2430 ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF)
2431 
2432 #undef UNARY_OPERATION
2433 #undef BINARY_OPERATION
2434 #undef BINARY_SHIFTED_REGISTER_OPERATION
2435 #undef INST_DEF
2436 
2437 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2438 #define BINARY_IMM_OPERATION(opc)                                                 \
2439     void EncodeVisitor::Visit##opc##I(GraphVisitor *visitor, Inst *inst)          \
2440     {                                                                             \
2441         auto binop = inst->CastTo##opc##I();                                      \
2442         EncodeVisitor *enc = static_cast<EncodeVisitor *>(visitor);               \
2443         auto type = inst->GetType();                                              \
2444         auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);   \
2445         auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type); \
2446         enc->GetEncoder()->Encode##opc(dst, src0, Imm(binop->GetImm()));          \
2447     }
2448 
2449 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2450 #define BINARY_IMM_OPS(DEF) DEF(Add) DEF(Sub) DEF(Shl) DEF(AShr) DEF(And) DEF(Or) DEF(Xor)
2451 
2452 BINARY_IMM_OPS(BINARY_IMM_OPERATION)
2453 
2454 #undef BINARY_IMM_OPS
2455 #undef BINARY_IMM_OPERATION
2456 
2457 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2458 #define BINARY_SIGN_UNSIGN_OPERATION(opc)                                         \
2459     void EncodeVisitor::Visit##opc(GraphVisitor *visitor, Inst *inst)             \
2460     {                                                                             \
2461         auto type = inst->GetType();                                              \
2462         EncodeVisitor *enc = static_cast<EncodeVisitor *>(visitor);               \
2463         auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);   \
2464         auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type); \
2465         auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type); \
2466         auto arch = enc->GetCodegen()->GetArch();                                 \
2467         if (!Codegen::InstEncodedWithLibCall(inst, arch)) {                       \
2468             enc->GetEncoder()->Encode##opc(dst, IsTypeSigned(type), src0, src1);  \
2469             return;                                                               \
2470         }                                                                         \
2471         ASSERT(arch == Arch::AARCH32);                                            \
2472         if (enc->cg_->GetGraph()->IsAotMode()) {                                  \
2473             enc->GetEncoder()->SetFalseResult();                                  \
2474             return;                                                               \
2475         }                                                                         \
2476         auto [liveRegs, liveVregs] = enc->GetCodegen()->GetLiveRegisters(inst);   \
2477         enc->GetEncoder()->SetRegister(&liveRegs, &liveVregs, dst, false);        \
2478         enc->GetCodegen()->SaveCallerRegisters(liveRegs, liveVregs, true);        \
2479         enc->GetEncoder()->Encode##opc(dst, IsTypeSigned(type), src0, src1);      \
2480         enc->GetCodegen()->LoadCallerRegisters(liveRegs, liveVregs, true);        \
2481     }
2482 
2483 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
2484 #define SIGN_UNSIGN_OPS(DEF) DEF(Div) DEF(Min) DEF(Max)
2485 
2486 SIGN_UNSIGN_OPS(BINARY_SIGN_UNSIGN_OPERATION)
2487 
2488 #undef SIGN_UNSIGN_OPS
2489 #undef BINARY_SIGN_UNSIGN_OPERATION
2490 
2491 void EncodeVisitor::VisitMod(GraphVisitor *visitor, Inst *inst)
2492 {
2493     auto type = inst->GetType();
2494     auto *enc = static_cast<EncodeVisitor *>(visitor);
2495     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2496     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2497     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2498     auto arch = enc->GetCodegen()->GetArch();
2499     if (!Codegen::InstEncodedWithLibCall(inst, arch)) {
2500         enc->GetEncoder()->EncodeMod(dst, IsTypeSigned(type), src0, src1);
2501         return;
2502     }
2503 
2504     if (DataType::IsFloatType(type)) {
2505         RuntimeInterface::IntrinsicId entry =
2506             ((type == DataType::FLOAT32) ? RuntimeInterface::IntrinsicId::LIB_CALL_FMODF
2507                                          : RuntimeInterface::IntrinsicId::LIB_CALL_FMOD);
2508         auto [liveRegs, liveVregs] = enc->GetCodegen()->GetLiveRegisters(inst);
2509         enc->GetCodegen()->SaveCallerRegisters(liveRegs, liveVregs, true);
2510 
2511         enc->GetCodegen()->FillCallParams(src0, src1);
2512         enc->GetCodegen()->CallIntrinsic(inst, entry);
2513 
2514         auto retVal = enc->GetCodegen()->GetTarget().GetReturnFpReg();
2515         if (retVal.GetType().IsFloat()) {
2516             // ret_val is FLOAT64 for Arm64, AMD64 and ARM32 HardFP, but dst can be FLOAT32
2517             // so we convert ret_val to FLOAT32
2518             enc->GetEncoder()->EncodeMov(dst, Reg(retVal.GetId(), dst.GetType()));
2519         } else {
2520             // case for ARM32 SoftFP
2521             enc->GetEncoder()->EncodeMov(dst,
2522                                          Reg(retVal.GetId(), dst.GetSize() == WORD_SIZE ? INT32_TYPE : INT64_TYPE));
2523         }
2524 
2525         enc->GetEncoder()->SetRegister(&liveRegs, &liveVregs, dst, false);
2526         enc->GetCodegen()->LoadCallerRegisters(liveRegs, liveVregs, true);
2527         return;
2528     }
2529 
2530     ASSERT(arch == Arch::AARCH32);
2531     // Fix after supporting AOT mode for arm32
2532     if (enc->cg_->GetGraph()->IsAotMode()) {
2533         enc->GetEncoder()->SetFalseResult();
2534         return;
2535     }
2536     auto [liveRegs, liveVregs] = enc->GetCodegen()->GetLiveRegisters(inst);
2537     enc->GetEncoder()->SetRegister(&liveRegs, &liveVregs, dst, false);
2538     enc->GetCodegen()->SaveCallerRegisters(liveRegs, liveVregs, true);
2539     enc->GetEncoder()->EncodeMod(dst, IsTypeSigned(type), src0, src1);
2540     enc->GetCodegen()->LoadCallerRegisters(liveRegs, liveVregs, true);
2541 }
2542 
VisitShrI(GraphVisitor * visitor,Inst * inst)2543 void EncodeVisitor::VisitShrI(GraphVisitor *visitor, Inst *inst)
2544 {
2545     auto binop = inst->CastToShrI();
2546     auto enc = static_cast<EncodeVisitor *>(visitor);
2547     auto type = inst->GetType();
2548     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2549     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2550     enc->GetEncoder()->EncodeShr(dst, src0, Imm(binop->GetImm()));
2551 }
2552 
VisitMAdd(GraphVisitor * visitor,Inst * inst)2553 void EncodeVisitor::VisitMAdd(GraphVisitor *visitor, Inst *inst)
2554 {
2555     auto type = inst->GetType();
2556     auto enc = static_cast<EncodeVisitor *>(visitor);
2557     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2558     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2559     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2560     constexpr int64_t IMM_2 = 2;
2561     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_2), type);
2562     enc->GetEncoder()->EncodeMAdd(dst, src0, src1, src2);
2563 }
2564 
VisitMSub(GraphVisitor * visitor,Inst * inst)2565 void EncodeVisitor::VisitMSub(GraphVisitor *visitor, Inst *inst)
2566 {
2567     auto type = inst->GetType();
2568     auto enc = static_cast<EncodeVisitor *>(visitor);
2569     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2570     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2571     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2572     constexpr int64_t IMM_2 = 2;
2573     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_2), type);
2574     enc->GetEncoder()->EncodeMSub(dst, src0, src1, src2);
2575 }
2576 
VisitMNeg(GraphVisitor * visitor,Inst * inst)2577 void EncodeVisitor::VisitMNeg(GraphVisitor *visitor, Inst *inst)
2578 {
2579     auto type = inst->GetType();
2580     auto enc = static_cast<EncodeVisitor *>(visitor);
2581     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2582     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2583     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2584     enc->GetEncoder()->EncodeMNeg(dst, src0, src1);
2585 }
2586 
VisitOrNot(GraphVisitor * visitor,Inst * inst)2587 void EncodeVisitor::VisitOrNot(GraphVisitor *visitor, Inst *inst)
2588 {
2589     auto type = inst->GetType();
2590     auto enc = static_cast<EncodeVisitor *>(visitor);
2591     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2592     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2593     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2594     enc->GetEncoder()->EncodeOrNot(dst, src0, src1);
2595 }
2596 
VisitAndNot(GraphVisitor * visitor,Inst * inst)2597 void EncodeVisitor::VisitAndNot(GraphVisitor *visitor, Inst *inst)
2598 {
2599     auto type = inst->GetType();
2600     auto enc = static_cast<EncodeVisitor *>(visitor);
2601     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2602     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2603     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2604     enc->GetEncoder()->EncodeAndNot(dst, src0, src1);
2605 }
2606 
VisitXorNot(GraphVisitor * visitor,Inst * inst)2607 void EncodeVisitor::VisitXorNot(GraphVisitor *visitor, Inst *inst)
2608 {
2609     auto type = inst->GetType();
2610     auto enc = static_cast<EncodeVisitor *>(visitor);
2611     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2612     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2613     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2614     enc->GetEncoder()->EncodeXorNot(dst, src0, src1);
2615 }
2616 
VisitNegSR(GraphVisitor * visitor,Inst * inst)2617 void EncodeVisitor::VisitNegSR(GraphVisitor *visitor, Inst *inst)
2618 {
2619     auto type = inst->GetType();
2620     auto enc = static_cast<EncodeVisitor *>(visitor);
2621     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2622     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2623     auto immShiftInst = static_cast<UnaryShiftedRegisterOperation *>(inst);
2624     enc->GetEncoder()->EncodeNeg(dst, Shift(src, immShiftInst->GetShiftType(), immShiftInst->GetImm()));
2625 }
2626 
VisitCast(GraphVisitor * visitor,Inst * inst)2627 void EncodeVisitor::VisitCast(GraphVisitor *visitor, Inst *inst)
2628 {
2629     auto enc = static_cast<EncodeVisitor *>(visitor);
2630     auto srcType = inst->GetInputType(0);
2631     auto dstType = inst->GetType();
2632 
2633     ASSERT(dstType != DataType::ANY);
2634 
2635     bool srcSigned = IsTypeSigned(srcType);
2636     bool dstSigned = IsTypeSigned(dstType);
2637 
2638     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), srcType);
2639     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), dstType);
2640     if (dstType == DataType::BOOL) {
2641         enc->GetEncoder()->EncodeCastToBool(dst, src);
2642         return;
2643     }
2644 
2645     if (inst->CastToCast()->IsDynamicCast()) {
2646         enc->GetCodegen()->EncodeDynamicCast(inst, dst, dstSigned, src);
2647         return;
2648     }
2649 
2650     auto arch = enc->GetCodegen()->GetArch();
2651     if (!Codegen::InstEncodedWithLibCall(inst, arch)) {
2652         enc->GetEncoder()->EncodeCast(dst, dstSigned, src, srcSigned);
2653         return;
2654     }
2655     ASSERT(arch == Arch::AARCH32);
2656     // Fix after supporting AOT mode for arm32
2657     if (enc->cg_->GetGraph()->IsAotMode()) {
2658         enc->GetEncoder()->SetFalseResult();
2659         return;
2660     }
2661     auto [liveRegs, liveVregs] = enc->GetCodegen()->GetLiveRegisters(inst);
2662     enc->GetEncoder()->SetRegister(&liveRegs, &liveVregs, dst, false);
2663     enc->GetCodegen()->SaveCallerRegisters(liveRegs, liveVregs, true);
2664     enc->GetEncoder()->EncodeCast(dst, dstSigned, src, srcSigned);
2665     enc->GetCodegen()->LoadCallerRegisters(liveRegs, liveVregs, true);
2666 }
2667 
VisitBitcast(GraphVisitor * visitor,Inst * inst)2668 void EncodeVisitor::VisitBitcast(GraphVisitor *visitor, Inst *inst)
2669 {
2670     auto enc = static_cast<EncodeVisitor *>(visitor);
2671     auto codegen = enc->GetCodegen();
2672     auto srcType = inst->GetInputType(0);
2673     auto dstType = inst->GetType();
2674     auto dst = codegen->ConvertRegister(inst->GetDstReg(), dstType);
2675     auto src = codegen->ConvertRegister(inst->GetSrcReg(0), srcType);
2676     enc->GetEncoder()->EncodeMov(dst, src);
2677 }
2678 
VisitPhi(GraphVisitor * visitor,Inst * inst)2679 void EncodeVisitor::VisitPhi([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst) {}
2680 
VisitConstant(GraphVisitor * visitor,Inst * inst)2681 void EncodeVisitor::VisitConstant(GraphVisitor *visitor, Inst *inst)
2682 {
2683     auto *enc = static_cast<EncodeVisitor *>(visitor);
2684     if (inst->GetDstReg() == INVALID_REG) {
2685         return;
2686     }
2687     if (inst->GetDstReg() == enc->cg_->GetGraph()->GetZeroReg()) {
2688         ASSERT(IsZeroConstant(inst));
2689         ASSERT(enc->GetRegfile()->GetZeroReg() != INVALID_REGISTER);
2690         return;
2691     }
2692     auto *constInst = inst->CastToConstant();
2693     auto type = inst->GetType();
2694     if (enc->cg_->GetGraph()->IsDynamicMethod() && type == DataType::INT64) {
2695         type = DataType::INT32;
2696     }
2697 
2698     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2699 #ifndef NDEBUG
2700     switch (type) {
2701         case DataType::FLOAT32:
2702             enc->GetEncoder()->EncodeMov(dst, Imm(constInst->GetFloatValue()));
2703             break;
2704         case DataType::FLOAT64:
2705             enc->GetEncoder()->EncodeMov(dst, Imm(constInst->GetDoubleValue()));
2706             break;
2707         default:
2708             enc->GetEncoder()->EncodeMov(dst, Imm(constInst->GetRawValue()));
2709     }
2710 #else
2711     enc->GetEncoder()->EncodeMov(dst, Imm(constInst->GetRawValue()));
2712 #endif
2713 }
2714 
VisitNullPtr(GraphVisitor * visitor,Inst * inst)2715 void EncodeVisitor::VisitNullPtr(GraphVisitor *visitor, Inst *inst)
2716 {
2717     auto *enc = static_cast<EncodeVisitor *>(visitor);
2718     if (inst->GetDstReg() == enc->cg_->GetGraph()->GetZeroReg()) {
2719         ASSERT_PRINT(enc->GetRegfile()->GetZeroReg() != INVALID_REGISTER,
2720                      "NullPtr doesn't have correct destination register");
2721         return;
2722     }
2723     auto type = inst->GetType();
2724     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2725     enc->GetEncoder()->EncodeMov(dst, Imm(0));
2726 }
2727 
VisitLoadUndefined(GraphVisitor * visitor,Inst * inst)2728 void EncodeVisitor::VisitLoadUndefined(GraphVisitor *visitor, Inst *inst)
2729 {
2730     auto *enc = static_cast<EncodeVisitor *>(visitor);
2731     auto type = inst->GetType();
2732     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
2733     auto runtime = enc->GetCodegen()->GetGraph()->GetRuntime();
2734     auto graph = enc->GetCodegen()->GetGraph();
2735     if (graph->IsJitOrOsrMode()) {
2736         enc->GetEncoder()->EncodeMov(dst, Imm(runtime->GetUndefinedObject()));
2737     } else {
2738         auto ref = MemRef(enc->GetCodegen()->ThreadReg(), runtime->GetTlsUndefinedObjectOffset(graph->GetArch()));
2739         enc->GetEncoder()->EncodeLdr(dst, false, ref);
2740     }
2741 }
2742 
2743 // Next visitors use calling convention
VisitCallIndirect(CallIndirectInst * inst)2744 void Codegen::VisitCallIndirect(CallIndirectInst *inst)
2745 {
2746     auto location = inst->GetLocation(0);
2747     ASSERT(location.IsFixedRegister() && location.IsRegisterValid());
2748     auto src = Reg(location.GetValue(), GetTarget().GetPtrRegType());
2749     auto dst = ConvertRegister(inst->GetDstReg(), inst->GetType());
2750 
2751     GetEncoder()->MakeCall(src);
2752     if (inst->HasUsers()) {
2753         GetEncoder()->EncodeMov(dst, GetTarget().GetReturnReg(dst.GetType()));
2754     }
2755 }
2756 
VisitCall(CallInst * inst)2757 void Codegen::VisitCall(CallInst *inst)
2758 {
2759     ASSERT(GetGraph()->GetRelocationHandler() != nullptr);
2760     ASSERT(!HasLiveCallerSavedRegs(inst));
2761 
2762     RelocationInfo relocation;
2763     relocation.data = inst->GetCallMethodId();
2764     GetEncoder()->MakeCall(&relocation);
2765     GetGraph()->GetRelocationHandler()->AddRelocation(relocation);
2766 
2767     if (inst->HasUsers()) {
2768         auto dstReg = ConvertRegister(inst->GetDstReg(), inst->GetType());
2769         ASSERT(dstReg.IsValid());
2770         GetEncoder()->EncodeMov(dstReg, GetTarget().GetReturnReg(dstReg.GetType()));
2771     }
2772 }
2773 
VisitCallIndirect(GraphVisitor * visitor,Inst * inst)2774 void EncodeVisitor::VisitCallIndirect(GraphVisitor *visitor, Inst *inst)
2775 {
2776     static_cast<EncodeVisitor *>(visitor)->GetCodegen()->VisitCallIndirect(inst->CastToCallIndirect());
2777 }
2778 
VisitCall(GraphVisitor * visitor,Inst * inst)2779 void EncodeVisitor::VisitCall(GraphVisitor *visitor, Inst *inst)
2780 {
2781     static_cast<EncodeVisitor *>(visitor)->GetCodegen()->VisitCall(inst->CastToCall());
2782 }
2783 
VisitCompare(GraphVisitor * visitor,Inst * inst)2784 void EncodeVisitor::VisitCompare(GraphVisitor *visitor, Inst *inst)
2785 {
2786     auto *enc = static_cast<EncodeVisitor *>(visitor);
2787 
2788     auto type = inst->CastToCompare()->GetOperandsType();
2789     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
2790     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2791     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2792     auto cc = enc->GetCodegen()->ConvertCc(inst->CastToCompare()->GetCc());
2793     if (IsTestCc(cc)) {
2794         enc->GetEncoder()->EncodeCompareTest(dst, src0, src1, cc);
2795     } else {
2796         enc->GetEncoder()->EncodeCompare(dst, src0, src1, cc);
2797     }
2798 }
2799 
VisitCmp(GraphVisitor * visitor,Inst * inst)2800 void EncodeVisitor::VisitCmp(GraphVisitor *visitor, Inst *inst)
2801 {
2802     auto *enc = static_cast<EncodeVisitor *>(visitor);
2803 
2804     auto cmpInst = inst->CastToCmp();
2805     auto type = cmpInst->GetOperandsType();
2806 
2807     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
2808     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
2809     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
2810 
2811     Condition cc;
2812     if (DataType::IsFloatType(type)) {
2813         // check whether MI is fully correct here
2814         cc = cmpInst->IsFcmpg() ? (Condition::MI) : (Condition::LT);
2815     } else if (IsTypeSigned(type)) {
2816         cc = Condition::LT;
2817     } else {
2818         cc = Condition::LO;
2819     }
2820     enc->GetEncoder()->EncodeCmp(dst, src0, src1, cc);
2821 }
2822 
VisitReturnVoid(GraphVisitor * visitor,Inst * inst)2823 void EncodeVisitor::VisitReturnVoid(GraphVisitor *visitor, Inst *inst)
2824 {
2825     auto *enc = static_cast<EncodeVisitor *>(visitor);
2826     if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
2827         enc->GetEncoder()->EncodeMemoryBarrier(memory_order::RELEASE);
2828     }
2829 
2830     enc->GetCodegen()->CreateReturn(inst);
2831 }
2832 
VisitReturn(GraphVisitor * visitor,Inst * inst)2833 void EncodeVisitor::VisitReturn(GraphVisitor *visitor, Inst *inst)
2834 {
2835     auto *enc = static_cast<EncodeVisitor *>(visitor);
2836     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), inst->GetType());
2837     enc->GetEncoder()->EncodeMov(enc->GetCodegen()->GetTarget().GetReturnReg(src.GetType()), src);
2838 
2839     enc->GetCodegen()->CreateReturn(inst);
2840 }
2841 
VisitReturnI(GraphVisitor * visitor,Inst * inst)2842 void EncodeVisitor::VisitReturnI(GraphVisitor *visitor, Inst *inst)
2843 {
2844     auto *enc = static_cast<EncodeVisitor *>(visitor);
2845     auto codegen = enc->GetCodegen();
2846     auto rzero = enc->GetRegfile()->GetZeroReg();
2847     int64_t immVal = inst->CastToReturnI()->GetImm();
2848     Imm imm = codegen->ConvertImmWithExtend(immVal, inst->GetType());
2849 
2850     auto returnReg = codegen->GetTarget().GetReturnReg(codegen->ConvertDataType(inst->GetType(), codegen->GetArch()));
2851 
2852     if (immVal == 0 && codegen->GetTarget().SupportZeroReg() && !DataType::IsFloatType(inst->GetType())) {
2853         enc->GetEncoder()->EncodeMov(returnReg, rzero);
2854     } else {
2855         enc->GetEncoder()->EncodeMov(returnReg, imm);
2856     }
2857 
2858     enc->GetCodegen()->CreateReturn(inst);
2859 }
2860 
2861 #if defined(EVENT_METHOD_EXIT_ENABLED) && EVENT_METHOD_EXIT_ENABLED != 0
GetCallInstFromReturnInlined(Inst * return_inlined)2862 static CallInst *GetCallInstFromReturnInlined(Inst *return_inlined)
2863 {
2864     auto ss = return_inlined->GetSaveState();
2865     for (auto &user : ss->GetUsers()) {
2866         auto inst = user.GetInst();
2867         if (inst->IsCall() && static_cast<CallInst *>(inst)->IsInlined()) {
2868             return static_cast<CallInst *>(inst);
2869         }
2870     }
2871     return nullptr;
2872 }
2873 #endif
2874 
VisitReturnInlined(GraphVisitor * visitor,Inst * inst)2875 void EncodeVisitor::VisitReturnInlined(GraphVisitor *visitor, Inst *inst)
2876 {
2877     auto *enc = static_cast<EncodeVisitor *>(visitor);
2878     if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
2879         enc->GetEncoder()->EncodeMemoryBarrier(memory_order::RELEASE);
2880     }
2881 
2882 #if defined(EVENT_METHOD_EXIT_ENABLED) && EVENT_METHOD_EXIT_ENABLED != 0
2883     if (!enc->cg_->GetGraph()->IsAotMode()) {
2884         auto callInst = GetCallInstFromReturnInlined(inst->CastToReturnInlined());
2885         ASSERT(callInst != nullptr);
2886         static_cast<EncodeVisitor *>(visitor)->GetCodegen()->InsertTrace(
2887             {Imm(static_cast<size_t>(TraceId::METHOD_EXIT)), Imm(reinterpret_cast<size_t>(callInst->GetCallMethod())),
2888              Imm(static_cast<size_t>(events::MethodExitKind::INLINED))});
2889     }
2890 #endif
2891 }
2892 
VisitLoadConstArray(GraphVisitor * visitor,Inst * inst)2893 void EncodeVisitor::VisitLoadConstArray(GraphVisitor *visitor, Inst *inst)
2894 {
2895     auto *enc = static_cast<EncodeVisitor *>(visitor);
2896     auto method = inst->CastToLoadConstArray()->GetMethod();
2897     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
2898     auto arrayType = inst->CastToLoadConstArray()->GetTypeId();
2899 
2900     enc->GetCodegen()->CallRuntimeWithMethod(inst, method, EntrypointId::RESOLVE_LITERAL_ARRAY, dst,
2901                                              TypedImm(arrayType));
2902 }
2903 
VisitFillConstArray(GraphVisitor * visitor,Inst * inst)2904 void EncodeVisitor::VisitFillConstArray(GraphVisitor *visitor, Inst *inst)
2905 {
2906     auto type = inst->GetType();
2907     ASSERT(type != DataType::REFERENCE);
2908     auto *enc = static_cast<EncodeVisitor *>(visitor);
2909     auto encoder = enc->GetEncoder();
2910     auto runtime = enc->cg_->GetGraph()->GetRuntime();
2911     auto arrayType = inst->CastToFillConstArray()->GetTypeId();
2912     auto arch = enc->cg_->GetGraph()->GetArch();
2913     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);
2914     auto method = inst->CastToFillConstArray()->GetMethod();
2915     auto offset = runtime->GetArrayDataOffset(enc->GetCodegen()->GetArch());
2916     auto arraySize = inst->CastToFillConstArray()->GetImm() << DataType::ShiftByType(type, arch);
2917 
2918     auto arrayReg = enc->GetCodegen()->ConvertInstTmpReg(inst, DataType::GetIntTypeForReference(arch));
2919     encoder->EncodeAdd(arrayReg, src, Imm(offset));
2920 
2921     ASSERT(arraySize != 0);
2922 
2923     if (enc->cg_->GetGraph()->IsAotMode()) {
2924         auto arrOffset = runtime->GetOffsetToConstArrayData(method, arrayType);
2925         auto pfOffset = runtime->GetPandaFileOffset(arch);
2926         ScopedTmpReg methodReg(encoder);
2927         enc->GetCodegen()->LoadMethod(methodReg);
2928         // load pointer to panda file
2929         encoder->EncodeLdr(methodReg, false, MemRef(methodReg, pfOffset));
2930         // load pointer to binary file
2931         encoder->EncodeLdr(methodReg, false, MemRef(methodReg, runtime->GetBinaryFileBaseOffset(enc->GetArch())));
2932         // Get pointer to array data
2933         encoder->EncodeAdd(methodReg, methodReg, Imm(arrOffset));
2934         // call memcpy
2935         RuntimeInterface::IntrinsicId entry = RuntimeInterface::IntrinsicId::LIB_CALL_MEM_COPY;
2936         auto [liveRegs, liveVregs] = enc->GetCodegen()->GetLiveRegisters(inst);
2937         enc->GetCodegen()->SaveCallerRegisters(liveRegs, liveVregs, true);
2938 
2939         enc->GetCodegen()->FillCallParams(arrayReg, methodReg, TypedImm(arraySize));
2940         enc->GetCodegen()->CallIntrinsic(inst, entry);
2941         enc->GetCodegen()->LoadCallerRegisters(liveRegs, liveVregs, true);
2942     } else {
2943         auto data = runtime->GetPointerToConstArrayData(method, arrayType);
2944         // call memcpy
2945         RuntimeInterface::IntrinsicId entry = RuntimeInterface::IntrinsicId::LIB_CALL_MEM_COPY;
2946         auto [liveRegs, liveVregs] = enc->GetCodegen()->GetLiveRegisters(inst);
2947         enc->GetCodegen()->SaveCallerRegisters(liveRegs, liveVregs, true);
2948 
2949         enc->GetCodegen()->FillCallParams(arrayReg, TypedImm(data), TypedImm(arraySize));
2950         enc->GetCodegen()->CallIntrinsic(inst, entry);
2951         enc->GetCodegen()->LoadCallerRegisters(liveRegs, liveVregs, true);
2952     }
2953 }
2954 
GetEntryPointId(uint64_t elementSize,RuntimeInterface::EntrypointId & eid)2955 static void GetEntryPointId(uint64_t elementSize, RuntimeInterface::EntrypointId &eid)
2956 {
2957     switch (elementSize) {
2958         case sizeof(uint8_t):
2959             eid = RuntimeInterface::EntrypointId::ALLOCATE_ARRAY_TLAB8;
2960             break;
2961         case sizeof(uint16_t):
2962             eid = RuntimeInterface::EntrypointId::ALLOCATE_ARRAY_TLAB16;
2963             break;
2964         case sizeof(uint32_t):
2965             eid = RuntimeInterface::EntrypointId::ALLOCATE_ARRAY_TLAB32;
2966             break;
2967         case sizeof(uint64_t):
2968             eid = RuntimeInterface::EntrypointId::ALLOCATE_ARRAY_TLAB64;
2969             break;
2970         default:
2971             UNREACHABLE();
2972     }
2973 }
2974 
VisitNewArray(Inst * inst)2975 void Codegen::VisitNewArray(Inst *inst)
2976 {
2977     auto method = inst->CastToNewArray()->GetMethod();
2978     auto dst = ConvertRegister(inst->GetDstReg(), inst->GetType());
2979     auto srcClass = ConvertRegister(inst->GetSrcReg(NewArrayInst::INDEX_CLASS), DataType::POINTER);
2980     auto srcSize = ConvertRegister(inst->GetSrcReg(NewArrayInst::INDEX_SIZE), DataType::Type::INT32);
2981     auto arrayType = inst->CastToNewArray()->GetTypeId();
2982     auto runtime = GetGraph()->GetRuntime();
2983     auto encoder = GetEncoder();
2984 
2985     auto maxTlabSize = runtime->GetTLABMaxSize();
2986     // NOTE(msherstennikov): support NewArray fast path for arm32
2987     if (maxTlabSize == 0 || GetArch() == Arch::AARCH32) {
2988         CallRuntime(inst, EntrypointId::CREATE_ARRAY, dst, RegMask::GetZeroMask(), srcClass, srcSize);
2989         if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
2990             encoder->EncodeMemoryBarrier(memory_order::RELEASE);
2991         }
2992         return;
2993     }
2994 
2995     auto lenInst = inst->GetDataFlowInput(0);
2996     auto classArraySize = runtime->GetClassArraySize(GetArch());
2997     uint64_t arraySize = 0;
2998     uint64_t elementSize = runtime->GetArrayElementSize(method, arrayType);
2999     uint64_t alignment = runtime->GetTLABAlignment();
3000     if (lenInst->GetOpcode() == Opcode::Constant) {
3001         ASSERT(lenInst->GetType() == DataType::INT64);
3002         arraySize = lenInst->CastToConstant()->GetIntValue() * elementSize + classArraySize;
3003         arraySize = (arraySize & ~(alignment - 1U)) + ((arraySize % alignment) != 0U ? alignment : 0U);
3004         if (arraySize > maxTlabSize) {
3005             CallRuntime(inst, EntrypointId::CREATE_ARRAY, dst, RegMask::GetZeroMask(), srcClass, srcSize);
3006             if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
3007                 encoder->EncodeMemoryBarrier(memory_order::RELEASE);
3008             }
3009             return;
3010         }
3011     }
3012 
3013     EntrypointId eid;
3014     GetEntryPointId(elementSize, eid);
3015     CallFastPath(inst, eid, dst, RegMask::GetZeroMask(), srcClass, srcSize);
3016     if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
3017         encoder->EncodeMemoryBarrier(memory_order::RELEASE);
3018     }
3019 }
3020 
VisitNewArray(GraphVisitor * visitor,Inst * inst)3021 void EncodeVisitor::VisitNewArray(GraphVisitor *visitor, Inst *inst)
3022 {
3023     auto *enc = static_cast<EncodeVisitor *>(visitor);
3024     return enc->GetCodegen()->VisitNewArray(inst);
3025 }
3026 
VisitParameter(GraphVisitor * visitor,Inst * inst)3027 void EncodeVisitor::VisitParameter(GraphVisitor *visitor, Inst *inst)
3028 {
3029     /*
3030         Default register parameters pushed in ir_builder
3031         In regalloc filled spill/fill parameters part.
3032     */
3033     auto *enc = static_cast<EncodeVisitor *>(visitor);
3034     auto codegen = enc->GetCodegen();
3035     auto paramInst = inst->CastToParameter();
3036     auto sf = paramInst->GetLocationData();
3037     if (sf.GetSrc() == sf.GetDst()) {
3038         return;
3039     }
3040 
3041     auto tmpSf = codegen->GetGraph()->CreateInstSpillFill();
3042     tmpSf->AddSpillFill(sf);
3043     SpillFillEncoder(codegen, tmpSf).EncodeSpillFill();
3044 }
3045 
VisitStoreArray(GraphVisitor * visitor,Inst * inst)3046 void EncodeVisitor::VisitStoreArray(GraphVisitor *visitor, Inst *inst)
3047 {
3048     auto *enc = static_cast<EncodeVisitor *>(visitor);
3049     auto array = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);
3050     auto index = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::INT32);
3051     constexpr int64_t IMM_2 = 2;
3052     auto storedValue = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_2), inst->GetType());
3053     int32_t offset = enc->cg_->GetGraph()->GetRuntime()->GetArrayDataOffset(enc->GetCodegen()->GetArch());
3054     int32_t scale = DataType::ShiftByType(inst->GetType(), enc->GetCodegen()->GetArch());
3055 
3056     auto memRef = [enc, inst, array, index, offset, scale]() {
3057         if (inst->CastToStoreArray()->GetNeedBarrier()) {
3058             auto tmpOffset =
3059                 enc->GetCodegen()->ConvertInstTmpReg(inst, DataType::GetIntTypeForReference(enc->GetArch()));
3060             enc->GetEncoder()->EncodeShl(tmpOffset, index, Imm(scale));
3061             enc->GetEncoder()->EncodeAdd(tmpOffset, tmpOffset, Imm(offset));
3062             return MemRef(array, tmpOffset, 0);
3063         }
3064 
3065         auto tmp = enc->GetCodegen()->ConvertInstTmpReg(inst, DataType::REFERENCE);
3066         enc->GetEncoder()->EncodeAdd(tmp, array, Imm(offset));
3067         return MemRef(tmp, index, scale);
3068     };
3069 
3070     auto mem = memRef();
3071     if (inst->CastToStoreArray()->GetNeedBarrier()) {
3072         enc->GetCodegen()->CreatePreWRB(inst, mem, MakeMask(array.GetId(), storedValue.GetId()));
3073     }
3074     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
3075     enc->GetEncoder()->EncodeStr(storedValue, mem);
3076     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
3077     if (inst->CastToStoreArray()->GetNeedBarrier()) {
3078         enc->GetCodegen()->CreatePostWRB(inst, mem, storedValue, INVALID_REGISTER);
3079     }
3080 }
3081 
VisitSpillFill(GraphVisitor * visitor,Inst * inst)3082 void EncodeVisitor::VisitSpillFill(GraphVisitor *visitor, Inst *inst)
3083 {
3084     auto codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
3085     SpillFillEncoder(codegen, inst).EncodeSpillFill();
3086 }
3087 
VisitSaveState(GraphVisitor * visitor,Inst * inst)3088 void EncodeVisitor::VisitSaveState([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
3089 {
3090     // Nothing to do, SaveState is processed in its users.
3091 }
3092 
VisitSaveStateDeoptimize(GraphVisitor * visitor,Inst * inst)3093 void EncodeVisitor::VisitSaveStateDeoptimize([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
3094 {
3095     // Nothing to do, SaveStateDeoptimize is processed in its users.
3096 }
3097 
VisitSaveStateOsr(GraphVisitor * visitor,Inst * inst)3098 void EncodeVisitor::VisitSaveStateOsr(GraphVisitor *visitor, Inst *inst)
3099 {
3100     static_cast<EncodeVisitor *>(visitor)->GetCodegen()->CreateOsrEntry(inst->CastToSaveStateOsr());
3101 }
3102 
VisitLoadArray(GraphVisitor * visitor,Inst * inst)3103 void EncodeVisitor::VisitLoadArray(GraphVisitor *visitor, Inst *inst)
3104 {
3105     auto instLoadArray = inst->CastToLoadArray();
3106     auto enc = static_cast<EncodeVisitor *>(visitor);
3107     auto runtime = enc->cg_->GetGraph()->GetRuntime();
3108     ASSERT(instLoadArray->IsArray() || !runtime->IsCompressedStringsEnabled());
3109     if (static_cast<LoadInst *>(inst)->GetNeedBarrier()) {
3110         // Consider inserting barriers for GC
3111     }
3112     auto type = inst->GetType();
3113     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // array
3114     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::INT32);      // index
3115     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);                   // load value
3116     int32_t offset = instLoadArray->IsArray() ? runtime->GetArrayDataOffset(enc->GetCodegen()->GetArch())
3117                                               : runtime->GetStringDataOffset(enc->GetArch());
3118     auto encoder = enc->GetEncoder();
3119     auto arch = encoder->GetArch();
3120     int32_t shift = DataType::ShiftByType(type, arch);
3121     ScopedTmpReg scopedTmp(encoder, Codegen::ConvertDataType(DataType::GetIntTypeForReference(arch), arch));
3122     auto tmp = scopedTmp.GetReg();
3123     encoder->EncodeAdd(tmp, src0, Imm(offset));
3124     auto mem = MemRef(tmp, src1, shift);
3125     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
3126     encoder->EncodeLdr(dst, IsTypeSigned(type), mem);
3127     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
3128 }
3129 
VisitLoadCompressedStringChar(GraphVisitor * visitor,Inst * inst)3130 void EncodeVisitor::VisitLoadCompressedStringChar(GraphVisitor *visitor, Inst *inst)
3131 {
3132     auto *enc = static_cast<EncodeVisitor *>(visitor);
3133     auto runtime = enc->cg_->GetGraph()->GetRuntime();
3134     auto type = inst->GetType();
3135     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // array
3136     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::INT32);      // index
3137     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(2), DataType::INT32);      // length
3138     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);                   // load value
3139     int32_t offset = runtime->GetStringDataOffset(enc->GetArch());
3140     auto encoder = enc->GetEncoder();
3141     auto arch = encoder->GetArch();
3142     int32_t shift = DataType::ShiftByType(type, arch);
3143     ScopedTmpReg scopedTmp(encoder, Codegen::ConvertDataType(DataType::GetIntTypeForReference(arch), arch));
3144     auto tmp = scopedTmp.GetReg();
3145 
3146     ASSERT(encoder->CanEncodeCompressedStringCharAt());
3147     auto mask = runtime->GetStringCompressionMask();
3148     if (mask != 1) {
3149         UNREACHABLE();  // mask is hardcoded in JCL, but verify it just in case it's changed
3150     }
3151     enc->GetEncoder()->EncodeCompressedStringCharAt(dst, src0, src1, src2, tmp, offset, shift);
3152 }
3153 
VisitLenArray(GraphVisitor * visitor,Inst * inst)3154 void EncodeVisitor::VisitLenArray(GraphVisitor *visitor, Inst *inst)
3155 {
3156     auto *enc = static_cast<EncodeVisitor *>(visitor);
3157     auto type = inst->GetType();
3158     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // array
3159     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);                   // len array
3160 
3161     auto lenArrayInst = inst->CastToLenArray();
3162     auto runtime = enc->cg_->GetGraph()->GetRuntime();
3163     int64_t offset = lenArrayInst->IsArray() ? runtime->GetArrayLengthOffset(enc->GetCodegen()->GetArch())
3164                                              : runtime->GetStringLengthOffset(enc->GetArch());
3165     auto mem = MemRef(src0, offset);
3166 
3167     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
3168     enc->GetEncoder()->EncodeLdr(dst, IsTypeSigned(type), mem);
3169     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
3170 }
3171 
VisitBuiltin(GraphVisitor * visitor,Inst * inst)3172 void EncodeVisitor::VisitBuiltin([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
3173 {
3174     UNREACHABLE();
3175 }
3176 
VisitNullCheck(GraphVisitor * visitor,Inst * inst)3177 void EncodeVisitor::VisitNullCheck(GraphVisitor *visitor, Inst *inst)
3178 {
3179     if (inst->CastToNullCheck()->IsImplicit()) {
3180         return;
3181     }
3182     auto *enc = static_cast<EncodeVisitor *>(visitor);
3183     enc->GetCodegen()->template CreateUnaryCheck<SlowPathImplicitNullCheck>(inst, EntrypointId::NULL_POINTER_EXCEPTION,
3184                                                                             DeoptimizeType::NULL_CHECK, Condition::EQ);
3185 }
3186 
VisitBoundsCheck(GraphVisitor * visitor,Inst * inst)3187 void EncodeVisitor::VisitBoundsCheck(GraphVisitor *visitor, Inst *inst)
3188 {
3189     auto *enc = static_cast<EncodeVisitor *>(visitor);
3190     auto lenType = inst->GetInputType(0);
3191     auto len = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), lenType);
3192     auto indexType = inst->GetInputType(1);
3193     auto index = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), indexType);
3194     [[maybe_unused]] constexpr int64_t IMM_2 = 2;
3195     ASSERT(inst->GetInput(IMM_2).GetInst()->GetOpcode() == Opcode::SaveState ||
3196            inst->GetInput(IMM_2).GetInst()->GetOpcode() == Opcode::SaveStateDeoptimize);
3197 
3198     EntrypointId entrypoint = inst->CastToBoundsCheck()->IsArray() ? EntrypointId::ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION
3199                                                                    : EntrypointId::STRING_INDEX_OUT_OF_BOUNDS_EXCEPTION;
3200 
3201     LabelHolder::LabelId label;
3202     if (inst->CanDeoptimize()) {
3203         DeoptimizeType type = DeoptimizeType::BOUNDS_CHECK_WITH_DEOPT;
3204         label = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, type)->GetLabel();
3205     } else {
3206         label = enc->GetCodegen()->CreateSlowPath<SlowPathCheck>(inst, entrypoint)->GetLabel();
3207     }
3208     enc->GetEncoder()->EncodeJump(label, index, len, Condition::HS);
3209 }
3210 
VisitRefTypeCheck(GraphVisitor * visitor,Inst * inst)3211 void EncodeVisitor::VisitRefTypeCheck(GraphVisitor *visitor, Inst *inst)
3212 {
3213     auto *enc = static_cast<EncodeVisitor *>(visitor);
3214     auto encoder = enc->GetEncoder();
3215     auto arrayReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);
3216     auto refReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
3217     [[maybe_unused]] constexpr int64_t IMM_2 = 2;
3218     ASSERT(inst->GetInput(IMM_2).GetInst()->GetOpcode() == Opcode::SaveState);
3219     auto runtime = enc->cg_->GetGraph()->GetRuntime();
3220 
3221     auto slowPath =
3222         enc->GetCodegen()->CreateSlowPath<SlowPathRefCheck>(inst, EntrypointId::CHECK_STORE_ARRAY_REFERENCE);
3223 
3224     slowPath->SetRegs(arrayReg, refReg);
3225     slowPath->CreateBackLabel(encoder);
3226 
3227     // We don't check if stored object is nullptr
3228     encoder->EncodeJump(slowPath->GetBackLabel(), refReg, Condition::EQ);
3229 
3230     ScopedTmpReg tmpReg(encoder, Codegen::ConvertDataType(DataType::REFERENCE, enc->GetCodegen()->GetArch()));
3231     ScopedTmpReg tmpReg1(encoder, Codegen::ConvertDataType(DataType::REFERENCE, enc->GetCodegen()->GetArch()));
3232 
3233     // Get Class from array
3234     enc->GetCodegen()->LoadClassFromObject(tmpReg, arrayReg);
3235 
3236     // Get element type Class from array class
3237     encoder->EncodeLdr(tmpReg, false, MemRef(tmpReg, runtime->GetClassComponentTypeOffset(enc->GetArch())));
3238 
3239     // Get Class from stored object
3240     enc->GetCodegen()->LoadClassFromObject(tmpReg1, refReg);
3241 
3242     // If the object's and array element's types match we do not check further
3243     encoder->EncodeJump(slowPath->GetBackLabel(), tmpReg, tmpReg1, Condition::EQ);
3244 
3245     // If the array's element class is not Object (baseclass == null)
3246     // we call CheckStoreArrayReference, otherwise we fall through
3247     encoder->EncodeLdr(tmpReg1, false, MemRef(tmpReg, runtime->GetClassBaseOffset(enc->GetArch())));
3248     encoder->EncodeJump(slowPath->GetLabel(), tmpReg1, Condition::NE);
3249 
3250     slowPath->BindBackLabel(encoder);
3251 }
3252 
VisitZeroCheck(GraphVisitor * visitor,Inst * inst)3253 void EncodeVisitor::VisitZeroCheck(GraphVisitor *visitor, Inst *inst)
3254 {
3255     auto *enc = static_cast<EncodeVisitor *>(visitor);
3256     enc->GetCodegen()->template CreateUnaryCheck<SlowPathCheck>(inst, EntrypointId::ARITHMETIC_EXCEPTION,
3257                                                                 DeoptimizeType::ZERO_CHECK, Condition::EQ);
3258 }
3259 
VisitNegativeCheck(GraphVisitor * visitor,Inst * inst)3260 void EncodeVisitor::VisitNegativeCheck(GraphVisitor *visitor, Inst *inst)
3261 {
3262     auto *enc = static_cast<EncodeVisitor *>(visitor);
3263     enc->GetCodegen()->template CreateUnaryCheck<SlowPathCheck>(inst, EntrypointId::NEGATIVE_ARRAY_SIZE_EXCEPTION,
3264                                                                 DeoptimizeType::NEGATIVE_CHECK, Condition::LT);
3265 }
3266 
VisitNotPositiveCheck(GraphVisitor * visitor,Inst * inst)3267 void EncodeVisitor::VisitNotPositiveCheck(GraphVisitor *visitor, Inst *inst)
3268 {
3269     auto *enc = static_cast<EncodeVisitor *>(visitor);
3270     auto srcType = inst->GetInputType(0);
3271     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), srcType);
3272     ASSERT(inst->GetInput(1).GetInst()->GetOpcode() == Opcode::SaveState ||
3273            inst->GetInput(1).GetInst()->GetOpcode() == Opcode::SaveStateDeoptimize);
3274 
3275     ASSERT(inst->CanDeoptimize());
3276     DeoptimizeType type = DeoptimizeType::NEGATIVE_CHECK;
3277     auto label = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, type)->GetLabel();
3278     enc->GetEncoder()->EncodeJump(label, src, Condition::LE);
3279 }
3280 
VisitDeoptimizeIf(GraphVisitor * visitor,Inst * inst)3281 void EncodeVisitor::VisitDeoptimizeIf(GraphVisitor *visitor, Inst *inst)
3282 {
3283     auto *enc = static_cast<EncodeVisitor *>(visitor);
3284     auto srcType = inst->GetInput(0).GetInst()->GetType();
3285     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), srcType);
3286 
3287     auto slowPath =
3288         enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, inst->CastToDeoptimizeIf()->GetDeoptimizeType());
3289 
3290     // create jump to slow path if src is true
3291     enc->GetEncoder()->EncodeJump(slowPath->GetLabel(), src, Condition::NE);
3292 }
3293 
VisitDeoptimizeCompare(GraphVisitor * visitor,Inst * inst)3294 void EncodeVisitor::VisitDeoptimizeCompare(GraphVisitor *visitor, Inst *inst)
3295 {
3296     auto *enc = static_cast<EncodeVisitor *>(visitor);
3297     auto deopt = inst->CastToDeoptimizeCompare();
3298     ASSERT(deopt->GetOperandsType() != DataType::NO_TYPE);
3299     auto src0 = enc->GetCodegen()->ConvertRegister(deopt->GetSrcReg(0), deopt->GetOperandsType());
3300     auto src1 = enc->GetCodegen()->ConvertRegister(deopt->GetSrcReg(1), deopt->GetOperandsType());
3301     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(
3302         inst, inst->CastToDeoptimizeCompare()->GetDeoptimizeType());
3303     enc->GetEncoder()->EncodeJump(slowPath->GetLabel(), src0, src1, enc->GetCodegen()->ConvertCc(deopt->GetCc()));
3304 }
3305 
VisitDeoptimizeCompareImm(GraphVisitor * visitor,Inst * inst)3306 void EncodeVisitor::VisitDeoptimizeCompareImm(GraphVisitor *visitor, Inst *inst)
3307 {
3308     auto *enc = static_cast<EncodeVisitor *>(visitor);
3309     auto encoder = enc->GetEncoder();
3310     auto deopt = inst->CastToDeoptimizeCompareImm();
3311     ASSERT(deopt->GetOperandsType() != DataType::NO_TYPE);
3312     auto cc = deopt->GetCc();
3313     auto src0 = enc->GetCodegen()->ConvertRegister(deopt->GetSrcReg(0), deopt->GetOperandsType());
3314     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(
3315         inst, inst->CastToDeoptimizeCompareImm()->GetDeoptimizeType());
3316 
3317     if (deopt->GetImm() == 0) {
3318         Arch arch = enc->GetCodegen()->GetArch();
3319         DataType::Type type = deopt->GetInput(0).GetInst()->GetType();
3320         ASSERT(!IsFloatType(type));
3321         if (IsTypeSigned(type) && (cc == ConditionCode::CC_LT || cc == ConditionCode::CC_GE)) {
3322             auto signBit = GetTypeSize(type, arch) - 1;
3323             if (cc == ConditionCode::CC_LT) {
3324                 // x < 0
3325                 encoder->EncodeBitTestAndBranch(slowPath->GetLabel(), src0, signBit, true);
3326                 return;
3327             }
3328             if (cc == ConditionCode::CC_GE) {
3329                 // x >= 0
3330                 encoder->EncodeBitTestAndBranch(slowPath->GetLabel(), src0, signBit, false);
3331                 return;
3332             }
3333         }
3334         if (enc->GetCodegen()->GetTarget().SupportZeroReg()) {
3335             auto zreg = enc->GetRegfile()->GetZeroReg();
3336             encoder->EncodeJump(slowPath->GetLabel(), src0, zreg, enc->GetCodegen()->ConvertCc(cc));
3337         } else {
3338             encoder->EncodeJump(slowPath->GetLabel(), src0, Imm(0), enc->GetCodegen()->ConvertCc(cc));
3339         }
3340         return;
3341     }
3342     encoder->EncodeJump(slowPath->GetLabel(), src0, Imm(deopt->GetImm()), enc->GetCodegen()->ConvertCc(cc));
3343 }
3344 
VisitLoadString(GraphVisitor * visitor,Inst * inst)3345 void EncodeVisitor::VisitLoadString(GraphVisitor *visitor, Inst *inst)
3346 {
3347     auto *enc = static_cast<EncodeVisitor *>(visitor);
3348     auto method = inst->CastToLoadString()->GetMethod();
3349     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
3350     auto stringType = inst->CastToLoadString()->GetTypeId();
3351     auto graph = enc->cg_->GetGraph();
3352     auto encoder = enc->GetEncoder();
3353     ASSERT(inst->IsRuntimeCall());
3354 
3355     // Static constructor invoked only once, so there is no sense in replacing regular
3356     // ResolveString runtime call with optimized version that will only slow down constructor's execution.
3357     auto isCctor = graph->GetRuntime()->IsMethodStaticConstructor(method);
3358     ObjectPointerType stringPtr {0};
3359 
3360     if (graph->IsAotMode() && g_options.IsCompilerAotLoadStringPlt() && !isCctor) {
3361         auto aotData = graph->GetAotData();
3362         intptr_t slotOffset = aotData->GetStringSlotOffset(encoder->GetCursorOffset(), stringType);
3363         ScopedTmpRegU64 addrReg(encoder);
3364         ScopedTmpRegU64 tmpDst(encoder);
3365         encoder->MakeLoadAotTableAddr(slotOffset, addrReg, tmpDst);
3366 
3367         auto slowPath =
3368             enc->GetCodegen()->CreateSlowPath<SlowPathResolveStringAot>(inst, EntrypointId::RESOLVE_STRING_AOT);
3369         slowPath->SetDstReg(dst);
3370         slowPath->SetAddrReg(addrReg);
3371         slowPath->SetStringId(stringType);
3372         slowPath->SetMethod(method);
3373         encoder->EncodeJump(slowPath->GetLabel(), tmpDst, Imm(RuntimeInterface::RESOLVE_STRING_AOT_COUNTER_LIMIT),
3374                             Condition::LT);
3375         encoder->EncodeMov(dst, Reg(tmpDst.GetReg().GetId(), dst.GetType()));
3376         slowPath->BindBackLabel(encoder);
3377     } else if (!graph->IsAotMode() && (stringPtr = graph->GetRuntime()->GetNonMovableString(method, stringType)) != 0) {
3378         encoder->EncodeMov(dst, Imm(stringPtr));
3379         EVENT_JIT_USE_RESOLVED_STRING(graph->GetRuntime()->GetMethodName(method), stringType);
3380     } else {
3381         enc->GetCodegen()->CallRuntimeWithMethod(inst, method, EntrypointId::RESOLVE_STRING, dst, TypedImm(stringType));
3382     }
3383 }
3384 
VisitLoadObject(GraphVisitor * visitor,Inst * inst)3385 void EncodeVisitor::VisitLoadObject(GraphVisitor *visitor, Inst *inst)
3386 {
3387     auto *enc = static_cast<EncodeVisitor *>(visitor);
3388     auto loadObj = inst->CastToLoadObject();
3389     if (loadObj->GetNeedBarrier()) {
3390         // Consider inserting barriers for GC
3391     }
3392     auto type = inst->GetType();
3393     auto typeInput = inst->GetInput(0).GetInst()->GetType();
3394     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), typeInput);  // obj
3395     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);        // load value
3396 
3397     auto graph = enc->cg_->GetGraph();
3398     auto field = loadObj->GetObjField();
3399     size_t offset = GetObjectOffset(graph, loadObj->GetObjectType(), field, loadObj->GetTypeId());
3400     auto mem = MemRef(src, offset);
3401     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
3402     if (loadObj->GetVolatile()) {
3403         enc->GetEncoder()->EncodeLdrAcquire(dst, IsTypeSigned(type), mem);
3404     } else {
3405         enc->GetEncoder()->EncodeLdr(dst, IsTypeSigned(type), mem);
3406     }
3407     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
3408 }
3409 
VisitResolveObjectField(GraphVisitor * visitor,Inst * inst)3410 void EncodeVisitor::VisitResolveObjectField(GraphVisitor *visitor, Inst *inst)
3411 {
3412     auto *enc = static_cast<EncodeVisitor *>(visitor);
3413     auto graph = enc->cg_->GetGraph();
3414     auto resolver = inst->CastToResolveObjectField();
3415     if (resolver->GetNeedBarrier()) {
3416         // Inserts barriers for GC
3417     }
3418     auto type = inst->GetType();
3419     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
3420     auto typeId = resolver->GetTypeId();
3421     auto method = resolver->GetMethod();
3422     if (graph->IsAotMode()) {
3423         enc->GetCodegen()->CallRuntimeWithMethod(inst, method, EntrypointId::GET_FIELD_OFFSET, dst, TypedImm(typeId));
3424     } else {
3425         auto skind = UnresolvedTypesInterface::SlotKind::FIELD;
3426         auto fieldOffsetAddr = graph->GetRuntime()->GetUnresolvedTypes()->GetTableSlot(method, typeId, skind);
3427         ScopedTmpReg tmpReg(enc->GetEncoder());
3428         // load field offset and if it's 0 then call runtime EntrypointId::GET_FIELD_OFFSET
3429         enc->GetEncoder()->EncodeMov(tmpReg, Imm(fieldOffsetAddr));
3430         enc->GetEncoder()->EncodeLdr(tmpReg, false, MemRef(tmpReg));
3431         auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathUnresolved>(inst, EntrypointId::GET_FIELD_OFFSET);
3432         slowPath->SetUnresolvedType(method, typeId);
3433         slowPath->SetDstReg(tmpReg);
3434         slowPath->SetSlotAddr(fieldOffsetAddr);
3435         enc->GetEncoder()->EncodeJump(slowPath->GetLabel(), tmpReg, Condition::EQ);
3436         slowPath->BindBackLabel(enc->GetEncoder());
3437         enc->GetEncoder()->EncodeMov(dst, tmpReg);
3438     }
3439 }
3440 
VisitLoadResolvedObjectField(GraphVisitor * visitor,Inst * inst)3441 void EncodeVisitor::VisitLoadResolvedObjectField([[maybe_unused]] GraphVisitor *visitor, Inst *inst)
3442 {
3443     auto *enc = static_cast<EncodeVisitor *>(visitor);
3444     auto load = inst->CastToLoadResolvedObjectField();
3445     if (load->GetNeedBarrier()) {
3446         // Inserts barriers for GC
3447     }
3448     auto type = inst->GetType();
3449     auto obj = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
3450     auto ofs = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::UINT32);     // field offset
3451     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);                  // load value
3452     ScopedTmpReg tmpReg(enc->GetEncoder());
3453     enc->GetEncoder()->EncodeAdd(tmpReg, obj, ofs);
3454     enc->GetEncoder()->EncodeLdrAcquire(dst, IsTypeSigned(type), MemRef(tmpReg));
3455 }
3456 
VisitLoad(GraphVisitor * visitor,Inst * inst)3457 void EncodeVisitor::VisitLoad(GraphVisitor *visitor, Inst *inst)
3458 {
3459     auto *enc = static_cast<EncodeVisitor *>(visitor);
3460     auto loadByOffset = inst->CastToLoad();
3461 
3462     auto type = inst->GetType();
3463     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0U), DataType::POINTER);  // pointer
3464     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1U), DataType::UINT32);   // offset
3465     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);                  // load value
3466 
3467     auto mem = MemRef(src0, src1, loadByOffset->GetScale());
3468 
3469     if (loadByOffset->GetVolatile()) {
3470         enc->GetEncoder()->EncodeLdrAcquire(dst, IsTypeSigned(type), mem);
3471     } else {
3472         enc->GetEncoder()->EncodeLdr(dst, IsTypeSigned(type), mem);
3473     }
3474 }
3475 
VisitLoadI(GraphVisitor * visitor,Inst * inst)3476 void EncodeVisitor::VisitLoadI(GraphVisitor *visitor, Inst *inst)
3477 {
3478     auto *enc = static_cast<EncodeVisitor *>(visitor);
3479     auto loadByOffset = inst->CastToLoadI();
3480 
3481     auto type = inst->GetType();
3482     auto base = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0U), DataType::POINTER);  // pointer
3483     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);                  // load value
3484 
3485     if (loadByOffset->GetVolatile()) {
3486         enc->GetEncoder()->EncodeLdrAcquire(dst, IsTypeSigned(type), MemRef(base, loadByOffset->GetImm()));
3487     } else {
3488         enc->GetEncoder()->EncodeLdr(dst, IsTypeSigned(type), MemRef(base, loadByOffset->GetImm()));
3489     }
3490 }
3491 
VisitStoreI(GraphVisitor * visitor,Inst * inst)3492 void EncodeVisitor::VisitStoreI(GraphVisitor *visitor, Inst *inst)
3493 {
3494     auto *enc = static_cast<EncodeVisitor *>(visitor);
3495     auto storeInst = inst->CastToStoreI();
3496 
3497     auto base = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0U), DataType::POINTER);
3498     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1U), inst->GetType());
3499 
3500     auto mem = MemRef(base, storeInst->GetImm());
3501     if (inst->CastToStoreI()->GetNeedBarrier()) {
3502         enc->GetCodegen()->CreatePreWRB(inst, mem, MakeMask(base.GetId(), src.GetId()));
3503     }
3504 
3505     if (storeInst->GetVolatile()) {
3506         enc->GetEncoder()->EncodeStrRelease(src, mem);
3507     } else {
3508         enc->GetEncoder()->EncodeStr(src, mem);
3509     }
3510 
3511     if (inst->CastToStoreI()->GetNeedBarrier()) {
3512         enc->GetCodegen()->CreatePostWRB(inst, mem, src, INVALID_REGISTER);
3513     }
3514 }
3515 
VisitStoreObject(GraphVisitor * visitor,Inst * inst)3516 void EncodeVisitor::VisitStoreObject(GraphVisitor *visitor, Inst *inst)
3517 {
3518     auto *enc = static_cast<EncodeVisitor *>(visitor);
3519     auto storeObj = inst->CastToStoreObject();
3520     auto codegen = enc->GetCodegen();
3521     auto src0 = codegen->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
3522     auto src1 = codegen->ConvertRegister(inst->GetSrcReg(1), inst->GetType());      // store value
3523 
3524     auto graph = enc->cg_->GetGraph();
3525     auto field = storeObj->GetObjField();
3526     size_t offset = GetObjectOffset(graph, storeObj->GetObjectType(), field, storeObj->GetTypeId());
3527     if (!enc->GetCodegen()->OffsetFitReferenceTypeSize(offset)) {
3528         // such code should not be executed
3529         enc->GetEncoder()->EncodeAbort();
3530         return;
3531     }
3532     auto mem = MemRef(src0, offset);
3533     auto encoder = enc->GetEncoder();
3534     if (inst->CastToStoreObject()->GetNeedBarrier()) {
3535         if (storeObj->GetObjectType() == ObjectType::MEM_DYN_CLASS) {
3536             codegen->CreatePreWRB<true>(inst, mem, MakeMask(src0.GetId(), src1.GetId()));
3537         } else {
3538             codegen->CreatePreWRB(inst, mem, MakeMask(src0.GetId(), src1.GetId()));
3539         }
3540     }
3541     auto prevOffset = encoder->GetCursorOffset();
3542     if (storeObj->GetVolatile()) {
3543         encoder->EncodeStrRelease(src1, mem);
3544     } else {
3545         encoder->EncodeStr(src1, mem);
3546     }
3547     codegen->TryInsertImplicitNullCheck(inst, prevOffset);
3548     if (inst->CastToStoreObject()->GetNeedBarrier()) {
3549         ScopedTmpRegLazy tmp(encoder);
3550         if (storeObj->GetObjectType() == ObjectType::MEM_DYN_CLASS) {
3551             tmp.AcquireIfInvalid();
3552             encoder->EncodeLdr(tmp, false, MemRef(src1, graph->GetRuntime()->GetManagedClassOffset(graph->GetArch())));
3553             src1 = tmp;
3554         }
3555         codegen->CreatePostWRB(inst, mem, src1, INVALID_REGISTER);
3556     }
3557 }
3558 
VisitStoreResolvedObjectField(GraphVisitor * visitor,Inst * inst)3559 void EncodeVisitor::VisitStoreResolvedObjectField(GraphVisitor *visitor, Inst *inst)
3560 {
3561     auto *enc = static_cast<EncodeVisitor *>(visitor);
3562     auto store = inst->CastToStoreResolvedObjectField();
3563     auto obj = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // object
3564     auto val = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), inst->GetType());      // store value
3565     auto ofs = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(2), DataType::UINT32);     // field offset
3566     auto mem = MemRef(obj, ofs, 0);
3567     if (store->GetNeedBarrier()) {
3568         enc->GetCodegen()->CreatePreWRB(inst, mem);
3569     }
3570     // Unknown store, assume it can be volatile
3571     enc->GetEncoder()->EncodeStrRelease(val, mem);
3572     if (store->GetNeedBarrier()) {
3573         enc->GetCodegen()->CreatePostWRB(inst, mem, val, INVALID_REGISTER);
3574     }
3575 }
3576 
VisitStore(GraphVisitor * visitor,Inst * inst)3577 void EncodeVisitor::VisitStore(GraphVisitor *visitor, Inst *inst)
3578 {
3579     auto *enc = static_cast<EncodeVisitor *>(visitor);
3580     auto storeByOffset = inst->CastToStore();
3581     auto type = inst->GetType();
3582     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0U), DataType::POINTER);  // pointer
3583     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1U), DataType::UINT32);   // offset
3584     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(2U), type);               // store value
3585 
3586     auto mem = MemRef(src0, src1, storeByOffset->GetScale());
3587     if (inst->CastToStore()->GetNeedBarrier()) {
3588         enc->GetCodegen()->CreatePreWRB(inst, mem, MakeMask(src0.GetId(), src2.GetId()));
3589     }
3590 
3591     if (storeByOffset->GetVolatile()) {
3592         enc->GetEncoder()->EncodeStrRelease(src2, mem);
3593     } else {
3594         enc->GetEncoder()->EncodeStr(src2, mem);
3595     }
3596 
3597     if (inst->CastToStore()->GetNeedBarrier()) {
3598         enc->GetCodegen()->CreatePostWRB(inst, mem, src2, INVALID_REGISTER);
3599     }
3600 }
3601 
VisitInitClass(GraphVisitor * visitor,Inst * inst)3602 void EncodeVisitor::VisitInitClass(GraphVisitor *visitor, Inst *inst)
3603 {
3604     auto *enc = static_cast<EncodeVisitor *>(visitor);
3605     auto graph = enc->cg_->GetGraph();
3606     auto runtime = graph->GetRuntime();
3607     auto classId = inst->CastToInitClass()->GetTypeId();
3608     auto encoder = enc->GetEncoder();
3609     ASSERT(inst->IsRuntimeCall());
3610 
3611     if (graph->IsAotMode()) {
3612         ScopedTmpReg tmpReg(encoder);
3613         ScopedTmpReg classReg(encoder);
3614 
3615         auto aotData = graph->GetAotData();
3616         intptr_t offset = aotData->GetClassSlotOffset(encoder->GetCursorOffset(), classId, true);
3617         encoder->MakeLoadAotTableAddr(offset, tmpReg, classReg);
3618 
3619         auto label = encoder->CreateLabel();
3620         encoder->EncodeJump(label, classReg, Condition::NE);
3621 
3622         // PLT Class Init Resolver has special calling convention:
3623         // First encoder temporary (tmp_reg) works as parameter and return value (which is unnecessary here)
3624         CHECK_EQ(tmpReg.GetReg().GetId(), encoder->GetTarget().GetTempRegsMask().GetMinRegister());
3625         enc->GetCodegen()->CreateJumpToClassResolverPltShared(inst, tmpReg.GetReg(), EntrypointId::CLASS_INIT_RESOLVER);
3626         encoder->BindLabel(label);
3627     } else {  // JIT mode
3628         auto klass = reinterpret_cast<uintptr_t>(inst->CastToInitClass()->GetClass());
3629         ASSERT(klass != 0);
3630         if (!runtime->IsClassInitialized(klass)) {
3631             auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::INITIALIZE_CLASS);
3632 
3633             auto stateOffset = runtime->GetClassStateOffset(enc->GetArch());
3634             int64_t initValue = runtime->GetClassInitializedValue();
3635             ScopedTmpReg tmpReg(encoder);
3636             encoder->EncodeMov(tmpReg, Imm(klass + stateOffset));
3637             auto tmpI8 = enc->GetCodegen()->ConvertRegister(tmpReg.GetReg().GetId(), DataType::INT8);
3638             encoder->EncodeLdr(tmpI8, false, MemRef(tmpReg));
3639 
3640             encoder->EncodeJump(slowPath->GetLabel(), tmpI8, Imm(initValue), Condition::NE);
3641 
3642             slowPath->BindBackLabel(encoder);
3643         }
3644     }
3645 }
3646 
VisitLoadClass(GraphVisitor * visitor,Inst * inst)3647 void EncodeVisitor::VisitLoadClass(GraphVisitor *visitor, Inst *inst)
3648 {
3649     auto *enc = static_cast<EncodeVisitor *>(visitor);
3650     auto encoder = enc->GetEncoder();
3651     auto loadClass = inst->CastToLoadClass();
3652     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
3653     auto graph = enc->cg_->GetGraph();
3654     auto typeId = loadClass->GetTypeId();
3655     ASSERT(inst->IsRuntimeCall());
3656 
3657     if (graph->IsAotMode()) {
3658         auto methodClassId = graph->GetRuntime()->GetClassIdForMethod(graph->GetMethod());
3659         if (methodClassId == typeId) {
3660             auto dstPtr = dst.As(Codegen::ConvertDataType(DataType::POINTER, graph->GetArch()));
3661             enc->GetCodegen()->LoadMethod(dstPtr);
3662             auto mem = MemRef(dstPtr, graph->GetRuntime()->GetClassOffset(graph->GetArch()));
3663             encoder->EncodeLdr(dst.As(Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch())), false, mem);
3664             return;
3665         }
3666         ScopedTmpReg tmpReg(encoder);
3667         enc->GetCodegen()->CreateLoadClassFromPLT(inst, tmpReg, dst, typeId);
3668     } else {  // JIT mode
3669         auto klass = loadClass->GetClass();
3670         if (klass == nullptr) {
3671             FillLoadClassUnresolved(visitor, inst);
3672         } else {
3673             encoder->EncodeMov(dst, Imm(reinterpret_cast<uintptr_t>(klass)));
3674         }
3675     }
3676 }
3677 
FillLoadClassUnresolved(GraphVisitor * visitor,Inst * inst)3678 void EncodeVisitor::FillLoadClassUnresolved(GraphVisitor *visitor, Inst *inst)
3679 {
3680     auto *enc = static_cast<EncodeVisitor *>(visitor);
3681     auto encoder = enc->GetEncoder();
3682     auto loadClass = inst->CastToLoadClass();
3683     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
3684     auto graph = enc->cg_->GetGraph();
3685     auto typeId = loadClass->GetTypeId();
3686     auto method = loadClass->GetMethod();
3687     auto utypes = graph->GetRuntime()->GetUnresolvedTypes();
3688     auto klassAddr = utypes->GetTableSlot(method, typeId, UnresolvedTypesInterface::SlotKind::CLASS);
3689     Reg dstPtr(dst.GetId(), enc->GetCodegen()->GetPtrRegType());
3690     encoder->EncodeMov(dstPtr, Imm(klassAddr));
3691     encoder->EncodeLdr(dst, false, MemRef(dstPtr));
3692     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathUnresolved>(inst, EntrypointId::RESOLVE_CLASS);
3693     slowPath->SetUnresolvedType(method, typeId);
3694     slowPath->SetDstReg(dst);
3695     slowPath->SetSlotAddr(klassAddr);
3696 
3697     encoder->EncodeJump(slowPath->GetLabel(), dst, Condition::EQ);
3698     slowPath->BindBackLabel(encoder);
3699 }
3700 
VisitGetGlobalVarAddress(GraphVisitor * visitor,Inst * inst)3701 void EncodeVisitor::VisitGetGlobalVarAddress(GraphVisitor *visitor, Inst *inst)
3702 {
3703     auto *enc = static_cast<EncodeVisitor *>(visitor);
3704     auto graph = enc->cg_->GetGraph();
3705     auto runtime = graph->GetRuntime();
3706     auto id = inst->CastToGetGlobalVarAddress()->GetTypeId();
3707     auto encoder = enc->GetEncoder();
3708     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());  // load value
3709     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::ANY);
3710     auto entrypointId = runtime->GetGlobalVarEntrypointId();
3711     ASSERT(inst->IsRuntimeCall());
3712     if (graph->IsAotMode()) {
3713         ScopedTmpReg addr(encoder);
3714         auto aotData = graph->GetAotData();
3715         Reg constPool = src;
3716         ScopedTmpRegLazy tmpReg(encoder);
3717         if (dst.GetId() == src.GetId()) {
3718             tmpReg.AcquireIfInvalid();
3719             constPool = tmpReg.GetReg().As(src.GetType());
3720             encoder->EncodeMov(constPool, src);
3721         }
3722         intptr_t offset = aotData->GetCommonSlotOffset(encoder->GetCursorOffset(), id);
3723         encoder->MakeLoadAotTableAddr(offset, addr, dst);
3724 
3725         auto label = encoder->CreateLabel();
3726         encoder->EncodeJump(label, dst, Condition::NE);
3727 
3728         enc->GetCodegen()->CallRuntime(inst, entrypointId, dst, RegMask::GetZeroMask(), constPool, TypedImm(id));
3729         encoder->EncodeStr(dst, MemRef(addr));
3730         encoder->BindLabel(label);
3731     } else {
3732         auto address = inst->CastToGetGlobalVarAddress()->GetAddress();
3733         if (address == 0) {
3734             address = runtime->GetGlobalVarAddress(graph->GetMethod(), id);
3735         }
3736         if (address == 0) {
3737             enc->GetCodegen()->CallRuntime(inst, entrypointId, dst, RegMask::GetZeroMask(), src, TypedImm(id));
3738         } else {
3739             encoder->EncodeMov(dst, Imm(address));
3740         }
3741     }
3742 }
3743 
VisitLoadRuntimeClass(GraphVisitor * visitor,Inst * inst)3744 void EncodeVisitor::VisitLoadRuntimeClass(GraphVisitor *visitor, Inst *inst)
3745 {
3746     auto *enc = static_cast<EncodeVisitor *>(visitor);
3747     auto codegen = enc->GetCodegen();
3748     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());  // load value
3749     size_t classAddrOffset = codegen->GetGraph()->GetRuntime()->GetTlsPromiseClassPointerOffset(codegen->GetArch());
3750 
3751     auto mem = MemRef(codegen->ThreadReg(), classAddrOffset);
3752     enc->GetEncoder()->EncodeLdr(dst, false, mem);
3753 }
3754 
VisitLoadAndInitClass(GraphVisitor * visitor,Inst * inst)3755 void EncodeVisitor::VisitLoadAndInitClass(GraphVisitor *visitor, Inst *inst)
3756 {
3757     auto *enc = static_cast<EncodeVisitor *>(visitor);
3758     auto graph = enc->cg_->GetGraph();
3759     auto runtime = graph->GetRuntime();
3760     auto classId = inst->CastToLoadAndInitClass()->GetTypeId();
3761     auto encoder = enc->GetEncoder();
3762     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());  // load value
3763     ASSERT(inst->IsRuntimeCall());
3764 
3765     if (graph->IsAotMode()) {
3766         auto methodClassId = runtime->GetClassIdForMethod(graph->GetMethod());
3767         if (methodClassId == classId) {
3768             auto dstPtr = dst.As(Codegen::ConvertDataType(DataType::POINTER, graph->GetArch()));
3769             enc->GetCodegen()->LoadMethod(dstPtr);
3770             auto mem = MemRef(dstPtr, graph->GetRuntime()->GetClassOffset(graph->GetArch()));
3771             encoder->EncodeLdr(dst.As(Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch())), false, mem);
3772             return;
3773         }
3774 
3775         ScopedTmpReg tmpReg(encoder);
3776 
3777         auto aotData = graph->GetAotData();
3778         intptr_t offset = aotData->GetClassSlotOffset(encoder->GetCursorOffset(), classId, true);
3779         encoder->MakeLoadAotTableAddr(offset, tmpReg, dst);
3780 
3781         auto label = encoder->CreateLabel();
3782         encoder->EncodeJump(label, dst, Condition::NE);
3783 
3784         // PLT Class Init Resolver has special calling convention:
3785         // First encoder temporary (tmp_reg) works as parameter and return value
3786         CHECK_EQ(tmpReg.GetReg().GetId(), encoder->GetTarget().GetTempRegsMask().GetMinRegister());
3787         enc->GetCodegen()->CreateJumpToClassResolverPltShared(inst, tmpReg.GetReg(), EntrypointId::CLASS_INIT_RESOLVER);
3788 
3789         encoder->EncodeMov(dst, tmpReg);
3790         encoder->BindLabel(label);
3791     } else {  // JIT mode
3792         auto klass = reinterpret_cast<uintptr_t>(inst->CastToLoadAndInitClass()->GetClass());
3793         encoder->EncodeMov(dst, Imm(klass));
3794 
3795         if (runtime->IsClassInitialized(klass)) {
3796             return;
3797         }
3798 
3799         auto methodClass = runtime->GetClass(graph->GetMethod());
3800         if (methodClass == inst->CastToLoadAndInitClass()->GetClass()) {
3801             return;
3802         }
3803 
3804         auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::INITIALIZE_CLASS);
3805 
3806         auto stateOffset = runtime->GetClassStateOffset(enc->GetArch());
3807         int64_t initValue = runtime->GetClassInitializedValue();
3808 
3809         ScopedTmpReg stateReg(encoder, INT8_TYPE);
3810         encoder->EncodeLdr(stateReg, false, MemRef(dst, stateOffset));
3811 
3812         encoder->EncodeJump(slowPath->GetLabel(), stateReg, Imm(initValue), Condition::NE);
3813 
3814         slowPath->BindBackLabel(encoder);
3815     }
3816 }
3817 
VisitUnresolvedLoadAndInitClass(GraphVisitor * visitor,Inst * inst)3818 void EncodeVisitor::VisitUnresolvedLoadAndInitClass(GraphVisitor *visitor, Inst *inst)
3819 {
3820     auto *enc = static_cast<EncodeVisitor *>(visitor);
3821     auto graph = enc->cg_->GetGraph();
3822     auto classId = inst->CastToUnresolvedLoadAndInitClass()->GetTypeId();
3823     auto encoder = enc->GetEncoder();
3824     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());  // load value
3825     ASSERT(inst->IsRuntimeCall());
3826 
3827     if (graph->IsAotMode()) {
3828         ScopedTmpReg tmpReg(encoder);
3829 
3830         auto aotData = graph->GetAotData();
3831         intptr_t offset = aotData->GetClassSlotOffset(encoder->GetCursorOffset(), classId, true);
3832         encoder->MakeLoadAotTableAddr(offset, tmpReg, dst);
3833 
3834         auto label = encoder->CreateLabel();
3835         encoder->EncodeJump(label, dst, Condition::NE);
3836 
3837         // PLT Class Init Resolver has special calling convention:
3838         // First encoder temporary (tmp_reg) works as parameter and return value
3839         CHECK_EQ(tmpReg.GetReg().GetId(), encoder->GetTarget().GetTempRegsMask().GetMinRegister());
3840         enc->GetCodegen()->CreateJumpToClassResolverPltShared(inst, tmpReg.GetReg(), EntrypointId::CLASS_INIT_RESOLVER);
3841 
3842         encoder->EncodeMov(dst, tmpReg);
3843         encoder->BindLabel(label);
3844     } else {  // JIT mode
3845         auto method = inst->CastToUnresolvedLoadAndInitClass()->GetMethod();
3846         auto utypes = graph->GetRuntime()->GetUnresolvedTypes();
3847         auto klassAddr = utypes->GetTableSlot(method, classId, UnresolvedTypesInterface::SlotKind::CLASS);
3848         Reg dstPtr(dst.GetId(), enc->GetCodegen()->GetPtrRegType());
3849         encoder->EncodeMov(dstPtr, Imm(klassAddr));
3850         encoder->EncodeLdr(dst, false, MemRef(dstPtr));
3851 
3852         auto slowPath =
3853             enc->GetCodegen()->CreateSlowPath<SlowPathUnresolved>(inst, EntrypointId::INITIALIZE_CLASS_BY_ID);
3854         slowPath->SetUnresolvedType(method, classId);
3855         slowPath->SetDstReg(dst);
3856         slowPath->SetSlotAddr(klassAddr);
3857 
3858         encoder->EncodeJump(slowPath->GetLabel(), dst, Condition::EQ);
3859         slowPath->BindBackLabel(encoder);
3860     }
3861 }
3862 
VisitLoadStatic(GraphVisitor * visitor,Inst * inst)3863 void EncodeVisitor::VisitLoadStatic(GraphVisitor *visitor, Inst *inst)
3864 {
3865     auto *enc = static_cast<EncodeVisitor *>(visitor);
3866     auto loadStatic = inst->CastToLoadStatic();
3867     if (loadStatic->GetNeedBarrier()) {
3868         // Consider inserting barriers for GC
3869     }
3870     auto type = inst->GetType();
3871     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);                   // load value
3872     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // class
3873 
3874     auto graph = enc->cg_->GetGraph();
3875     auto field = loadStatic->GetObjField();
3876     auto offset = graph->GetRuntime()->GetFieldOffset(field);
3877     auto mem = MemRef(src0, offset);
3878     if (loadStatic->GetVolatile()) {
3879         enc->GetEncoder()->EncodeLdrAcquire(dst, IsTypeSigned(type), mem);
3880     } else {
3881         enc->GetEncoder()->EncodeLdr(dst, IsTypeSigned(type), mem);
3882     }
3883 }
3884 
VisitResolveObjectFieldStatic(GraphVisitor * visitor,Inst * inst)3885 void EncodeVisitor::VisitResolveObjectFieldStatic(GraphVisitor *visitor, Inst *inst)
3886 {
3887     auto *enc = static_cast<EncodeVisitor *>(visitor);
3888     auto graph = enc->cg_->GetGraph();
3889     auto resolver = inst->CastToResolveObjectFieldStatic();
3890     ASSERT(resolver->GetType() == DataType::REFERENCE);
3891     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
3892     auto typeId = resolver->GetTypeId();
3893     auto method = resolver->GetMethod();
3894     EntrypointId entrypoint = EntrypointId::GET_UNKNOWN_STATIC_FIELD_MEMORY_ADDRESS;  // REFERENCE
3895     UnresolvedTypesInterface::SlotKind slotKind = UnresolvedTypesInterface::SlotKind::FIELD;
3896 
3897     if (graph->IsAotMode()) {
3898         enc->GetCodegen()->CallRuntimeWithMethod(inst, method, entrypoint, dst, TypedImm(typeId), TypedImm(0));
3899     } else {
3900         ScopedTmpReg tmpReg(enc->GetEncoder());
3901         auto fieldAddr = graph->GetRuntime()->GetUnresolvedTypes()->GetTableSlot(method, typeId, slotKind);
3902         enc->GetEncoder()->EncodeMov(tmpReg, Imm(fieldAddr));
3903         enc->GetEncoder()->EncodeLdr(tmpReg, false, MemRef(tmpReg));
3904         auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathUnresolved>(inst, entrypoint);
3905         slowPath->SetUnresolvedType(method, typeId);
3906         slowPath->SetDstReg(tmpReg);
3907         slowPath->SetSlotAddr(fieldAddr);
3908         enc->GetEncoder()->EncodeJump(slowPath->GetLabel(), tmpReg, Condition::EQ);
3909         slowPath->BindBackLabel(enc->GetEncoder());
3910         enc->GetEncoder()->EncodeMov(dst, tmpReg);
3911     }
3912 }
3913 
VisitLoadResolvedObjectFieldStatic(GraphVisitor * visitor,Inst * inst)3914 void EncodeVisitor::VisitLoadResolvedObjectFieldStatic(GraphVisitor *visitor, Inst *inst)
3915 {
3916     auto *enc = static_cast<EncodeVisitor *>(visitor);
3917     auto load = inst->CastToLoadResolvedObjectFieldStatic();
3918     if (load->GetNeedBarrier()) {
3919         // Insert barriers for GC
3920     }
3921     auto type = inst->GetType();
3922     auto fieldAddr = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);
3923     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
3924     // Unknown load, assume it can be volatile
3925     enc->GetEncoder()->EncodeLdrAcquire(dst, IsTypeSigned(type), MemRef(fieldAddr));
3926 }
3927 
VisitStoreStatic(GraphVisitor * visitor,Inst * inst)3928 void EncodeVisitor::VisitStoreStatic(GraphVisitor *visitor, Inst *inst)
3929 {
3930     auto *enc = static_cast<EncodeVisitor *>(visitor);
3931     auto storeStatic = inst->CastToStoreStatic();
3932     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // class
3933     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), inst->GetType());      // store value
3934 
3935     auto graph = enc->cg_->GetGraph();
3936     auto runtime = graph->GetRuntime();
3937     auto field = storeStatic->GetObjField();
3938     auto offset = runtime->GetFieldOffset(field);
3939     auto mem = MemRef(src0, offset);
3940 
3941     if (inst->CastToStoreStatic()->GetNeedBarrier()) {
3942         enc->GetCodegen()->CreatePreWRB(inst, mem, MakeMask(src1.GetId()));
3943     }
3944     if (storeStatic->GetVolatile()) {
3945         enc->GetEncoder()->EncodeStrRelease(src1, mem);
3946     } else {
3947         enc->GetEncoder()->EncodeStr(src1, mem);
3948     }
3949     if (inst->CastToStoreStatic()->GetNeedBarrier()) {
3950         auto arch = enc->GetEncoder()->GetArch();
3951         auto tmpReg = enc->GetCodegen()->ConvertInstTmpReg(inst, DataType::GetIntTypeForReference(arch));
3952         enc->GetEncoder()->EncodeLdr(tmpReg, false, MemRef(src0, runtime->GetManagedClassOffset(enc->GetArch())));
3953         auto classHeaderMem = MemRef(tmpReg);
3954         enc->GetCodegen()->CreatePostWRB(inst, classHeaderMem, src1, INVALID_REGISTER);
3955     }
3956 }
3957 
VisitLoadObjectDynamic(GraphVisitor * visitor,Inst * inst)3958 void EncodeVisitor::VisitLoadObjectDynamic(GraphVisitor *visitor, Inst *inst)
3959 {
3960     auto *enc = static_cast<EncodeVisitor *>(visitor);
3961     auto *codegen = enc->GetCodegen();
3962     codegen->CreateLoadObjectDynamic(inst);
3963 }
3964 
VisitStoreObjectDynamic(GraphVisitor * visitor,Inst * inst)3965 void EncodeVisitor::VisitStoreObjectDynamic(GraphVisitor *visitor, Inst *inst)
3966 {
3967     auto *enc = static_cast<EncodeVisitor *>(visitor);
3968     auto *codegen = enc->GetCodegen();
3969     codegen->CreateStoreObjectDynamic(inst);
3970 }
3971 
VisitUnresolvedStoreStatic(GraphVisitor * visitor,Inst * inst)3972 void EncodeVisitor::VisitUnresolvedStoreStatic(GraphVisitor *visitor, Inst *inst)
3973 {
3974     auto *enc = static_cast<EncodeVisitor *>(visitor);
3975     auto storeStatic = inst->CastToUnresolvedStoreStatic();
3976     ASSERT(storeStatic->GetType() == DataType::REFERENCE);
3977     ASSERT(storeStatic->GetNeedBarrier());
3978     auto typeId = storeStatic->GetTypeId();
3979     auto value = enc->GetCodegen()->ConvertRegister(storeStatic->GetSrcReg(0), storeStatic->GetType());
3980     auto entrypoint = RuntimeInterface::EntrypointId::UNRESOLVED_STORE_STATIC_BARRIERED;
3981     auto method = storeStatic->GetMethod();
3982     ASSERT(method != nullptr);
3983     enc->GetCodegen()->CallRuntimeWithMethod(storeStatic, method, entrypoint, Reg(), TypedImm(typeId), value);
3984 }
3985 
VisitStoreResolvedObjectFieldStatic(GraphVisitor * visitor,Inst * inst)3986 void EncodeVisitor::VisitStoreResolvedObjectFieldStatic(GraphVisitor *visitor, Inst *inst)
3987 {
3988     auto *enc = static_cast<EncodeVisitor *>(visitor);
3989     auto store = inst->CastToStoreResolvedObjectFieldStatic();
3990     ASSERT(store->GetType() != DataType::REFERENCE);
3991     ASSERT(!store->GetNeedBarrier());
3992     auto val = enc->GetCodegen()->ConvertRegister(store->GetSrcReg(1), store->GetType());
3993     auto reg = enc->GetCodegen()->ConvertRegister(store->GetSrcReg(0), DataType::REFERENCE);
3994     // Non-barriered case. Unknown store, assume it can be volatile
3995     enc->GetEncoder()->EncodeStrRelease(val, MemRef(reg));
3996 }
3997 
VisitNewObject(GraphVisitor * visitor,Inst * inst)3998 void EncodeVisitor::VisitNewObject(GraphVisitor *visitor, Inst *inst)
3999 {
4000     auto *enc = static_cast<EncodeVisitor *>(visitor);
4001     // NOTE(msherstennikov): use irtoced entrypoint once spill-fills will be supported for entrypoints mode.
4002     if (enc->cg_->GetArch() == Arch::AARCH32) {
4003         enc->GetCodegen()->CreateNewObjCallOld(inst->CastToNewObject());
4004     } else {
4005         enc->GetCodegen()->CreateNewObjCall(inst->CastToNewObject());
4006     }
4007     if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
4008         enc->GetEncoder()->EncodeMemoryBarrier(memory_order::RELEASE);
4009     }
4010 }
4011 
VisitUnresolvedLoadType(GraphVisitor * visitor,Inst * inst)4012 void EncodeVisitor::VisitUnresolvedLoadType(GraphVisitor *visitor, Inst *inst)
4013 {
4014     auto *enc = static_cast<EncodeVisitor *>(visitor);
4015     auto encoder = enc->GetEncoder();
4016     auto codegen = enc->GetCodegen();
4017     auto loadType = inst->CastToUnresolvedLoadType();
4018     if (loadType->GetNeedBarrier()) {
4019         // Consider inserting barriers for GC
4020     }
4021     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
4022     auto graph = enc->cg_->GetGraph();
4023     auto typeId = loadType->GetTypeId();
4024 
4025     auto runtime = graph->GetRuntime();
4026     auto method = loadType->GetMethod();
4027 
4028     if (graph->IsAotMode()) {
4029         ScopedTmpReg tmpReg(encoder);
4030         // Load pointer to klass from PLT
4031         codegen->CreateLoadClassFromPLT(inst, tmpReg, dst, typeId);
4032         // Finally load Object
4033         encoder->EncodeLdr(dst, false, MemRef(dst, runtime->GetManagedClassOffset(enc->GetArch())));
4034     } else {
4035         auto utypes = runtime->GetUnresolvedTypes();
4036         auto clsAddr = utypes->GetTableSlot(method, typeId, UnresolvedTypesInterface::SlotKind::MANAGED_CLASS);
4037         Reg dstPtr(dst.GetId(), codegen->GetPtrRegType());
4038         encoder->EncodeMov(dstPtr, Imm(clsAddr));
4039         encoder->EncodeLdr(dst, false, MemRef(dstPtr));
4040 
4041         auto slowPath = codegen->CreateSlowPath<SlowPathUnresolved>(inst, EntrypointId::RESOLVE_CLASS_OBJECT);
4042         slowPath->SetUnresolvedType(method, typeId);
4043         slowPath->SetDstReg(dst);
4044         slowPath->SetSlotAddr(clsAddr);
4045         encoder->EncodeJump(slowPath->GetLabel(), dst, Condition::EQ);
4046         slowPath->BindBackLabel(encoder);
4047     }
4048 }
4049 
VisitLoadType(GraphVisitor * visitor,Inst * inst)4050 void EncodeVisitor::VisitLoadType(GraphVisitor *visitor, Inst *inst)
4051 {
4052     auto *enc = static_cast<EncodeVisitor *>(visitor);
4053     auto encoder = enc->GetEncoder();
4054     auto loadType = inst->CastToLoadType();
4055     if (loadType->GetNeedBarrier()) {
4056         // Consider inserting barriers for GC
4057     }
4058     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
4059     auto graph = enc->cg_->GetGraph();
4060     auto typeId = loadType->GetTypeId();
4061 
4062     auto runtime = graph->GetRuntime();
4063     auto method = loadType->GetMethod();
4064 
4065     if (graph->IsAotMode()) {
4066         auto methodClassId = runtime->GetClassIdForMethod(graph->GetMethod());
4067         if (methodClassId == typeId) {
4068             auto dstPtr = dst.As(Codegen::ConvertDataType(DataType::POINTER, graph->GetArch()));
4069             enc->GetCodegen()->LoadMethod(dstPtr);
4070             auto mem = MemRef(dstPtr, graph->GetRuntime()->GetClassOffset(graph->GetArch()));
4071             encoder->EncodeLdr(dst.As(Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch())), false, mem);
4072         } else {
4073             ScopedTmpReg tmpReg(encoder);
4074             // Load pointer to klass from PLT
4075             enc->GetCodegen()->CreateLoadClassFromPLT(inst, tmpReg, dst, typeId);
4076         }
4077         // Finally load ManagedClass object
4078         encoder->EncodeLdr(dst, false, MemRef(dst, runtime->GetManagedClassOffset(enc->GetArch())));
4079     } else {  // JIT mode
4080         auto klass = reinterpret_cast<uintptr_t>(runtime->ResolveType(method, typeId));
4081         auto managedKlass = runtime->GetManagedType(klass);
4082         encoder->EncodeMov(dst, Imm(managedKlass));
4083     }
4084 }
4085 
FillUnresolvedClass(GraphVisitor * visitor,Inst * inst)4086 void EncodeVisitor::FillUnresolvedClass(GraphVisitor *visitor, Inst *inst)
4087 {
4088     auto *enc = static_cast<EncodeVisitor *>(visitor);
4089     auto graph = enc->cg_->GetGraph();
4090     auto encoder = enc->GetEncoder();
4091     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4092     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::CHECK_CAST);
4093     encoder->EncodeJump(slowPath->GetLabel(), classReg, Condition::EQ);
4094     slowPath->CreateBackLabel(encoder);
4095     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
4096     encoder->EncodeJump(slowPath->GetBackLabel(), src, Condition::EQ);
4097     ScopedTmpReg tmpReg(encoder, Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch()));
4098     enc->GetCodegen()->LoadClassFromObject(tmpReg, src);
4099     encoder->EncodeJump(slowPath->GetLabel(), tmpReg, classReg, Condition::NE);
4100     slowPath->BindBackLabel(encoder);
4101 }
4102 
FillObjectClass(GraphVisitor * visitor,Reg tmpReg,LabelHolder::LabelId throwLabel)4103 void EncodeVisitor::FillObjectClass(GraphVisitor *visitor, Reg tmpReg, LabelHolder::LabelId throwLabel)
4104 {
4105     auto *enc = static_cast<EncodeVisitor *>(visitor);
4106     auto graph = enc->cg_->GetGraph();
4107     auto runtime = graph->GetRuntime();
4108     auto encoder = enc->GetEncoder();
4109 
4110     Reg typeReg(tmpReg.GetId(), INT8_TYPE);
4111     // Load type class
4112     encoder->EncodeLdr(typeReg, false, MemRef(tmpReg, runtime->GetClassTypeOffset(enc->GetArch())));
4113     // Jump to EH if type not reference
4114     encoder->EncodeJump(throwLabel, typeReg, Imm(runtime->GetReferenceTypeMask()), Condition::NE);
4115 }
4116 
4117 /* The CheckCast class should be a subclass of input class:
4118     ......................
4119     bool Class::IsSubClassOf(const Class *klass) const {
4120         const Class *current = this;
4121         do {
4122             if (current == klass) {
4123                 return true;
4124             }
4125             current = current->GetBase();
4126         } while (current != nullptr);
4127         return false;
4128     }
4129 */
4130 
FillOtherClass(GraphVisitor * visitor,Inst * inst,Reg tmpReg,LabelHolder::LabelId throwLabel)4131 void EncodeVisitor::FillOtherClass(GraphVisitor *visitor, Inst *inst, Reg tmpReg, LabelHolder::LabelId throwLabel)
4132 {
4133     auto *enc = static_cast<EncodeVisitor *>(visitor);
4134     auto graph = enc->cg_->GetGraph();
4135     auto encoder = enc->GetEncoder();
4136     auto loopLabel = encoder->CreateLabel();
4137 
4138     // First compare `current == klass` we make before switch
4139     encoder->BindLabel(loopLabel);
4140     // Load base klass
4141     encoder->EncodeLdr(tmpReg, false, MemRef(tmpReg, graph->GetRuntime()->GetClassBaseOffset(enc->GetArch())));
4142     encoder->EncodeJump(throwLabel, tmpReg, Condition::EQ);
4143     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4144     encoder->EncodeJump(loopLabel, tmpReg, classReg, Condition::NE);
4145 }
4146 
FillArrayObjectClass(GraphVisitor * visitor,Reg tmpReg,LabelHolder::LabelId throwLabel)4147 void EncodeVisitor::FillArrayObjectClass(GraphVisitor *visitor, Reg tmpReg, LabelHolder::LabelId throwLabel)
4148 {
4149     auto *enc = static_cast<EncodeVisitor *>(visitor);
4150     auto graph = enc->cg_->GetGraph();
4151     auto runtime = graph->GetRuntime();
4152     auto encoder = enc->GetEncoder();
4153 
4154     Reg typeReg(tmpReg.GetId(), INT8_TYPE);
4155     // Load Component class
4156     encoder->EncodeLdr(tmpReg, false, MemRef(tmpReg, runtime->GetClassComponentTypeOffset(enc->GetArch())));
4157     // Jump to EH if src is not array class
4158     encoder->EncodeJump(throwLabel, tmpReg, Condition::EQ);
4159     // Load type of the component class
4160     encoder->EncodeLdr(typeReg, false, MemRef(tmpReg, runtime->GetClassTypeOffset(enc->GetArch())));
4161     // Jump to EH if type not reference
4162     encoder->EncodeJump(throwLabel, typeReg, Imm(runtime->GetReferenceTypeMask()), Condition::NE);
4163 }
4164 
FillArrayClass(GraphVisitor * visitor,Inst * inst,Reg tmpReg,LabelHolder::LabelId throwLabel)4165 void EncodeVisitor::FillArrayClass(GraphVisitor *visitor, Inst *inst, Reg tmpReg, LabelHolder::LabelId throwLabel)
4166 {
4167     auto *enc = static_cast<EncodeVisitor *>(visitor);
4168     auto graph = enc->cg_->GetGraph();
4169     auto runtime = graph->GetRuntime();
4170     auto encoder = enc->GetEncoder();
4171 
4172     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::CHECK_CAST);
4173 
4174     // Load Component type of Input
4175     encoder->EncodeLdr(tmpReg, false, MemRef(tmpReg, runtime->GetClassComponentTypeOffset(enc->GetArch())));
4176     // Check that src is array class
4177     encoder->EncodeJump(throwLabel, tmpReg, Condition::EQ);
4178     // Load Component type of the instance
4179     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4180     ScopedTmpReg tmpReg1(encoder, Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch()));
4181     encoder->EncodeLdr(tmpReg1, false, MemRef(classReg, runtime->GetClassComponentTypeOffset(enc->GetArch())));
4182     // Compare component types
4183     encoder->EncodeJump(slowPath->GetLabel(), tmpReg, tmpReg1, Condition::NE);
4184 
4185     slowPath->BindBackLabel(encoder);
4186 }
4187 
FillInterfaceClass(GraphVisitor * visitor,Inst * inst)4188 void EncodeVisitor::FillInterfaceClass(GraphVisitor *visitor, Inst *inst)
4189 {
4190     auto enc = static_cast<EncodeVisitor *>(visitor);
4191     auto encoder = enc->GetEncoder();
4192     auto codegen = enc->GetCodegen();
4193     if (codegen->GetArch() == Arch::AARCH32) {
4194         auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::CHECK_CAST);
4195         encoder->EncodeJump(slowPath->GetLabel());
4196         slowPath->BindBackLabel(encoder);
4197     } else {
4198         codegen->CreateCheckCastInterfaceCall(inst);
4199     }
4200 }
4201 
FillCheckCast(GraphVisitor * visitor,Inst * inst,Reg src,LabelHolder::LabelId endLabel,compiler::ClassType klassType)4202 void EncodeVisitor::FillCheckCast(GraphVisitor *visitor, Inst *inst, Reg src, LabelHolder::LabelId endLabel,
4203                                   compiler::ClassType klassType)
4204 {
4205     if (klassType == ClassType::INTERFACE_CLASS) {
4206         FillInterfaceClass(visitor, inst);
4207         return;
4208     }
4209     auto *enc = static_cast<EncodeVisitor *>(visitor);
4210     auto graph = enc->cg_->GetGraph();
4211     auto encoder = enc->GetEncoder();
4212     // class_reg - CheckCast class
4213     // tmp_reg - input class
4214     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4215     ScopedTmpReg tmpReg(encoder, Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch()));
4216     enc->GetCodegen()->LoadClassFromObject(tmpReg, src);
4217     // There is no exception if the classes are equal
4218     encoder->EncodeJump(endLabel, classReg, tmpReg, Condition::EQ);
4219 
4220     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathCheckCast>(inst, EntrypointId::CLASS_CAST_EXCEPTION);
4221     slowPath->SetClassReg(classReg);
4222     auto throwLabel = slowPath->GetLabel();
4223     switch (klassType) {
4224         // The input class should be not primitive type
4225         case ClassType::OBJECT_CLASS: {
4226             FillObjectClass(visitor, tmpReg, throwLabel);
4227             break;
4228         }
4229         case ClassType::OTHER_CLASS: {
4230             FillOtherClass(visitor, inst, tmpReg, throwLabel);
4231             break;
4232         }
4233         // The input class should be array class and component type should be not primitive type
4234         case ClassType::ARRAY_OBJECT_CLASS: {
4235             FillArrayObjectClass(visitor, tmpReg, throwLabel);
4236             break;
4237         }
4238         // Check that components types are equals, else call slow path
4239         case ClassType::ARRAY_CLASS: {
4240             FillArrayClass(visitor, inst, tmpReg, throwLabel);
4241             break;
4242         }
4243         case ClassType::FINAL_CLASS: {
4244             EVENT_CODEGEN_SIMPLIFICATION(events::CodegenSimplificationInst::CHECKCAST,
4245                                          events::CodegenSimplificationReason::FINAL_CLASS);
4246             encoder->EncodeJump(throwLabel);
4247             break;
4248         }
4249         default: {
4250             UNREACHABLE();
4251         }
4252     }
4253 }
4254 
VisitCheckCast(GraphVisitor * visitor,Inst * inst)4255 void EncodeVisitor::VisitCheckCast(GraphVisitor *visitor, Inst *inst)
4256 {
4257     auto *enc = static_cast<EncodeVisitor *>(visitor);
4258     auto method = inst->CastToCheckCast()->GetMethod();
4259     auto typeId = inst->CastToCheckCast()->GetTypeId();
4260     auto encoder = enc->GetEncoder();
4261 
4262     auto klassType = inst->CastToCheckCast()->GetClassType();
4263     if (klassType == ClassType::UNRESOLVED_CLASS) {
4264         FillUnresolvedClass(visitor, inst);
4265         return;
4266     }
4267     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
4268     auto endLabel = encoder->CreateLabel();
4269 
4270     if (inst->CastToCheckCast()->GetOmitNullCheck()) {
4271         EVENT_CODEGEN_SIMPLIFICATION(events::CodegenSimplificationInst::CHECKCAST,
4272                                      events::CodegenSimplificationReason::SKIP_NULLCHECK);
4273     } else {
4274         // Compare with nullptr
4275         encoder->EncodeJump(endLabel, src, Condition::EQ);
4276     }
4277 
4278     [[maybe_unused]] auto klass = enc->cg_->GetGraph()->GetRuntime()->GetClass(method, typeId);
4279     ASSERT(klass != nullptr);
4280 
4281     FillCheckCast(visitor, inst, src, endLabel, klassType);
4282     encoder->BindLabel(endLabel);
4283 }
4284 
FillIsInstanceUnresolved(GraphVisitor * visitor,Inst * inst)4285 void EncodeVisitor::FillIsInstanceUnresolved(GraphVisitor *visitor, Inst *inst)
4286 {
4287     auto *enc = static_cast<EncodeVisitor *>(visitor);
4288     auto graph = enc->cg_->GetGraph();
4289     auto encoder = enc->GetEncoder();
4290     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
4291     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4292     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
4293 
4294     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::IS_INSTANCE);
4295     encoder->EncodeJump(slowPath->GetLabel(), classReg, Condition::EQ);
4296     slowPath->CreateBackLabel(encoder);
4297     auto endLabel = slowPath->GetBackLabel();
4298 
4299     // Compare with nullptr
4300     auto nextLabel = encoder->CreateLabel();
4301     encoder->EncodeJump(nextLabel, src, Condition::NE);
4302     encoder->EncodeMov(dst, Imm(0));
4303     encoder->EncodeJump(endLabel);
4304     encoder->BindLabel(nextLabel);
4305 
4306     // Get instance class
4307     ScopedTmpReg tmpReg(encoder, Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch()));
4308     enc->GetCodegen()->LoadClassFromObject(tmpReg, src);
4309 
4310     // Sets true if the classes are equal
4311     encoder->EncodeJump(slowPath->GetLabel(), tmpReg, classReg, Condition::NE);
4312     encoder->EncodeMov(dst, Imm(1));
4313 
4314     slowPath->BindBackLabel(encoder);
4315 }
4316 
FillIsInstanceCaseObject(GraphVisitor * visitor,Inst * inst,Reg tmpReg)4317 void EncodeVisitor::FillIsInstanceCaseObject(GraphVisitor *visitor, Inst *inst, Reg tmpReg)
4318 {
4319     auto *enc = static_cast<EncodeVisitor *>(visitor);
4320     auto encoder = enc->GetEncoder();
4321     auto runtime = enc->cg_->GetGraph()->GetRuntime();
4322     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
4323 
4324     // ClassType::OBJECT_CLASS
4325     Reg typeReg(tmpReg.GetId(), INT8_TYPE);
4326     // Load type class
4327     encoder->EncodeLdr(typeReg, false, MemRef(tmpReg, runtime->GetClassTypeOffset(enc->GetArch())));
4328     ScopedTmpReg typeMaskReg(encoder, INT8_TYPE);
4329     encoder->EncodeMov(typeMaskReg, Imm(runtime->GetReferenceTypeMask()));
4330     encoder->EncodeCompare(dst, typeMaskReg, typeReg, Condition::EQ);
4331 }
4332 
4333 /* Sets true if IsInstance class is a subclass of input class:
4334     ......................
4335     bool Class::IsSubClassOf(const Class *klass) const {
4336         const Class *current = this;
4337         do {
4338             if (current == klass) {
4339                 return true;
4340             }
4341             current = current->GetBase();
4342         } while (current != nullptr);
4343         return false;
4344     }
4345 */
4346 
FillIsInstanceCaseOther(GraphVisitor * visitor,Inst * inst,Reg tmpReg,LabelHolder::LabelId endLabel)4347 void EncodeVisitor::FillIsInstanceCaseOther(GraphVisitor *visitor, Inst *inst, Reg tmpReg,
4348                                             LabelHolder::LabelId endLabel)
4349 {
4350     auto *enc = static_cast<EncodeVisitor *>(visitor);
4351     auto encoder = enc->GetEncoder();
4352     auto runtime = enc->cg_->GetGraph()->GetRuntime();
4353     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
4354     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4355 
4356     // ClassType::OTHER_CLASS
4357     auto loopLabel = encoder->CreateLabel();
4358     auto falseLabel = encoder->CreateLabel();
4359 
4360     // First compare `current == klass` we make before switch
4361     encoder->BindLabel(loopLabel);
4362     // Load base klass
4363     encoder->EncodeLdr(tmpReg, false, MemRef(tmpReg, runtime->GetClassBaseOffset(enc->GetArch())));
4364     encoder->EncodeJump(falseLabel, tmpReg, Condition::EQ);
4365     encoder->EncodeJump(loopLabel, tmpReg, classReg, Condition::NE);
4366 
4367     // Set true result and jump to exit
4368     encoder->EncodeMov(dst, Imm(1));
4369     encoder->EncodeJump(endLabel);
4370 
4371     // Set false result and jump to exit
4372     encoder->BindLabel(falseLabel);
4373     encoder->EncodeMov(dst, Imm(0));
4374 }
4375 
4376 // Sets true if the Input class is array class and component type is not primitive type
FillIsInstanceCaseArrayObject(GraphVisitor * visitor,Inst * inst,Reg tmpReg,LabelHolder::LabelId endLabel)4377 void EncodeVisitor::FillIsInstanceCaseArrayObject(GraphVisitor *visitor, Inst *inst, Reg tmpReg,
4378                                                   LabelHolder::LabelId endLabel)
4379 {
4380     auto *enc = static_cast<EncodeVisitor *>(visitor);
4381     auto encoder = enc->GetEncoder();
4382     auto graph = enc->cg_->GetGraph();
4383     auto runtime = graph->GetRuntime();
4384     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
4385 
4386     // ClassType::ARRAY_OBJECT_CLASS
4387     Reg dstRef(dst.GetId(), Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch()));
4388     Reg typeReg(tmpReg.GetId(), INT8_TYPE);
4389     // Load Component class
4390     encoder->EncodeLdr(dstRef, false, MemRef(tmpReg, runtime->GetClassComponentTypeOffset(enc->GetArch())));
4391     // Check that src is array class
4392     encoder->EncodeJump(endLabel, dstRef, Condition::EQ);
4393     // Load type of the component class
4394     encoder->EncodeLdr(typeReg, false, MemRef(dstRef, runtime->GetClassTypeOffset(enc->GetArch())));
4395     ScopedTmpReg typeMaskReg(encoder, INT8_TYPE);
4396     encoder->EncodeMov(typeMaskReg, Imm(runtime->GetReferenceTypeMask()));
4397     encoder->EncodeCompare(dst, typeMaskReg, typeReg, Condition::EQ);
4398 }
4399 
4400 // Check that components types are equals, else call slow path
FillIsInstanceCaseArrayClass(GraphVisitor * visitor,Inst * inst,Reg tmpReg,LabelHolder::LabelId endLabel)4401 void EncodeVisitor::FillIsInstanceCaseArrayClass(GraphVisitor *visitor, Inst *inst, Reg tmpReg,
4402                                                  LabelHolder::LabelId endLabel)
4403 {
4404     auto *enc = static_cast<EncodeVisitor *>(visitor);
4405     auto encoder = enc->GetEncoder();
4406     auto graph = enc->cg_->GetGraph();
4407     auto runtime = graph->GetRuntime();
4408     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
4409 
4410     // ClassType::ARRAY_CLASS
4411     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::IS_INSTANCE);
4412 
4413     auto nextLabel1 = encoder->CreateLabel();
4414     // Load Component type of Input
4415     encoder->EncodeLdr(tmpReg, false, MemRef(tmpReg, runtime->GetClassComponentTypeOffset(enc->GetArch())));
4416     // Check that src is array class
4417     encoder->EncodeJump(nextLabel1, tmpReg, Condition::NE);
4418     encoder->EncodeMov(dst, Imm(0));
4419     encoder->EncodeJump(endLabel);
4420     encoder->BindLabel(nextLabel1);
4421     // Load Component type of the instance
4422     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4423     ScopedTmpReg tmpReg1(encoder, Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch()));
4424     encoder->EncodeLdr(tmpReg1, false, MemRef(classReg, runtime->GetClassComponentTypeOffset(enc->GetArch())));
4425     // Compare component types
4426     encoder->EncodeJump(slowPath->GetLabel(), tmpReg, tmpReg1, Condition::NE);
4427     encoder->EncodeMov(dst, Imm(1));
4428 
4429     slowPath->BindBackLabel(encoder);
4430 }
4431 
FillIsInstanceCaseInterface(GraphVisitor * visitor,Inst * inst)4432 void EncodeVisitor::FillIsInstanceCaseInterface(GraphVisitor *visitor, Inst *inst)
4433 {
4434     auto *enc = static_cast<EncodeVisitor *>(visitor);
4435     auto encoder = enc->GetEncoder();
4436     // ClassType::INTERFACE_CLASS
4437     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::IS_INSTANCE);
4438 
4439     encoder->EncodeJump(slowPath->GetLabel());
4440 
4441     slowPath->BindBackLabel(encoder);
4442 }
4443 
FillIsInstance(GraphVisitor * visitor,Inst * inst,Reg tmpReg,LabelHolder::LabelId endLabel)4444 void EncodeVisitor::FillIsInstance(GraphVisitor *visitor, Inst *inst, Reg tmpReg, LabelHolder::LabelId endLabel)
4445 {
4446     auto *enc = static_cast<EncodeVisitor *>(visitor);
4447     auto encoder = enc->GetEncoder();
4448     auto src = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
4449     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
4450 
4451     if (inst->CastToIsInstance()->GetOmitNullCheck()) {
4452         EVENT_CODEGEN_SIMPLIFICATION(events::CodegenSimplificationInst::ISINSTANCE,
4453                                      events::CodegenSimplificationReason::SKIP_NULLCHECK);
4454     } else {
4455         // Compare with nullptr
4456         auto nextLabel = encoder->CreateLabel();
4457         encoder->EncodeJump(nextLabel, src, Condition::NE);
4458         encoder->EncodeMov(dst, Imm(0));
4459         encoder->EncodeJump(endLabel);
4460         encoder->BindLabel(nextLabel);
4461     }
4462 
4463     auto classReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::REFERENCE);
4464     enc->GetCodegen()->LoadClassFromObject(tmpReg, src);
4465 
4466     // Sets true if the classes are equals
4467     if (inst->CastToIsInstance()->GetClassType() == ClassType::FINAL_CLASS) {
4468         encoder->EncodeCompare(dst, classReg, tmpReg, Condition::EQ);
4469     } else if (dst.GetId() != src.GetId() && dst.GetId() != classReg.GetId()) {
4470         encoder->EncodeCompare(dst, classReg, tmpReg, Condition::EQ);
4471         encoder->EncodeJump(endLabel, dst, Condition::NE);
4472     } else {
4473         auto nextLabel1 = encoder->CreateLabel();
4474         encoder->EncodeJump(nextLabel1, classReg, tmpReg, Condition::NE);
4475         encoder->EncodeMov(dst, Imm(1));
4476         encoder->EncodeJump(endLabel);
4477         encoder->BindLabel(nextLabel1);
4478     }
4479 }
4480 
VisitIsInstance(GraphVisitor * visitor,Inst * inst)4481 void EncodeVisitor::VisitIsInstance(GraphVisitor *visitor, Inst *inst)
4482 {
4483     auto *enc = static_cast<EncodeVisitor *>(visitor);
4484     auto graph = enc->cg_->GetGraph();
4485     auto encoder = enc->GetEncoder();
4486     auto klassType = inst->CastToIsInstance()->GetClassType();
4487     if (klassType == ClassType::UNRESOLVED_CLASS) {
4488         FillIsInstanceUnresolved(visitor, inst);
4489         return;
4490     }
4491     // tmp_reg - input class
4492     ScopedTmpReg tmpReg(encoder, Codegen::ConvertDataType(DataType::REFERENCE, graph->GetArch()));
4493     auto endLabel = encoder->CreateLabel();
4494 
4495     FillIsInstance(visitor, inst, tmpReg, endLabel);
4496     switch (klassType) {
4497         // Sets true if the Input class is not primitive type
4498         case ClassType::OBJECT_CLASS: {
4499             FillIsInstanceCaseObject(visitor, inst, tmpReg);
4500             break;
4501         }
4502         case ClassType::OTHER_CLASS: {
4503             FillIsInstanceCaseOther(visitor, inst, tmpReg, endLabel);
4504             break;
4505         }
4506         // Sets true if the Input class is array class and component type is not primitive type
4507         case ClassType::ARRAY_OBJECT_CLASS: {
4508             FillIsInstanceCaseArrayObject(visitor, inst, tmpReg, endLabel);
4509             break;
4510         }
4511         // Check that components types are equals, else call slow path
4512         case ClassType::ARRAY_CLASS: {
4513             FillIsInstanceCaseArrayClass(visitor, inst, tmpReg, endLabel);
4514             break;
4515         }
4516         case ClassType::INTERFACE_CLASS: {
4517             FillIsInstanceCaseInterface(visitor, inst);
4518             break;
4519         }
4520         case ClassType::FINAL_CLASS: {
4521             EVENT_CODEGEN_SIMPLIFICATION(events::CodegenSimplificationInst::ISINSTANCE,
4522                                          events::CodegenSimplificationReason::FINAL_CLASS);
4523             break;
4524         }
4525         default: {
4526             UNREACHABLE();
4527         }
4528     }
4529     encoder->BindLabel(endLabel);
4530 }
4531 
CreateMonitorCall(MonitorInst * inst)4532 void Codegen::CreateMonitorCall(MonitorInst *inst)
4533 {
4534     auto src = ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
4535     auto id = inst->IsExit() ? EntrypointId::MONITOR_EXIT_FAST_PATH : EntrypointId::MONITOR_ENTER_FAST_PATH;
4536     CallFastPath(inst, id, INVALID_REGISTER, RegMask::GetZeroMask(), src);
4537 }
4538 
CreateMonitorCallOld(MonitorInst * inst)4539 void Codegen::CreateMonitorCallOld(MonitorInst *inst)
4540 {
4541     auto src = ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // obj
4542     auto dst = ConvertRegister(inst->GetDstReg(), inst->GetType());
4543     auto id = inst->IsExit() ? EntrypointId::UNLOCK_OBJECT : EntrypointId::LOCK_OBJECT;
4544     CallRuntime(inst, id, dst, RegMask::GetZeroMask(), src);
4545 }
4546 
CreateCheckCastInterfaceCall(Inst * inst)4547 void Codegen::CreateCheckCastInterfaceCall(Inst *inst)
4548 {
4549     auto obj = ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);
4550     auto interface = ConvertRegister(inst->GetSrcReg(SECOND_OPERAND), DataType::REFERENCE);
4551     CallFastPath(inst, EntrypointId::CHECK_CAST_INTERFACE, INVALID_REGISTER, RegMask::GetZeroMask(), obj, interface);
4552 }
4553 
VisitMonitor(GraphVisitor * visitor,Inst * inst)4554 void EncodeVisitor::VisitMonitor(GraphVisitor *visitor, Inst *inst)
4555 {
4556     auto *enc = static_cast<EncodeVisitor *>(visitor);
4557     if (enc->GetCodegen()->GetArch() == Arch::AARCH32) {
4558         enc->GetCodegen()->CreateMonitorCallOld(inst->CastToMonitor());
4559     } else {
4560         enc->GetCodegen()->CreateMonitorCall(inst->CastToMonitor());
4561     }
4562 }
4563 
TryInsertImplicitNullCheck(Inst * inst,size_t prevOffset)4564 void Codegen::TryInsertImplicitNullCheck(Inst *inst, size_t prevOffset)
4565 {
4566     if (!IsSuitableForImplicitNullCheck(inst)) {
4567         return;
4568     }
4569     if (!inst->CanThrow()) {
4570         return;
4571     }
4572 
4573     auto nullcheck = inst->GetInput(0).GetInst();
4574     ASSERT(nullcheck->GetOpcode() == Opcode::NullCheck && nullcheck->CastToNullCheck()->IsImplicit());
4575     auto currOffset = GetEncoder()->GetCursorOffset();
4576     ASSERT(currOffset > prevOffset);
4577     GetCodeBuilder()->AddImplicitNullCheck(currOffset, currOffset - prevOffset);
4578     CreateStackMap(nullcheck, inst);
4579 }
4580 
CreateFloatIsInf(IntrinsicInst * inst,Reg dst,SRCREGS src)4581 void Codegen::CreateFloatIsInf([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4582 {
4583     GetEncoder()->EncodeIsInf(dst, src[0]);
4584 }
4585 
CreateFloatIsInteger(IntrinsicInst * inst,Reg dst,SRCREGS src)4586 void Codegen::CreateFloatIsInteger([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4587 {
4588     GetEncoder()->EncodeIsInteger(dst, src[0]);
4589 }
4590 
CreateFloatIsSafeInteger(IntrinsicInst * inst,Reg dst,SRCREGS src)4591 void Codegen::CreateFloatIsSafeInteger([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4592 {
4593     GetEncoder()->EncodeIsSafeInteger(dst, src[0]);
4594 }
4595 
CreateStringEquals(IntrinsicInst * inst,Reg dst,SRCREGS src)4596 void Codegen::CreateStringEquals([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4597 {
4598     auto entrypointId = GetRuntime()->IsCompressedStringsEnabled() ? EntrypointId::STRING_EQUALS_COMPRESSED
4599                                                                    : EntrypointId::STRING_EQUALS;
4600     CallFastPath(inst, entrypointId, dst, {}, src[0], src[1U]);
4601 }
4602 
CreateMathCeil(IntrinsicInst * inst,Reg dst,SRCREGS src)4603 void Codegen::CreateMathCeil([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4604 {
4605     GetEncoder()->EncodeCeil(dst, src[0]);
4606 }
4607 
CreateMathFloor(IntrinsicInst * inst,Reg dst,SRCREGS src)4608 void Codegen::CreateMathFloor([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4609 {
4610     GetEncoder()->EncodeFloor(dst, src[0]);
4611 }
4612 
CreateCountLeadingZeroBits(IntrinsicInst * inst,Reg dst,SRCREGS src)4613 void Codegen::CreateCountLeadingZeroBits([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4614 {
4615     GetEncoder()->EncodeCountLeadingZeroBits(Reg(dst.GetId(), src[0].GetType()), src[0]);
4616 }
4617 
CreateStringBuilderChar(IntrinsicInst * inst,Reg dst,SRCREGS src)4618 void Codegen::CreateStringBuilderChar(IntrinsicInst *inst, [[maybe_unused]] Reg dst, SRCREGS src)
4619 {
4620     CallFastPath(inst, EntrypointId::STRING_BUILDER_CHAR, dst, RegMask::GetZeroMask(), src[0], src[1U]);
4621 }
4622 
CreateStringBuilderBool(IntrinsicInst * inst,Reg dst,SRCREGS src)4623 void Codegen::CreateStringBuilderBool(IntrinsicInst *inst, [[maybe_unused]] Reg dst, SRCREGS src)
4624 {
4625     CallFastPath(inst, EntrypointId::STRING_BUILDER_BOOL, dst, RegMask::GetZeroMask(), src[0], src[1U]);
4626 }
4627 
CreateStringBuilderString(IntrinsicInst * inst,Reg dst,SRCREGS src)4628 void Codegen::CreateStringBuilderString(IntrinsicInst *inst, [[maybe_unused]] Reg dst, SRCREGS src)
4629 {
4630     auto entrypointId = GetRuntime()->IsCompressedStringsEnabled() ? EntrypointId::STRING_BUILDER_STRING_COMPRESSED
4631                                                                    : EntrypointId::STRING_BUILDER_STRING;
4632 
4633     CallFastPath(inst, entrypointId, dst, RegMask::GetZeroMask(), src[0], src[1U]);
4634 }
4635 
CallFastCreateStringFromCharArrayTlab(Inst * inst,Reg dst,Reg offset,Reg count,Reg array,std::variant<Reg,TypedImm> klass)4636 void Codegen::CallFastCreateStringFromCharArrayTlab(Inst *inst, Reg dst, Reg offset, Reg count, Reg array,
4637                                                     std::variant<Reg, TypedImm> klass)
4638 {
4639     if (GetRegfile()->GetZeroReg().GetId() == offset.GetId()) {
4640         auto entryId = GetRuntime()->IsCompressedStringsEnabled()
4641                            ? EntrypointId::CREATE_STRING_FROM_ZERO_BASED_CHAR_ARRAY_TLAB_COMPRESSED
4642                            : EntrypointId::CREATE_STRING_FROM_ZERO_BASED_CHAR_ARRAY_TLAB;
4643         if (std::holds_alternative<TypedImm>(klass)) {
4644             CallFastPath(inst, entryId, dst, RegMask::GetZeroMask(), count, array, std::get<TypedImm>(klass));
4645         } else {
4646             CallFastPath(inst, entryId, dst, RegMask::GetZeroMask(), count, array, std::get<Reg>(klass));
4647         }
4648     } else {
4649         auto entryId = GetRuntime()->IsCompressedStringsEnabled()
4650                            ? EntrypointId::CREATE_STRING_FROM_CHAR_ARRAY_TLAB_COMPRESSED
4651                            : EntrypointId::CREATE_STRING_FROM_CHAR_ARRAY_TLAB;
4652         if (std::holds_alternative<TypedImm>(klass)) {
4653             CallFastPath(inst, entryId, dst, RegMask::GetZeroMask(), offset, count, array, std::get<TypedImm>(klass));
4654         } else {
4655             CallFastPath(inst, entryId, dst, RegMask::GetZeroMask(), offset, count, array, std::get<Reg>(klass));
4656         }
4657     }
4658 }
4659 
CreateStringFromCharArrayTlab(IntrinsicInst * inst,Reg dst,SRCREGS src)4660 void Codegen::CreateStringFromCharArrayTlab(IntrinsicInst *inst, Reg dst, SRCREGS src)
4661 {
4662     auto runtime = GetGraph()->GetRuntime();
4663     auto offset = src[FIRST_OPERAND];
4664     auto count = src[SECOND_OPERAND];
4665     auto array = src[THIRD_OPERAND];
4666     if (GetGraph()->IsAotMode()) {
4667         ScopedTmpReg klassReg(GetEncoder());
4668         GetEncoder()->EncodeLdr(klassReg, false,
4669                                 MemRef(ThreadReg(), runtime->GetStringClassPointerTlsOffset(GetArch())));
4670         CallFastCreateStringFromCharArrayTlab(inst, dst, offset, count, array, klassReg);
4671     } else {
4672         auto klassImm = TypedImm(reinterpret_cast<uintptr_t>(runtime->GetStringClass(GetGraph()->GetMethod())));
4673         CallFastCreateStringFromCharArrayTlab(inst, dst, offset, count, array, klassImm);
4674     }
4675 }
4676 
CreateStringFromStringTlab(IntrinsicInst * inst,Reg dst,SRCREGS src)4677 void Codegen::CreateStringFromStringTlab(IntrinsicInst *inst, Reg dst, SRCREGS src)
4678 {
4679     auto entryId = GetRuntime()->IsCompressedStringsEnabled() ? EntrypointId::CREATE_STRING_FROM_STRING_TLAB_COMPRESSED
4680                                                               : EntrypointId::CREATE_STRING_FROM_STRING_TLAB;
4681     auto srcStr = src[FIRST_OPERAND];
4682     CallFastPath(inst, entryId, dst, RegMask::GetZeroMask(), srcStr);
4683 }
4684 
CreateStringSubstringTlab(IntrinsicInst * inst,Reg dst,SRCREGS src)4685 void Codegen::CreateStringSubstringTlab([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4686 {
4687     auto entrypointId = GetRuntime()->IsCompressedStringsEnabled()
4688                             ? EntrypointId::SUB_STRING_FROM_STRING_TLAB_COMPRESSED
4689                             : EntrypointId::SUB_STRING_FROM_STRING_TLAB;
4690     CallFastPath(inst, entrypointId, dst, {}, src[FIRST_OPERAND], src[SECOND_OPERAND], src[THIRD_OPERAND]);
4691 }
4692 
CreateStringGetCharsTlab(IntrinsicInst * inst,Reg dst,SRCREGS src)4693 void Codegen::CreateStringGetCharsTlab([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4694 {
4695     auto entrypointId = GetRuntime()->IsCompressedStringsEnabled() ? EntrypointId::STRING_GET_CHARS_TLAB_COMPRESSED
4696                                                                    : EntrypointId::STRING_GET_CHARS_TLAB;
4697     auto runtime = GetGraph()->GetRuntime();
4698     if (GetGraph()->IsAotMode()) {
4699         ScopedTmpReg klassReg(GetEncoder());
4700         GetEncoder()->EncodeLdr(klassReg, false,
4701                                 MemRef(ThreadReg(), runtime->GetArrayU16ClassPointerTlsOffset(GetArch())));
4702         CallFastPath(inst, entrypointId, dst, {}, src[FIRST_OPERAND], src[SECOND_OPERAND], src[THIRD_OPERAND],
4703                      klassReg);
4704     } else {
4705         auto klassImm = TypedImm(reinterpret_cast<uintptr_t>(runtime->GetArrayU16Class(GetGraph()->GetMethod())));
4706         CallFastPath(inst, entrypointId, dst, {}, src[FIRST_OPERAND], src[SECOND_OPERAND], src[THIRD_OPERAND],
4707                      klassImm);
4708     }
4709 }
4710 
CreateStringHashCode(IntrinsicInst * inst,Reg dst,SRCREGS src)4711 void Codegen::CreateStringHashCode([[maybe_unused]] IntrinsicInst *inst, Reg dst, SRCREGS src)
4712 {
4713     auto entrypoint = GetRuntime()->IsCompressedStringsEnabled() ? EntrypointId::STRING_HASH_CODE_COMPRESSED
4714                                                                  : EntrypointId::STRING_HASH_CODE;
4715     auto strReg = src[FIRST_OPERAND];
4716     auto mref = MemRef(strReg, panda::coretypes::String::GetHashcodeOffset());
4717     auto slowPath = CreateSlowPath<SlowPathStringHashCode>(inst, entrypoint);
4718     slowPath->SetDstReg(dst);
4719     slowPath->SetSrcReg(strReg);
4720     if (dst.GetId() != strReg.GetId()) {
4721         GetEncoder()->EncodeLdr(ConvertRegister(dst.GetId(), DataType::INT32), false, mref);
4722         GetEncoder()->EncodeJump(slowPath->GetLabel(), dst, Condition::EQ);
4723     } else {
4724         ScopedTmpReg hashReg(GetEncoder(), INT32_TYPE);
4725         GetEncoder()->EncodeLdr(hashReg, false, mref);
4726         GetEncoder()->EncodeJump(slowPath->GetLabel(), hashReg, Condition::EQ);
4727         GetEncoder()->EncodeMov(dst, hashReg);
4728     }
4729     slowPath->BindBackLabel(GetEncoder());
4730 }
4731 
4732 #include "intrinsics_codegen.inl"
4733 
CreateBuiltinIntrinsic(IntrinsicInst * inst)4734 void Codegen::CreateBuiltinIntrinsic(IntrinsicInst *inst)
4735 {
4736     Reg dst = INVALID_REGISTER;
4737     SRCREGS src;
4738 
4739     if (!inst->NoDest()) {
4740         dst = ConvertRegister(inst->GetDstReg(), inst->GetType());
4741     }
4742 
4743     for (size_t i = 0; i < inst->GetInputsCount(); ++i) {
4744         if (inst->GetInput(i).GetInst()->IsSaveState()) {
4745             continue;
4746         }
4747         auto location = inst->GetLocation(i);
4748         auto type = inst->GetInputType(i);
4749         src[i] = ConvertRegister(location.GetValue(), type);
4750     }
4751     FillBuiltin(inst, src, dst);
4752 }
4753 
VisitIntrinsic(GraphVisitor * visitor,Inst * inst)4754 void EncodeVisitor::VisitIntrinsic(GraphVisitor *visitor, Inst *inst)
4755 {
4756     auto *enc = static_cast<EncodeVisitor *>(visitor);
4757     auto codegen = enc->GetCodegen();
4758     auto intrinsic = inst->CastToIntrinsic();
4759     auto id = intrinsic->GetIntrinsicId();
4760     auto arch = codegen->GetGraph()->GetArch();
4761     auto runtime = codegen->GetGraph()->GetRuntime();
4762     if (EncodesBuiltin(runtime, id, arch) || IsIrtocIntrinsic(id)) {
4763         codegen->CreateBuiltinIntrinsic(intrinsic);
4764         return;
4765     }
4766     codegen->CreateCallIntrinsic(intrinsic);
4767 }
4768 
VisitBoundsCheckI(GraphVisitor * visitor,Inst * inst)4769 void EncodeVisitor::VisitBoundsCheckI(GraphVisitor *visitor, Inst *inst)
4770 {
4771     auto *enc = static_cast<EncodeVisitor *>(visitor);
4772     auto lenReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), inst->GetInputType(0));
4773 
4774     ASSERT(inst->GetInput(1).GetInst()->GetOpcode() == Opcode::SaveState ||
4775            inst->GetInput(1).GetInst()->GetOpcode() == Opcode::SaveStateDeoptimize);
4776     EntrypointId entrypoint = inst->CastToBoundsCheckI()->IsArray()
4777                                   ? EntrypointId::ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION
4778                                   : EntrypointId::STRING_INDEX_OUT_OF_BOUNDS_EXCEPTION;
4779     LabelHolder::LabelId label;
4780     if (inst->CanDeoptimize()) {
4781         label = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, DeoptimizeType::BOUNDS_CHECK)->GetLabel();
4782     } else {
4783         label = enc->GetCodegen()->CreateSlowPath<SlowPathCheck>(inst, entrypoint)->GetLabel();
4784     }
4785 
4786     auto value = inst->CastToBoundsCheckI()->GetImm();
4787     if (enc->GetEncoder()->CanEncodeImmAddSubCmp(value, WORD_SIZE, false)) {
4788         enc->GetEncoder()->EncodeJump(label, lenReg, Imm(value), Condition::LS);
4789     } else {
4790         ScopedTmpReg tmp(enc->GetEncoder(), lenReg.GetType());
4791         enc->GetEncoder()->EncodeMov(tmp, Imm(value));
4792         enc->GetEncoder()->EncodeJump(label, lenReg, tmp, Condition::LS);
4793     }
4794 }
4795 
VisitStoreArrayI(GraphVisitor * visitor,Inst * inst)4796 void EncodeVisitor::VisitStoreArrayI(GraphVisitor *visitor, Inst *inst)
4797 {
4798     auto *enc = static_cast<EncodeVisitor *>(visitor);
4799     auto arrayReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);
4800     auto type = inst->GetType();
4801     auto value = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
4802 
4803     auto index = inst->CastToStoreArrayI()->GetImm();
4804     int64_t offset = enc->cg_->GetGraph()->GetRuntime()->GetArrayDataOffset(enc->GetCodegen()->GetArch()) +
4805                      (index << DataType::ShiftByType(type, enc->GetCodegen()->GetArch()));
4806     if (!enc->GetCodegen()->OffsetFitReferenceTypeSize(offset)) {
4807         // such code should not be executed
4808         enc->GetEncoder()->EncodeAbort();
4809         return;
4810     }
4811     auto mem = MemRef(arrayReg, offset);
4812     if (inst->CastToStoreArrayI()->GetNeedBarrier()) {
4813         enc->GetCodegen()->CreatePreWRB(inst, mem, MakeMask(arrayReg.GetId(), value.GetId()));
4814     }
4815     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
4816     enc->GetEncoder()->EncodeStr(value, mem);
4817     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
4818     if (inst->CastToStoreArrayI()->GetNeedBarrier()) {
4819         enc->GetCodegen()->CreatePostWRB(inst, mem, value, INVALID_REGISTER);
4820     }
4821 }
4822 
VisitLoadArrayI(GraphVisitor * visitor,Inst * inst)4823 void EncodeVisitor::VisitLoadArrayI(GraphVisitor *visitor, Inst *inst)
4824 {
4825     auto *enc = static_cast<EncodeVisitor *>(visitor);
4826     auto instLoadArrayI = inst->CastToLoadArrayI();
4827     auto runtime = enc->cg_->GetGraph()->GetRuntime();
4828     ASSERT(instLoadArrayI->IsArray() || !runtime->IsCompressedStringsEnabled());
4829     if (instLoadArrayI->GetNeedBarrier()) {
4830         // Consider inserting barriers for GC
4831     }
4832     auto arrayReg = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0));
4833     uint32_t index = instLoadArrayI->GetImm();
4834     auto type = inst->GetType();
4835     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);
4836     int64_t dataOffset = instLoadArrayI->IsArray() ? runtime->GetArrayDataOffset(enc->GetArch())
4837                                                    : runtime->GetStringDataOffset(enc->GetArch());
4838     uint32_t shift = DataType::ShiftByType(type, enc->GetArch());
4839     int64_t offset = dataOffset + (index << shift);
4840     auto mem = MemRef(arrayReg, offset);
4841     auto encoder = enc->GetEncoder();
4842     auto arch = enc->GetArch();
4843     ScopedTmpReg scopedTmp(encoder, Codegen::ConvertDataType(DataType::GetIntTypeForReference(arch), arch));
4844     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
4845     encoder->EncodeLdr(dst, IsTypeSigned(type), mem);
4846     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
4847 }
4848 
VisitLoadCompressedStringCharI(GraphVisitor * visitor,Inst * inst)4849 void EncodeVisitor::VisitLoadCompressedStringCharI(GraphVisitor *visitor, Inst *inst)
4850 {
4851     auto *enc = static_cast<EncodeVisitor *>(visitor);
4852     auto runtime = enc->cg_->GetGraph()->GetRuntime();
4853     auto type = inst->GetType();
4854     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0));                   // array
4855     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::INT32);  // length
4856     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), type);               // load value
4857     int32_t offset = runtime->GetStringDataOffset(enc->GetArch());
4858     auto encoder = enc->GetEncoder();
4859     auto arch = encoder->GetArch();
4860     int32_t shift = DataType::ShiftByType(type, arch);
4861     auto index = inst->CastToLoadCompressedStringCharI()->GetImm();
4862     ASSERT(encoder->CanEncodeCompressedStringCharAt());
4863     auto mask = runtime->GetStringCompressionMask();
4864     if (mask != 1) {
4865         UNREACHABLE();  // mask is hardcoded in JCL, but verify it just in case it's changed
4866     }
4867     enc->GetEncoder()->EncodeCompressedStringCharAtI(dst, src0, src1, offset, index, shift);
4868 }
4869 
VisitMultiArray(GraphVisitor * visitor,Inst * inst)4870 void EncodeVisitor::VisitMultiArray(GraphVisitor *visitor, Inst *inst)
4871 {
4872     auto *enc = static_cast<EncodeVisitor *>(visitor);
4873     auto codegen = enc->GetCodegen();
4874 
4875     auto arrayInst = inst->CastToMultiArray();
4876     codegen->CreateMultiArrayCall(arrayInst);
4877     if (inst->GetFlag(inst_flags::MEM_BARRIER)) {
4878         enc->GetEncoder()->EncodeMemoryBarrier(memory_order::RELEASE);
4879     }
4880 }
4881 
VisitInitEmptyString(GraphVisitor * visitor,Inst * inst)4882 void EncodeVisitor::VisitInitEmptyString(GraphVisitor *visitor, Inst *inst)
4883 {
4884     auto codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
4885     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
4886     codegen->CallRuntime(inst, EntrypointId::CREATE_EMPTY_STRING, dst, RegMask::GetZeroMask());
4887 }
4888 
VisitInitString(GraphVisitor * visitor,Inst * inst)4889 void EncodeVisitor::VisitInitString(GraphVisitor *visitor, Inst *inst)
4890 {
4891     auto cg = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
4892     auto initStr = inst->CastToInitString();
4893 
4894     auto dst = cg->ConvertRegister(initStr->GetDstReg(), initStr->GetType());
4895     auto ctorArg = cg->ConvertRegister(initStr->GetSrcReg(0), initStr->GetInputType(0));
4896 
4897     if (cg->GetArch() == Arch::AARCH32) {
4898         auto entryId =
4899             initStr->IsFromString() ? EntrypointId::CREATE_STRING_FROM_STRING : EntrypointId::CREATE_STRING_FROM_CHARS;
4900         cg->CallRuntime(initStr, entryId, dst, RegMask::GetZeroMask(), ctorArg);
4901         return;
4902     }
4903 
4904     if (initStr->IsFromString()) {
4905         auto entryId = cg->GetRuntime()->IsCompressedStringsEnabled()
4906                            ? compiler::RuntimeInterface::EntrypointId::CREATE_STRING_FROM_STRING_TLAB_COMPRESSED
4907                            : compiler::RuntimeInterface::EntrypointId::CREATE_STRING_FROM_STRING_TLAB;
4908         cg->CallFastPath(initStr, entryId, dst, RegMask::GetZeroMask(), ctorArg);
4909     } else {
4910         auto enc = cg->GetEncoder();
4911         auto runtime = cg->GetGraph()->GetRuntime();
4912         auto mem = MemRef(ctorArg, static_cast<int64_t>(runtime->GetArrayLengthOffset(cg->GetArch())));
4913         ScopedTmpReg lengthReg(enc);
4914         enc->EncodeLdr(lengthReg, IsTypeSigned(initStr->GetType()), mem);
4915         if (cg->GetGraph()->IsAotMode()) {
4916             auto klassOffs = runtime->GetStringClassPointerTlsOffset(cg->GetArch());
4917             ScopedTmpReg klassReg(enc);
4918             enc->EncodeLdr(klassReg, false, MemRef(cg->ThreadReg(), klassOffs));
4919             cg->CallFastCreateStringFromCharArrayTlab(initStr, dst, cg->GetRegfile()->GetZeroReg(), lengthReg, ctorArg,
4920                                                       klassReg);
4921         } else {
4922             auto klassPtr = runtime->GetStringClass(cg->GetGraph()->GetMethod());
4923             auto klassImm = TypedImm(reinterpret_cast<uintptr_t>(klassPtr));
4924             cg->CallFastCreateStringFromCharArrayTlab(initStr, dst, cg->GetRegfile()->GetZeroReg(), lengthReg, ctorArg,
4925                                                       klassImm);
4926         }
4927     }
4928 }
4929 
VisitCallLaunchStatic(GraphVisitor * visitor,Inst * inst)4930 void EncodeVisitor::VisitCallLaunchStatic(GraphVisitor *visitor, Inst *inst)
4931 {
4932     auto *enc = static_cast<EncodeVisitor *>(visitor);
4933     enc->GetCodegen()->CreateLaunchCall(inst->CastToCallLaunchStatic());
4934 }
4935 
VisitCallLaunchVirtual(GraphVisitor * visitor,Inst * inst)4936 void EncodeVisitor::VisitCallLaunchVirtual(GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
4937 {
4938     auto *enc = static_cast<EncodeVisitor *>(visitor);
4939     enc->GetCodegen()->CreateLaunchCall(inst->CastToCallLaunchVirtual());
4940 }
4941 
VisitCallResolvedLaunchStatic(GraphVisitor * visitor,Inst * inst)4942 void EncodeVisitor::VisitCallResolvedLaunchStatic(GraphVisitor *visitor, Inst *inst)
4943 {
4944     auto *enc = static_cast<EncodeVisitor *>(visitor);
4945     enc->GetCodegen()->CreateLaunchCall(inst->CastToCallResolvedLaunchStatic());
4946 }
4947 
VisitCallResolvedLaunchVirtual(GraphVisitor * visitor,Inst * inst)4948 void EncodeVisitor::VisitCallResolvedLaunchVirtual(GraphVisitor *visitor, Inst *inst)
4949 {
4950     auto *enc = static_cast<EncodeVisitor *>(visitor);
4951     enc->GetCodegen()->CreateLaunchCall(inst->CastToCallResolvedLaunchVirtual());
4952 }
4953 
VisitResolveStatic(GraphVisitor * visitor,Inst * inst)4954 void EncodeVisitor::VisitResolveStatic(GraphVisitor *visitor, Inst *inst)
4955 {
4956     auto *enc = static_cast<EncodeVisitor *>(visitor);
4957     enc->GetCodegen()->EmitResolveStatic(inst->CastToResolveStatic());
4958 }
4959 
VisitCallResolvedStatic(GraphVisitor * visitor,Inst * inst)4960 void EncodeVisitor::VisitCallResolvedStatic(GraphVisitor *visitor, Inst *inst)
4961 {
4962     auto *enc = static_cast<EncodeVisitor *>(visitor);
4963     enc->GetCodegen()->EmitCallResolvedStatic(inst->CastToCallResolvedStatic());
4964 }
4965 
VisitCallStatic(GraphVisitor * visitor,Inst * inst)4966 void EncodeVisitor::VisitCallStatic(GraphVisitor *visitor, Inst *inst)
4967 {
4968     auto *enc = static_cast<EncodeVisitor *>(visitor);
4969     enc->GetCodegen()->EmitCallStatic(inst->CastToCallStatic());
4970 }
4971 
VisitCallVirtual(GraphVisitor * visitor,Inst * inst)4972 void EncodeVisitor::VisitCallVirtual(GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
4973 {
4974     auto *enc = static_cast<EncodeVisitor *>(visitor);
4975     enc->GetCodegen()->EmitCallVirtual(inst->CastToCallVirtual());
4976 }
4977 
VisitResolveVirtual(GraphVisitor * visitor,Inst * inst)4978 void EncodeVisitor::VisitResolveVirtual(GraphVisitor *visitor, Inst *inst)
4979 {
4980     auto *enc = static_cast<EncodeVisitor *>(visitor);
4981     enc->GetCodegen()->EmitResolveVirtual(inst->CastToResolveVirtual());
4982 }
4983 
VisitCallResolvedVirtual(GraphVisitor * visitor,Inst * inst)4984 void EncodeVisitor::VisitCallResolvedVirtual(GraphVisitor *visitor, Inst *inst)
4985 {
4986     auto *enc = static_cast<EncodeVisitor *>(visitor);
4987     enc->GetCodegen()->EmitCallResolvedVirtual(inst->CastToCallResolvedVirtual());
4988 }
4989 
VisitCallDynamic(GraphVisitor * visitor,Inst * inst)4990 void EncodeVisitor::VisitCallDynamic(GraphVisitor *visitor, Inst *inst)
4991 {
4992     auto *enc = static_cast<EncodeVisitor *>(visitor);
4993     enc->GetCodegen()->EmitCallDynamic(inst->CastToCallDynamic());
4994 }
4995 
VisitLoadConstantPool(GraphVisitor * visitor,Inst * inst)4996 void EncodeVisitor::VisitLoadConstantPool(GraphVisitor *visitor, Inst *inst)
4997 {
4998     if (TryLoadConstantPoolGen(inst, static_cast<EncodeVisitor *>(visitor))) {
4999         return;
5000     }
5001     UNREACHABLE();
5002 }
5003 
VisitLoadLexicalEnv(GraphVisitor * visitor,Inst * inst)5004 void EncodeVisitor::VisitLoadLexicalEnv(GraphVisitor *visitor, Inst *inst)
5005 {
5006     if (TryLoadLexicalEnvGen(inst, static_cast<EncodeVisitor *>(visitor))) {
5007         return;
5008     }
5009     UNREACHABLE();
5010 }
5011 
VisitLoadFromConstantPool(GraphVisitor * visitor,Inst * inst)5012 void EncodeVisitor::VisitLoadFromConstantPool([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
5013 {
5014     UNREACHABLE();
5015 }
5016 
VisitSafePoint(GraphVisitor * visitor,Inst * inst)5017 void EncodeVisitor::VisitSafePoint(GraphVisitor *visitor, Inst *inst)
5018 {
5019     auto *enc = static_cast<EncodeVisitor *>(visitor);
5020     auto codegen = enc->GetCodegen();
5021     auto graph = codegen->GetGraph();
5022     auto encoder = enc->GetEncoder();
5023     int64_t flagAddrOffset = graph->GetRuntime()->GetFlagAddrOffset(codegen->GetArch());
5024     ScopedTmpRegU16 tmp(encoder);
5025 
5026     // TMP <= Flag
5027     auto mem = MemRef(codegen->ThreadReg(), flagAddrOffset);
5028     encoder->EncodeLdr(tmp, false, mem);
5029 
5030     // check value and jump to call GC
5031     auto slowPath = codegen->CreateSlowPath<SlowPathEntrypoint>(inst, EntrypointId::SAFEPOINT);
5032 
5033     encoder->EncodeJump(slowPath->GetLabel(), tmp, Condition::NE);
5034 
5035     slowPath->BindBackLabel(encoder);
5036 }
5037 
VisitSelect(GraphVisitor * visitor,Inst * inst)5038 void EncodeVisitor::VisitSelect(GraphVisitor *visitor, Inst *inst)
5039 {
5040     auto *enc = static_cast<EncodeVisitor *>(visitor);
5041     auto dstType = inst->GetType();
5042     auto cmpType = inst->CastToSelect()->GetOperandsType();
5043 
5044     constexpr int32_t IMM_2 = 2;
5045     constexpr int32_t IMM_3 = 3;
5046     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), dstType);
5047     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), dstType);
5048     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), dstType);
5049     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_2), cmpType);
5050     auto src3 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_3), cmpType);
5051     auto cc = enc->GetCodegen()->ConvertCc(inst->CastToSelect()->GetCc());
5052     if (IsTestCc(cc)) {
5053         enc->GetEncoder()->EncodeSelectTest(dst, src0, src1, src2, src3, cc);
5054     } else {
5055         enc->GetEncoder()->EncodeSelect(dst, src0, src1, src2, src3, cc);
5056     }
5057 }
5058 
VisitSelectImm(GraphVisitor * visitor,Inst * inst)5059 void EncodeVisitor::VisitSelectImm(GraphVisitor *visitor, Inst *inst)
5060 {
5061     auto *enc = static_cast<EncodeVisitor *>(visitor);
5062     auto dstType = inst->GetType();
5063     auto cmpType = inst->CastToSelectImm()->GetOperandsType();
5064 
5065     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), dstType);
5066     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), dstType);
5067     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), dstType);
5068     constexpr int32_t IMM_2 = 2;
5069     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_2), cmpType);
5070     auto imm = Imm(inst->CastToSelectImm()->GetImm());
5071     auto cc = enc->GetCodegen()->ConvertCc(inst->CastToSelectImm()->GetCc());
5072     if (IsTestCc(cc)) {
5073         enc->GetEncoder()->EncodeSelectTest(dst, src0, src1, src2, imm, cc);
5074     } else {
5075         enc->GetEncoder()->EncodeSelect(dst, src0, src1, src2, imm, cc);
5076     }
5077 }
5078 
VisitIf(GraphVisitor * visitor,Inst * inst)5079 void EncodeVisitor::VisitIf(GraphVisitor *visitor, Inst *inst)
5080 {
5081     auto *enc = static_cast<EncodeVisitor *>(visitor);
5082 
5083     auto bb = inst->GetBasicBlock();
5084     auto label = bb->GetTrueSuccessor()->GetId();
5085 
5086     auto type = inst->CastToIf()->GetOperandsType();
5087     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
5088     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
5089     auto cc = enc->GetCodegen()->ConvertCc(inst->CastToIf()->GetCc());
5090     if (IsTestCc(cc)) {
5091         enc->GetEncoder()->EncodeJumpTest(label, src0, src1, cc);
5092     } else {
5093         enc->GetEncoder()->EncodeJump(label, src0, src1, cc);
5094     }
5095 }
5096 
VisitIfImm(GraphVisitor * visitor,Inst * inst)5097 void EncodeVisitor::VisitIfImm(GraphVisitor *visitor, Inst *inst)
5098 {
5099     auto *enc = static_cast<EncodeVisitor *>(visitor);
5100 
5101     auto bb = inst->GetBasicBlock();
5102     auto label = bb->GetTrueSuccessor()->GetId();
5103 
5104     auto type = inst->CastToIfImm()->GetOperandsType();
5105     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
5106     auto imm = Imm(inst->CastToIfImm()->GetImm());
5107     auto cc = enc->GetCodegen()->ConvertCc(inst->CastToIfImm()->GetCc());
5108     if (IsTestCc(cc)) {
5109         enc->GetEncoder()->EncodeJumpTest(label, src0, imm, cc);
5110     } else {
5111         enc->GetEncoder()->EncodeJump(label, src0, imm, cc);
5112     }
5113 }
5114 
VisitAddOverflow(GraphVisitor * visitor,Inst * inst)5115 void EncodeVisitor::VisitAddOverflow(GraphVisitor *visitor, Inst *inst)
5116 {
5117     auto *enc = static_cast<EncodeVisitor *>(visitor);
5118 
5119     auto bb = inst->GetBasicBlock();
5120     auto label = bb->GetTrueSuccessor()->GetId();
5121 
5122     auto type = inst->CastToAddOverflow()->GetOperandsType();
5123     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
5124     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
5125     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
5126     auto cc = enc->GetCodegen()->ConvertCcOverflow(inst->CastToAddOverflow()->GetCc());
5127     enc->GetEncoder()->EncodeAddOverflow(label, dst, src0, src1, cc);
5128 }
5129 
VisitAddOverflowCheck(GraphVisitor * visitor,Inst * inst)5130 void EncodeVisitor::VisitAddOverflowCheck(GraphVisitor *visitor, Inst *inst)
5131 {
5132     ASSERT(DataType::IsTypeNumeric(inst->GetInput(0).GetInst()->GetType()));
5133     ASSERT(DataType::IsTypeNumeric(inst->GetInput(1).GetInst()->GetType()));
5134     auto *enc = static_cast<EncodeVisitor *>(visitor);
5135     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, DeoptimizeType::OVERFLOW);
5136     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
5137     auto src0 = Reg(inst->GetSrcReg(0), INT32_TYPE);
5138     auto src1 = Reg(inst->GetSrcReg(1), INT32_TYPE);
5139     enc->GetEncoder()->EncodeAddOverflow(slowPath->GetLabel(), dst, src0, src1, Condition::VS);
5140 }
5141 
VisitSubOverflow(GraphVisitor * visitor,Inst * inst)5142 void EncodeVisitor::VisitSubOverflow(GraphVisitor *visitor, Inst *inst)
5143 {
5144     auto *enc = static_cast<EncodeVisitor *>(visitor);
5145 
5146     auto bb = inst->GetBasicBlock();
5147     auto label = bb->GetTrueSuccessor()->GetId();
5148 
5149     auto type = inst->CastToSubOverflow()->GetOperandsType();
5150     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
5151     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), type);
5152     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);
5153     auto cc = enc->GetCodegen()->ConvertCcOverflow(inst->CastToSubOverflow()->GetCc());
5154     enc->GetEncoder()->EncodeSubOverflow(label, dst, src0, src1, cc);
5155 }
5156 
VisitSubOverflowCheck(GraphVisitor * visitor,Inst * inst)5157 void EncodeVisitor::VisitSubOverflowCheck(GraphVisitor *visitor, Inst *inst)
5158 {
5159     ASSERT(DataType::IsTypeNumeric(inst->GetInput(0).GetInst()->GetType()));
5160     ASSERT(DataType::IsTypeNumeric(inst->GetInput(1).GetInst()->GetType()));
5161     auto *enc = static_cast<EncodeVisitor *>(visitor);
5162     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, DeoptimizeType::OVERFLOW);
5163     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
5164     auto src0 = Reg(inst->GetSrcReg(0), INT32_TYPE);
5165     auto src1 = Reg(inst->GetSrcReg(1), INT32_TYPE);
5166     enc->GetEncoder()->EncodeSubOverflow(slowPath->GetLabel(), dst, src0, src1, Condition::VS);
5167 }
5168 
VisitNegOverflowAndZeroCheck(GraphVisitor * visitor,Inst * inst)5169 void EncodeVisitor::VisitNegOverflowAndZeroCheck(GraphVisitor *visitor, Inst *inst)
5170 {
5171     ASSERT(DataType::IsTypeNumeric(inst->GetInput(0).GetInst()->GetType()));
5172     auto *enc = static_cast<EncodeVisitor *>(visitor);
5173     auto slowPath = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, DeoptimizeType::OVERFLOW);
5174     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
5175     auto src = Reg(inst->GetSrcReg(0), INT32_TYPE);
5176     enc->GetEncoder()->EncodeNegOverflowAndZero(slowPath->GetLabel(), dst, src);
5177 }
5178 
VisitLoadArrayPair(GraphVisitor * visitor,Inst * inst)5179 void EncodeVisitor::VisitLoadArrayPair(GraphVisitor *visitor, Inst *inst)
5180 {
5181     auto *enc = static_cast<EncodeVisitor *>(visitor);
5182     if (inst->CastToLoadArrayPair()->GetNeedBarrier()) {
5183         // Consider inserting barriers for GC
5184     }
5185     auto type = inst->GetType();
5186     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // array
5187     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::INT32);      // index
5188     auto dst0 = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(0), type);                 // first value
5189     auto dst1 = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(1), type);                 // second value
5190     uint64_t index = inst->CastToLoadArrayPair()->GetImm();
5191     int64_t offset = enc->cg_->GetGraph()->GetRuntime()->GetArrayDataOffset(enc->GetCodegen()->GetArch()) +
5192                      (index << DataType::ShiftByType(type, enc->GetCodegen()->GetArch()));
5193     ScopedTmpReg tmp(enc->GetEncoder());
5194 
5195     int32_t scale = DataType::ShiftByType(type, enc->GetCodegen()->GetArch());
5196     enc->GetEncoder()->EncodeAdd(tmp, src0, Shift(src1, scale));
5197     auto mem = MemRef(tmp, offset);
5198     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
5199     enc->GetEncoder()->EncodeLdp(dst0, dst1, IsTypeSigned(type), mem);
5200     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
5201 }
5202 
VisitLoadArrayPairI(GraphVisitor * visitor,Inst * inst)5203 void EncodeVisitor::VisitLoadArrayPairI(GraphVisitor *visitor, Inst *inst)
5204 {
5205     auto *enc = static_cast<EncodeVisitor *>(visitor);
5206     if (inst->CastToLoadArrayPairI()->GetNeedBarrier()) {
5207         // Consider inserting barriers for GC
5208     }
5209     auto type = inst->GetType();
5210     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // array
5211     auto dst0 = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(0), type);                 // first value
5212     auto dst1 = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(1), type);                 // second value
5213     uint64_t index = inst->CastToLoadArrayPairI()->GetImm();
5214     int64_t offset = enc->cg_->GetGraph()->GetRuntime()->GetArrayDataOffset(enc->GetCodegen()->GetArch()) +
5215                      (index << DataType::ShiftByType(type, enc->GetCodegen()->GetArch()));
5216     auto mem = MemRef(src0, offset);
5217 
5218     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
5219     enc->GetEncoder()->EncodeLdp(dst0, dst1, IsTypeSigned(type), mem);
5220     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
5221 }
5222 
5223 /**
5224  * It is a pseudo instruction that is needed to separate multiple outputs from a single instruction in SSA such as
5225  * LoadArrayPair and LoadArrayPairI.  No codegeneration is required.
5226  */
VisitLoadPairPart(GraphVisitor * visitor,Inst * inst)5227 void EncodeVisitor::VisitLoadPairPart([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst) {}
5228 
VisitStoreArrayPair(GraphVisitor * visitor,Inst * inst)5229 void EncodeVisitor::VisitStoreArrayPair(GraphVisitor *visitor, Inst *inst)
5230 {
5231     auto *enc = static_cast<EncodeVisitor *>(visitor);
5232     auto type = inst->GetType();
5233     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // array
5234     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), DataType::INT32);      // index
5235     constexpr int32_t IMM_2 = 2;
5236     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_2), type);  // first value
5237     constexpr int32_t IMM_3 = 3;
5238     auto src3 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_3), type);  // second value
5239     uint64_t index = inst->CastToStoreArrayPair()->GetImm();
5240     int64_t offset = enc->cg_->GetGraph()->GetRuntime()->GetArrayDataOffset(enc->GetCodegen()->GetArch()) +
5241                      (index << DataType::ShiftByType(type, enc->GetCodegen()->GetArch()));
5242     int32_t scale = DataType::ShiftByType(type, enc->GetCodegen()->GetArch());
5243 
5244     auto tmp = enc->GetCodegen()->ConvertInstTmpReg(inst, DataType::REFERENCE);
5245     enc->GetEncoder()->EncodeAdd(tmp, src0, Shift(src1, scale));
5246     auto mem = MemRef(tmp, offset);
5247     if (inst->CastToStoreArrayPair()->GetNeedBarrier()) {
5248         enc->GetCodegen()->CreatePreWRB(inst, mem, MakeMask(src0.GetId(), src2.GetId(), src3.GetId()), true);
5249     }
5250     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
5251     enc->GetEncoder()->EncodeStp(src2, src3, mem);
5252     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
5253 
5254     if (inst->CastToStoreArrayPair()->GetNeedBarrier()) {
5255         auto tmpOffset = enc->GetCodegen()->ConvertInstTmpReg(inst, DataType::GetIntTypeForReference(enc->GetArch()));
5256         enc->GetEncoder()->EncodeShl(tmpOffset, src1, Imm(scale));
5257         enc->GetEncoder()->EncodeAdd(tmpOffset, tmpOffset, Imm(offset));
5258         auto mem1 = MemRef(src0, tmpOffset, 0);
5259         enc->GetCodegen()->CreatePostWRB(inst, mem1, src2, src3);
5260     }
5261 }
5262 
VisitStoreArrayPairI(GraphVisitor * visitor,Inst * inst)5263 void EncodeVisitor::VisitStoreArrayPairI(GraphVisitor *visitor, Inst *inst)
5264 {
5265     auto *enc = static_cast<EncodeVisitor *>(visitor);
5266     auto type = inst->GetType();
5267     auto src0 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(0), DataType::REFERENCE);  // array
5268     auto src1 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(1), type);                 // first value
5269     constexpr int32_t IMM_2 = 2;
5270     auto src2 = enc->GetCodegen()->ConvertRegister(inst->GetSrcReg(IMM_2), type);  // second value
5271 
5272     auto index = inst->CastToStoreArrayPairI()->GetImm();
5273     int64_t offset = enc->cg_->GetGraph()->GetRuntime()->GetArrayDataOffset(enc->GetCodegen()->GetArch()) +
5274                      (index << DataType::ShiftByType(type, enc->GetCodegen()->GetArch()));
5275     if (!enc->GetCodegen()->OffsetFitReferenceTypeSize(offset)) {
5276         // such code should not be executed
5277         enc->GetEncoder()->EncodeAbort();
5278         return;
5279     }
5280     auto mem = MemRef(src0, offset);
5281     if (inst->CastToStoreArrayPairI()->GetNeedBarrier()) {
5282         enc->GetCodegen()->CreatePreWRB(inst, mem, MakeMask(src0.GetId(), src1.GetId(), src2.GetId()), true);
5283     }
5284     auto prevOffset = enc->GetEncoder()->GetCursorOffset();
5285     enc->GetEncoder()->EncodeStp(src1, src2, mem);
5286     enc->GetCodegen()->TryInsertImplicitNullCheck(inst, prevOffset);
5287     if (inst->CastToStoreArrayPairI()->GetNeedBarrier()) {
5288         enc->GetCodegen()->CreatePostWRB(inst, mem, src1, src2);
5289     }
5290 }
5291 
VisitNOP(GraphVisitor * visitor,Inst * inst)5292 void EncodeVisitor::VisitNOP([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
5293 {
5294 #ifndef NDEBUG
5295     COMPILER_LOG(DEBUG, CODEGEN) << "The NOP wasn't removed before " << *inst;
5296 #endif
5297 }
5298 
VisitThrow(GraphVisitor * visitor,Inst * inst)5299 void EncodeVisitor::VisitThrow(GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
5300 {
5301     auto codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
5302     SlowPathCheck slowPath(codegen->GetEncoder()->CreateLabel(), inst, EntrypointId::THROW_EXCEPTION);
5303     slowPath.Generate(codegen);
5304 }
5305 
VisitDeoptimize(GraphVisitor * visitor,Inst * inst)5306 void EncodeVisitor::VisitDeoptimize(GraphVisitor *visitor, Inst *inst)
5307 {
5308     auto codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
5309     ASSERT(inst->GetSaveState() != nullptr);
5310 
5311     SlowPathDeoptimize slowPath(codegen->GetEncoder()->CreateLabel(), inst,
5312                                 inst->CastToDeoptimize()->GetDeoptimizeType());
5313     slowPath.Generate(codegen);
5314 }
5315 
VisitIsMustDeoptimize(GraphVisitor * visitor,Inst * inst)5316 void EncodeVisitor::VisitIsMustDeoptimize(GraphVisitor *visitor, Inst *inst)
5317 {
5318     auto *codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
5319     auto *enc = static_cast<EncodeVisitor *>(visitor)->GetEncoder();
5320     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
5321     auto offset = CFrameFlags::GetOffsetFromSpInBytes(codegen->GetFrameLayout());
5322 
5323     enc->EncodeLdr(dst, false, MemRef(codegen->SpReg(), offset));
5324     enc->EncodeAnd(dst, dst, Imm(1));
5325 }
5326 
VisitGetInstanceClass(GraphVisitor * visitor,Inst * inst)5327 void EncodeVisitor::VisitGetInstanceClass(GraphVisitor *visitor, Inst *inst)
5328 {
5329     auto *codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
5330     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
5331     auto objReg = codegen->ConvertRegister(inst->GetSrcReg(0), inst->GetType());
5332     ASSERT(objReg.IsValid());
5333     codegen->LoadClassFromObject(dst, objReg);
5334 }
5335 
VisitLoadImmediate(GraphVisitor * visitor,Inst * inst)5336 void EncodeVisitor::VisitLoadImmediate(GraphVisitor *visitor, Inst *inst)
5337 {
5338     auto codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
5339     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
5340     auto loadImm = inst->CastToLoadImmediate();
5341     if (loadImm->GetObjectType() != LoadImmediateInst::ObjectType::PANDA_FILE_OFFSET) {
5342         codegen->GetEncoder()->EncodeMov(dst, Imm(reinterpret_cast<uintptr_t>(loadImm->GetObject())));
5343     } else {
5344         auto runtime = codegen->GetGraph()->GetRuntime();
5345         auto pfOffset = runtime->GetPandaFileOffset(codegen->GetGraph()->GetArch());
5346         codegen->LoadMethod(dst);
5347         // load pointer to panda file
5348         codegen->GetEncoder()->EncodeLdr(dst, false, MemRef(dst, pfOffset));
5349         codegen->GetEncoder()->EncodeLdr(dst, false, MemRef(dst, cross_values::GetFileBaseOffset(codegen->GetArch())));
5350         // add pointer to pf with offset to str
5351         codegen->GetEncoder()->EncodeAdd(dst, dst, Imm(loadImm->GetPandaFileOffset()));
5352     }
5353 }
5354 
VisitFunctionImmediate(GraphVisitor * visitor,Inst * inst)5355 void EncodeVisitor::VisitFunctionImmediate(GraphVisitor *visitor, Inst *inst)
5356 {
5357     auto *codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
5358     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
5359 
5360     codegen->GetEncoder()->EncodeMov(dst, Imm(inst->CastToFunctionImmediate()->GetFunctionPtr()));
5361     codegen->GetEncoder()->EncodeLdr(dst, false, MemRef(dst, 0U));
5362 }
5363 
VisitLoadObjFromConst(GraphVisitor * visitor,Inst * inst)5364 void EncodeVisitor::VisitLoadObjFromConst(GraphVisitor *visitor, Inst *inst)
5365 {
5366     auto *codegen = static_cast<EncodeVisitor *>(visitor)->GetCodegen();
5367     auto dst = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
5368 
5369     Reg dstPointer(dst.As(TypeInfo::FromDataType(DataType::POINTER, codegen->GetArch())));
5370     codegen->GetEncoder()->EncodeMov(dstPointer, Imm(inst->CastToLoadObjFromConst()->GetObjPtr()));
5371     codegen->GetEncoder()->EncodeLdr(dst, false, MemRef(dstPointer, 0U));
5372 }
5373 
VisitRegDef(GraphVisitor * visitor,Inst * inst)5374 void EncodeVisitor::VisitRegDef([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst) {}
5375 
VisitLiveIn(GraphVisitor * visitor,Inst * inst)5376 void EncodeVisitor::VisitLiveIn([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst) {}
5377 
VisitLiveOut(GraphVisitor * visitor,Inst * inst)5378 void EncodeVisitor::VisitLiveOut([[maybe_unused]] GraphVisitor *visitor, [[maybe_unused]] Inst *inst)
5379 {
5380     auto enc = static_cast<EncodeVisitor *>(visitor);
5381     auto codegen = enc->GetCodegen();
5382 
5383     codegen->AddLiveOut(inst->GetBasicBlock(), inst->GetDstReg());
5384 
5385     auto dstReg = codegen->ConvertRegister(inst->GetDstReg(), inst->GetType());
5386     if (codegen->GetTarget().GetTempRegsMask().Test(dstReg.GetId()) &&
5387         enc->GetEncoder()->IsScratchRegisterReleased(dstReg)) {
5388         enc->GetEncoder()->AcquireScratchRegister(dstReg);
5389     }
5390 
5391     if (inst->GetLocation(0) != inst->GetDstLocation()) {
5392         auto *src = inst->GetInput(0).GetInst();
5393         enc->GetEncoder()->EncodeMov(dstReg, codegen->ConvertRegister(inst->GetSrcReg(0), src->GetType()));
5394     }
5395 }
5396 
VisitCompareAnyType(GraphVisitor * visitor,Inst * inst)5397 void EncodeVisitor::VisitCompareAnyType(GraphVisitor *visitor, Inst *inst)
5398 {
5399     auto enc = static_cast<EncodeVisitor *>(visitor);
5400     const auto *cati = inst->CastToCompareAnyType();
5401 
5402     if (cati->GetInputType(0) != DataType::Type::ANY) {
5403         enc->GetEncoder()->EncodeAbort();
5404         UNREACHABLE();
5405         return;
5406     }
5407 
5408     if (TryCompareAnyTypePluginGen(cati, enc)) {
5409         return;
5410     }
5411 
5412     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), inst->GetType());
5413     if (cati->GetAnyType() == AnyBaseType::UNDEFINED_TYPE) {
5414         enc->GetEncoder()->EncodeMov(dst, Imm(true));
5415     } else {
5416         enc->GetEncoder()->EncodeMov(dst, Imm(false));
5417     }
5418 }
5419 
VisitGetAnyTypeName(GraphVisitor * visitor,Inst * inst)5420 void EncodeVisitor::VisitGetAnyTypeName(GraphVisitor *visitor, Inst *inst)
5421 {
5422     auto enc = static_cast<EncodeVisitor *>(visitor);
5423     const auto *cati = inst->CastToGetAnyTypeName();
5424 
5425     if (TryGetAnyTypeNamePluginGen(cati, enc)) {
5426         return;
5427     }
5428 
5429     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), DataType::Type::BOOL);
5430     enc->GetEncoder()->EncodeMov(dst, Imm(0));
5431 }
5432 
VisitCastAnyTypeValue(GraphVisitor * visitor,Inst * inst)5433 void EncodeVisitor::VisitCastAnyTypeValue(GraphVisitor *visitor, Inst *inst)
5434 {
5435     auto enc = static_cast<EncodeVisitor *>(visitor);
5436     const auto *cati = inst->CastToCastAnyTypeValue();
5437 
5438     if (cati->GetInputType(0) != DataType::Type::ANY) {
5439         enc->GetEncoder()->EncodeAbort();
5440         UNREACHABLE();
5441         return;
5442     }
5443 
5444     if (TryCastAnyTypeValuePluginGen(cati, enc)) {
5445         return;
5446     }
5447 
5448     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), DataType::Type::BOOL);
5449     enc->GetEncoder()->EncodeMov(dst, Imm(0));
5450 }
5451 
VisitCastValueToAnyType(GraphVisitor * visitor,Inst * inst)5452 void EncodeVisitor::VisitCastValueToAnyType(GraphVisitor *visitor, Inst *inst)
5453 {
5454     auto enc = static_cast<EncodeVisitor *>(visitor);
5455     const auto *cvai = inst->CastToCastValueToAnyType();
5456 
5457     /* // NOTE(vpukhov): AnyConst
5458     if (cvai->GetInputType(0) == DataType::Type::ANY) {
5459         enc->GetEncoder()->EncodeAbort();
5460         UNREACHABLE();
5461         return;
5462     }
5463     */
5464 
5465     if (TryCastValueToAnyTypePluginGen(cvai, enc)) {
5466         return;
5467     }
5468 
5469     auto dst = enc->GetCodegen()->ConvertRegister(inst->GetDstReg(), DataType::Type::BOOL);
5470     enc->GetEncoder()->EncodeMov(dst, Imm(0));
5471 }
5472 
VisitAnyTypeCheck(GraphVisitor * visitor,Inst * inst)5473 void EncodeVisitor::VisitAnyTypeCheck(GraphVisitor *visitor, Inst *inst)
5474 {
5475     auto enc = static_cast<EncodeVisitor *>(visitor);
5476     auto *checkInst = inst->CastToAnyTypeCheck();
5477 
5478     if (checkInst->GetInputType(0) != DataType::Type::ANY) {
5479         enc->GetEncoder()->EncodeAbort();
5480         UNREACHABLE();
5481     }
5482     // Empty check
5483     if (checkInst->GetAnyType() == AnyBaseType::UNDEFINED_TYPE) {
5484         return;
5485     }
5486 
5487     if (TryAnyTypeCheckPluginGen(checkInst, enc)) {
5488         return;
5489     }
5490     UNREACHABLE();
5491 }
5492 
VisitHclassCheck(GraphVisitor * visitor,Inst * inst)5493 void EncodeVisitor::VisitHclassCheck(GraphVisitor *visitor, Inst *inst)
5494 {
5495     auto enc = static_cast<EncodeVisitor *>(visitor);
5496     auto *checkInst = inst->CastToHclassCheck();
5497 
5498     if (checkInst->GetInputType(0) != DataType::Type::REFERENCE) {
5499         enc->GetEncoder()->EncodeAbort();
5500         UNREACHABLE();
5501     }
5502 
5503     if (TryHclassCheckPluginGen(checkInst, enc)) {
5504         return;
5505     }
5506     UNREACHABLE();
5507 }
5508 
VisitObjByIndexCheck(GraphVisitor * visitor,Inst * inst)5509 void EncodeVisitor::VisitObjByIndexCheck(GraphVisitor *visitor, Inst *inst)
5510 {
5511     auto enc = static_cast<EncodeVisitor *>(visitor);
5512     const auto *checkInst = inst->CastToObjByIndexCheck();
5513 
5514     if (checkInst->GetInputType(0) != DataType::Type::ANY) {
5515         enc->GetEncoder()->EncodeAbort();
5516         UNREACHABLE();
5517     }
5518     auto id = enc->GetCodegen()->CreateSlowPath<SlowPathDeoptimize>(inst, DeoptimizeType::ANY_TYPE_CHECK)->GetLabel();
5519     if (TryObjByIndexCheckPluginGen(checkInst, enc, id)) {
5520         return;
5521     }
5522     UNREACHABLE();
5523 }
5524 
GetNeedBarrierProperty(const Inst * inst)5525 static bool GetNeedBarrierProperty(const Inst *inst)
5526 {
5527     Opcode op = inst->GetOpcode();
5528     if (op == Opcode::LoadObject) {
5529         return inst->CastToLoadObject()->GetNeedBarrier();
5530     }
5531     if (op == Opcode::StoreObject) {
5532         return inst->CastToStoreObject()->GetNeedBarrier();
5533     }
5534     if (op == Opcode::LoadArray) {
5535         return inst->CastToLoadArray()->GetNeedBarrier();
5536     }
5537     if (op == Opcode::StoreArray) {
5538         return inst->CastToStoreArray()->GetNeedBarrier();
5539     }
5540     if (op == Opcode::LoadArrayI) {
5541         return inst->CastToLoadArrayI()->GetNeedBarrier();
5542     }
5543     if (op == Opcode::StoreArrayI) {
5544         return inst->CastToStoreArrayI()->GetNeedBarrier();
5545     }
5546     if (op == Opcode::LoadArrayPair) {
5547         return inst->CastToLoadArrayPair()->GetNeedBarrier();
5548     }
5549     if (op == Opcode::StoreArrayPair) {
5550         return inst->CastToStoreArrayPair()->GetNeedBarrier();
5551     }
5552     if (op == Opcode::LoadArrayPairI) {
5553         return inst->CastToLoadArrayPairI()->GetNeedBarrier();
5554     }
5555     if (op == Opcode::StoreArrayPairI) {
5556         return inst->CastToStoreArrayPairI()->GetNeedBarrier();
5557     }
5558     if (op == Opcode::LoadStatic) {
5559         return inst->CastToLoadStatic()->GetNeedBarrier();
5560     }
5561     if (op == Opcode::StoreStatic) {
5562         return inst->CastToStoreStatic()->GetNeedBarrier();
5563     }
5564     return false;
5565 }
5566 
5567 /**
5568  * Returns true if codegen emits call(s) to some library function(s)
5569  * while processing the instruction.
5570  */
InstEncodedWithLibCall(const Inst * inst,Arch arch)5571 bool Codegen::InstEncodedWithLibCall(const Inst *inst, Arch arch)
5572 {
5573     ASSERT(inst != nullptr);
5574     Opcode op = inst->GetOpcode();
5575     if (op == Opcode::Mod) {
5576         auto dstType = inst->GetType();
5577         if (arch == Arch::AARCH64 || arch == Arch::X86_64) {
5578             return dstType == DataType::FLOAT32 || dstType == DataType::FLOAT64;
5579         }
5580         return arch == Arch::AARCH32;
5581     }
5582     if (op == Opcode::Div && arch == Arch::AARCH32) {
5583         auto dstType = inst->GetType();
5584         return dstType == DataType::INT64 || dstType == DataType::UINT64;
5585     }
5586     if (op == Opcode::Cast && arch == Arch::AARCH32) {
5587         auto dstType = inst->GetType();
5588         auto srcType = inst->GetInputType(0);
5589         if (dstType == DataType::FLOAT32 || dstType == DataType::FLOAT64) {
5590             return srcType == DataType::INT64 || srcType == DataType::UINT64;
5591         }
5592         if (srcType == DataType::FLOAT32 || srcType == DataType::FLOAT64) {
5593             return dstType == DataType::INT64 || dstType == DataType::UINT64;
5594         }
5595         return false;
5596     }
5597 
5598     return GetNeedBarrierProperty(inst);
5599 }
5600 
ConvertInstTmpReg(const Inst * inst,DataType::Type type) const5601 Reg Codegen::ConvertInstTmpReg(const Inst *inst, DataType::Type type) const
5602 {
5603     ASSERT(inst->GetTmpLocation().IsFixedRegister());
5604     return Reg(inst->GetTmpLocation().GetValue(), ConvertDataType(type, GetArch()));
5605 }
5606 
ConvertInstTmpReg(const Inst * inst) const5607 Reg Codegen::ConvertInstTmpReg(const Inst *inst) const
5608 {
5609     return ConvertInstTmpReg(inst, Is64BitsArch(GetArch()) ? DataType::INT64 : DataType::INT32);
5610 }
5611 
5612 }  // namespace panda::compiler
5613