• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "libabckit/src/codegen/codegen_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