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