• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "codegen.h"
16 #include "common.h"
17 #include "runtime/include/coretypes/tagged_value.h"
18 #include "generate_ecma.inl"
19 
20 namespace panda::bytecodeopt {
21 
22 using panda_file::LiteralTag;
23 
DoLda(compiler::Register reg,std::vector<pandasm::Ins> & result)24 void DoLda(compiler::Register reg, std::vector<pandasm::Ins> &result)
25 {
26     if (reg != compiler::ACC_REG_ID) {
27         result.emplace_back(pandasm::Create_LDA(reg));
28     }
29 }
30 
DoSta(compiler::Register reg,std::vector<pandasm::Ins> & result)31 void DoSta(compiler::Register reg, std::vector<pandasm::Ins> &result)
32 {
33     if (reg != compiler::ACC_REG_ID) {
34         result.emplace_back(pandasm::Create_STA(reg));
35     }
36 }
37 
AppendCatchBlock(uint32_t type_id,const compiler::BasicBlock * try_begin,const compiler::BasicBlock * try_end,const compiler::BasicBlock * catch_begin,const compiler::BasicBlock * catch_end)38 void BytecodeGen::AppendCatchBlock(uint32_t type_id, const compiler::BasicBlock *try_begin,
39                                    const compiler::BasicBlock *try_end, const compiler::BasicBlock *catch_begin,
40                                    const compiler::BasicBlock *catch_end)
41 {
42     auto cb = pandasm::Function::CatchBlock();
43     if (type_id != 0) {
44         cb.exception_record = ir_interface_->GetTypeIdByOffset(type_id);
45     }
46     cb.try_begin_label = BytecodeGen::LabelName(try_begin->GetId());
47     cb.try_end_label = "end_" + BytecodeGen::LabelName(try_end->GetId());
48     cb.catch_begin_label = BytecodeGen::LabelName(catch_begin->GetId());
49     cb.catch_end_label =
50         catch_end == nullptr ? cb.catch_begin_label : "end_" + BytecodeGen::LabelName(catch_end->GetId());
51     catch_blocks_.emplace_back(cb);
52 }
53 
VisitTryBegin(const compiler::BasicBlock * bb)54 void BytecodeGen::VisitTryBegin(const compiler::BasicBlock *bb)
55 {
56     ASSERT(bb->IsTryBegin());
57     auto try_inst = GetTryBeginInst(bb);
58     auto try_end = try_inst->GetTryEndBlock();
59     ASSERT(try_end != nullptr && try_end->IsTryEnd());
60 
61     bb->EnumerateCatchHandlers([&, bb, try_end](BasicBlock *catch_handler, size_t type_id) {
62         AppendCatchBlock(type_id, bb, try_end, catch_handler);
63         return true;
64     });
65 }
66 
RunImpl()67 bool BytecodeGen::RunImpl()
68 {
69     Reserve(function_->ins.size());
70     TypeInfoComponents elements;
71     AddTypeInfoIndexForArguments(&elements);
72     bool need_handle_ins_type = GetGraph()->GetRuntime()->HasInsTypeinfo();
73     int32_t insn_order = 0;
74     for (auto *bb : GetGraph()->GetBlocksLinearOrder()) {
75         EmitLabel(BytecodeGen::LabelName(bb->GetId()));
76         if (bb->IsTryEnd() || bb->IsCatchEnd()) {
77             auto label = "end_" + BytecodeGen::LabelName(bb->GetId());
78             EmitLabel(label);
79         }
80         for (const auto &inst : bb->AllInsts()) {
81             auto start = GetResult().size();
82             VisitInstruction(inst);
83             if (!GetStatus()) {
84                 return false;
85             }
86             auto end = GetResult().size();
87             ASSERT(end >= start);
88             for (auto i = start; i < end; ++i) {
89                 AddLineNumber(inst, i);
90                 AddColumnNumber(inst, i);
91             }
92             if (need_handle_ins_type && end > start) {
93                 // fill ins types. Need to exclude invalid ins as they do not emit
94                 insn_order += std::count_if(GetResult().begin() + start, GetResult().end(),
95                                             [](const auto &ins) { return ins.opcode != pandasm::Opcode::INVALID; });
96                 AddTypeInfoIndexForIns(insn_order - 1, inst->GetId(), &elements);
97             }
98         }
99         if (bb->NeedsJump()) {
100             EmitJump(bb);
101             insn_order++;
102         }
103     }
104     if (!GetStatus()) {
105         return false;
106     }
107     // Visit try-blocks in order they were declared
108     for (auto *bb : GetGraph()->GetTryBeginBlocks()) {
109         VisitTryBegin(bb);
110     }
111     function_->ins = std::move(GetResult());
112     function_->catch_blocks = catch_blocks_;
113     if (need_handle_ins_type) {
114         UpdateTypeInfoIndexAnnotation(&elements);
115     }
116     return true;
117 }
118 
AddTypeInfoIndexForArguments(TypeInfoComponents * elements) const119 void BytecodeGen::AddTypeInfoIndexForArguments(TypeInfoComponents *elements) const
120 {
121     std::unordered_map<int32_t, TypeInfoIndex> args_types_map;
122     if (GetGraph()->GetRuntime()->FillArgTypePairs(&args_types_map)) {
123         for (const auto &[arg, type] : args_types_map) {
124             ASSERT(arg < 0);
125             AddOrderAndTypeInfoIndex(arg, type, elements);
126         }
127     }
128 }
129 
AddOrderAndTypeInfoIndex(int32_t order,TypeInfoIndex type,TypeInfoComponents * elements) const130 void BytecodeGen::AddOrderAndTypeInfoIndex(int32_t order, TypeInfoIndex type, TypeInfoComponents *elements) const
131 {
132     pandasm::LiteralArray::Literal order_tag;
133     order_tag.tag_ = LiteralTag::TAGVALUE;
134     order_tag.value_ = static_cast<uint8_t>(LiteralTag::INTEGER);
135     elements->emplace_back(order_tag);
136 
137     pandasm::LiteralArray::Literal order_lit;
138     order_lit.tag_ = LiteralTag::INTEGER;
139     order_lit.value_ = bit_cast<uint32_t>(order);
140     elements->emplace_back(order_lit);
141 
142     pandasm::LiteralArray::Literal type_tag;
143     type_tag.tag_ = LiteralTag::TAGVALUE;
144     pandasm::LiteralArray::Literal type_lit;
145     if (std::holds_alternative<std::string>(type)) {
146         type_tag.value_ = static_cast<uint8_t>(LiteralTag::LITERALARRAY);
147         type_lit.tag_ = LiteralTag::LITERALARRAY;
148         type_lit.value_ = std::get<std::string>(type);
149     } else {
150         type_tag.value_ = static_cast<uint8_t>(LiteralTag::BUILTINTYPEINDEX);
151         type_lit.tag_ = LiteralTag::BUILTINTYPEINDEX;
152         type_lit.value_ = std::get<BuiltinIndexType>(type);
153     }
154 
155     elements->emplace_back(type_tag);
156     elements->emplace_back(type_lit);
157 }
158 
AddTypeInfoIndexForIns(int32_t order,size_t id,TypeInfoComponents * elements) const159 void BytecodeGen::AddTypeInfoIndexForIns(int32_t order, size_t id, TypeInfoComponents *elements) const
160 {
161     auto type = GetGraph()->GetRuntime()->GetTypeInfoIndexByInstId(id);
162     if (type != NO_EXPLICIT_TYPE) {
163         AddOrderAndTypeInfoIndex(order, type, elements);
164     }
165 }
166 
UpdateTypeInfoIndexAnnotation(const TypeInfoComponents * elements)167 void BytecodeGen::UpdateTypeInfoIndexAnnotation(const TypeInfoComponents *elements)
168 {
169 #ifndef NDEBUG
170     LOG(DEBUG, BYTECODE_OPTIMIZER) << "Typeinfo after optimization for function : " << function_->name;
171     const size_t PAIR_GAP = 4;  // 4: tag, order, tag, value, ...
172     ASSERT(elements->size() % PAIR_GAP == 0);
173     for (size_t i = 1; i < elements->size(); i += PAIR_GAP) {
174         auto order = bit_cast<int32_t>(std::get<uint32_t>((*elements)[i].value_));
175         const auto &element = (*elements)[i + 2];  // 2: gap between order and value
176         if (element.tag_ == LiteralTag::LITERALARRAY) {
177             auto type = std::get<std::string>(element.value_);
178             LOG(DEBUG, BYTECODE_OPTIMIZER) << "[" << order << ", " << type << "], ";
179         } else {
180             ASSERT(element.tag_ == LiteralTag::BUILTINTYPEINDEX);
181             auto type = std::get<BuiltinIndexType>(element.value_);
182             LOG(DEBUG, BYTECODE_OPTIMIZER) << "[" << order << ", " << type << "], ";
183         }
184     }
185 #endif
186 
187     const auto &key = *(GetGraph()->GetRuntime()->GetTypeLiteralArrayKey());
188     auto &litarr_table = GetProgram()->literalarray_table;
189     ASSERT(litarr_table.find(key) != litarr_table.end());
190     pandasm::LiteralArray array(*elements);
191     litarr_table[key] = array;
192 }
193 
EmitJump(const BasicBlock * bb)194 void BytecodeGen::EmitJump(const BasicBlock *bb)
195 {
196     BasicBlock *suc_bb = nullptr;
197     ASSERT(bb != nullptr);
198 
199     if (bb->GetLastInst() == nullptr) {
200         ASSERT(bb->IsEmpty());
201         suc_bb = bb->GetSuccsBlocks()[0];
202         result_.push_back(pandasm::Create_JMP(BytecodeGen::LabelName(suc_bb->GetId())));
203         return;
204     }
205 
206     ASSERT(bb->GetLastInst() != nullptr);
207     switch (bb->GetLastInst()->GetOpcode()) {
208         case Opcode::If:
209         case Opcode::IfImm:
210             ASSERT(bb->GetSuccsBlocks().size() == compiler::MAX_SUCCS_NUM);
211             suc_bb = bb->GetFalseSuccessor();
212             break;
213         default:
214             suc_bb = bb->GetSuccsBlocks()[0];
215             break;
216     }
217     result_.push_back(pandasm::Create_JMP(BytecodeGen::LabelName(suc_bb->GetId())));
218 }
219 
AddLineNumber(const Inst * inst,const size_t idx)220 void BytecodeGen::AddLineNumber(const Inst *inst, const size_t idx)
221 {
222     if (ir_interface_ != nullptr && idx < result_.size()) {
223         auto ln = ir_interface_->GetLineNumberByPc(inst->GetPc());
224         result_[idx].ins_debug.SetLineNumber(ln);
225     }
226 }
227 
AddColumnNumber(const Inst * inst,const uint32_t idx)228 void BytecodeGen::AddColumnNumber(const Inst *inst, const uint32_t idx)
229 {
230     if (ir_interface_ != nullptr && idx < result_.size()) {
231         auto cn = ir_interface_->GetLineNumberByPc(inst->GetPc());
232         result_[idx].ins_debug.SetColumnNumber(cn);
233     }
234 }
235 
EncodeSpillFillData(const compiler::SpillFillData & sf)236 void BytecodeGen::EncodeSpillFillData(const compiler::SpillFillData &sf)
237 {
238     if (sf.SrcType() != compiler::LocationType::REGISTER || sf.DstType() != compiler::LocationType::REGISTER) {
239         LOG(ERROR, BYTECODE_OPTIMIZER) << "EncodeSpillFillData with unknown move type, src_type: "
240                                        << static_cast<int>(sf.SrcType())
241                                        << " dst_type: " << static_cast<int>(sf.DstType());
242         success_ = false;
243         UNREACHABLE();
244         return;
245     }
246     ASSERT(sf.GetType() != compiler::DataType::NO_TYPE);
247     ASSERT(sf.SrcValue() != compiler::INVALID_REG && sf.DstValue() != compiler::INVALID_REG);
248 
249     if (sf.SrcValue() == sf.DstValue()) {
250         return;
251     }
252 
253     pandasm::Ins move;
254     if (GetGraph()->IsDynamicMethod()) {
255         result_.emplace_back(pandasm::Create_MOV(sf.DstValue(), sf.SrcValue()));
256         return;
257     }
258     UNREACHABLE();
259 }
260 
VisitSpillFill(GraphVisitor * visitor,Inst * inst)261 void BytecodeGen::VisitSpillFill(GraphVisitor *visitor, Inst *inst)
262 {
263     auto *enc = static_cast<BytecodeGen *>(visitor);
264     for (auto sf : inst->CastToSpillFill()->GetSpillFills()) {
265         enc->EncodeSpillFillData(sf);
266     }
267 }
268 
269 template <typename UnaryPred>
HasUserPredicate(Inst * inst,UnaryPred p)270 bool HasUserPredicate(Inst *inst, UnaryPred p)
271 {
272     bool found = false;
273     for (auto const &u : inst->GetUsers()) {
274         if (p(u.GetInst())) {
275             found = true;
276             break;
277         }
278     }
279     return found;
280 }
281 
VisitConstant(GraphVisitor * visitor,Inst * inst)282 void BytecodeGen::VisitConstant(GraphVisitor *visitor, Inst *inst)
283 {
284     auto *enc = static_cast<BytecodeGen *>(visitor);
285     auto type = inst->GetType();
286 
287     /* Do not emit unused code for Const -> CastValueToAnyType chains */
288     if (enc->GetGraph()->IsDynamicMethod()) {
289         if (!HasUserPredicate(inst,
290                               [](Inst const *i) { return i->GetOpcode() != compiler::Opcode::CastValueToAnyType; })) {
291             return;
292         }
293     }
294 
295     pandasm::Ins movi;
296     movi.regs.emplace_back(inst->GetDstReg());
297     switch (type) {
298         case compiler::DataType::INT64:
299         case compiler::DataType::UINT64:
300             if (enc->GetGraph()->IsDynamicMethod()) {
301                 enc->result_.emplace_back(pandasm::Create_LDAI(inst->CastToConstant()->GetInt64Value()));
302                 DoSta(inst->GetDstReg(), enc->result_);
303             } else {
304                 UNREACHABLE();
305             }
306             break;
307         case compiler::DataType::FLOAT64:
308             if (enc->GetGraph()->IsDynamicMethod()) {
309                 enc->result_.emplace_back(pandasm::Create_FLDAI(inst->CastToConstant()->GetDoubleValue()));
310                 DoSta(inst->GetDstReg(), enc->result_);
311             } else {
312                 UNREACHABLE();
313             }
314             break;
315         case compiler::DataType::BOOL:
316         case compiler::DataType::INT8:
317         case compiler::DataType::UINT8:
318         case compiler::DataType::INT16:
319         case compiler::DataType::UINT16:
320         case compiler::DataType::INT32:
321         case compiler::DataType::UINT32:
322             if (enc->GetGraph()->IsDynamicMethod()) {
323                 enc->result_.emplace_back(pandasm::Create_LDAI(inst->CastToConstant()->GetInt32Value()));
324                 DoSta(inst->GetDstReg(), enc->result_);
325             } else {
326                 UNREACHABLE();
327             }
328             break;
329         case compiler::DataType::FLOAT32:
330             if (enc->GetGraph()->IsDynamicMethod()) {
331                 enc->result_.emplace_back(pandasm::Create_FLDAI(inst->CastToConstant()->GetFloatValue()));
332                 DoSta(inst->GetDstReg(), enc->result_);
333             } else {
334                 UNREACHABLE();
335             }
336             break;
337         default:
338             UNREACHABLE();
339             LOG(ERROR, BYTECODE_OPTIMIZER) << "VisitConstant with unknown type" << type;
340             enc->success_ = false;
341     }
342 }
343 
EncodeSta(compiler::Register reg,compiler::DataType::Type type)344 void BytecodeGen::EncodeSta(compiler::Register reg, compiler::DataType::Type type)
345 {
346     pandasm::Opcode opc;
347     switch (type) {
348         case compiler::DataType::ANY:
349             opc = pandasm::Opcode::STA;
350             break;
351         default:
352             UNREACHABLE();
353             LOG(ERROR, BYTECODE_OPTIMIZER) << "EncodeSta with unknown type" << type;
354             success_ = false;
355     }
356     pandasm::Ins sta;
357     sta.opcode = opc;
358     sta.regs.emplace_back(reg);
359 
360     result_.emplace_back(sta);
361 }
362 
363 // NOLINTNEXTLINE(readability-function-size)
VisitIf(GraphVisitor * v,Inst * inst_base)364 void BytecodeGen::VisitIf(GraphVisitor *v, Inst *inst_base)
365 {
366     auto enc = static_cast<BytecodeGen *>(v);
367     auto inst = inst_base->CastToIf();
368     switch (inst->GetInputType(0)) {
369         case compiler::DataType::ANY: {
370             if (enc->GetGraph()->IsDynamicMethod()) {
371 #if defined(ENABLE_BYTECODE_OPT) && defined(PANDA_WITH_ECMASCRIPT) && defined(ARK_INTRINSIC_SET)
372                 IfEcma(v, inst);
373                 break;
374 #endif
375             }
376             LOG(ERROR, BYTECODE_OPTIMIZER)
377                 << "Codegen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
378             enc->success_ = false;
379             break;
380         }
381         default:
382             LOG(ERROR, BYTECODE_OPTIMIZER)
383                 << "Codegen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
384             enc->success_ = false;
385     }
386 }
387 
388 #if defined(ENABLE_BYTECODE_OPT) && defined(PANDA_WITH_ECMASCRIPT)
IsEcmaConstTemplate(Inst const * inst)389 static std::optional<coretypes::TaggedValue> IsEcmaConstTemplate(Inst const *inst)
390 {
391     if (inst->GetOpcode() != compiler::Opcode::CastValueToAnyType) {
392         return {};
393     }
394     auto cvat_inst = inst->CastToCastValueToAnyType();
395     if (!cvat_inst->GetInput(0).GetInst()->IsConst()) {
396         return {};
397     }
398     auto const_inst = cvat_inst->GetInput(0).GetInst()->CastToConstant();
399 
400     switch (cvat_inst->GetAnyType()) {
401         case compiler::AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE:
402             return coretypes::TaggedValue(coretypes::TaggedValue::VALUE_UNDEFINED);
403         case compiler::AnyBaseType::ECMASCRIPT_INT_TYPE:
404             return coretypes::TaggedValue(static_cast<int32_t>(const_inst->GetIntValue()));
405         case compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE:
406             return coretypes::TaggedValue(const_inst->GetDoubleValue());
407         case compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE:
408             return coretypes::TaggedValue(static_cast<bool>(const_inst->GetInt64Value() != 0));
409         case compiler::AnyBaseType::ECMASCRIPT_NULL_TYPE:
410             return coretypes::TaggedValue(coretypes::TaggedValue::VALUE_NULL);
411         default:
412             return {};
413     }
414 }
415 
416 #if defined(ARK_INTRINSIC_SET)
IfEcma(GraphVisitor * v,compiler::IfInst * inst)417 void BytecodeGen::IfEcma(GraphVisitor *v, compiler::IfInst *inst)
418 {
419     auto enc = static_cast<BytecodeGen *>(v);
420 
421     compiler::Register reg = compiler::INVALID_REG_ID;
422     coretypes::TaggedValue cmp_val;
423 
424     auto test_lhs = IsEcmaConstTemplate(inst->GetInput(0).GetInst());
425     auto test_rhs = IsEcmaConstTemplate(inst->GetInput(1).GetInst());
426 
427     if (test_lhs.has_value() && test_lhs->IsBoolean()) {
428         cmp_val = test_lhs.value();
429         reg = inst->GetSrcReg(1);
430     } else if (test_rhs.has_value() && test_rhs->IsBoolean()) {
431         cmp_val = test_rhs.value();
432         reg = inst->GetSrcReg(0);
433     } else {
434         LOG(ERROR, BYTECODE_OPTIMIZER) << "Codegen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
435         enc->success_ = false;
436         return;
437     }
438 
439     DoLda(reg, enc->result_);
440     switch (inst->GetCc()) {
441         case compiler::CC_EQ: {
442             if (cmp_val.IsTrue()) {
443                 enc->result_.emplace_back(
444                     pandasm::Create_ECMA_JTRUE(LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId())));
445             } else {
446                 enc->result_.emplace_back(
447                     pandasm::Create_ECMA_JFALSE(LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId())));
448             }
449             break;
450         }
451         case compiler::CC_NE: {
452             if (cmp_val.IsTrue()) {
453                 enc->result_.emplace_back(pandasm::Create_ECMA_ISTRUE());
454             } else {
455                 enc->result_.emplace_back(pandasm::Create_ECMA_ISFALSE());
456             }
457             enc->result_.emplace_back(
458                 pandasm::Create_ECMA_JFALSE(LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId())));
459             break;
460         }
461         default:
462             LOG(ERROR, BYTECODE_OPTIMIZER)
463                 << "Codegen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
464             enc->success_ = false;
465             return;
466     }
467 }
468 #endif
469 #endif
470 
VisitIfImm(GraphVisitor * v,Inst * inst_base)471 void BytecodeGen::VisitIfImm(GraphVisitor *v, Inst *inst_base)
472 {
473     auto inst = inst_base->CastToIfImm();
474     auto imm = inst->GetImm();
475     if (imm == 0) {
476         IfImmZero(v, inst_base);
477         return;
478     }
479     IfImmNonZero(v, inst_base);
480 }
481 
IfImmZero(GraphVisitor * v,Inst * inst_base)482 void BytecodeGen::IfImmZero(GraphVisitor *v, Inst *inst_base)
483 {
484     auto enc = static_cast<BytecodeGen *>(v);
485     auto inst = inst_base->CastToIfImm();
486     ASSERT(enc->GetGraph()->IsDynamicMethod());
487     DoLda(inst->GetSrcReg(0), enc->result_);
488     auto label = LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
489     switch (inst->GetCc()) {
490         case compiler::CC_EQ:
491             enc->result_.emplace_back(pandasm::Create_JEQZ(label));
492             return;
493         case compiler::CC_NE:
494             enc->result_.emplace_back(pandasm::Create_JNEZ(label));
495             return;
496         default:
497             UNREACHABLE();
498     }
499 }
500 
501 // NOLINTNEXTLINE(readability-function-size)
IfImmNonZero(GraphVisitor * v,Inst * inst_base)502 void BytecodeGen::IfImmNonZero(GraphVisitor *v, Inst *inst_base)
503 {
504     UNREACHABLE();
505 }
506 
507 // NOLINTNEXTLINE(readability-function-size)
IfImm64(GraphVisitor * v,Inst * inst_base)508 void BytecodeGen::IfImm64(GraphVisitor *v, Inst *inst_base)
509 {
510     UNREACHABLE();
511 }
512 
513 // NOLINTNEXTLINE(readability-function-size)
VisitCast(GraphVisitor * v,Inst * inst_base)514 void BytecodeGen::VisitCast(GraphVisitor *v, Inst *inst_base)
515 {
516     UNREACHABLE();
517 }
518 
VisitLoadString(GraphVisitor * v,Inst * inst_base)519 void BytecodeGen::VisitLoadString(GraphVisitor *v, Inst *inst_base)
520 {
521     pandasm::Ins ins;
522     auto enc = static_cast<BytecodeGen *>(v);
523     auto inst = inst_base->CastToLoadString();
524 
525     /* Do not emit unused code for Str -> CastValueToAnyType chains */
526     if (enc->GetGraph()->IsDynamicMethod()) {
527         if (!HasUserPredicate(inst,
528                               [](Inst const *i) { return i->GetOpcode() != compiler::Opcode::CastValueToAnyType; })) {
529             return;
530         }
531     }
532 
533     enc->result_.emplace_back(pandasm::Create_LDA_STR(enc->ir_interface_->GetStringIdByOffset(inst->GetTypeId())));
534     if (inst->GetDstReg() != compiler::ACC_REG_ID) {
535         if (enc->GetGraph()->IsDynamicMethod()) {
536             enc->result_.emplace_back(pandasm::Create_STA(inst->GetDstReg()));
537         } else {
538             UNREACHABLE();
539         }
540     }
541 }
542 
VisitReturn(GraphVisitor * v,Inst * inst_base)543 void BytecodeGen::VisitReturn(GraphVisitor *v, Inst *inst_base)
544 {
545     pandasm::Ins ins;
546     auto enc = static_cast<BytecodeGen *>(v);
547     auto inst = inst_base->CastToReturn();
548     switch (inst->GetType()) {
549         case compiler::DataType::ANY: {
550 #if defined(ENABLE_BYTECODE_OPT) && defined(PANDA_WITH_ECMASCRIPT)
551             auto test_arg = IsEcmaConstTemplate(inst->GetInput(0).GetInst());
552             if (test_arg.has_value() && test_arg->IsUndefined()) {
553                 enc->result_.emplace_back(pandasm::Create_RETURNUNDEFINED());
554                 break;
555             }
556 #endif
557             DoLda(inst->GetSrcReg(0), enc->result_);
558             enc->result_.emplace_back(pandasm::Create_RETURN());
559             break;
560         }
561         default:
562             LOG(ERROR, BYTECODE_OPTIMIZER)
563                 << "Codegen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
564             enc->success_ = false;
565     }
566 }
567 
VisitCastValueToAnyType(GraphVisitor * v,Inst * inst_base)568 void BytecodeGen::VisitCastValueToAnyType([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst_base)
569 {
570     auto enc = static_cast<BytecodeGen *>(v);
571 
572 #if defined(ENABLE_BYTECODE_OPT) && defined(PANDA_WITH_ECMASCRIPT)
573     auto cvat = inst_base->CastToCastValueToAnyType();
574     switch (cvat->GetAnyType()) {
575         case compiler::AnyBaseType::ECMASCRIPT_NULL_TYPE:
576             enc->result_.emplace_back(pandasm::Create_LDNULL());
577             break;
578         case compiler::AnyBaseType::ECMASCRIPT_UNDEFINED_TYPE:
579             if (!HasUserPredicate(cvat,
580                                   [](Inst const *inst) { return inst->GetOpcode() != compiler::Opcode::Return; })) {
581                 return;
582             }
583             enc->result_.emplace_back(pandasm::Create_LDUNDEFINED());
584             break;
585         case compiler::AnyBaseType::ECMASCRIPT_INT_TYPE: {
586             ASSERT(cvat->GetInput(0).GetInst()->IsConst());
587             auto input = cvat->GetInput(0).GetInst()->CastToConstant();
588             enc->result_.emplace_back(pandasm::Create_LDAI(input->GetIntValue()));
589             break;
590         }
591         case compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE: {
592             ASSERT(cvat->GetInput(0).GetInst()->IsConst());
593             auto input = cvat->GetInput(0).GetInst()->CastToConstant();
594             enc->result_.emplace_back(pandasm::Create_FLDAI(input->GetDoubleValue()));
595             break;
596         }
597         case compiler::AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE: {
598             ASSERT(cvat->GetInput(0).GetInst()->IsBoolConst());
599             auto input = cvat->GetInput(0).GetInst()->CastToConstant();
600             if (!HasUserPredicate(cvat, [](Inst const *inst) { return inst->GetOpcode() != compiler::Opcode::If; })) {
601                 return;
602             }
603             uint64_t val = input->GetInt64Value();
604             if (val != 0) {
605                 enc->result_.emplace_back(pandasm::Create_LDTRUE());
606             } else {
607                 enc->result_.emplace_back(pandasm::Create_LDFALSE());
608             }
609             break;
610         }
611         case compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE: {
612             auto input = cvat->GetInput(0).GetInst()->CastToLoadString();
613             enc->result_.emplace_back(
614                 pandasm::Create_LDA_STR(enc->ir_interface_->GetStringIdByOffset(input->GetTypeId())));
615             break;
616         }
617         default:
618             return;
619     }
620     DoSta(cvat->GetDstReg(), enc->result_);
621 #else
622     LOG(ERROR, BYTECODE_OPTIMIZER) << "Codegen for " << compiler::GetOpcodeString(inst_base->GetOpcode()) << " failed";
623     enc->success_ = false;
624 #endif
625 }
626 
627 // NOLINTNEXTLINE(readability-function-size)
VisitIntrinsic(GraphVisitor * visitor,Inst * inst_base)628 void BytecodeGen::VisitIntrinsic(GraphVisitor *visitor, Inst *inst_base)
629 {
630     ASSERT(inst_base->IsIntrinsic());
631     auto inst = inst_base->CastToIntrinsic();
632     auto enc = static_cast<BytecodeGen *>(visitor);
633 
634     if (!enc->GetGraph()->IsDynamicMethod()) {
635         LOG(ERROR, BYTECODE_OPTIMIZER) << "Codegen for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
636         enc->success_ = false;
637     } else {
638 #ifdef ENABLE_BYTECODE_OPT
639         VisitEcma(visitor, inst_base);
640 #endif
641     }
642 }
643 
VisitCatchPhi(GraphVisitor * v,Inst * inst)644 void BytecodeGen::VisitCatchPhi(GraphVisitor *v, Inst *inst)
645 {
646     if (inst->CastToCatchPhi()->IsAcc()) {
647         for (auto &user : inst->GetUsers()) {
648             if (!user.GetInst()->IsSaveState()) {
649                 UNREACHABLE();
650             }
651         }
652     }
653 }
654 
655 #include "generated/codegen_intrinsics.cpp"
656 #include "generated/insn_selection.cpp"
657 }  // namespace panda::bytecodeopt
658