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 BuildCallHelper<OPCODE, IS_RANGE, ACC_READ>(bcInst, this, newObj);
43 UpdateDefinitionAcc(newObj);
44 }
45
46 template void InstBuilder::BuildLaunch<Opcode::CallLaunchStatic, false, true>(const BytecodeInstruction *bc_inst);
47 template void InstBuilder::BuildLaunch<Opcode::CallLaunchStatic, true, false>(const BytecodeInstruction *bcInst);
48 template void InstBuilder::BuildLaunch<Opcode::CallLaunchStatic, false, false>(const BytecodeInstruction *bcInst);
49
50 template void InstBuilder::BuildLaunch<Opcode::CallLaunchVirtual, false, true>(const BytecodeInstruction *bc_inst);
51 template void InstBuilder::BuildLaunch<Opcode::CallLaunchVirtual, true, false>(const BytecodeInstruction *bcInst);
52 template void InstBuilder::BuildLaunch<Opcode::CallLaunchVirtual, false, false>(const BytecodeInstruction *bcInst);
53
BuildLdObjByName(const BytecodeInstruction * bcInst,DataType::Type type)54 void InstBuilder::BuildLdObjByName(const BytecodeInstruction *bcInst, DataType::Type type)
55 {
56 auto pc = GetPc(bcInst->GetAddress());
57 // Create SaveState instruction
58 auto saveState = CreateSaveState(Opcode::SaveState, pc);
59
60 // Create NullCheck instruction
61 auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
62
63 auto runtime = GetRuntime();
64 auto fieldIndex = bcInst->GetId(0).AsIndex();
65 auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
66 if (type != DataType::REFERENCE) {
67 type = runtime->GetFieldTypeById(GetMethod(), fieldId);
68 }
69
70 RuntimeInterface::IntrinsicId id;
71 switch (type) {
72 case DataType::REFERENCE:
73 id = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_OBJ;
74 break;
75 case DataType::FLOAT64:
76 id = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_F64;
77 break;
78 case DataType::FLOAT32:
79 id = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_F32;
80 break;
81 case DataType::UINT64:
82 case DataType::INT64:
83 id = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_I64;
84 break;
85 case DataType::UINT8:
86 case DataType::INT8:
87 case DataType::UINT16:
88 case DataType::INT16:
89 case DataType::UINT32:
90 case DataType::INT32:
91 id = RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_LD_OBJ_BY_NAME_I32;
92 break;
93 default:
94 UNREACHABLE();
95 break;
96 }
97 auto intrinsic = GetGraph()->CreateInstIntrinsic(type, pc, id);
98 intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 2_I);
99
100 intrinsic->AppendInput(nullCheck);
101 intrinsic->AddInputType(DataType::REFERENCE);
102
103 intrinsic->AppendInput(saveState);
104 intrinsic->AddInputType(DataType::NO_TYPE);
105
106 intrinsic->AddImm(GetGraph()->GetAllocator(), fieldId);
107 intrinsic->AddImm(GetGraph()->GetAllocator(), pc);
108
109 intrinsic->SetMethodFirstInput();
110 intrinsic->SetMethod(GetMethod());
111
112 AddInstruction(saveState);
113 AddInstruction(nullCheck);
114 AddInstruction(intrinsic);
115
116 UpdateDefinitionAcc(intrinsic);
117 }
118
ExtractIntrinsicIdByType(DataType::Type type)119 std::pair<RuntimeInterface::IntrinsicId, DataType::Type> ExtractIntrinsicIdByType(DataType::Type type)
120 {
121 switch (type) {
122 case DataType::REFERENCE:
123 return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_OBJ, type};
124 case DataType::FLOAT64:
125 return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_F64, type};
126 case DataType::FLOAT32:
127 return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_F32, type};
128 case DataType::UINT64:
129 case DataType::INT64:
130 return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I64, DataType::INT64};
131 case DataType::UINT8:
132 case DataType::INT8:
133 return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I8, DataType::INT8};
134 case DataType::UINT16:
135 case DataType::INT16:
136 return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I16, DataType::INT16};
137 case DataType::UINT32:
138 case DataType::INT32:
139 return {RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_ST_OBJ_BY_NAME_I32, DataType::INT32};
140 default:
141 UNREACHABLE();
142 break;
143 }
144 UNREACHABLE();
145 }
146
CreateStObjByNameIntrinsic(size_t pc,DataType::Type type)147 IntrinsicInst *InstBuilder::CreateStObjByNameIntrinsic(size_t pc, DataType::Type type)
148 {
149 auto [id, extractedType] = ExtractIntrinsicIdByType(type);
150 type = extractedType;
151 auto *intrinsic = GetGraph()->CreateInstIntrinsic(DataType::VOID, pc, id);
152 intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 3_I);
153 intrinsic->AddInputType(DataType::REFERENCE);
154 intrinsic->AddInputType(type);
155 intrinsic->AddInputType(DataType::NO_TYPE);
156 return intrinsic;
157 }
158
BuildStObjByName(const BytecodeInstruction * bcInst,DataType::Type type)159 void InstBuilder::BuildStObjByName(const BytecodeInstruction *bcInst, DataType::Type type)
160 {
161 auto pc = GetPc(bcInst->GetAddress());
162 // Create SaveState instruction
163 auto saveState = CreateSaveState(Opcode::SaveState, pc);
164 // Create NullCheck instruction
165 auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
166
167 auto runtime = GetRuntime();
168 auto fieldIndex = bcInst->GetId(0).AsIndex();
169 auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
170 if (type != DataType::REFERENCE) {
171 type = runtime->GetFieldTypeById(GetMethod(), fieldId);
172 }
173
174 // Get a value to store
175 Inst *storeVal = nullptr;
176 storeVal = GetDefinitionAcc();
177
178 auto *intrinsic = CreateStObjByNameIntrinsic(pc, type);
179 intrinsic->AppendInput(nullCheck);
180 intrinsic->AppendInput(storeVal);
181 intrinsic->AppendInput(saveState);
182 intrinsic->AddImm(GetGraph()->GetAllocator(), fieldId);
183 intrinsic->AddImm(GetGraph()->GetAllocator(), pc);
184
185 intrinsic->SetMethodFirstInput();
186 intrinsic->SetMethod(GetMethod());
187
188 AddInstruction(saveState);
189 AddInstruction(nullCheck);
190 AddInstruction(intrinsic);
191 }
192
BuildEquals(const BytecodeInstruction * bcInst)193 void InstBuilder::BuildEquals(const BytecodeInstruction *bcInst)
194 {
195 auto pc = GetPc(bcInst->GetAddress());
196
197 Inst *obj1 = GetDefinition(bcInst->GetVReg(0));
198 Inst *obj2 = GetDefinition(bcInst->GetVReg(1));
199
200 auto intrinsic = GetGraph()->CreateInstIntrinsic(DataType::BOOL, pc,
201 RuntimeInterface::IntrinsicId::INTRINSIC_COMPILER_ETS_EQUALS);
202 intrinsic->AllocateInputTypes(GetGraph()->GetAllocator(), 2_I);
203
204 intrinsic->AppendInput(obj1);
205 intrinsic->AddInputType(DataType::REFERENCE);
206 intrinsic->AppendInput(obj2);
207 intrinsic->AddInputType(DataType::REFERENCE);
208
209 AddInstruction(intrinsic);
210 UpdateDefinitionAcc(intrinsic);
211 }
212
213 } // namespace ark::compiler
214