• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "libabckit/src/codegen/codegen_static.h"
16 #include "static_core/runtime/include/coretypes/tagged_value.h"
17 namespace ark {
18 #include <generated/abckit_intrinsics.inl>
19 }  // namespace ark
20 
21 namespace libabckit {
22 
AccReadIndex(const compiler::Inst * inst)23 uint8_t AccReadIndex(const compiler::Inst *inst)
24 {
25     // Calls can have accumulator at any position, return false for them
26     ASSERT(!inst->IsCall());
27 
28     if (inst->IsIntrinsic() && inst->IsAccRead()) {
29         ASSERT(inst->GetInputsCount() >= 1U);
30         return 0U;
31     }
32 
33     return 0U;
34 }
35 
36 // This method is used by bytecode optimizer's codegen.
CanConvertToIncI(const compiler::BinaryImmOperation * binop)37 bool CanConvertToIncI(const compiler::BinaryImmOperation *binop)
38 {
39     ASSERT(binop->GetBasicBlock()->GetGraph()->IsRegAllocApplied());
40     ASSERT(binop->GetOpcode() == compiler::Opcode::AddI || binop->GetOpcode() == compiler::Opcode::SubI);
41 
42     // IncI works on the same register.
43     if (binop->GetSrcReg(0U) != binop->GetDstReg()) {
44         return false;
45     }
46 
47     // IncI cannot write accumulator.
48     if (binop->GetSrcReg(0U) == compiler::GetAccReg()) {
49         return false;
50     }
51 
52     // IncI users cannot read from accumulator.
53     // While Addi/SubI stores the output in accumulator, IncI works directly on registers.
54     for (const auto &user : binop->GetUsers()) {
55         const auto *uinst = user.GetInst();
56 
57         if (uinst->IsCall()) {
58             continue;
59         }
60 
61         const uint8_t index = AccReadIndex(uinst);
62         if (uinst->GetInput(index).GetInst() == binop && uinst->GetSrcReg(index) == compiler::GetAccReg()) {
63             return false;
64         }
65     }
66 
67     constexpr uint64_t BITMASK = 0xffffffff;
68     // Define min and max values of i4 type.
69     // NOLINTNEXTLINE(readability-identifier-naming)
70     constexpr int32_t min = -8;
71     // NOLINTNEXTLINE(readability-identifier-naming)
72     constexpr int32_t max = 7;
73 
74     int32_t imm = binop->GetImm() & BITMASK;
75     // Note: subi 3 is the same as inci v2, -3.
76     if (binop->GetOpcode() == compiler::Opcode::SubI) {
77         imm = -imm;
78     }
79 
80     // IncI works only with 4 bits immediates.
81     return imm >= min && imm <= max;
82 }
83 
DoLdaObj(compiler::Register reg,std::vector<pandasm::Ins> & result)84 void DoLdaObj(compiler::Register reg, std::vector<pandasm::Ins> &result)
85 {
86     if (reg != compiler::GetAccReg()) {
87         if (reg > compiler::INVALID_REG) {
88             ASSERT(compiler::IsFrameSizeLarge());
89             result.emplace_back(pandasm::Create_MOV_OBJ(CodeGenStatic::RESERVED_REG, reg));
90             result.emplace_back(pandasm::Create_LDA_OBJ(CodeGenStatic::RESERVED_REG));
91         } else {
92             result.emplace_back(pandasm::Create_LDA_OBJ(reg));
93         }
94     }
95 }
96 
DoLda(compiler::Register reg,std::vector<pandasm::Ins> & result)97 void DoLda(compiler::Register reg, std::vector<pandasm::Ins> &result)
98 {
99     if (reg != compiler::GetAccReg()) {
100         if (reg > compiler::INVALID_REG) {
101             ASSERT(compiler::IsFrameSizeLarge());
102             result.emplace_back(pandasm::Create_MOV(CodeGenStatic::RESERVED_REG, reg));
103             result.emplace_back(pandasm::Create_LDA(CodeGenStatic::RESERVED_REG));
104         } else {
105             result.emplace_back(pandasm::Create_LDA(reg));
106         }
107     }
108 }
109 
DoLda64(compiler::Register reg,std::vector<pandasm::Ins> & result)110 void DoLda64(compiler::Register reg, std::vector<pandasm::Ins> &result)
111 {
112     if (reg != compiler::GetAccReg()) {
113         if (reg > compiler::INVALID_REG) {
114             ASSERT(compiler::IsFrameSizeLarge());
115             result.emplace_back(pandasm::Create_MOV_64(CodeGenStatic::RESERVED_REG, reg));
116             result.emplace_back(pandasm::Create_LDA_64(CodeGenStatic::RESERVED_REG));
117         } else {
118             result.emplace_back(pandasm::Create_LDA_64(reg));
119         }
120     }
121 }
122 
DoStaObj(compiler::Register reg,std::vector<pandasm::Ins> & result)123 void DoStaObj(compiler::Register reg, std::vector<pandasm::Ins> &result)
124 {
125     if (reg != compiler::GetAccReg()) {
126         if (reg > compiler::INVALID_REG) {
127             ASSERT(compiler::IsFrameSizeLarge());
128             result.emplace_back(pandasm::Create_STA_OBJ(CodeGenStatic::RESERVED_REG));
129             result.emplace_back(pandasm::Create_MOV_OBJ(reg, CodeGenStatic::RESERVED_REG));
130         } else {
131             result.emplace_back(pandasm::Create_STA_OBJ(reg));
132         }
133     }
134 }
135 
DoSta(compiler::Register reg,std::vector<pandasm::Ins> & result)136 void DoSta(compiler::Register reg, std::vector<pandasm::Ins> &result)
137 {
138     if (reg != compiler::GetAccReg()) {
139         if (reg > compiler::INVALID_REG) {
140             ASSERT(compiler::IsFrameSizeLarge());
141             result.emplace_back(pandasm::Create_STA(CodeGenStatic::RESERVED_REG));
142             result.emplace_back(pandasm::Create_MOV(reg, CodeGenStatic::RESERVED_REG));
143         } else {
144             result.emplace_back(pandasm::Create_STA(reg));
145         }
146     }
147 }
148 
DoSta64(compiler::Register reg,std::vector<pandasm::Ins> & result)149 void DoSta64(compiler::Register reg, std::vector<pandasm::Ins> &result)
150 {
151     if (reg != compiler::GetAccReg()) {
152         if (reg > compiler::INVALID_REG) {
153             ASSERT(compiler::IsFrameSizeLarge());
154             result.emplace_back(pandasm::Create_STA_64(CodeGenStatic::RESERVED_REG));
155             result.emplace_back(pandasm::Create_MOV_64(reg, CodeGenStatic::RESERVED_REG));
156         } else {
157             result.emplace_back(pandasm::Create_STA_64(reg));
158         }
159     }
160 }
161 
DoSta(compiler::DataType::Type type,compiler::Register reg,std::vector<pandasm::Ins> & result)162 void DoSta(compiler::DataType::Type type, compiler::Register reg, std::vector<pandasm::Ins> &result)
163 {
164     if (compiler::DataType::Is64Bits(type, Arch::NONE)) {
165         DoSta64(reg, result);
166     } else {
167         DoSta(reg, result);
168     }
169 }
170 
DoLdaDyn(compiler::Register reg,std::vector<pandasm::Ins> & result)171 void DoLdaDyn(compiler::Register reg, std::vector<pandasm::Ins> &result)
172 {
173     ASSERT(reg <= compiler::INVALID_REG);
174     if (reg != compiler::GetAccReg()) {
175         result.emplace_back(pandasm::Create_LDA_DYN(reg));
176     }
177 }
178 
DoStaDyn(compiler::Register reg,std::vector<pandasm::Ins> & result)179 void DoStaDyn(compiler::Register reg, std::vector<pandasm::Ins> &result)
180 {
181     ASSERT(reg <= compiler::INVALID_REG);
182     if (reg != compiler::GetAccReg()) {
183         result.emplace_back(pandasm::Create_STA_DYN(reg));
184     }
185 }
186 
AppendCatchBlock(uint32_t typeId,const compiler::BasicBlock * tryBegin,const compiler::BasicBlock * tryEnd,const compiler::BasicBlock * catchBegin,const compiler::BasicBlock * catchEnd)187 void CodeGenStatic::AppendCatchBlock(uint32_t typeId, const compiler::BasicBlock *tryBegin,
188                                      const compiler::BasicBlock *tryEnd, const compiler::BasicBlock *catchBegin,
189                                      const compiler::BasicBlock *catchEnd)
190 {
191     auto cb = pandasm::Function::CatchBlock();
192     if (typeId != 0U) {
193         cb.exceptionRecord = irInterface_->GetTypeIdByOffset(typeId);
194     }
195     cb.tryBeginLabel = CodeGenStatic::LabelName(tryBegin->GetId());
196     cb.tryEndLabel = "end_" + CodeGenStatic::LabelName(tryEnd->GetId());
197     cb.catchBeginLabel = CodeGenStatic::LabelName(catchBegin->GetId());
198     cb.catchEndLabel = catchEnd == nullptr ? cb.catchBeginLabel : "end_" + CodeGenStatic::LabelName(catchEnd->GetId());
199     catchBlocks_.emplace_back(cb);
200 }
201 
VisitTryBegin(const compiler::BasicBlock * bb)202 void CodeGenStatic::VisitTryBegin(const compiler::BasicBlock *bb)
203 {
204     ASSERT(bb->IsTryBegin());
205     auto tryInst = GetTryBeginInst(bb);
206     auto tryEnd = tryInst->GetTryEndBlock();
207     ASSERT(tryEnd != nullptr && tryEnd->IsTryEnd());
208 
209     bb->EnumerateCatchHandlers([&, bb, tryEnd](BasicBlock *catchHandler, size_t typeId) {
210         AppendCatchBlock(typeId, bb, tryEnd, catchHandler);
211         return true;
212     });
213 }
214 
AddLineAndColumnNumber(const compiler::Inst * inst,size_t idx)215 void CodeGenStatic::AddLineAndColumnNumber(const compiler::Inst *inst, size_t idx)
216 {
217     AddLineNumber(inst, idx);
218 }
219 
RunImpl()220 bool CodeGenStatic::RunImpl()
221 {
222     Reserve(function_->ins.size());
223     for (auto *bb : GetGraph()->GetBlocksLinearOrder()) {
224         EmitLabel(CodeGenStatic::LabelName(bb->GetId()));
225         // NOTE(ivagin) if (bb->IsTryEnd() || bb->IsCatchEnd()) {
226         if (bb->IsTryEnd() || bb->IsCatch()) {
227             auto label = "end_" + CodeGenStatic::LabelName(bb->GetId());
228             EmitLabel(label);
229         }
230         for (const auto &inst : bb->AllInsts()) {
231             auto start = GetResult().size();
232             VisitInstruction(inst);
233             if (!GetStatus()) {
234                 return false;
235             }
236             auto end = GetResult().size();
237             ASSERT(end >= start);
238             for (auto i = start; i < end; ++i) {
239                 AddLineAndColumnNumber(inst, i);
240             }
241         }
242         if (bb->NeedsJump()) {
243             EmitJump(bb);
244         }
245     }
246     if (!GetStatus()) {
247         return false;
248     }
249     // Visit try-blocks in order they were declared
250     for (auto *bb : GetGraph()->GetTryBeginBlocks()) {
251         VisitTryBegin(bb);
252     }
253     function_->ins = std::move(GetResult());
254     function_->catchBlocks = catchBlocks_;
255     return true;
256 }
257 
EmitJump(const BasicBlock * bb)258 void CodeGenStatic::EmitJump(const BasicBlock *bb)
259 {
260     BasicBlock *sucBb = nullptr;
261     ASSERT(bb != nullptr);
262 
263     if (bb->GetLastInst() == nullptr) {
264         ASSERT(bb->IsEmpty());
265         sucBb = bb->GetSuccsBlocks()[0U];
266         result_.push_back(pandasm::Create_JMP(CodeGenStatic::LabelName(sucBb->GetId())));
267         return;
268     }
269 
270     ASSERT(bb->GetLastInst() != nullptr);
271     switch (bb->GetLastInst()->GetOpcode()) {
272         case Opcode::If:
273         case Opcode::IfImm:
274             ASSERT(bb->GetSuccsBlocks().size() == compiler::MAX_SUCCS_NUM);
275             sucBb = bb->GetFalseSuccessor();
276             break;
277         default:
278             sucBb = bb->GetSuccsBlocks()[0U];
279             break;
280     }
281     result_.push_back(pandasm::Create_JMP(CodeGenStatic::LabelName(sucBb->GetId())));
282 }
283 
AddLineNumber(const Inst * inst,const size_t idx)284 void CodeGenStatic::AddLineNumber([[maybe_unused]] const Inst *inst, [[maybe_unused]] const size_t idx) {}
285 
AddColumnNumber(const Inst * inst,const uint32_t idx)286 void CodeGenStatic::AddColumnNumber([[maybe_unused]] const Inst *inst, [[maybe_unused]] const uint32_t idx) {}
287 
EncodeSpillFillData(const compiler::SpillFillData & sf)288 void CodeGenStatic::EncodeSpillFillData(const compiler::SpillFillData &sf)
289 {
290     if (sf.SrcType() != compiler::LocationType::REGISTER || sf.DstType() != compiler::LocationType::REGISTER) {
291         std::cerr << "EncodeSpillFillData with unknown move type, src_type: " << static_cast<int>(sf.SrcType())
292                   << " dst_type: " << static_cast<int>(sf.DstType()) << std::endl;
293         success_ = false;
294         UNREACHABLE();
295         return;
296     }
297     ASSERT(sf.GetType() != compiler::DataType::NO_TYPE);
298     ASSERT(sf.SrcValue() != compiler::GetInvalidReg() && sf.DstValue() != compiler::GetInvalidReg());
299 
300     if (sf.SrcValue() == sf.DstValue()) {
301         return;
302     }
303 
304     pandasm::Ins move;
305     switch (sf.GetType()) {
306         case compiler::DataType::INT64:
307         case compiler::DataType::UINT64:
308         case compiler::DataType::FLOAT64:
309             move = pandasm::Create_MOV_64(sf.DstValue(), sf.SrcValue());
310             break;
311         case compiler::DataType::REFERENCE:
312             move = pandasm::Create_MOV_OBJ(sf.DstValue(), sf.SrcValue());
313             break;
314         default:
315             move = pandasm::Create_MOV(sf.DstValue(), sf.SrcValue());
316     }
317     result_.emplace_back(move);
318 }
319 
VisitSpillFill(GraphVisitor * visitor,Inst * inst)320 void CodeGenStatic::VisitSpillFill(GraphVisitor *visitor, Inst *inst)
321 {
322     auto *enc = static_cast<CodeGenStatic *>(visitor);
323     for (auto sf : inst->CastToSpillFill()->GetSpillFills()) {
324         enc->EncodeSpillFillData(sf);
325     }
326 }
327 
328 template <typename UnaryPred>
HasUserPredicate(Inst * inst,UnaryPred p)329 bool HasUserPredicate(Inst *inst, UnaryPred p)
330 {
331     bool found = false;
332     for (auto const &u : inst->GetUsers()) {
333         if (p(u.GetInst())) {
334             found = true;
335             break;
336         }
337     }
338     return found;
339 }
340 
VisitConstant32(compiler::Inst * inst,std::vector<pandasm::Ins> & res)341 static void VisitConstant32(compiler::Inst *inst, std::vector<pandasm::Ins> &res)
342 {
343     auto type = inst->GetType();
344     ASSERT(compiler::DataType::Is32Bits(type, Arch::NONE));
345 
346     pandasm::Ins movi;
347     auto dstReg = inst->GetDstReg();
348     movi.regs.emplace_back(inst->GetDstReg());
349 
350     switch (type) {
351         case compiler::DataType::BOOL:
352         case compiler::DataType::INT8:
353         case compiler::DataType::UINT8:
354         case compiler::DataType::INT16:
355         case compiler::DataType::UINT16:
356         case compiler::DataType::INT32:
357         case compiler::DataType::UINT32:
358             if (dstReg == compiler::GetAccReg()) {
359                 pandasm::Ins ldai = pandasm::Create_LDAI(inst->CastToConstant()->GetInt32Value());
360                 res.emplace_back(ldai);
361             } else {
362                 movi = pandasm::Create_MOVI(dstReg, inst->CastToConstant()->GetInt32Value());
363                 res.emplace_back(movi);
364             }
365             break;
366         case compiler::DataType::FLOAT32:
367             if (dstReg == compiler::GetAccReg()) {
368                 pandasm::Ins ldai = pandasm::Create_FLDAI(inst->CastToConstant()->GetFloatValue());
369                 res.emplace_back(ldai);
370             } else {
371                 movi = pandasm::Create_FMOVI(dstReg, inst->CastToConstant()->GetFloatValue());
372                 res.emplace_back(movi);
373             }
374             break;
375         default:
376             UNREACHABLE();
377     }
378 }
379 
VisitConstant64(compiler::Inst * inst,std::vector<pandasm::Ins> & res)380 static void VisitConstant64(compiler::Inst *inst, std::vector<pandasm::Ins> &res)
381 {
382     auto type = inst->GetType();
383     ASSERT(compiler::DataType::Is64Bits(type, Arch::NONE));
384 
385     pandasm::Ins movi;
386     auto dstReg = inst->GetDstReg();
387     movi.regs.emplace_back(inst->GetDstReg());
388 
389     switch (type) {
390         case compiler::DataType::INT64:
391         case compiler::DataType::UINT64:
392             if (dstReg == compiler::GetAccReg()) {
393                 pandasm::Ins ldai = pandasm::Create_LDAI_64(inst->CastToConstant()->GetInt64Value());
394                 res.emplace_back(ldai);
395             } else {
396                 movi = pandasm::Create_MOVI_64(dstReg, inst->CastToConstant()->GetInt64Value());
397                 res.emplace_back(movi);
398             }
399             break;
400         case compiler::DataType::FLOAT64:
401             if (dstReg == compiler::GetAccReg()) {
402                 pandasm::Ins ldai = pandasm::Create_FLDAI_64(inst->CastToConstant()->GetDoubleValue());
403                 res.emplace_back(ldai);
404             } else {
405                 movi = pandasm::Create_FMOVI_64(dstReg, inst->CastToConstant()->GetDoubleValue());
406                 res.emplace_back(movi);
407             }
408             break;
409         default:
410             UNREACHABLE();
411     }
412 }
413 
VisitConstant(GraphVisitor * visitor,Inst * inst)414 void CodeGenStatic::VisitConstant(GraphVisitor *visitor, Inst *inst)
415 {
416     auto *enc = static_cast<CodeGenStatic *>(visitor);
417     auto type = inst->GetType();
418 
419     switch (type) {
420         case compiler::DataType::BOOL:
421         case compiler::DataType::INT8:
422         case compiler::DataType::UINT8:
423         case compiler::DataType::INT16:
424         case compiler::DataType::UINT16:
425         case compiler::DataType::INT32:
426         case compiler::DataType::UINT32:
427         case compiler::DataType::FLOAT32:
428             VisitConstant32(inst, enc->result_);
429             break;
430         case compiler::DataType::INT64:
431         case compiler::DataType::UINT64:
432         case compiler::DataType::FLOAT64:
433             VisitConstant64(inst, enc->result_);
434             break;
435         case compiler::DataType::ANY: {
436             UNREACHABLE();
437         }
438         default:
439             UNREACHABLE();
440             std::cerr << "VisitConstant with unknown type" << type << std::endl;
441             enc->success_ = false;
442     }
443 }
444 
EncodeSta(compiler::Register reg,compiler::DataType::Type type)445 void CodeGenStatic::EncodeSta(compiler::Register reg, compiler::DataType::Type type)
446 {
447     pandasm::Opcode opc;
448     switch (type) {
449         case compiler::DataType::BOOL:
450         case compiler::DataType::UINT8:
451         case compiler::DataType::INT8:
452         case compiler::DataType::UINT16:
453         case compiler::DataType::INT16:
454         case compiler::DataType::UINT32:
455         case compiler::DataType::INT32:
456         case compiler::DataType::FLOAT32:
457             opc = pandasm::Opcode::STA;
458             break;
459         case compiler::DataType::UINT64:
460         case compiler::DataType::INT64:
461         case compiler::DataType::FLOAT64:
462             opc = pandasm::Opcode::STA_64;
463             break;
464         case compiler::DataType::ANY:
465             opc = pandasm::Opcode::STA_DYN;
466             break;
467         case compiler::DataType::REFERENCE:
468             opc = pandasm::Opcode::STA_OBJ;
469             break;
470         default:
471             UNREACHABLE();
472             std::cerr << "EncodeSta with unknown type" << type << std::endl;
473             success_ = false;
474     }
475     pandasm::Ins sta;
476     sta.opcode = opc;
477     sta.regs.emplace_back(reg);
478 
479     result_.emplace_back(sta);
480 }
481 
ChooseCallOpcode(compiler::Opcode op,size_t nargs)482 static pandasm::Opcode ChooseCallOpcode(compiler::Opcode op, size_t nargs)
483 {
484     ASSERT(op == compiler::Opcode::CallStatic || op == compiler::Opcode::CallVirtual ||
485            op == compiler::Opcode::Intrinsic);
486     if (nargs > MAX_NUM_NON_RANGE_ARGS) {
487         switch (op) {
488             case compiler::Opcode::CallStatic:
489                 return pandasm::Opcode::CALL_RANGE;
490             case compiler::Opcode::CallVirtual:
491                 return pandasm::Opcode::CALL_VIRT_RANGE;
492             case compiler::Opcode::Intrinsic:
493                 return pandasm::Opcode::INITOBJ_RANGE;
494             default:
495                 UNREACHABLE();
496         }
497     } else if (nargs > MAX_NUM_SHORT_CALL_ARGS) {
498         switch (op) {
499             case compiler::Opcode::CallStatic:
500                 return pandasm::Opcode::CALL;
501             case compiler::Opcode::CallVirtual:
502                 return pandasm::Opcode::CALL_VIRT;
503             case compiler::Opcode::Intrinsic:
504                 return pandasm::Opcode::INITOBJ;
505             default:
506                 UNREACHABLE();
507         }
508     }
509     switch (op) {
510         case compiler::Opcode::CallStatic:
511             return pandasm::Opcode::CALL_SHORT;
512         case compiler::Opcode::CallVirtual:
513             return pandasm::Opcode::CALL_VIRT_SHORT;
514         case compiler::Opcode::Intrinsic:
515             return pandasm::Opcode::INITOBJ_SHORT;
516         default:
517             UNREACHABLE();
518     }
519 }
520 
ChooseCallAccOpcode(pandasm::Opcode op)521 static pandasm::Opcode ChooseCallAccOpcode(pandasm::Opcode op)
522 {
523     switch (op) {
524         case pandasm::Opcode::CALL_SHORT:
525             return pandasm::Opcode::CALL_ACC_SHORT;
526         case pandasm::Opcode::CALL:
527             return pandasm::Opcode::CALL_ACC;
528         case pandasm::Opcode::CALL_VIRT_SHORT:
529             return pandasm::Opcode::CALL_VIRT_ACC_SHORT;
530         case pandasm::Opcode::CALL_VIRT:
531             return pandasm::Opcode::CALL_VIRT_ACC;
532         default:
533             return pandasm::Opcode::INVALID;
534     }
535 }
536 
CastToCall(ark::compiler::Inst * inst)537 static ark::compiler::CallInst *CastToCall(ark::compiler::Inst *inst)
538 {
539     switch (inst->GetOpcode()) {
540         case compiler::Opcode::CallStatic:
541             return inst->CastToCallStatic();
542         case compiler::Opcode::CallVirtual:
543             return inst->CastToCallVirtual();
544         default:
545             UNREACHABLE();
546     }
547 }
548 
CallHandler(GraphVisitor * visitor,Inst * inst,std::string methodId)549 void CodeGenStatic::CallHandler(GraphVisitor *visitor, Inst *inst, std::string methodId)
550 {
551     auto op = inst->GetOpcode();
552     ASSERT(op == compiler::Opcode::CallStatic || op == compiler::Opcode::CallVirtual ||
553            op == compiler::Opcode::Intrinsic);
554     auto *enc = static_cast<CodeGenStatic *>(visitor);
555     auto sfCount = inst->GetInputsCount() - (inst->RequireState() ? 1U : 0U);
556     size_t start = 0U;
557     auto nargs = sfCount;
558     pandasm::Ins ins;
559 
560     ins.opcode = ChooseCallOpcode(op, nargs);
561 
562     if (nargs > MAX_NUM_NON_RANGE_ARGS) {
563 #ifndef NDEBUG
564         auto startReg = inst->GetSrcReg(start);
565         ASSERT(startReg <= MAX_8_BIT_REG);
566         for (auto i = start; i < sfCount; ++i) {
567             auto reg = inst->GetSrcReg(i);
568             ASSERT(reg - startReg == static_cast<int>(i - start));  // check 'range-ness' of registers
569         }
570 #endif  // !NDEBUG
571         ins.regs.emplace_back(inst->GetSrcReg(start));
572     } else {
573         for (size_t i = start; i < sfCount; ++i) {
574             auto reg = inst->GetSrcReg(i);
575             ASSERT(reg < NUM_COMPACTLY_ENCODED_REGS || reg == compiler::GetAccReg());
576             if (reg == compiler::GetAccReg()) {
577                 ASSERT(inst->IsCallOrIntrinsic());
578                 ins.imms.emplace_back(static_cast<int64_t>(i));
579                 ins.opcode = ChooseCallAccOpcode(ins.opcode);
580             } else {
581                 ins.regs.emplace_back(reg);
582             }
583         }
584     }
585     ins.ids.emplace_back(std::move(methodId));
586     enc->result_.emplace_back(ins);
587     if (inst->GetDstReg() != compiler::GetInvalidReg() && inst->GetDstReg() != compiler::GetAccReg()) {
588         enc->EncodeSta(inst->GetDstReg(), inst->GetType());
589     }
590 }
591 
CallHandler(GraphVisitor * visitor,Inst * inst)592 void CodeGenStatic::CallHandler(GraphVisitor *visitor, Inst *inst)
593 {
594     auto *enc = static_cast<CodeGenStatic *>(visitor);
595     uint32_t methodOffset = 0;
596     if (inst->IsIntrinsic()) {
597         ASSERT(IsAbcKitInitObject(inst->CastToIntrinsic()->GetIntrinsicId()));
598         methodOffset = inst->CastToIntrinsic()->GetImm(0);
599     } else {
600         methodOffset = CastToCall(inst)->GetCallMethodId();
601     }
602     CallHandler(visitor, inst, enc->irInterface_->GetMethodIdByOffset(methodOffset));
603 }
604 
VisitCallStatic(GraphVisitor * visitor,Inst * inst)605 void CodeGenStatic::VisitCallStatic(GraphVisitor *visitor, Inst *inst)
606 {
607     CallHandler(visitor, inst);
608 }
609 
VisitCallVirtual(GraphVisitor * visitor,Inst * inst)610 void CodeGenStatic::VisitCallVirtual(GraphVisitor *visitor, Inst *inst)
611 {
612     CallHandler(visitor, inst);
613 }
614 
VisitIf32(compiler::IfInst * inst,std::vector<pandasm::Ins> & res,bool & success)615 static void VisitIf32(compiler::IfInst *inst, std::vector<pandasm::Ins> &res, bool &success)
616 {
617     ASSERT(Is32Bits(inst->GetInputType(0U), Arch::NONE));
618 
619     DoLda(inst->GetSrcReg(0U), res);
620 
621     compiler::Register src = inst->GetSrcReg(1);
622     std::string label = CodeGenStatic::LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
623 
624     switch (inst->GetCc()) {
625         case compiler::CC_EQ: {
626             res.emplace_back(pandasm::Create_JEQ(src, label));
627             break;
628         }
629         case compiler::CC_NE: {
630             res.emplace_back(pandasm::Create_JNE(src, label));
631             break;
632         }
633         case compiler::CC_LT: {
634             res.emplace_back(pandasm::Create_JLT(src, label));
635             break;
636         }
637         case compiler::CC_LE: {
638             res.emplace_back(pandasm::Create_JLE(src, label));
639             break;
640         }
641         case compiler::CC_GT: {
642             res.emplace_back(pandasm::Create_JGT(src, label));
643             break;
644         }
645         case compiler::CC_GE: {
646             res.emplace_back(pandasm::Create_JGE(src, label));
647             break;
648         }
649         default:
650             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
651             success = false;
652     }
653 }
654 
VisitIf64Signed(compiler::IfInst * inst,std::vector<pandasm::Ins> & res,bool & success)655 static void VisitIf64Signed(compiler::IfInst *inst, std::vector<pandasm::Ins> &res, bool &success)
656 {
657     ASSERT(Is64Bits(inst->GetInputType(0U), Arch::NONE));
658     ASSERT(IsTypeSigned(inst->GetInputType(0U)));
659 
660     DoLda64(inst->GetSrcReg(0U), res);
661 
662     res.emplace_back(pandasm::Create_CMP_64(inst->GetSrcReg(1U)));
663     std::string label = CodeGenStatic::LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
664 
665     switch (inst->GetCc()) {
666         case compiler::CC_EQ: {
667             res.emplace_back(pandasm::Create_JEQZ(label));
668             break;
669         }
670         case compiler::CC_NE: {
671             res.emplace_back(pandasm::Create_JNEZ(label));
672             break;
673         }
674         case compiler::CC_LT: {
675             res.emplace_back(pandasm::Create_JLTZ(label));
676             break;
677         }
678         case compiler::CC_LE: {
679             res.emplace_back(pandasm::Create_JLEZ(label));
680             break;
681         }
682         case compiler::CC_GT: {
683             res.emplace_back(pandasm::Create_JGTZ(label));
684             break;
685         }
686         case compiler::CC_GE: {
687             res.emplace_back(pandasm::Create_JGEZ(label));
688             break;
689         }
690         default:
691             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
692             success = false;
693     }
694 }
695 
VisitIf64Unsigned(compiler::IfInst * inst,std::vector<pandasm::Ins> & res,bool & success)696 static void VisitIf64Unsigned(compiler::IfInst *inst, std::vector<pandasm::Ins> &res, bool &success)
697 {
698     ASSERT(Is64Bits(inst->GetInputType(0U), Arch::NONE));
699     ASSERT(!IsTypeSigned(inst->GetInputType(0U)));
700 
701     DoLda64(inst->GetSrcReg(0U), res);
702 
703     res.emplace_back(pandasm::Create_UCMP_64(inst->GetSrcReg(1U)));
704     std::string label = CodeGenStatic::LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
705 
706     switch (inst->GetCc()) {
707         case compiler::CC_EQ: {
708             res.emplace_back(pandasm::Create_JEQZ(label));
709             break;
710         }
711         case compiler::CC_NE: {
712             res.emplace_back(pandasm::Create_JNEZ(label));
713             break;
714         }
715         case compiler::CC_LT: {
716             res.emplace_back(pandasm::Create_JLTZ(label));
717             break;
718         }
719         case compiler::CC_LE: {
720             res.emplace_back(pandasm::Create_JLEZ(label));
721             break;
722         }
723         case compiler::CC_GT: {
724             res.emplace_back(pandasm::Create_JGTZ(label));
725             break;
726         }
727         case compiler::CC_GE: {
728             res.emplace_back(pandasm::Create_JGEZ(label));
729             break;
730         }
731         default:
732             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
733             success = false;
734     }
735 }
736 
VisitIfRef(CodeGenStatic * enc,compiler::IfInst * inst,std::vector<pandasm::Ins> & res,bool & success)737 static void VisitIfRef([[maybe_unused]] CodeGenStatic *enc, compiler::IfInst *inst, std::vector<pandasm::Ins> &res,
738                        bool &success)
739 {
740     ASSERT(IsReference(inst->GetInputType(0U)));
741 
742     DoLdaObj(inst->GetSrcReg(0U), res);
743 
744     compiler::Register src = inst->GetSrcReg(1);
745     std::string label = CodeGenStatic::LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
746 
747     switch (inst->GetCc()) {
748         case compiler::CC_EQ: {
749             res.emplace_back(pandasm::Create_JEQ_OBJ(src, label));
750             break;
751         }
752         case compiler::CC_NE: {
753             res.emplace_back(pandasm::Create_JNE_OBJ(src, label));
754             break;
755         }
756         default:
757             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
758             success = false;
759     }
760 }
761 
762 // NOLINTNEXTLINE(readability-function-size)
VisitIf(GraphVisitor * v,Inst * instBase)763 void CodeGenStatic::VisitIf(GraphVisitor *v, Inst *instBase)
764 {
765     auto enc = static_cast<CodeGenStatic *>(v);
766     auto inst = instBase->CastToIf();
767     switch (inst->GetInputType(0U)) {
768         case compiler::DataType::BOOL:
769         case compiler::DataType::UINT8:
770         case compiler::DataType::INT8:
771         case compiler::DataType::UINT16:
772         case compiler::DataType::INT16:
773         case compiler::DataType::UINT32:
774         case compiler::DataType::INT32: {
775             VisitIf32(inst, enc->result_, enc->success_);
776             break;
777         }
778         case compiler::DataType::INT64: {
779             VisitIf64Signed(inst, enc->result_, enc->success_);
780             break;
781         }
782         case compiler::DataType::UINT64: {
783             VisitIf64Unsigned(inst, enc->result_, enc->success_);
784             break;
785         }
786         case compiler::DataType::REFERENCE: {
787             VisitIfRef(enc, inst, enc->result_, enc->success_);
788             break;
789         }
790         case compiler::DataType::ANY: {
791             UNREACHABLE();
792         }
793         default:
794             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
795             enc->success_ = false;
796     }
797 }
798 
VisitIfImm(GraphVisitor * v,Inst * instBase)799 void CodeGenStatic::VisitIfImm(GraphVisitor *v, Inst *instBase)
800 {
801     auto inst = instBase->CastToIfImm();
802     auto imm = inst->GetImm();
803     if (imm == 0U) {
804         IfImmZero(v, instBase);
805         return;
806     }
807     IfImmNonZero(v, instBase);
808 }
809 
IfImmZero32(compiler::IfImmInst * inst,std::vector<pandasm::Ins> & res,bool & success)810 static void IfImmZero32(compiler::IfImmInst *inst, std::vector<pandasm::Ins> &res, bool &success)
811 {
812     ASSERT(Is32Bits(inst->GetInputType(0U), Arch::NONE));
813 
814     DoLda(inst->GetSrcReg(0U), res);
815 
816     std::string label = CodeGenStatic::LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
817 
818     switch (inst->GetCc()) {
819         case compiler::CC_EQ: {
820             res.emplace_back(pandasm::Create_JEQZ(label));
821             break;
822         }
823         case compiler::CC_NE: {
824             res.emplace_back(pandasm::Create_JNEZ(label));
825             break;
826         }
827         case compiler::CC_LT: {
828             res.emplace_back(pandasm::Create_JLTZ(label));
829             break;
830         }
831         case compiler::CC_LE: {
832             res.emplace_back(pandasm::Create_JLEZ(label));
833             break;
834         }
835         case compiler::CC_GT: {
836             res.emplace_back(pandasm::Create_JGTZ(label));
837             break;
838         }
839         case compiler::CC_GE: {
840             res.emplace_back(pandasm::Create_JGEZ(label));
841             break;
842         }
843         default:
844             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
845             success = false;
846     }
847 }
848 
IfImmZeroRef(compiler::IfImmInst * inst,std::vector<pandasm::Ins> & res,bool & success)849 static void IfImmZeroRef(compiler::IfImmInst *inst, std::vector<pandasm::Ins> &res, bool &success)
850 {
851     ASSERT(IsReference(inst->GetInputType(0U)));
852 
853     DoLdaObj(inst->GetSrcReg(0U), res);
854 
855     std::string label = CodeGenStatic::LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
856 
857     switch (inst->GetCc()) {
858         case compiler::CC_EQ: {
859             res.emplace_back(pandasm::Create_JEQZ_OBJ(label));
860             break;
861         }
862         case compiler::CC_NE: {
863             res.emplace_back(pandasm::Create_JNEZ_OBJ(label));
864             break;
865         }
866         default:
867             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
868             success = false;
869     }
870 }
871 
872 // NOLINTNEXTLINE(readability-function-size)
IfImmZero(GraphVisitor * v,Inst * instBase)873 void CodeGenStatic::IfImmZero(GraphVisitor *v, Inst *instBase)
874 {
875     auto enc = static_cast<CodeGenStatic *>(v);
876     auto inst = instBase->CastToIfImm();
877     switch (inst->GetInputType(0U)) {
878         case compiler::DataType::BOOL:
879         case compiler::DataType::UINT8:
880         case compiler::DataType::INT8:
881         case compiler::DataType::UINT16:
882         case compiler::DataType::INT16:
883         case compiler::DataType::UINT32:
884         case compiler::DataType::INT32: {
885             IfImmZero32(inst, enc->result_, enc->success_);
886             break;
887         }
888         case compiler::DataType::INT64:
889         case compiler::DataType::UINT64: {
890             IfImm64(v, instBase);
891             break;
892         }
893         case compiler::DataType::REFERENCE: {
894             IfImmZeroRef(inst, enc->result_, enc->success_);
895             break;
896         }
897         default:
898             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
899             enc->success_ = false;
900     }
901 }
902 
IfImmNonZero32(compiler::IfImmInst * inst,std::vector<pandasm::Ins> & res,bool & success)903 static void IfImmNonZero32(compiler::IfImmInst *inst, std::vector<pandasm::Ins> &res, bool &success)
904 {
905     ASSERT(Is32Bits(inst->GetInputType(0U), Arch::NONE));
906 
907     res.emplace_back(pandasm::Create_LDAI(inst->GetImm()));
908 
909     compiler::Register src = inst->GetSrcReg(0);
910     std::string label = CodeGenStatic::LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
911 
912     switch (inst->GetCc()) {
913         case compiler::CC_EQ: {
914             res.emplace_back(pandasm::Create_JEQ(src, label));
915             break;
916         }
917         case compiler::CC_NE: {
918             res.emplace_back(pandasm::Create_JNE(src, label));
919             break;
920         }
921         case compiler::CC_LT: {
922             res.emplace_back(pandasm::Create_JLT(src, label));
923             break;
924         }
925         case compiler::CC_LE: {
926             res.emplace_back(pandasm::Create_JLE(src, label));
927             break;
928         }
929         case compiler::CC_GT: {
930             res.emplace_back(pandasm::Create_JGT(src, label));
931             break;
932         }
933         case compiler::CC_GE: {
934             res.emplace_back(pandasm::Create_JGE(src, label));
935             break;
936         }
937         default:
938             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
939             success = false;
940     }
941 }
942 
943 // NOLINTNEXTLINE(readability-function-size)
IfImmNonZero(GraphVisitor * v,Inst * instBase)944 void CodeGenStatic::IfImmNonZero(GraphVisitor *v, Inst *instBase)
945 {
946     auto enc = static_cast<CodeGenStatic *>(v);
947     auto inst = instBase->CastToIfImm();
948     switch (inst->GetInputType(0U)) {
949         case compiler::DataType::BOOL:
950         case compiler::DataType::UINT8:
951         case compiler::DataType::INT8:
952         case compiler::DataType::UINT16:
953         case compiler::DataType::INT16:
954         case compiler::DataType::UINT32:
955         case compiler::DataType::INT32: {
956             IfImmNonZero32(inst, enc->result_, enc->success_);
957             break;
958         }
959         case compiler::DataType::INT64:
960         case compiler::DataType::UINT64: {
961             IfImm64(v, instBase);
962             break;
963         }
964         case compiler::DataType::REFERENCE: {
965             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
966             std::cerr << "VisitIfImm does not support non-zero imm of type reference, as no pandasm matches";
967             enc->success_ = false;
968             break;
969         }
970         default:
971             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
972             enc->success_ = false;
973     }
974 }
975 
976 // NOLINTNEXTLINE(readability-function-size)
IfImm64(GraphVisitor * v,Inst * instBase)977 void CodeGenStatic::IfImm64(GraphVisitor *v, Inst *instBase)
978 {
979     auto enc = static_cast<CodeGenStatic *>(v);
980     auto inst = instBase->CastToIfImm();
981 
982     enc->result_.emplace_back(pandasm::Create_LDAI_64(inst->GetImm()));
983 
984     std::string label = LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
985 
986     switch (inst->GetInputType(0U)) {
987         case compiler::DataType::INT64: {
988             enc->result_.emplace_back(pandasm::Create_CMP_64(inst->GetSrcReg(0U)));
989             break;
990         }
991         case compiler::DataType::UINT64: {
992             enc->result_.emplace_back(pandasm::Create_UCMP_64(inst->GetSrcReg(0U)));
993             break;
994         }
995         default:
996             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
997             enc->success_ = false;
998             return;
999     }
1000 
1001     switch (inst->GetCc()) {
1002         case compiler::CC_EQ: {
1003             enc->result_.emplace_back(pandasm::Create_JEQZ(label));
1004             break;
1005         }
1006         case compiler::CC_NE: {
1007             enc->result_.emplace_back(pandasm::Create_JNEZ(label));
1008             break;
1009         }
1010         case compiler::CC_LT: {
1011             enc->result_.emplace_back(pandasm::Create_JGTZ(label));
1012             break;
1013         }
1014         case compiler::CC_LE: {
1015             enc->result_.emplace_back(pandasm::Create_JGEZ(label));
1016             break;
1017         }
1018         case compiler::CC_GT: {
1019             enc->result_.emplace_back(pandasm::Create_JLTZ(label));
1020             break;
1021         }
1022         case compiler::CC_GE: {
1023             enc->result_.emplace_back(pandasm::Create_JLEZ(label));
1024             break;
1025         }
1026         default:
1027             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1028             enc->success_ = false;
1029             return;
1030     }
1031 }
1032 
CastAccDownFromI32(compiler::DataType::Type type,std::vector<pandasm::Ins> & res)1033 static void CastAccDownFromI32(compiler::DataType::Type type, std::vector<pandasm::Ins> &res)
1034 {
1035     auto sizeBits = compiler::DataType::GetTypeSize(type, Arch::NONE);
1036     if (compiler::DataType::IsTypeSigned(type)) {
1037         auto shift = compiler::WORD_SIZE - sizeBits;
1038         res.emplace_back(pandasm::Create_SHLI(shift));
1039         res.emplace_back(pandasm::Create_ASHRI(shift));
1040     } else {
1041         auto andMask = (1U << sizeBits) - 1U;
1042         res.emplace_back(pandasm::Create_ANDI(andMask));
1043     }
1044 }
1045 
VisitCastFromI32(CodeGenStatic * enc,compiler::CastInst * inst,std::vector<pandasm::Ins> & res,bool & success)1046 static void VisitCastFromI32([[maybe_unused]] CodeGenStatic *enc, compiler::CastInst *inst,
1047                              std::vector<pandasm::Ins> &res, bool &success)
1048 {
1049     ASSERT(Is32Bits(inst->GetInputType(0U), Arch::NONE));
1050 
1051     if (inst->GetType() == compiler::DataType::UINT32) {
1052         return;
1053     }
1054     DoLda(inst->GetSrcReg(0U), res);
1055 
1056     switch (inst->GetType()) {
1057         case compiler::DataType::FLOAT32: {
1058             res.emplace_back(pandasm::Create_I32TOF32());
1059             break;
1060         }
1061         case compiler::DataType::FLOAT64: {
1062             res.emplace_back(pandasm::Create_I32TOF64());
1063             break;
1064         }
1065         case compiler::DataType::INT64: {
1066             res.emplace_back(pandasm::Create_I32TOI64());
1067             break;
1068         }
1069         case compiler::DataType::INT16:
1070         case compiler::DataType::UINT16:
1071         case compiler::DataType::INT8:
1072         case compiler::DataType::UINT8: {
1073             CastAccDownFromI32(inst->GetType(), res);
1074             break;
1075         }
1076         case compiler::DataType::ANY: {
1077             UNREACHABLE();
1078         }
1079         default:
1080             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1081             success = false;
1082             return;
1083     }
1084     DoSta(inst->GetType(), inst->GetDstReg(), res);
1085 }
1086 
VisitCastFromU32(CodeGenStatic * enc,compiler::CastInst * inst,std::vector<pandasm::Ins> & res,bool & success)1087 static void VisitCastFromU32([[maybe_unused]] CodeGenStatic *enc, compiler::CastInst *inst,
1088                              std::vector<pandasm::Ins> &res, bool &success)
1089 {
1090     ASSERT(Is32Bits(inst->GetInputType(0U), Arch::NONE));
1091 
1092     if (inst->GetType() == compiler::DataType::INT32) {
1093         return;
1094     }
1095     DoLda(inst->GetSrcReg(0U), res);
1096 
1097     switch (inst->GetType()) {
1098         case compiler::DataType::FLOAT32: {
1099             res.emplace_back(pandasm::Create_U32TOF32());
1100             break;
1101         }
1102         case compiler::DataType::FLOAT64: {
1103             res.emplace_back(pandasm::Create_U32TOF64());
1104             break;
1105         }
1106         case compiler::DataType::INT64: {
1107             res.emplace_back(pandasm::Create_U32TOI64());
1108             break;
1109         }
1110         case compiler::DataType::INT16:
1111         case compiler::DataType::UINT16:
1112         case compiler::DataType::INT8:
1113         case compiler::DataType::UINT8: {
1114             CastAccDownFromI32(inst->GetType(), res);
1115             break;
1116         }
1117         case compiler::DataType::ANY: {
1118             UNREACHABLE();
1119         }
1120         default:
1121             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1122             success = false;
1123             return;
1124     }
1125     DoSta(inst->GetType(), inst->GetDstReg(), res);
1126 }
1127 
VisitCastFromI64(CodeGenStatic * enc,compiler::CastInst * inst,std::vector<pandasm::Ins> & res,bool & success)1128 static void VisitCastFromI64([[maybe_unused]] CodeGenStatic *enc, compiler::CastInst *inst,
1129                              std::vector<pandasm::Ins> &res, bool &success)
1130 {
1131     ASSERT(Is64Bits(inst->GetInputType(0U), Arch::NONE));
1132     constexpr int64_t ANDI_32 = 0xffffffff;
1133 
1134     DoLda64(inst->GetSrcReg(0U), res);
1135 
1136     switch (inst->GetType()) {
1137         case compiler::DataType::INT32: {
1138             res.emplace_back(pandasm::Create_I64TOI32());
1139             break;
1140         }
1141         case compiler::DataType::UINT32: {
1142             res.emplace_back(pandasm::Create_ANDI(ANDI_32));
1143             break;
1144         }
1145         case compiler::DataType::FLOAT32: {
1146             res.emplace_back(pandasm::Create_I64TOF32());
1147             break;
1148         }
1149         case compiler::DataType::FLOAT64: {
1150             res.emplace_back(pandasm::Create_I64TOF64());
1151             break;
1152         }
1153         case compiler::DataType::INT16:
1154         case compiler::DataType::UINT16:
1155         case compiler::DataType::INT8:
1156         case compiler::DataType::UINT8: {
1157             res.emplace_back(pandasm::Create_I64TOI32());
1158             CastAccDownFromI32(inst->GetType(), res);
1159             break;
1160         }
1161         case compiler::DataType::ANY: {
1162             UNREACHABLE();
1163         }
1164         default:
1165             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1166             success = false;
1167             return;
1168     }
1169     DoSta(inst->GetType(), inst->GetDstReg(), res);
1170 }
1171 
VisitCastFromF32(CodeGenStatic * enc,compiler::CastInst * inst,std::vector<pandasm::Ins> & res,bool & success)1172 static void VisitCastFromF32([[maybe_unused]] CodeGenStatic *enc, compiler::CastInst *inst,
1173                              std::vector<pandasm::Ins> &res, bool &success)
1174 {
1175     ASSERT(Is32Bits(inst->GetInputType(0U), Arch::NONE));
1176     ASSERT(IsFloatType(inst->GetInputType(0U)));
1177 
1178     constexpr int64_t ANDI_32 = 0xffffffff;
1179 
1180     DoLda(inst->GetSrcReg(0U), res);
1181 
1182     switch (inst->GetType()) {
1183         case compiler::DataType::FLOAT64: {
1184             res.emplace_back(pandasm::Create_F32TOF64());
1185             break;
1186         }
1187         case compiler::DataType::INT64: {
1188             res.emplace_back(pandasm::Create_F32TOI64());
1189             break;
1190         }
1191         case compiler::DataType::UINT64: {
1192             res.emplace_back(pandasm::Create_F32TOU64());
1193             break;
1194         }
1195         case compiler::DataType::INT32: {
1196             res.emplace_back(pandasm::Create_F32TOI32());
1197             break;
1198         }
1199         case compiler::DataType::UINT32: {
1200             res.emplace_back(pandasm::Create_F32TOU32());
1201             res.emplace_back(pandasm::Create_ANDI(ANDI_32));
1202             break;
1203         }
1204         case compiler::DataType::ANY: {
1205             UNREACHABLE();
1206         }
1207         default:
1208             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1209             success = false;
1210             return;
1211     }
1212     DoSta(inst->GetType(), inst->GetDstReg(), res);
1213 }
1214 
VisitCastFromF64(CodeGenStatic * enc,compiler::CastInst * inst,std::vector<pandasm::Ins> & res,bool & success)1215 static void VisitCastFromF64([[maybe_unused]] CodeGenStatic *enc, compiler::CastInst *inst,
1216                              std::vector<pandasm::Ins> &res, bool &success)
1217 {
1218     ASSERT(Is64Bits(inst->GetInputType(0U), Arch::NONE));
1219     ASSERT(IsFloatType(inst->GetInputType(0U)));
1220 
1221     constexpr int64_t ANDI_32 = 0xffffffff;
1222 
1223     DoLda64(inst->GetSrcReg(0U), res);
1224 
1225     switch (inst->GetType()) {
1226         case compiler::DataType::FLOAT32: {
1227             res.emplace_back(pandasm::Create_F64TOF32());
1228             break;
1229         }
1230         case compiler::DataType::INT64: {
1231             res.emplace_back(pandasm::Create_F64TOI64());
1232             break;
1233         }
1234         case compiler::DataType::INT32: {
1235             res.emplace_back(pandasm::Create_F64TOI32());
1236             break;
1237         }
1238         case compiler::DataType::UINT32: {
1239             res.emplace_back(pandasm::Create_F64TOI64());
1240             res.emplace_back(pandasm::Create_ANDI(ANDI_32));
1241             break;
1242         }
1243         case compiler::DataType::ANY: {
1244             UNREACHABLE();
1245         }
1246         default:
1247             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1248             success = false;
1249             return;
1250     }
1251     DoSta(inst->GetType(), inst->GetDstReg(), res);
1252 }
1253 
1254 // NOLINTNEXTLINE(readability-function-size)
VisitCast(GraphVisitor * v,Inst * instBase)1255 void CodeGenStatic::VisitCast(GraphVisitor *v, Inst *instBase)
1256 {
1257     auto enc = static_cast<CodeGenStatic *>(v);
1258     auto inst = instBase->CastToCast();
1259     switch (inst->GetInputType(0U)) {
1260         case compiler::DataType::INT32: {
1261             VisitCastFromI32(enc, inst, enc->result_, enc->success_);
1262             break;
1263         }
1264         case compiler::DataType::UINT32: {
1265             VisitCastFromU32(enc, inst, enc->result_, enc->success_);
1266             break;
1267         }
1268         case compiler::DataType::INT64: {
1269             VisitCastFromI64(enc, inst, enc->result_, enc->success_);
1270             break;
1271         }
1272         case compiler::DataType::FLOAT32: {
1273             VisitCastFromF32(enc, inst, enc->result_, enc->success_);
1274             break;
1275         }
1276         case compiler::DataType::FLOAT64: {
1277             VisitCastFromF64(enc, inst, enc->result_, enc->success_);
1278             break;
1279         }
1280         case compiler::DataType::REFERENCE: {
1281             switch (inst->GetType()) {
1282                 case compiler::DataType::ANY: {
1283                     UNREACHABLE();
1284                 }
1285                 default:
1286                     std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1287                     enc->success_ = false;
1288             }
1289             break;
1290         }
1291         default:
1292             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1293             enc->success_ = false;
1294     }
1295 }
1296 
VisitReturn(GraphVisitor * v,Inst * instBase)1297 void CodeGenStatic::VisitReturn(GraphVisitor *v, Inst *instBase)
1298 {
1299     pandasm::Ins ins;
1300     auto enc = static_cast<CodeGenStatic *>(v);
1301     auto inst = instBase->CastToReturn();
1302     switch (inst->GetType()) {
1303         case compiler::DataType::BOOL:
1304         case compiler::DataType::UINT8:
1305         case compiler::DataType::INT8:
1306         case compiler::DataType::UINT16:
1307         case compiler::DataType::INT16:
1308         case compiler::DataType::UINT32:
1309         case compiler::DataType::INT32:
1310         case compiler::DataType::FLOAT32: {
1311             DoLda(inst->GetSrcReg(0U), enc->result_);
1312             enc->result_.emplace_back(pandasm::Create_RETURN());
1313             break;
1314         }
1315         case compiler::DataType::INT64:
1316         case compiler::DataType::UINT64:
1317         case compiler::DataType::FLOAT64: {
1318             DoLda64(inst->GetSrcReg(0U), enc->result_);
1319             enc->result_.emplace_back(pandasm::Create_RETURN_64());
1320             break;
1321         }
1322         case compiler::DataType::REFERENCE: {
1323             DoLdaObj(inst->GetSrcReg(0U), enc->result_);
1324             enc->result_.emplace_back(pandasm::Create_RETURN_OBJ());
1325             break;
1326         }
1327         case compiler::DataType::VOID: {
1328             enc->result_.emplace_back(pandasm::Create_RETURN_VOID());
1329             break;
1330         }
1331         case compiler::DataType::ANY: {
1332             UNREACHABLE();
1333             break;
1334         }
1335         default:
1336             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1337             enc->success_ = false;
1338     }
1339 }
1340 
1341 // NOLINTNEXTLINE(readability-function-size)
VisitStoreObjectIntrinsic(GraphVisitor * v,Inst * instBase)1342 void CodeGenStatic::VisitStoreObjectIntrinsic(GraphVisitor *v, Inst *instBase)
1343 {
1344     auto enc = static_cast<CodeGenStatic *>(v);
1345     const compiler::IntrinsicInst *inst = instBase->CastToIntrinsic();
1346 
1347     compiler::Register vd = inst->GetSrcReg(1U);
1348     compiler::Register vs = inst->GetSrcReg(0U);
1349     std::string id = enc->irInterface_->GetFieldIdByOffset(inst->GetImm(0));
1350 
1351     bool isAccType = (vs == compiler::GetAccReg());
1352 
1353     switch (inst->GetType()) {
1354         case compiler::DataType::BOOL:
1355         case compiler::DataType::UINT8:
1356         case compiler::DataType::INT8:
1357         case compiler::DataType::UINT16:
1358         case compiler::DataType::INT16:
1359         case compiler::DataType::UINT32:
1360         case compiler::DataType::INT32:
1361         case compiler::DataType::FLOAT32:
1362             if (isAccType) {
1363                 enc->result_.emplace_back(pandasm::Create_STOBJ(vd, id));
1364             } else {
1365                 enc->result_.emplace_back(pandasm::Create_STOBJ_V(vd, vs, id));
1366             }
1367             break;
1368         case compiler::DataType::INT64:
1369         case compiler::DataType::UINT64:
1370         case compiler::DataType::FLOAT64:
1371             if (isAccType) {
1372                 enc->result_.emplace_back(pandasm::Create_STOBJ_64(vd, id));
1373             } else {
1374                 enc->result_.emplace_back(pandasm::Create_STOBJ_V_64(vd, vs, id));
1375             }
1376             break;
1377         case compiler::DataType::REFERENCE:
1378             if (isAccType) {
1379                 enc->result_.emplace_back(pandasm::Create_STOBJ_OBJ(vd, id));
1380             } else {
1381                 enc->result_.emplace_back(pandasm::Create_STOBJ_V_OBJ(vd, vs, id));
1382             }
1383             break;
1384         default:
1385             std::cerr << "Wrong DataType for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1386             enc->success_ = false;
1387     }
1388 }
1389 
VisitStoreStaticIntrinsic(GraphVisitor * v,Inst * instBase)1390 void CodeGenStatic::VisitStoreStaticIntrinsic(GraphVisitor *v, Inst *instBase)
1391 {
1392     auto enc = static_cast<CodeGenStatic *>(v);
1393     auto inst = instBase->CastToIntrinsic();
1394 
1395     compiler::Register vs = inst->GetSrcReg(0U);
1396     std::string id = enc->irInterface_->GetFieldIdByOffset(inst->GetImm(0));
1397 
1398     switch (inst->GetType()) {
1399         case compiler::DataType::BOOL:
1400         case compiler::DataType::UINT8:
1401         case compiler::DataType::INT8:
1402         case compiler::DataType::UINT16:
1403         case compiler::DataType::INT16:
1404         case compiler::DataType::UINT32:
1405         case compiler::DataType::INT32:
1406         case compiler::DataType::FLOAT32:
1407             DoLda(vs, enc->result_);
1408             enc->result_.emplace_back(pandasm::Create_STSTATIC(id));
1409             break;
1410         case compiler::DataType::INT64:
1411         case compiler::DataType::UINT64:
1412         case compiler::DataType::FLOAT64:
1413             DoLda64(vs, enc->result_);
1414             enc->result_.emplace_back(pandasm::Create_STSTATIC_64(id));
1415             break;
1416         case compiler::DataType::REFERENCE:
1417             DoLdaObj(vs, enc->result_);
1418             enc->result_.emplace_back(pandasm::Create_STSTATIC_OBJ(id));
1419             break;
1420         default:
1421             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1422             enc->success_ = false;
1423     }
1424 }
1425 
VisitLoadObjectIntrinsic(GraphVisitor * v,Inst * instBase)1426 void CodeGenStatic::VisitLoadObjectIntrinsic(GraphVisitor *v, Inst *instBase)
1427 {
1428     auto enc = static_cast<CodeGenStatic *>(v);
1429     auto inst = instBase->CastToIntrinsic();
1430 
1431     compiler::Register vs = inst->GetSrcReg(0U);
1432     compiler::Register vd = inst->GetDstReg();
1433     std::string id = enc->irInterface_->GetFieldIdByOffset(inst->GetImm(0));
1434 
1435     bool isAccType = (inst->GetDstReg() == compiler::GetAccReg());
1436 
1437     switch (inst->GetType()) {
1438         case compiler::DataType::BOOL:
1439         case compiler::DataType::UINT8:
1440         case compiler::DataType::INT8:
1441         case compiler::DataType::UINT16:
1442         case compiler::DataType::INT16:
1443         case compiler::DataType::UINT32:
1444         case compiler::DataType::INT32:
1445         case compiler::DataType::FLOAT32:
1446             if (isAccType) {
1447                 enc->result_.emplace_back(pandasm::Create_LDOBJ(vs, id));
1448             } else {
1449                 enc->result_.emplace_back(pandasm::Create_LDOBJ_V(vd, vs, id));
1450             }
1451             break;
1452         case compiler::DataType::INT64:
1453         case compiler::DataType::UINT64:
1454         case compiler::DataType::FLOAT64:
1455             if (isAccType) {
1456                 enc->result_.emplace_back(pandasm::Create_LDOBJ_64(vs, id));
1457             } else {
1458                 enc->result_.emplace_back(pandasm::Create_LDOBJ_V_64(vd, vs, id));
1459             }
1460             break;
1461         case compiler::DataType::REFERENCE:
1462             if (isAccType) {
1463                 enc->result_.emplace_back(pandasm::Create_LDOBJ_OBJ(vs, id));
1464             } else {
1465                 enc->result_.emplace_back(pandasm::Create_LDOBJ_V_OBJ(vd, vs, id));
1466             }
1467             break;
1468         default:
1469             std::cerr << "Wrong DataType for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1470             enc->success_ = false;
1471     }
1472 }
1473 
VisitLoadStaticIntrinsic(GraphVisitor * v,Inst * instBase)1474 void CodeGenStatic::VisitLoadStaticIntrinsic(GraphVisitor *v, Inst *instBase)
1475 {
1476     auto enc = static_cast<CodeGenStatic *>(v);
1477     auto inst = instBase->CastToIntrinsic();
1478 
1479     compiler::Register vd = inst->GetDstReg();
1480     std::string id = enc->irInterface_->GetFieldIdByOffset(inst->GetImm(0));
1481 
1482     switch (inst->GetType()) {
1483         case compiler::DataType::BOOL:
1484         case compiler::DataType::UINT8:
1485         case compiler::DataType::INT8:
1486         case compiler::DataType::UINT16:
1487         case compiler::DataType::INT16:
1488         case compiler::DataType::UINT32:
1489         case compiler::DataType::INT32:
1490         case compiler::DataType::FLOAT32:
1491             enc->result_.emplace_back(pandasm::Create_LDSTATIC(id));
1492             DoSta(vd, enc->result_);
1493             break;
1494         case compiler::DataType::INT64:
1495         case compiler::DataType::UINT64:
1496         case compiler::DataType::FLOAT64:
1497             enc->result_.emplace_back(pandasm::Create_LDSTATIC_64(id));
1498             DoSta64(vd, enc->result_);
1499             break;
1500         case compiler::DataType::REFERENCE:
1501             enc->result_.emplace_back(pandasm::Create_LDSTATIC_OBJ(id));
1502             DoStaObj(vd, enc->result_);
1503             break;
1504         default:
1505             std::cerr << "CodeGen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed\n";
1506             enc->success_ = false;
1507     }
1508 }
1509 
VisitCatchPhi(GraphVisitor * v,Inst * inst)1510 void CodeGenStatic::VisitCatchPhi(GraphVisitor *v, Inst *inst)
1511 {
1512     if (inst->CastToCatchPhi()->IsAcc()) {
1513         bool hasRealUsers = false;
1514         for (auto &user : inst->GetUsers()) {
1515             if (!user.GetInst()->IsSaveState()) {
1516                 hasRealUsers = true;
1517                 break;
1518             }
1519         }
1520         if (hasRealUsers) {
1521             auto enc = static_cast<CodeGenStatic *>(v);
1522             enc->result_.emplace_back(pandasm::Create_STA_OBJ(inst->GetDstReg()));
1523         }
1524     }
1525 }
1526 
1527 #include "generated/codegen_intrinsics_static.cpp"
1528 #include "generated/insn_selection_static.cpp"
1529 }  // namespace libabckit
1530