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_dynamic.h"
16 #include "libabckit/src/adapter_dynamic/runtime_adapter_dynamic.h"
17 #include "generated/generate_ecma.inl"
18 #include "static_core/runtime/include/coretypes/tagged_value.h"
19
20 namespace libabckit {
21
DoLda(ark::compiler::Register reg,std::vector<InsWrapper> & result)22 void DoLda(ark::compiler::Register reg, std::vector<InsWrapper> &result)
23 {
24 if (reg != ark::compiler::GetAccReg()) {
25 if (reg > ark::compiler::INVALID_REG) {
26 ASSERT(ark::compiler::IsFrameSizeLarge());
27 result.emplace_back(PandasmWrapper::Create_MOV_Wrapper(CodeGenDynamic::RESERVED_REG, reg));
28 result.emplace_back(PandasmWrapper::Create_LDA_Wrapper(CodeGenDynamic::RESERVED_REG));
29 } else {
30 result.emplace_back(PandasmWrapper::Create_LDA_Wrapper(reg));
31 }
32 }
33 }
34
DoSta(ark::compiler::Register reg,std::vector<InsWrapper> & result)35 void DoSta(ark::compiler::Register reg, std::vector<InsWrapper> &result)
36 {
37 if (reg != ark::compiler::GetAccReg()) {
38 if (reg > ark::compiler::INVALID_REG) {
39 ASSERT(ark::compiler::IsFrameSizeLarge());
40 result.emplace_back(PandasmWrapper::Create_STA_Wrapper(CodeGenDynamic::RESERVED_REG));
41 result.emplace_back(PandasmWrapper::Create_MOV_Wrapper(reg, CodeGenDynamic::RESERVED_REG));
42 } else {
43 result.emplace_back(PandasmWrapper::Create_STA_Wrapper(reg));
44 }
45 }
46 }
47
AppendCatchBlock(uint32_t typeId,const ark::compiler::BasicBlock * tryBegin,const ark::compiler::BasicBlock * tryEnd,const ark::compiler::BasicBlock * catchBegin,const ark::compiler::BasicBlock * catchEnd)48 void CodeGenDynamic::AppendCatchBlock(uint32_t typeId, const ark::compiler::BasicBlock *tryBegin,
49 const ark::compiler::BasicBlock *tryEnd,
50 const ark::compiler::BasicBlock *catchBegin,
51 const ark::compiler::BasicBlock *catchEnd)
52 {
53 auto cb = FunctionWrapper::CatchBlockWrapper();
54 if (typeId != 0) {
55 cb.exceptionRecord = irInterface_->GetTypeIdByOffset(typeId);
56 }
57 cb.tryBeginLabel = LabelName(tryBegin->GetId());
58 cb.tryEndLabel = "end_" + LabelName(tryEnd->GetId());
59 cb.catchBeginLabel = LabelName(catchBegin->GetId());
60 cb.catchEndLabel = catchEnd == nullptr ? cb.catchBeginLabel : "end_" + LabelName(catchEnd->GetId());
61 catchBlocks_.emplace_back(cb);
62 }
63
VisitTryBegin(const ark::compiler::BasicBlock * bb)64 void CodeGenDynamic::VisitTryBegin(const ark::compiler::BasicBlock *bb)
65 {
66 ASSERT(bb->IsTryBegin());
67 auto tryInst = GetTryBeginInst(bb);
68 auto tryEnd = tryInst->GetTryEndBlock();
69 ASSERT(tryEnd != nullptr && tryEnd->IsTryEnd());
70
71 bb->EnumerateCatchHandlers([&, bb, tryEnd](BasicBlock *catchHandler, size_t typeId) {
72 AppendCatchBlock(typeId, bb, tryEnd, catchHandler);
73 return true;
74 });
75 }
76
RunImpl()77 bool CodeGenDynamic::RunImpl()
78 {
79 Reserve(function_->ins.size());
80 if (!GetGraph()->GetTryBeginBlocks().empty()) {
81 // Workaround for AOT and JIT
82 result_.emplace_back(PandasmWrapper::Create_NOP_Wrapper());
83 }
84 for (auto *bb : GetGraph()->GetBlocksLinearOrder()) {
85 EmitLabel(LabelName(bb->GetId()));
86 if (bb->IsTryEnd() || bb->IsCatch()) {
87 auto label = "end_" + LabelName(bb->GetId());
88 EmitLabel(label);
89 }
90 for (const auto &inst : bb->AllInsts()) {
91 auto start = GetResult().size();
92 VisitInstruction(inst);
93 if (!GetStatus()) {
94 return false;
95 }
96 auto end = GetResult().size();
97 ASSERT(end >= start);
98 for (auto i = start; i < end; ++i) {
99 AddLineNumber(inst, i);
100 AddColumnNumber(inst, i);
101 }
102 }
103 if (bb->NeedsJump()) {
104 EmitJump(bb);
105 }
106 }
107 if (!GetStatus()) {
108 return false;
109 }
110 // Visit try-blocks in order they were declared
111 for (auto *bb : GetGraph()->GetTryBeginBlocks()) {
112 VisitTryBegin(bb);
113 }
114 function_->ins = std::move(GetResult());
115 function_->catchBlocks = catchBlocks_;
116 return true;
117 }
118
EmitJump(const BasicBlock * bb)119 void CodeGenDynamic::EmitJump(const BasicBlock *bb)
120 {
121 BasicBlock *sucBb = nullptr;
122 ASSERT(bb != nullptr);
123
124 if (bb->GetLastInst() == nullptr) {
125 ASSERT(bb->IsEmpty());
126 sucBb = bb->GetSuccsBlocks()[0];
127 result_.push_back(PandasmWrapper::Create_JMP_Wrapper(LabelName(sucBb->GetId())));
128 return;
129 }
130
131 ASSERT(bb->GetLastInst() != nullptr);
132 switch (bb->GetLastInst()->GetOpcode()) {
133 case Opcode::If:
134 case Opcode::IfImm:
135 ASSERT(bb->GetSuccsBlocks().size() == ark::compiler::MAX_SUCCS_NUM);
136 sucBb = bb->GetFalseSuccessor();
137 break;
138 default:
139 sucBb = bb->GetSuccsBlocks()[0];
140 break;
141 }
142 result_.push_back(PandasmWrapper::Create_JMP_Wrapper(LabelName(sucBb->GetId())));
143 }
144
AddLineNumber(const Inst * inst,const size_t idx)145 void CodeGenDynamic::AddLineNumber([[maybe_unused]] const Inst *inst, [[maybe_unused]] const size_t idx) {}
146
AddColumnNumber(const Inst * inst,const uint32_t idx)147 void CodeGenDynamic::AddColumnNumber([[maybe_unused]] const Inst *inst, [[maybe_unused]] const uint32_t idx) {}
148
EncodeSpillFillData(const ark::compiler::SpillFillData & sf)149 void CodeGenDynamic::EncodeSpillFillData(const ark::compiler::SpillFillData &sf)
150 {
151 if (sf.SrcType() != ark::compiler::LocationType::REGISTER ||
152 sf.DstType() != ark::compiler::LocationType::REGISTER) {
153 std::cerr << "EncodeSpillFillData with unknown move type, src_type: " << static_cast<int>(sf.SrcType())
154 << " dst_type: " << static_cast<int>(sf.DstType());
155 success_ = false;
156 UNREACHABLE();
157 return;
158 }
159 ASSERT(sf.GetType() != ark::compiler::DataType::NO_TYPE);
160 ASSERT(sf.SrcValue() != ark::compiler::GetInvalidReg() && sf.DstValue() != ark::compiler::GetInvalidReg());
161
162 if (sf.SrcValue() == sf.DstValue()) {
163 return;
164 }
165
166 result_.emplace_back(PandasmWrapper::Create_MOV_Wrapper(sf.DstValue(), sf.SrcValue()));
167 }
168
VisitSpillFill(GraphVisitor * visitor,Inst * inst)169 void CodeGenDynamic::VisitSpillFill(GraphVisitor *visitor, Inst *inst)
170 {
171 auto *enc = static_cast<CodeGenDynamic *>(visitor);
172 for (auto sf : inst->CastToSpillFill()->GetSpillFills()) {
173 enc->EncodeSpillFillData(sf);
174 }
175 }
176
177 template <typename UnaryPred>
HasUserPredicate(Inst * inst,UnaryPred p)178 bool HasUserPredicate(Inst *inst, UnaryPred p)
179 {
180 bool found = false;
181 for (auto const &u : inst->GetUsers()) {
182 if (p(u.GetInst())) {
183 found = true;
184 break;
185 }
186 }
187 return found;
188 }
189
VisitConstant(GraphVisitor * visitor,Inst * inst)190 void CodeGenDynamic::VisitConstant(GraphVisitor *visitor, Inst *inst)
191 {
192 auto *enc = static_cast<CodeGenDynamic *>(visitor);
193 auto type = inst->GetType();
194
195 InsWrapper movi;
196 movi.regs.emplace_back(inst->GetDstReg());
197 switch (type) {
198 case ark::compiler::DataType::INT64:
199 case ark::compiler::DataType::UINT64:
200 enc->result_.emplace_back(PandasmWrapper::Create_LDAI_Wrapper(inst->CastToConstant()->GetInt64Value()));
201 DoSta(inst->GetDstReg(), enc->result_);
202 break;
203 case ark::compiler::DataType::FLOAT64:
204 enc->result_.emplace_back(PandasmWrapper::Create_FLDAI_Wrapper(inst->CastToConstant()->GetDoubleValue()));
205 DoSta(inst->GetDstReg(), enc->result_);
206 break;
207 case ark::compiler::DataType::INT32:
208 case ark::compiler::DataType::UINT32:
209 enc->result_.emplace_back(PandasmWrapper::Create_LDAI_Wrapper(inst->CastToConstant()->GetInt32Value()));
210 DoSta(inst->GetDstReg(), enc->result_);
211 break;
212 default:
213 UNREACHABLE();
214 std::cerr << "VisitConstant with unknown type" << type;
215 enc->success_ = false;
216 }
217 }
218
EncodeSta(ark::compiler::Register reg,ark::compiler::DataType::Type type)219 void CodeGenDynamic::EncodeSta(ark::compiler::Register reg, ark::compiler::DataType::Type type)
220 {
221 std::string opc;
222 if (type != ark::compiler::DataType::ANY) {
223 UNREACHABLE();
224 std::cerr << "EncodeSta with unknown type" << type;
225 success_ = false;
226 }
227 InsWrapper sta;
228 sta.opcode = "STA";
229 sta.regs.emplace_back(reg);
230
231 result_.emplace_back(sta);
232 }
233
234 // NOLINTNEXTLINE(readability-function-size)
VisitIf(GraphVisitor * v,Inst * instBase)235 void CodeGenDynamic::VisitIf(GraphVisitor *v, Inst *instBase)
236 {
237 auto inst = instBase->CastToIf();
238
239 size_t notZeroConstIdx = 1;
240 if (IsZeroConstant(inst->GetInput(0).GetInst())) {
241 notZeroConstIdx = 1;
242 } else if (IsZeroConstant(inst->GetInput(1).GetInst())) {
243 notZeroConstIdx = 0;
244 } else {
245 UNREACHABLE();
246 }
247
248 auto enc = static_cast<CodeGenDynamic *>(v);
249 DoLda(inst->GetSrcReg(notZeroConstIdx), enc->result_);
250 auto label = LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
251 switch (inst->GetCc()) {
252 case ark::compiler::CC_NE:
253 enc->result_.emplace_back(PandasmWrapper::Create_JNEZ_Wrapper(label));
254 return;
255 case ark::compiler::CC_EQ:
256 enc->result_.emplace_back(PandasmWrapper::Create_JEQZ_Wrapper(label));
257 return;
258 default:
259 UNREACHABLE();
260 }
261 }
262
VisitIfImm(GraphVisitor * v,Inst * instBase)263 void CodeGenDynamic::VisitIfImm(GraphVisitor *v, Inst *instBase)
264 {
265 auto inst = instBase->CastToIfImm();
266 auto imm = inst->GetImm();
267 if (imm == 0) {
268 IfImmZero(v, instBase);
269 return;
270 }
271 }
272
IfImmZero(GraphVisitor * v,Inst * instBase)273 void CodeGenDynamic::IfImmZero(GraphVisitor *v, Inst *instBase)
274 {
275 auto enc = static_cast<CodeGenDynamic *>(v);
276 auto inst = instBase->CastToIfImm();
277 DoLda(inst->GetSrcReg(0), enc->result_);
278 auto label = LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId());
279 switch (inst->GetCc()) {
280 case ark::compiler::CC_EQ:
281 enc->result_.emplace_back(PandasmWrapper::Create_JEQZ_Wrapper(label));
282 return;
283 case ark::compiler::CC_NE:
284 enc->result_.emplace_back(PandasmWrapper::Create_JNEZ_Wrapper(label));
285 return;
286 default:
287 UNREACHABLE();
288 }
289 }
290
VisitLoadString(GraphVisitor *,Inst *)291 void CodeGenDynamic::VisitLoadString(GraphVisitor * /*v*/, Inst * /*instBase*/)
292 {
293 UNREACHABLE();
294 }
295
VisitLoadStringIntrinsic(GraphVisitor * v,Inst * instBase)296 void CodeGenDynamic::VisitLoadStringIntrinsic(GraphVisitor *v, Inst *instBase)
297 {
298 InsWrapper ins;
299 auto enc = static_cast<CodeGenDynamic *>(v);
300 auto inst = instBase->CastToIntrinsic();
301 enc->result_.emplace_back(
302 PandasmWrapper::Create_LDA_STR_Wrapper(enc->irInterface_->GetStringIdByOffset(inst->GetImm(0))));
303 DoSta(inst->GetDstReg(), enc->result_);
304 }
305
VisitReturn(GraphVisitor * v,Inst * instBase)306 void CodeGenDynamic::VisitReturn(GraphVisitor *v, Inst *instBase)
307 {
308 InsWrapper ins;
309 auto enc = static_cast<CodeGenDynamic *>(v);
310 auto inst = instBase->CastToReturn();
311 switch (inst->GetType()) {
312 case ark::compiler::DataType::ANY: {
313 #if defined(PANDA_WITH_ECMASCRIPT)
314 auto test_arg = IsEcmaConstTemplate(inst->GetInput(0).GetInst());
315 if (test_arg.has_value() && test_arg->IsUndefined()) {
316 enc->result_.emplace_back(PandasmWrapper::Create_RETURNUNDEFINED_Wrapper());
317 break;
318 }
319 #endif
320 DoLda(inst->GetSrcReg(0), enc->result_);
321 enc->result_.emplace_back(PandasmWrapper::Create_RETURN_Wrapper());
322 break;
323 }
324 default:
325 std::cerr << "Codegen for " << ark::compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
326 enc->success_ = false;
327 }
328 }
329
330 // NOLINTNEXTLINE(readability-function-size)
VisitIntrinsic(GraphVisitor * visitor,Inst * instBase)331 void CodeGenDynamic::VisitIntrinsic(GraphVisitor *visitor, Inst *instBase)
332 {
333 ASSERT(instBase->IsIntrinsic());
334 if (instBase->CastToIntrinsic()->GetIntrinsicId() ==
335 ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_STRING) {
336 VisitLoadStringIntrinsic(visitor, instBase);
337 return;
338 }
339 VisitEcma(visitor, instBase);
340 }
341
VisitCatchPhi(GraphVisitor * visitor,Inst * inst)342 void CodeGenDynamic::VisitCatchPhi(GraphVisitor *visitor, Inst *inst)
343 {
344 // The Acc register stores the exception object.
345 // Create an STA instruction if the exception is used later in virtual registers.
346 if (inst->CastToCatchPhi()->IsAcc()) {
347 bool hasRealUsers = false;
348 for (auto &user : inst->GetUsers()) {
349 if (!user.GetInst()->IsSaveState()) {
350 hasRealUsers = true;
351 break;
352 }
353 }
354 if (hasRealUsers) {
355 auto enc = static_cast<CodeGenDynamic *>(visitor);
356 DoSta(inst->GetDstReg(), enc->result_);
357 }
358 }
359 }
360
361 #include "generated/insn_selection_dynamic.cpp"
362 } // namespace libabckit
363