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