• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 
16 #include <cstdint>
17 #include "libpandabase/utils/utils.h"
18 #include "compiler_logger.h"
19 #include "optimizer/ir/datatype.h"
20 #include "optimizer/ir/runtime_interface.h"
21 #include "optimizer/ir_builder/inst_builder.h"
22 #include "optimizer/ir_builder/ir_builder.h"
23 #include "optimizer/ir/inst.h"
24 #include "bytecode_instruction.h"
25 #include "bytecode_instruction-inl.h"
26 
27 namespace ark::compiler {
28 
GetIntrinsicId(DataType::Type type)29 static RuntimeInterface::IntrinsicId GetIntrinsicId(DataType::Type type)
30 {
31     switch (type) {
32         case DataType::REFERENCE:
33             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_OBJ;
34         case DataType::FLOAT64:
35             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_F64;
36         case DataType::FLOAT32:
37             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_F32;
38         case DataType::UINT64:
39         case DataType::INT64:
40             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_I64;
41         case DataType::UINT8:
42         case DataType::INT8:
43         case DataType::UINT16:
44         case DataType::INT16:
45         case DataType::UINT32:
46         case DataType::INT32:
47             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_I32;
48         default:
49             UNREACHABLE();
50     }
51 }
52 
53 template <bool IS_ABC_KIT>
BuildLdObjByName(const BytecodeInstruction * bcInst,compiler::DataType::Type type)54 void InstBuilder::BuildLdObjByName(const BytecodeInstruction *bcInst, compiler::DataType::Type type)
55 {
56     auto pc = GetPc(bcInst->GetAddress());
57 
58     auto runtime = GetRuntime();
59     auto fieldIndex = bcInst->GetId(0).AsIndex();
60     auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
61     if (type != DataType::REFERENCE) {
62         type = runtime->GetFieldTypeById(GetMethod(), fieldId);
63     }
64 
65     auto intrinsic = GetGraph()->CreateInstIntrinsic(type, pc, GetIntrinsicId(type));
66     if constexpr (!IS_ABC_KIT) {
67         intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 2_I);
68 
69         // Create SaveState instruction
70         auto saveState = CreateSaveState(Opcode::SaveState, pc);
71 
72         // Create NullCheck instruction
73         auto nullCheck =
74             graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
75 
76         intrinsic->AppendInput(nullCheck);
77         intrinsic->AddInputType(DataType::REFERENCE);
78         intrinsic->AppendInput(saveState);
79         intrinsic->AddInputType(DataType::NO_TYPE);
80 
81         AddInstruction(saveState);
82         AddInstruction(nullCheck);
83     }
84 
85     intrinsic->AddImm(GetGraph()->GetAllocator(), fieldId);
86     intrinsic->AddImm(GetGraph()->GetAllocator(), pc);
87 
88     intrinsic->SetMethodFirstInput();
89     intrinsic->SetMethod(GetMethod());
90 
91     AddInstruction(intrinsic);
92 
93     UpdateDefinitionAcc(intrinsic);
94 }
95 
96 template void InstBuilder::BuildLdObjByName<true>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
97 template void InstBuilder::BuildLdObjByName<false>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
98 
ExtractIntrinsicIdByType(DataType::Type type)99 std::pair<RuntimeInterface::IntrinsicId, DataType::Type> ExtractIntrinsicIdByType(DataType::Type type)
100 {
101     switch (type) {
102         case DataType::REFERENCE:
103             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_OBJ, type};
104         case DataType::FLOAT64:
105             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_F64, type};
106         case DataType::FLOAT32:
107             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_F32, type};
108         case DataType::UINT64:
109         case DataType::INT64:
110             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I64, DataType::INT64};
111         case DataType::UINT8:
112         case DataType::INT8:
113             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I8, DataType::INT8};
114         case DataType::UINT16:
115         case DataType::INT16:
116             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I16, DataType::INT16};
117         case DataType::UINT32:
118         case DataType::INT32:
119             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I32, DataType::INT32};
120         default:
121             UNREACHABLE();
122             break;
123     }
124     UNREACHABLE();
125 }
126 
127 template <bool IS_ABC_KIT>
CreateStObjByNameIntrinsic(size_t pc,compiler::DataType::Type type)128 IntrinsicInst *InstBuilder::CreateStObjByNameIntrinsic(size_t pc, compiler::DataType::Type type)
129 {
130     auto [id, extractedType] = ExtractIntrinsicIdByType(type);
131     type = extractedType;
132     auto *intrinsic = GetGraph()->CreateInstIntrinsic(DataType::VOID, pc, id);
133 
134     if (intrinsic->RequireState()) {
135         intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 3_I);
136         intrinsic->AddInputType(DataType::REFERENCE);
137         intrinsic->AddInputType(type);
138         intrinsic->AddInputType(DataType::NO_TYPE);
139     } else {
140         intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 1_I);
141         intrinsic->AddInputType(type);
142     }
143     return intrinsic;
144 }
145 
146 template IntrinsicInst *InstBuilder::CreateStObjByNameIntrinsic<true>(size_t pc, compiler::DataType::Type type);
147 template IntrinsicInst *InstBuilder::CreateStObjByNameIntrinsic<false>(size_t pc, compiler::DataType::Type type);
148 
149 template <bool IS_ABC_KIT>
BuildStObjByName(const BytecodeInstruction * bcInst,compiler::DataType::Type type)150 void InstBuilder::BuildStObjByName(const BytecodeInstruction *bcInst, compiler::DataType::Type type)
151 {
152     auto pc = GetPc(bcInst->GetAddress());
153 
154     auto runtime = GetRuntime();
155     auto fieldIndex = bcInst->GetId(0).AsIndex();
156     auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
157     if (type != DataType::REFERENCE) {
158         type = runtime->GetFieldTypeById(GetMethod(), fieldId);
159     }
160 
161     // Get a value to store
162     Inst *storeVal = nullptr;
163     storeVal = GetDefinitionAcc();
164 
165     auto *intrinsic = CreateStObjByNameIntrinsic<IS_ABC_KIT>(pc, type);
166 
167     if constexpr (!IS_ABC_KIT) {
168         // Create SaveState instruction
169         auto saveState = CreateSaveState(Opcode::SaveState, pc);
170         // Create NullCheck instruction
171         auto nullCheck =
172             graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
173 
174         intrinsic->AppendInput(nullCheck);
175         intrinsic->AppendInput(storeVal);
176         intrinsic->AppendInput(saveState);
177         AddInstruction(saveState);
178         AddInstruction(nullCheck);
179     } else {
180         intrinsic->AppendInput(storeVal);
181     }
182 
183     intrinsic->AddImm(GetGraph()->GetAllocator(), fieldId);
184     intrinsic->AddImm(GetGraph()->GetAllocator(), pc);
185 
186     intrinsic->SetMethodFirstInput();
187     intrinsic->SetMethod(GetMethod());
188 
189     AddInstruction(intrinsic);
190 }
191 
192 template void InstBuilder::BuildStObjByName<true>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
193 template void InstBuilder::BuildStObjByName<false>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
194 
BuildIsNullValue(const BytecodeInstruction * bcInst)195 void InstBuilder::BuildIsNullValue(const BytecodeInstruction *bcInst)
196 {
197     auto uniqueObjInst = graph_->GetOrCreateUniqueObjectInst();
198     auto cmpInst = graph_->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), GetDefinitionAcc(),
199                                              uniqueObjInst, DataType::REFERENCE, ConditionCode::CC_EQ);
200     AddInstruction(cmpInst);
201     UpdateDefinitionAcc(cmpInst);
202 }
203 
204 template <bool IS_STRICT>
BuildEquals(const BytecodeInstruction * bcInst)205 void InstBuilder::BuildEquals(const BytecodeInstruction *bcInst)
206 {
207     auto pc = GetPc(bcInst->GetAddress());
208 
209     Inst *obj1 = GetDefinition(bcInst->GetVReg(0));
210     Inst *obj2 = GetDefinition(bcInst->GetVReg(1));
211 
212     auto intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_EQUALS;
213     if constexpr (IS_STRICT) {
214         intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_STRICT_EQUALS;
215     }
216 #if defined(ENABLE_LIBABCKIT)
217     if (GetGraph()->IsAbcKit()) {
218         if constexpr (IS_STRICT) {
219             intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STRICT_EQUALS;
220         } else {
221             intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_EQUALS;
222         }
223     }
224 #endif
225     auto intrinsic = GetGraph()->CreateInstIntrinsic(DataType::BOOL, pc, intrinsicId);
226     intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 2_I);
227 
228     intrinsic->AppendInput(obj1);
229     intrinsic->AddInputType(DataType::REFERENCE);
230     intrinsic->AppendInput(obj2);
231     intrinsic->AddInputType(DataType::REFERENCE);
232 
233     AddInstruction(intrinsic);
234     UpdateDefinitionAcc(intrinsic);
235 }
236 
237 template void InstBuilder::BuildEquals<true>(const BytecodeInstruction *bcInst);
238 template void InstBuilder::BuildEquals<false>(const BytecodeInstruction *bcInst);
239 
BuildTypeof(const BytecodeInstruction * bcInst)240 void InstBuilder::BuildTypeof(const BytecodeInstruction *bcInst)
241 {
242     auto pc = GetPc(bcInst->GetAddress());
243     Inst *obj = GetDefinition(bcInst->GetVReg(0));
244 
245     RuntimeInterface::IntrinsicId intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_TYPEOF;
246     auto intrinsic = GetGraph()->CreateInstIntrinsic(DataType::REFERENCE, pc, intrinsicId);
247     auto saveState = CreateSaveState(Opcode::SaveState, pc);
248 
249     intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 2_I);
250     intrinsic->AppendInput(obj);
251     intrinsic->AddInputType(DataType::REFERENCE);
252     intrinsic->AppendInput(saveState);
253     intrinsic->AddInputType(DataType::NO_TYPE);
254 
255     AddInstruction(saveState);
256     AddInstruction(intrinsic);
257     UpdateDefinitionAcc(intrinsic);
258 }
259 
BuildIstrue(const BytecodeInstruction * bcInst)260 void InstBuilder::BuildIstrue(const BytecodeInstruction *bcInst)
261 {
262     auto pc = GetPc(bcInst->GetAddress());
263     Inst *obj = GetDefinition(bcInst->GetVReg(0));
264 
265     RuntimeInterface::IntrinsicId intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ISTRUE;
266     auto intrinsic = GetGraph()->CreateInstIntrinsic(DataType::BOOL, pc, intrinsicId);
267     intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 1_I);
268     intrinsic->AppendInput(obj);
269     intrinsic->AddInputType(DataType::REFERENCE);
270 
271     AddInstruction(intrinsic);
272     UpdateDefinitionAcc(intrinsic);
273 }
274 
275 template <bool IS_RANGE>
BuildCallByName(const BytecodeInstruction * bcInst)276 void InstBuilder::BuildCallByName(const BytecodeInstruction *bcInst)
277 {
278     // Suppress BytecodeOptimizer if call.name was encountered
279     if (GetGraph()->IsBytecodeOptimizer()) {
280         failed_ = true;
281         return;
282     }
283 
284     auto pc = GetPc(bcInst->GetAddress());
285     auto startReg = bcInst->GetVReg(0);
286     auto objRef = GetDefinition(startReg++);
287     auto methodIndex = bcInst->GetId(0).AsIndex();
288     auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
289     auto argsCount = GetMethodArgumentsCount(methodId);
290     auto retType = GetMethodReturnType(methodId);
291 
292     auto saveState = CreateSaveState(Opcode::SaveState, pc);
293     auto nullCheck = GetGraph()->CreateInstNullCheck(DataType::REFERENCE, pc, objRef, saveState);
294 
295     ASSERT(saveState != nullptr);
296     ASSERT(nullCheck != nullptr);
297 
298     ResolveVirtualInst *resolver = GetGraph()->CreateInstResolveByName(DataType::POINTER, pc, methodId, GetMethod());
299 
300     ASSERT(resolver != nullptr);
301 
302     resolver->SetInput(0, nullCheck);
303     resolver->SetInput(1, saveState);
304 
305     CallInst *call = GetGraph()->CreateInstCallResolvedVirtual(retType, pc, methodId, nullptr);
306 
307     // + 1 because the first param is objRef
308     // + 1 because of resolver
309     // + 1 because CallResolvedVirtual has saveState as input (last)
310     call->ReserveInputs(argsCount + 3_I);
311     call->AllocateInputTypes(GetGraph()->GetAllocator(), argsCount + 3_I);
312     call->AppendInput(resolver, DataType::POINTER);
313     call->AppendInput(nullCheck, DataType::REFERENCE);
314 
315     if constexpr (IS_RANGE) {
316         for (size_t i = 0; i < argsCount; startReg++, i++) {
317             call->AppendInput(GetDefinition(startReg), GetMethodArgumentType(methodId, i));
318         }
319     } else {
320         for (size_t i = 0; i < argsCount; i++) {
321             call->AppendInput(GetDefinition(bcInst->GetVReg(i + 1)), GetMethodArgumentType(methodId, i));
322         }
323     }
324     call->AppendInput(saveState, DataType::NO_TYPE);
325 
326     AddInstruction(saveState);
327     AddInstruction(nullCheck);
328     AddInstruction(resolver);
329     AddInstruction(call);
330 
331     if (retType != DataType::VOID) {
332         UpdateDefinitionAcc(call);
333     } else {
334         UpdateDefinitionAcc(nullptr);
335     }
336 }
337 
338 template void InstBuilder::BuildCallByName<true>(const BytecodeInstruction *bcInst);
339 template void InstBuilder::BuildCallByName<false>(const BytecodeInstruction *bcInst);
340 
341 }  // namespace ark::compiler
342