• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 
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 
29 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ>
BuildLaunch(const BytecodeInstruction * bcInst)30 void InstBuilder::BuildLaunch(const BytecodeInstruction *bcInst)
31 {
32     if (graph_->GetArch() == Arch::AARCH32) {
33         failed_ = true;
34         return;
35     }
36     auto pc = GetPc(bcInst->GetAddress());
37     auto inst = graph_->CreateInstLoadRuntimeClass(
38         DataType::REFERENCE, pc, TypeIdMixin {TypeIdMixin::MEM_PROMISE_CLASS_ID, GetGraph()->GetMethod()}, nullptr);
39     auto saveState = CreateSaveState(Opcode::SaveState, pc);
40     auto newObj = CreateNewObjectInst(pc, TypeIdMixin::MEM_PROMISE_CLASS_ID, saveState, inst);
41     AddInstruction(saveState, inst, newObj);
42     if (GetGraph()->IsAbcKit()) {
43         BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, false>(bcInst, this, newObj);
44     } else {
45         BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, true>(bcInst, this, newObj);
46     }
47     UpdateDefinitionAcc(newObj);
48 }
49 
50 template void InstBuilder::BuildLaunch<Opcode::CallLaunchStatic, false, true>(const BytecodeInstruction *bc_inst);
51 template void InstBuilder::BuildLaunch<Opcode::CallLaunchStatic, true, false>(const BytecodeInstruction *bcInst);
52 template void InstBuilder::BuildLaunch<Opcode::CallLaunchStatic, false, false>(const BytecodeInstruction *bcInst);
53 
54 template void InstBuilder::BuildLaunch<Opcode::CallLaunchVirtual, false, true>(const BytecodeInstruction *bc_inst);
55 template void InstBuilder::BuildLaunch<Opcode::CallLaunchVirtual, true, false>(const BytecodeInstruction *bcInst);
56 template void InstBuilder::BuildLaunch<Opcode::CallLaunchVirtual, false, false>(const BytecodeInstruction *bcInst);
57 
GetIntrinsicId(DataType::Type type)58 static RuntimeInterface::IntrinsicId GetIntrinsicId(DataType::Type type)
59 {
60     switch (type) {
61         case DataType::REFERENCE:
62             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_OBJ;
63         case DataType::FLOAT64:
64             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_F64;
65         case DataType::FLOAT32:
66             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_F32;
67         case DataType::UINT64:
68         case DataType::INT64:
69             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_I64;
70         case DataType::UINT8:
71         case DataType::INT8:
72         case DataType::UINT16:
73         case DataType::INT16:
74         case DataType::UINT32:
75         case DataType::INT32:
76             return RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_I32;
77         default:
78             UNREACHABLE();
79     }
80 }
81 
82 template <bool IS_ABC_KIT>
BuildLdObjByName(const BytecodeInstruction * bcInst,compiler::DataType::Type type)83 void InstBuilder::BuildLdObjByName(const BytecodeInstruction *bcInst, compiler::DataType::Type type)
84 {
85     auto pc = GetPc(bcInst->GetAddress());
86 
87     auto runtime = GetRuntime();
88     auto fieldIndex = bcInst->GetId(0).AsIndex();
89     auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
90     if (type != DataType::REFERENCE) {
91         type = runtime->GetFieldTypeById(GetMethod(), fieldId);
92     }
93 
94     auto intrinsic = GetGraph()->CreateInstIntrinsic(type, pc, GetIntrinsicId(type));
95     if constexpr (!IS_ABC_KIT) {
96         intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 2_I);
97 
98         // Create SaveState instruction
99         auto saveState = CreateSaveState(Opcode::SaveState, pc);
100 
101         // Create NullCheck instruction
102         auto nullCheck =
103             graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
104 
105         intrinsic->AppendInput(nullCheck);
106         intrinsic->AddInputType(DataType::REFERENCE);
107         intrinsic->AppendInput(saveState);
108         intrinsic->AddInputType(DataType::NO_TYPE);
109 
110         AddInstruction(saveState);
111         AddInstruction(nullCheck);
112     }
113 
114     intrinsic->AddImm(GetGraph()->GetAllocator(), fieldId);
115     intrinsic->AddImm(GetGraph()->GetAllocator(), pc);
116 
117     intrinsic->SetMethodFirstInput();
118     intrinsic->SetMethod(GetMethod());
119 
120     AddInstruction(intrinsic);
121 
122     UpdateDefinitionAcc(intrinsic);
123 }
124 
125 template void InstBuilder::BuildLdObjByName<true>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
126 template void InstBuilder::BuildLdObjByName<false>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
127 
ExtractIntrinsicIdByType(DataType::Type type)128 std::pair<RuntimeInterface::IntrinsicId, DataType::Type> ExtractIntrinsicIdByType(DataType::Type type)
129 {
130     switch (type) {
131         case DataType::REFERENCE:
132             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_OBJ, type};
133         case DataType::FLOAT64:
134             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_F64, type};
135         case DataType::FLOAT32:
136             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_F32, type};
137         case DataType::UINT64:
138         case DataType::INT64:
139             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I64, DataType::INT64};
140         case DataType::UINT8:
141         case DataType::INT8:
142             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I8, DataType::INT8};
143         case DataType::UINT16:
144         case DataType::INT16:
145             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I16, DataType::INT16};
146         case DataType::UINT32:
147         case DataType::INT32:
148             return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I32, DataType::INT32};
149         default:
150             UNREACHABLE();
151             break;
152     }
153     UNREACHABLE();
154 }
155 
156 template <bool IS_ABC_KIT>
CreateStObjByNameIntrinsic(size_t pc,compiler::DataType::Type type)157 IntrinsicInst *InstBuilder::CreateStObjByNameIntrinsic(size_t pc, compiler::DataType::Type type)
158 {
159     auto [id, extractedType] = ExtractIntrinsicIdByType(type);
160     type = extractedType;
161     auto *intrinsic = GetGraph()->CreateInstIntrinsic(DataType::VOID, pc, id);
162 
163     if (intrinsic->RequireState()) {
164         intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 3_I);
165         intrinsic->AddInputType(DataType::REFERENCE);
166         intrinsic->AddInputType(type);
167         intrinsic->AddInputType(DataType::NO_TYPE);
168     } else {
169         intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 1_I);
170         intrinsic->AddInputType(type);
171     }
172     return intrinsic;
173 }
174 
175 template IntrinsicInst *InstBuilder::CreateStObjByNameIntrinsic<true>(size_t pc, compiler::DataType::Type type);
176 template IntrinsicInst *InstBuilder::CreateStObjByNameIntrinsic<false>(size_t pc, compiler::DataType::Type type);
177 
178 template <bool IS_ABC_KIT>
BuildStObjByName(const BytecodeInstruction * bcInst,compiler::DataType::Type type)179 void InstBuilder::BuildStObjByName(const BytecodeInstruction *bcInst, compiler::DataType::Type type)
180 {
181     auto pc = GetPc(bcInst->GetAddress());
182 
183     auto runtime = GetRuntime();
184     auto fieldIndex = bcInst->GetId(0).AsIndex();
185     auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
186     if (type != DataType::REFERENCE) {
187         type = runtime->GetFieldTypeById(GetMethod(), fieldId);
188     }
189 
190     // Get a value to store
191     Inst *storeVal = nullptr;
192     storeVal = GetDefinitionAcc();
193 
194     auto *intrinsic = CreateStObjByNameIntrinsic<IS_ABC_KIT>(pc, type);
195 
196     if constexpr (!IS_ABC_KIT) {
197         // Create SaveState instruction
198         auto saveState = CreateSaveState(Opcode::SaveState, pc);
199         // Create NullCheck instruction
200         auto nullCheck =
201             graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
202 
203         intrinsic->AppendInput(nullCheck);
204         intrinsic->AppendInput(storeVal);
205         intrinsic->AppendInput(saveState);
206         AddInstruction(saveState);
207         AddInstruction(nullCheck);
208     } else {
209         intrinsic->AppendInput(storeVal);
210     }
211 
212     intrinsic->AddImm(GetGraph()->GetAllocator(), fieldId);
213     intrinsic->AddImm(GetGraph()->GetAllocator(), pc);
214 
215     intrinsic->SetMethodFirstInput();
216     intrinsic->SetMethod(GetMethod());
217 
218     AddInstruction(intrinsic);
219 }
220 
221 template void InstBuilder::BuildStObjByName<true>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
222 template void InstBuilder::BuildStObjByName<false>(const BytecodeInstruction *bcInst, compiler::DataType::Type type);
223 
BuildIsUndefined(const BytecodeInstruction * bcInst)224 void InstBuilder::BuildIsUndefined(const BytecodeInstruction *bcInst)
225 {
226     auto undefInst = graph_->GetOrCreateUndefinedInst();
227     auto cmpInst = graph_->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), GetDefinitionAcc(), undefInst,
228                                              DataType::REFERENCE, ConditionCode::CC_EQ);
229     AddInstruction(cmpInst);
230     UpdateDefinitionAcc(cmpInst);
231 }
232 
BuildEquals(const BytecodeInstruction * bcInst)233 void InstBuilder::BuildEquals(const BytecodeInstruction *bcInst)
234 {
235     auto pc = GetPc(bcInst->GetAddress());
236 
237     Inst *obj1 = GetDefinition(bcInst->GetVReg(0));
238     Inst *obj2 = GetDefinition(bcInst->GetVReg(1));
239 
240     RuntimeInterface::IntrinsicId intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_EQUALS;
241 #if defined(ENABLE_LIBABCKIT)
242     if (GetGraph()->IsAbcKit()) {
243         intrinsicId = RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_EQUALS;
244     }
245 #endif
246     auto intrinsic = GetGraph()->CreateInstIntrinsic(DataType::BOOL, pc, intrinsicId);
247     intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 2_I);
248 
249     intrinsic->AppendInput(obj1);
250     intrinsic->AddInputType(DataType::REFERENCE);
251     intrinsic->AppendInput(obj2);
252     intrinsic->AddInputType(DataType::REFERENCE);
253 
254     AddInstruction(intrinsic);
255     UpdateDefinitionAcc(intrinsic);
256 }
257 
258 }  // namespace ark::compiler
259