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 #ifndef PANDA_INST_BUILDER_INL_H
17 #define PANDA_INST_BUILDER_INL_H
18
19 #include "inst_builder.h"
20 #include "optimizer/code_generator/encode.h"
21
22 namespace ark::compiler {
23
24 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
GetClassId()25 uint32_t InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::GetClassId()
26 {
27 if (method_ == nullptr) {
28 return 0;
29 }
30 if (GetGraph()->IsAotMode()) {
31 return GetRuntime()->GetClassIdWithinFile(GetMethod(), GetRuntime()->GetClass(method_));
32 }
33 return GetRuntime()->GetClassIdForMethod(GetMethod(), methodId_);
34 }
35
36 // NOLINTNEXTLINE(misc-definitions-in-headers,readability-function-size)
37 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildCallHelper(const BytecodeInstruction * bcInst,InstBuilder * builder,Inst * additionalInput)38 InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildCallHelper(
39 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput)
40 : builder_(builder), bcInst_(bcInst)
41 {
42 methodId_ = GetRuntime()->ResolveMethodIndex(Builder()->GetMethod(), bcInst->GetId(0).AsIndex());
43 pc_ = Builder()->GetPc(bcInst->GetAddress());
44 hasImplicitArg_ = !GetRuntime()->IsMethodStatic(Builder()->GetMethod(), methodId_);
45
46 if (GetRuntime()->IsMethodIntrinsic(Builder()->GetMethod(), methodId_)) {
47 // Do not move "GetMethodId" ouside this if! Success of "IsMethodIntrinsic" guarantees that class and method are
48 // loaded. Thus value of "method_" is not nullptr and can be used in BuildIntrinsic.
49 method_ = GetRuntime()->GetMethodById(Builder()->GetMethod(), methodId_);
50 BuildIntrinsic();
51 return;
52 }
53 // Here "GetMethodById" can be used without additional checks, result may be nullptr and it is normal situation
54 method_ = GetRuntime()->GetMethodById(Builder()->GetMethod(), methodId_);
55 saveState_ = nullptr;
56 uint32_t classId = 0;
57 if constexpr (HAS_SAVE_STATE) {
58 saveState_ = Builder()->CreateSaveState(Opcode::SaveState, pc_);
59 if (hasImplicitArg_) {
60 nullCheck_ = GetGraph()->CreateInstNullCheck(DataType::REFERENCE, pc_,
61 Builder()->GetArgDefinition(bcInst, 0, ACC_READ), saveState_);
62 } else {
63 classId = GetClassId();
64 }
65 } else {
66 classId = GetClassId();
67 }
68
69 // NOLINTNEXTLINE(readability-magic-numbers)
70 BuildCallInst(classId);
71 SetCallArgs(additionalInput);
72
73 if constexpr (HAS_SAVE_STATE) {
74 // Add SaveState
75 if (saveState_ != nullptr) {
76 Builder()->AddInstruction(saveState_);
77 }
78 // Add NullCheck
79 if (hasImplicitArg_) {
80 ASSERT(nullCheck_ != nullptr);
81 Builder()->AddInstruction(nullCheck_);
82 } else if (!call_->IsUnresolved() && static_cast<CallInst *>(call_)->GetCallMethod() != nullptr) {
83 // Initialize class as call is resolved
84 BuildInitClassInstForCallStatic(classId);
85 }
86 // Add resolver
87 if (resolver_ != nullptr) {
88 if (call_->IsStaticCall()) {
89 resolver_->SetInput(0, saveState_);
90 } else {
91 resolver_->SetInput(0, nullCheck_);
92 resolver_->SetInput(1, saveState_);
93 }
94 Builder()->AddInstruction(resolver_);
95 }
96 }
97 // Add Call
98 AddCallInstruction();
99 }
100
101 // NOLINTNEXTLINE(misc-definitions-in-headers)
102 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
SetCallArgs(Inst * additionalInput)103 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::SetCallArgs(Inst *additionalInput)
104 {
105 size_t hiddenArgsCount = hasImplicitArg_ ? 1 : 0; // +1 for non-static call
106 size_t additionalArgsCount = additionalInput == nullptr ? 0 : 1; // +1 for launch call
107 size_t argsCount = Builder()->GetMethodArgumentsCount(methodId_);
108 size_t totalArgsCount = hiddenArgsCount + argsCount + additionalArgsCount;
109 size_t inputsCount = totalArgsCount + (call_->RequireState() ? 0 : 1) + (resolver_ == nullptr ? 0 : 1);
110 call_->ReserveInputs(inputsCount);
111 call_->AllocateInputTypes(GetGraph()->GetAllocator(), inputsCount);
112 if (resolver_ != nullptr) {
113 call_->AppendInput(resolver_);
114 call_->AddInputType(DataType::POINTER);
115 }
116 if (additionalInput != nullptr) {
117 ASSERT(call_->RequireState() && saveState_ != nullptr);
118 call_->AppendInput(additionalInput);
119 call_->AddInputType(DataType::REFERENCE);
120 saveState_->AppendBridge(additionalInput);
121 }
122 if (hasImplicitArg_ && nullCheck_ != nullptr) {
123 call_->AppendInput(nullCheck_);
124 call_->AddInputType(DataType::REFERENCE);
125 }
126 if constexpr (!HAS_SAVE_STATE) {
127 if (hasImplicitArg_) {
128 call_->AppendInput(Builder()->GetArgDefinition(bcInst_, 0, ACC_READ));
129 call_->AddInputType(DataType::REFERENCE);
130 }
131 }
132 if constexpr (IS_RANGE) {
133 auto startReg = bcInst_->GetVReg(0);
134 // start reg for Virtual call was added
135 if (hasImplicitArg_) {
136 ++startReg;
137 }
138 for (size_t i = 0; i < argsCount; startReg++, i++) {
139 call_->AppendInput(Builder()->GetDefinition(startReg));
140 call_->AddInputType(Builder()->GetMethodArgumentType(methodId_, i));
141 }
142 } else {
143 for (size_t i = 0; i < argsCount; i++) {
144 call_->AppendInput(Builder()->GetArgDefinition(bcInst_, i + hiddenArgsCount, ACC_READ));
145 call_->AddInputType(Builder()->GetMethodArgumentType(methodId_, i));
146 }
147 }
148 if (call_->RequireState()) {
149 call_->AppendInput(saveState_);
150 call_->AddInputType(DataType::NO_TYPE);
151 }
152 }
153
154 // NOLINTNEXTLINE(misc-definitions-in-headers)
155 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildInitClassInstForCallStatic(uint32_t classId)156 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildInitClassInstForCallStatic(
157 uint32_t classId)
158 {
159 if (Builder()->GetClassId() != classId) {
160 auto initClass = GetGraph()->CreateInstInitClass(DataType::NO_TYPE, pc_, saveState_,
161 TypeIdMixin {classId, GetGraph()->GetMethod()},
162 GetRuntime()->GetClass(method_));
163 Builder()->AddInstruction(initClass);
164 }
165 }
166
167 // NOLINTNEXTLINE(misc-definitions-in-headers)
168 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildCallStaticInst(uint32_t classId)169 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildCallStaticInst(uint32_t classId)
170 {
171 constexpr auto SLOT_KIND = UnresolvedTypesInterface::SlotKind::METHOD;
172 if (method_ == nullptr || (GetRuntime()->IsMethodStatic(GetMethod(), methodId_) && classId == 0) ||
173 Builder()->ForceUnresolved() || (OPCODE == Opcode::CallLaunchStatic && GetGraph()->IsAotMode())) {
174 resolver_ = GetGraph()->CreateInstResolveStatic(DataType::POINTER, pc_, methodId_, nullptr);
175 if constexpr (OPCODE == Opcode::CallStatic) {
176 call_ = GetGraph()->CreateInstCallResolvedStatic(Builder()->GetMethodReturnType(methodId_), pc_, methodId_);
177 } else {
178 call_ = GetGraph()->CreateInstCallResolvedLaunchStatic(DataType::VOID, pc_, methodId_);
179 }
180 if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
181 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), methodId_, SLOT_KIND);
182 }
183 } else {
184 if constexpr (OPCODE == Opcode::CallStatic) {
185 call_ =
186 GetGraph()->CreateInstCallStatic(Builder()->GetMethodReturnType(methodId_), pc_, methodId_, method_);
187 } else {
188 call_ = GetGraph()->CreateInstCallLaunchStatic(DataType::VOID, pc_, methodId_, method_);
189 }
190 }
191 }
192
193 // NOLINTNEXTLINE(misc-definitions-in-headers)
194 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildCallVirtualInst()195 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildCallVirtualInst()
196 {
197 constexpr auto SLOT_KIND = UnresolvedTypesInterface::SlotKind::VIRTUAL_METHOD;
198 ASSERT(!GetRuntime()->IsMethodStatic(Builder()->GetMethod(), methodId_));
199 if (method_ != nullptr && (GetRuntime()->IsInterfaceMethod(method_) || GetGraph()->IsAotNoChaMode())) {
200 resolver_ = GetGraph()->CreateInstResolveVirtual(DataType::POINTER, pc_, methodId_, method_);
201 if constexpr (OPCODE == Opcode::CallVirtual) {
202 call_ = GetGraph()->CreateInstCallResolvedVirtual(Builder()->GetMethodReturnType(methodId_), pc_, methodId_,
203 method_);
204 } else {
205 call_ = GetGraph()->CreateInstCallResolvedLaunchVirtual(DataType::VOID, pc_, methodId_, method_);
206 }
207 } else if (method_ == nullptr || Builder()->ForceUnresolved()) {
208 resolver_ = GetGraph()->CreateInstResolveVirtual(DataType::POINTER, pc_, methodId_, nullptr);
209 if constexpr (OPCODE == Opcode::CallVirtual) {
210 call_ =
211 GetGraph()->CreateInstCallResolvedVirtual(Builder()->GetMethodReturnType(methodId_), pc_, methodId_);
212 } else {
213 call_ = GetGraph()->CreateInstCallResolvedLaunchVirtual(DataType::VOID, pc_, methodId_);
214 }
215 if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
216 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(Builder()->GetMethod(), methodId_, SLOT_KIND);
217 }
218 } else {
219 ASSERT(method_ != nullptr);
220 if constexpr (OPCODE == Opcode::CallVirtual) {
221 call_ =
222 GetGraph()->CreateInstCallVirtual(Builder()->GetMethodReturnType(methodId_), pc_, methodId_, method_);
223 } else {
224 call_ = GetGraph()->CreateInstCallLaunchVirtual(DataType::VOID, pc_, methodId_, method_);
225 }
226 }
227 }
228
229 // NOLINTNEXTLINE(misc-definitions-in-headers)
230 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildCallInst(uint32_t classId)231 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildCallInst(
232 // CC-OFFNXT(G.FMT.06) false positive
233 [[maybe_unused]] uint32_t classId)
234 {
235 // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements,bugprone-suspicious-semicolon)
236 if constexpr (OPCODE == Opcode::CallStatic || OPCODE == Opcode::CallLaunchStatic) {
237 BuildCallStaticInst(classId);
238 }
239 // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements,bugprone-suspicious-semicolon)
240 if constexpr (OPCODE == Opcode::CallVirtual || OPCODE == Opcode::CallLaunchVirtual) {
241 BuildCallVirtualInst();
242 }
243 if (UNLIKELY(call_ == nullptr)) {
244 UNREACHABLE();
245 }
246 static_cast<CallInst *>(call_)->SetCanNativeException(method_ == nullptr ||
247 GetRuntime()->HasNativeException(method_));
248 }
249
250 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildMonitor(const BytecodeInstruction * bcInst,Inst * def,bool isEnter)251 void InstBuilder::BuildMonitor(const BytecodeInstruction *bcInst, Inst *def, bool isEnter)
252 {
253 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
254 auto inst = GetGraph()->CreateInstMonitor(DataType::VOID, GetPc(bcInst->GetAddress()));
255 AddInstruction(saveState);
256 if (!isEnter) {
257 inst->CastToMonitor()->SetExit();
258 } else {
259 // Create NullCheck instruction
260 auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, GetPc(bcInst->GetAddress()), def, saveState);
261 def = nullCheck;
262 AddInstruction(nullCheck);
263 }
264 inst->SetInput(0, def);
265 inst->SetInput(1, saveState);
266
267 AddInstruction(inst);
268 }
269
270 #include <intrinsics_ir_build.inl>
271
272 // NOLINTNEXTLINE(misc-definitions-in-headers)
273 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildDefaultStaticIntrinsic(RuntimeInterface::IntrinsicId intrinsicId)274 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildDefaultStaticIntrinsic(
275 RuntimeInterface::IntrinsicId intrinsicId)
276 {
277 ASSERT(intrinsicId != RuntimeInterface::IntrinsicId::COUNT);
278 auto retType = Builder()->GetMethodReturnType(methodId_);
279 call_ = GetGraph()->CreateInstIntrinsic(retType, pc_, intrinsicId);
280 // If an intrinsic may call runtime then we need a SaveState
281 saveState_ = call_->RequireState() ? Builder()->CreateSaveState(Opcode::SaveState, pc_) : nullptr;
282 SetCallArgs();
283 if (saveState_ != nullptr) {
284 Builder()->AddInstruction(saveState_);
285 }
286 /* if there are reference type args to be checked for NULL ('need_nullcheck' intrinsic property) */
287 Builder()->template AddArgNullcheckIfNeeded<false>(intrinsicId, call_, saveState_, pc_);
288 AddCallInstruction();
289 if (NeedSafePointAfterIntrinsic(intrinsicId)) {
290 Builder()->AddInstruction(Builder()->CreateSafePoint(Builder()->GetCurrentBlock()));
291 }
292 }
293
294 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildAbsIntrinsic(const BytecodeInstruction * bcInst,bool accRead)295 void InstBuilder::BuildAbsIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
296 {
297 auto methodIndex = bcInst->GetId(0).AsIndex();
298 auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
299 auto inst = GetGraph()->CreateInstAbs(GetMethodReturnType(methodId), GetPc(bcInst->GetAddress()));
300 ASSERT(GetMethodArgumentsCount(methodId) == 1);
301 inst->SetInput(0, GetArgDefinition(bcInst, 0, accRead));
302 AddInstruction(inst);
303 UpdateDefinitionAcc(inst);
304 }
305
306 template <Opcode OPCODE>
307 static BinaryOperation *CreateBinaryOperation(Graph *graph, DataType::Type returnType, size_t pc) = delete;
308
309 template <>
310 BinaryOperation *CreateBinaryOperation<Opcode::Min>(Graph *graph, DataType::Type returnType, size_t pc)
311 {
312 return graph->CreateInstMin(returnType, pc);
313 }
314
315 template <>
316 BinaryOperation *CreateBinaryOperation<Opcode::Max>(Graph *graph, DataType::Type returnType, size_t pc)
317 {
318 return graph->CreateInstMax(returnType, pc);
319 }
320
321 template <>
322 BinaryOperation *CreateBinaryOperation<Opcode::Mod>(Graph *graph, DataType::Type returnType, size_t pc)
323 {
324 return graph->CreateInstMod(returnType, pc);
325 }
326
327 template void InstBuilder::BuildBinaryOperationIntrinsic<Opcode::Mod>(const BytecodeInstruction *bcInst, bool accRead);
328
329 template <Opcode OPCODE>
BuildBinaryOperationIntrinsic(const BytecodeInstruction * bcInst,bool accRead)330 void InstBuilder::BuildBinaryOperationIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
331 {
332 auto methodIndex = bcInst->GetId(0).AsIndex();
333 [[maybe_unused]] auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
334 ASSERT(GetMethodArgumentsCount(methodId) == 2U);
335 // NOLINTNEXTLINE(readability-magic-numbers)
336 auto inst = CreateBinaryOperation<OPCODE>(GetGraph(), GetMethodReturnType(methodId), GetPc(bcInst->GetAddress()));
337 inst->SetInput(0, GetArgDefinition(bcInst, 0, accRead));
338 inst->SetInput(1, GetArgDefinition(bcInst, 1, accRead));
339 AddInstruction(inst);
340 UpdateDefinitionAcc(inst);
341 }
342
343 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildSqrtIntrinsic(const BytecodeInstruction * bcInst,bool accRead)344 void InstBuilder::BuildSqrtIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
345 {
346 auto methodIndex = bcInst->GetId(0).AsIndex();
347 [[maybe_unused]] auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
348 auto inst = GetGraph()->CreateInstSqrt(GetMethodReturnType(methodId), GetPc(bcInst->GetAddress()));
349 ASSERT(GetMethodArgumentsCount(methodId) == 1);
350 Inst *def = GetArgDefinition(bcInst, 0, accRead);
351 inst->SetInput(0, def);
352 AddInstruction(inst);
353 UpdateDefinitionAcc(inst);
354 }
355
356 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildIsNanIntrinsic(const BytecodeInstruction * bcInst,bool accRead)357 void InstBuilder::BuildIsNanIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
358 {
359 auto methodIndex = bcInst->GetId(0).AsIndex();
360 auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
361 // No need to create specialized node for isNaN. Since NaN != NaN, simple float compare node is fine.
362 // Also, ensure that float comparison node is implemented for specific architecture
363 auto vreg = GetArgDefinition(bcInst, 0, accRead);
364 auto inst = GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), vreg, vreg,
365 GetMethodArgumentType(methodId, 0), ConditionCode::CC_NE);
366 inst->SetOperandsType(GetMethodArgumentType(methodId, 0));
367 AddInstruction(inst);
368 UpdateDefinitionAcc(inst);
369 }
370
371 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStringLengthIntrinsic(const BytecodeInstruction * bcInst,bool accRead)372 void InstBuilder::BuildStringLengthIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
373 {
374 auto bcAddr = GetPc(bcInst->GetAddress());
375 auto saveState = CreateSaveState(Opcode::SaveState, bcAddr);
376
377 auto nullCheck =
378 graph_->CreateInstNullCheck(DataType::REFERENCE, bcAddr, GetArgDefinition(bcInst, 0, accRead), saveState);
379 auto arrayLength = graph_->CreateInstLenArray(DataType::INT32, bcAddr, nullCheck, false);
380
381 AddInstruction(saveState);
382 AddInstruction(nullCheck);
383 AddInstruction(arrayLength);
384
385 Inst *stringLength;
386 if (graph_->GetRuntime()->IsCompressedStringsEnabled()) {
387 auto constOneInst = graph_->FindOrCreateConstant(1);
388 stringLength = graph_->CreateInstShr(DataType::INT32, bcAddr, arrayLength, constOneInst);
389 AddInstruction(stringLength);
390 } else {
391 stringLength = arrayLength;
392 }
393 UpdateDefinitionAcc(stringLength);
394 }
395
396 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStringIsEmptyIntrinsic(const BytecodeInstruction * bcInst,bool accRead)397 void InstBuilder::BuildStringIsEmptyIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
398 {
399 auto bcAddr = GetPc(bcInst->GetAddress());
400 auto saveState = CreateSaveState(Opcode::SaveState, bcAddr);
401 auto nullCheck =
402 graph_->CreateInstNullCheck(DataType::REFERENCE, bcAddr, GetArgDefinition(bcInst, 0, accRead), saveState);
403 auto length = graph_->CreateInstLenArray(DataType::INT32, bcAddr, nullCheck, false);
404 auto zeroConst = graph_->FindOrCreateConstant(0);
405 auto checkZeroLength =
406 graph_->CreateInstCompare(DataType::BOOL, bcAddr, length, zeroConst, DataType::INT32, ConditionCode::CC_EQ);
407 AddInstruction(saveState);
408 AddInstruction(nullCheck);
409 AddInstruction(length);
410 AddInstruction(checkZeroLength);
411 UpdateDefinitionAcc(checkZeroLength);
412 }
413
414 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharIsUpperCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)415 void InstBuilder::BuildCharIsUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
416 {
417 // IsUpperCase(char) = (char - 'A') < ('Z' - 'A')
418
419 ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
420
421 // Adding InstCast here as the aternative compiler backend requires inputs of InstSub to be of the same type.
422 // The InstCast instructon makes no harm as normally they are removed by the following compiler stages.
423 auto argInput = GetArgDefinition(bcInst, 0, accRead);
424 auto constInput = graph_->FindOrCreateConstant('A');
425 auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
426 auto constA =
427 GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
428
429 auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
430 auto inst2 =
431 GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
432 graph_->FindOrCreateConstant('Z' - 'A'), DataType::UINT16, ConditionCode::CC_BE);
433
434 AddInstruction(arg);
435 AddInstruction(constA);
436 AddInstruction(inst1);
437 AddInstruction(inst2);
438 UpdateDefinitionAcc(inst2);
439 }
440
441 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharToUpperCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)442 void InstBuilder::BuildCharToUpperCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
443 {
444 // ToUpperCase(char) = ((char - 'a') < ('z' - 'a')) * ('Z' - 'z') + char
445
446 ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
447
448 auto argInput = GetArgDefinition(bcInst, 0, accRead);
449 auto constInput = graph_->FindOrCreateConstant('a');
450 auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
451 auto constA =
452 GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
453
454 auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
455 auto inst2 =
456 GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
457 graph_->FindOrCreateConstant('z' - 'a'), DataType::UINT16, ConditionCode::CC_BE);
458 auto inst3 = GetGraph()->CreateInstMul(DataType::UINT16, GetPc(bcInst->GetAddress()), inst2,
459 graph_->FindOrCreateConstant('Z' - 'z'));
460 auto inst4 = GetGraph()->CreateInstAdd(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, inst3);
461
462 AddInstruction(arg);
463 AddInstruction(constA);
464 AddInstruction(inst1);
465 AddInstruction(inst2);
466 AddInstruction(inst3);
467 AddInstruction(inst4);
468 UpdateDefinitionAcc(inst4);
469 }
470
471 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharIsLowerCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)472 void InstBuilder::BuildCharIsLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
473 {
474 ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
475
476 auto argInput = GetArgDefinition(bcInst, 0, accRead);
477 auto constInput = graph_->FindOrCreateConstant('a');
478 auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
479 auto constA =
480 GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
481
482 auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
483 auto inst2 =
484 GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
485 graph_->FindOrCreateConstant('z' - 'a'), DataType::UINT16, ConditionCode::CC_BE);
486
487 AddInstruction(arg);
488 AddInstruction(constA);
489 AddInstruction(inst1);
490 AddInstruction(inst2);
491 UpdateDefinitionAcc(inst2);
492 }
493
494 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCharToLowerCaseIntrinsic(const BytecodeInstruction * bcInst,bool accRead)495 void InstBuilder::BuildCharToLowerCaseIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
496 {
497 ASSERT(GetMethodArgumentsCount(GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex())) == 1);
498
499 auto argInput = GetArgDefinition(bcInst, 0, accRead);
500 auto constInput = graph_->FindOrCreateConstant('A');
501 auto arg = GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), argInput, argInput->GetType());
502 auto constA =
503 GetGraph()->CreateInstCast(DataType::UINT16, GetPc(bcInst->GetAddress()), constInput, constInput->GetType());
504
505 auto inst1 = GetGraph()->CreateInstSub(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, constA);
506 auto inst2 =
507 GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), inst1,
508 graph_->FindOrCreateConstant('Z' - 'A'), DataType::UINT16, ConditionCode::CC_BE);
509 auto inst3 = GetGraph()->CreateInstMul(DataType::UINT16, GetPc(bcInst->GetAddress()), inst2,
510 graph_->FindOrCreateConstant('z' - 'Z'));
511 auto inst4 = GetGraph()->CreateInstAdd(DataType::UINT16, GetPc(bcInst->GetAddress()), arg, inst3);
512
513 AddInstruction(arg);
514 AddInstruction(constA);
515 AddInstruction(inst1);
516 AddInstruction(inst2);
517 AddInstruction(inst3);
518 AddInstruction(inst4);
519 UpdateDefinitionAcc(inst4);
520 }
521
522 // NOLINTNEXTLINE(misc-definitions-in-headers)
GetArgDefinition(const BytecodeInstruction * bcInst,size_t idx,bool accRead,bool isRange)523 Inst *InstBuilder::GetArgDefinition(const BytecodeInstruction *bcInst, size_t idx, bool accRead, bool isRange)
524 {
525 if (isRange) {
526 return GetArgDefinitionRange(bcInst, idx);
527 }
528 if (accRead) {
529 auto accPos = static_cast<size_t>(bcInst->GetImm64());
530 if (idx < accPos) {
531 return GetDefinition(bcInst->GetVReg(idx));
532 }
533 if (accPos == idx) {
534 return GetDefinitionAcc();
535 }
536 return GetDefinition(bcInst->GetVReg(idx - 1));
537 }
538 return GetDefinition(bcInst->GetVReg(idx));
539 }
540
541 // NOLINTNEXTLINE(misc-definitions-in-headers)
GetArgDefinitionRange(const BytecodeInstruction * bcInst,size_t idx)542 Inst *InstBuilder::GetArgDefinitionRange(const BytecodeInstruction *bcInst, size_t idx)
543 {
544 auto startReg = bcInst->GetVReg(0);
545 return GetDefinition(startReg + idx);
546 }
547
548 // NOLINTNEXTLINE(misc-definitions-in-headers)
549 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildMonitorIntrinsic(bool isEnter)550 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildMonitorIntrinsic(bool isEnter)
551 {
552 ASSERT(Builder()->GetMethodReturnType(methodId_) == DataType::VOID);
553 ASSERT(Builder()->GetMethodArgumentsCount(methodId_) == 1);
554 Builder()->BuildMonitor(bcInst_, Builder()->GetArgDefinition(bcInst_, 0, ACC_READ), isEnter);
555 }
556
557 // NOLINTNEXTLINE(misc-definitions-in-headers)
558 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildIntrinsic()559 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildIntrinsic()
560 {
561 ASSERT(method_ != nullptr);
562 auto intrinsicId = GetRuntime()->GetIntrinsicId(method_);
563 auto isVirtual = IsVirtual(intrinsicId);
564 if (GetGraph()->IsBytecodeOptimizer() || !g_options.IsCompilerEncodeIntrinsics()) {
565 BuildDefaultIntrinsic(intrinsicId, isVirtual);
566 return;
567 }
568 if (!isVirtual) {
569 return BuildStaticCallIntrinsic(intrinsicId);
570 }
571 return BuildVirtualCallIntrinsic(intrinsicId);
572 }
573
574 // NOLINTNEXTLINE(misc-definitions-in-headers)
575 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildDefaultIntrinsic(RuntimeInterface::IntrinsicId intrinsicId,bool isVirtual)576 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildDefaultIntrinsic(
577 RuntimeInterface::IntrinsicId intrinsicId, bool isVirtual)
578 {
579 if (intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER ||
580 intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_EXIT) {
581 BuildMonitorIntrinsic(intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER);
582 return;
583 }
584 // NOLINTNEXTLINE(readability-braces-around-statements)
585 if (!isVirtual) {
586 BuildDefaultStaticIntrinsic(intrinsicId);
587 // NOLINTNEXTLINE(readability-misleading-indentation)
588 } else {
589 BuildDefaultVirtualCallIntrinsic(intrinsicId);
590 }
591 }
592
593 // do not specify reason for tidy suppression because comment does not fit single line
594 // NOLINTNEXTLINE
595 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildStaticCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId)596 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildStaticCallIntrinsic(
597 RuntimeInterface::IntrinsicId intrinsicId)
598 {
599 switch (intrinsicId) {
600 case RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER:
601 case RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_EXIT: {
602 BuildMonitorIntrinsic(intrinsicId == RuntimeInterface::IntrinsicId::INTRINSIC_OBJECT_MONITOR_ENTER);
603 break;
604 }
605 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_I32:
606 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_I64:
607 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_F32:
608 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_ABS_F64: {
609 Builder()->BuildAbsIntrinsic(bcInst_, ACC_READ);
610 break;
611 }
612 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_SQRT_F32:
613 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_SQRT_F64: {
614 Builder()->BuildSqrtIntrinsic(bcInst_, ACC_READ);
615 break;
616 }
617 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_I32:
618 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_I64:
619 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_F32:
620 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MIN_F64: {
621 Builder()->template BuildBinaryOperationIntrinsic<Opcode::Min>(bcInst_, ACC_READ);
622 break;
623 }
624 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_I32:
625 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_I64:
626 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_F32:
627 case RuntimeInterface::IntrinsicId::INTRINSIC_MATH_MAX_F64: {
628 Builder()->template BuildBinaryOperationIntrinsic<Opcode::Max>(bcInst_, ACC_READ);
629 break;
630 }
631 #include "intrinsics_ir_build_static_call.inl"
632 default: {
633 BuildDefaultStaticIntrinsic(intrinsicId);
634 }
635 }
636 }
637
638 // NOLINTNEXTLINE(misc-definitions-in-headers)
639 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
AddCallInstruction()640 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::AddCallInstruction()
641 {
642 Builder()->AddInstruction(call_);
643 if (call_->GetType() != DataType::VOID) {
644 Builder()->UpdateDefinitionAcc(call_);
645 } else {
646 Builder()->UpdateDefinitionAcc(nullptr);
647 }
648 }
649
650 // NOLINTNEXTLINE(misc-definitions-in-headers)
651 template <Opcode OPCODE, bool IS_RANGE, bool ACC_READ, bool HAS_SAVE_STATE>
BuildDefaultVirtualCallIntrinsic(RuntimeInterface::IntrinsicId intrinsicId)652 void InstBuilder::BuildCallHelper<OPCODE, IS_RANGE, ACC_READ, HAS_SAVE_STATE>::BuildDefaultVirtualCallIntrinsic(
653 RuntimeInterface::IntrinsicId intrinsicId)
654 {
655 saveState_ = Builder()->CreateSaveState(Opcode::SaveState, pc_);
656 nullCheck_ = GetGraph()->CreateInstNullCheck(DataType::REFERENCE, pc_,
657 Builder()->GetArgDefinition(bcInst_, 0, ACC_READ), saveState_);
658
659 call_ = GetGraph()->CreateInstIntrinsic(Builder()->GetMethodReturnType(methodId_), pc_, intrinsicId);
660 SetCallArgs();
661
662 Builder()->AddInstruction(saveState_);
663 Builder()->AddInstruction(nullCheck_);
664
665 /* if there are reference type args to be checked for NULL */
666 Builder()->template AddArgNullcheckIfNeeded<true>(intrinsicId, call_, saveState_, pc_);
667
668 AddCallInstruction();
669 if (NeedSafePointAfterIntrinsic(intrinsicId)) {
670 Builder()->AddInstruction(Builder()->CreateSafePoint(Builder()->GetCurrentBlock()));
671 }
672 }
673
674 template InstBuilder::BuildCallHelper<Opcode::CallResolvedStatic, false, false>::BuildCallHelper(
675 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
676 template InstBuilder::BuildCallHelper<Opcode::CallResolvedStatic, false, false, false>::BuildCallHelper(
677 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
678 template InstBuilder::BuildCallHelper<Opcode::CallLaunchStatic, false, false>::BuildCallHelper(
679 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
680 template InstBuilder::BuildCallHelper<Opcode::CallLaunchStatic, false, false, false>::BuildCallHelper(
681 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
682 template InstBuilder::BuildCallHelper<Opcode::CallLaunchStatic, false, true>::BuildCallHelper(
683 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
684 template InstBuilder::BuildCallHelper<Opcode::CallLaunchStatic, false, true, false>::BuildCallHelper(
685 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
686 template InstBuilder::BuildCallHelper<Opcode::CallLaunchStatic, true, false>::BuildCallHelper(
687 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
688 template InstBuilder::BuildCallHelper<Opcode::CallLaunchStatic, true, false, false>::BuildCallHelper(
689 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
690 template InstBuilder::BuildCallHelper<Opcode::CallLaunchVirtual, false, false>::BuildCallHelper(
691 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
692 template InstBuilder::BuildCallHelper<Opcode::CallLaunchVirtual, false, false, false>::BuildCallHelper(
693 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
694 template InstBuilder::BuildCallHelper<Opcode::CallLaunchVirtual, false, true>::BuildCallHelper(
695 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
696 template InstBuilder::BuildCallHelper<Opcode::CallLaunchVirtual, false, true, false>::BuildCallHelper(
697 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
698 template InstBuilder::BuildCallHelper<Opcode::CallLaunchVirtual, true, false>::BuildCallHelper(
699 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
700 template InstBuilder::BuildCallHelper<Opcode::CallLaunchVirtual, true, false, false>::BuildCallHelper(
701 const BytecodeInstruction *bcInst, InstBuilder *builder, Inst *additionalInput);
702
703 // NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers)
704 template <bool IS_ACC_WRITE>
BuildLoadObject(const BytecodeInstruction * bcInst,DataType::Type type)705 void InstBuilder::BuildLoadObject(const BytecodeInstruction *bcInst, DataType::Type type)
706 {
707 auto pc = GetPc(bcInst->GetAddress());
708 // Create SaveState instruction
709 auto saveState = CreateSaveState(Opcode::SaveState, pc);
710 // Create NullCheck instruction
711 auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, pc,
712 GetDefinition(bcInst->GetVReg(IS_ACC_WRITE ? 0 : 1)), saveState);
713 auto runtime = GetRuntime();
714 auto fieldIndex = bcInst->GetId(0).AsIndex();
715 auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
716 auto field = runtime->ResolveField(GetMethod(), fieldId, !GetGraph()->IsAotMode(), nullptr);
717 if (type != DataType::REFERENCE) {
718 type = runtime->GetFieldTypeById(GetMethod(), fieldId);
719 }
720
721 // Create LoadObject instruction
722 Inst *inst;
723 AddInstruction(saveState, nullCheck);
724 if (field == nullptr || ForceUnresolved()) {
725 // 1. Create an instruction to resolve an object's field
726 if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
727 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), fieldId,
728 UnresolvedTypesInterface::SlotKind::FIELD);
729 }
730 auto *resolveField = graph_->CreateInstResolveObjectField(DataType::UINT32, pc, saveState,
731 TypeIdMixin {fieldId, GetGraph()->GetMethod()});
732 AddInstruction(resolveField);
733 // 2. Create an instruction to load a value from the resolved field
734 auto loadField = graph_->CreateInstLoadResolvedObjectField(type, pc, nullCheck, resolveField,
735 TypeIdMixin {fieldId, GetGraph()->GetMethod()});
736 inst = loadField;
737 } else {
738 auto loadField =
739 graph_->CreateInstLoadObject(type, pc, nullCheck, TypeIdMixin {fieldId, GetGraph()->GetMethod()}, field,
740 runtime->IsFieldVolatile(field));
741 // 'final' field can be reassigned e. g. with reflection, but 'readonly' cannot
742 // `IsInConstructor` check should not be necessary, but need proper frontend support first
743 constexpr bool IS_STATIC = false;
744 if (runtime->IsFieldReadonly(field) && !IsInConstructor<IS_STATIC>()) {
745 loadField->ClearFlag(inst_flags::NO_CSE);
746 }
747 inst = loadField;
748 }
749
750 AddInstruction(inst);
751 // NOLINTNEXTLINE(readability-braces-around-statements)
752 if constexpr (IS_ACC_WRITE) {
753 UpdateDefinitionAcc(inst);
754 // NOLINTNEXTLINE(readability-misleading-indentation)
755 } else {
756 UpdateDefinition(bcInst->GetVReg(0), inst);
757 }
758 }
759
760 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStoreObjectInst(const BytecodeInstruction * bcInst,DataType::Type type,RuntimeInterface::FieldPtr field,uint32_t fieldId,Inst ** resolveInst)761 Inst *InstBuilder::BuildStoreObjectInst(const BytecodeInstruction *bcInst, DataType::Type type,
762 RuntimeInterface::FieldPtr field, uint32_t fieldId, Inst **resolveInst)
763 {
764 auto pc = GetPc(bcInst->GetAddress());
765 if (field == nullptr || ForceUnresolved()) {
766 // The field is unresolved, so we have to resolve it and then store
767 // 1. Create an instruction to resolve an object's field
768 auto resolveField = graph_->CreateInstResolveObjectField(DataType::UINT32, pc, nullptr,
769 TypeIdMixin {fieldId, GetGraph()->GetMethod()});
770 if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
771 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), fieldId,
772 UnresolvedTypesInterface::SlotKind::FIELD);
773 }
774 // 2. Create an instruction to store a value to the resolved field
775 auto storeField = graph_->CreateInstStoreResolvedObjectField(type, pc, nullptr, nullptr, nullptr,
776 TypeIdMixin {fieldId, GetGraph()->GetMethod()},
777 false, type == DataType::REFERENCE);
778 *resolveInst = resolveField;
779 return storeField;
780 }
781
782 ASSERT(field != nullptr);
783 auto storeField =
784 graph_->CreateInstStoreObject(type, pc, nullptr, nullptr, TypeIdMixin {fieldId, GetGraph()->GetMethod()}, field,
785 GetRuntime()->IsFieldVolatile(field), type == DataType::REFERENCE);
786 *resolveInst = nullptr; // resolver is not needed in this case
787 return storeField;
788 }
789
790 // NOLINTNEXTLINE(misc-definitions-in-headers)
791 template <bool IS_ACC_READ>
BuildStoreObject(const BytecodeInstruction * bcInst,DataType::Type type)792 void InstBuilder::BuildStoreObject(const BytecodeInstruction *bcInst, DataType::Type type)
793 {
794 // Create SaveState instruction
795 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
796
797 // Create NullCheck instruction
798 auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, GetPc(bcInst->GetAddress()),
799 GetDefinition(bcInst->GetVReg(IS_ACC_READ ? 0 : 1)), saveState);
800
801 auto runtime = GetRuntime();
802 auto fieldIndex = bcInst->GetId(0).AsIndex();
803 auto fieldId = runtime->ResolveFieldIndex(GetMethod(), fieldIndex);
804 auto field = runtime->ResolveField(GetMethod(), fieldId, !GetGraph()->IsAotMode(), nullptr);
805 if (type != DataType::REFERENCE) {
806 type = runtime->GetFieldTypeById(GetMethod(), fieldId);
807 }
808
809 // Get a value to store
810 Inst *storeVal = nullptr;
811 // NOLINTNEXTLINE(readability-braces-around-statements)
812 if constexpr (IS_ACC_READ) {
813 storeVal = GetDefinitionAcc();
814 } else { // NOLINT(readability-misleading-indentation)
815 storeVal = GetDefinition(bcInst->GetVReg(0));
816 }
817
818 // Create StoreObject instruction
819 Inst *resolveField = nullptr;
820 Inst *storeField = BuildStoreObjectInst(bcInst, type, field, fieldId, &resolveField);
821 storeField->SetInput(0, nullCheck);
822 storeField->SetInput(1, storeVal);
823
824 AddInstruction(saveState);
825 AddInstruction(nullCheck);
826 if (resolveField != nullptr) {
827 ASSERT(field == nullptr || ForceUnresolved());
828 resolveField->SetInput(0, saveState);
829 storeField->SetInput(2U, resolveField);
830 AddInstruction(resolveField);
831 }
832 AddInstruction(storeField);
833 }
834
835 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadStaticInst(size_t pc,DataType::Type type,uint32_t typeId,Inst * saveState)836 Inst *InstBuilder::BuildLoadStaticInst(size_t pc, DataType::Type type, uint32_t typeId, Inst *saveState)
837 {
838 uint32_t classId;
839 auto field = GetRuntime()->ResolveField(GetMethod(), typeId, !GetGraph()->IsAotMode(), &classId);
840 if (field == nullptr || ForceUnresolved()) {
841 // The static field is unresolved, so we have to resolve it and then load
842 // 1. Create an instruction to resolve an object's static field.
843 // Its result is a static field memory address (not an offset as there is no object)
844 auto resolveField = graph_->CreateInstResolveObjectFieldStatic(DataType::REFERENCE, pc, saveState,
845 TypeIdMixin {typeId, GetGraph()->GetMethod()});
846 if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
847 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), typeId,
848 UnresolvedTypesInterface::SlotKind::FIELD);
849 }
850 AddInstruction(resolveField);
851 // 2. Create an instruction to load a value from the resolved static field address
852 auto loadField = graph_->CreateInstLoadResolvedObjectFieldStatic(type, pc, resolveField,
853 TypeIdMixin {typeId, GetGraph()->GetMethod()});
854 return loadField;
855 }
856
857 ASSERT(field != nullptr);
858 auto initClass = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, saveState,
859 TypeIdMixin {classId, GetGraph()->GetMethod()},
860 GetRuntime()->GetClassForField(field));
861 auto loadField = graph_->CreateInstLoadStatic(type, pc, initClass, TypeIdMixin {typeId, GetGraph()->GetMethod()},
862 field, GetRuntime()->IsFieldVolatile(field));
863 // 'final' field can be reassigned e. g. with reflection, but 'readonly' cannot
864 // `IsInConstructor` check should not be necessary, but need proper frontend support first
865 constexpr bool IS_STATIC = true;
866 if (GetRuntime()->IsFieldReadonly(field) && !IsInConstructor<IS_STATIC>()) {
867 loadField->ClearFlag(inst_flags::NO_CSE);
868 }
869 AddInstruction(initClass);
870 return loadField;
871 }
872
873 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildAnyTypeCheckInst(size_t bcAddr,Inst * input,Inst * saveState,AnyBaseType type)874 AnyTypeCheckInst *InstBuilder::BuildAnyTypeCheckInst(size_t bcAddr, Inst *input, Inst *saveState, AnyBaseType type)
875 {
876 auto anyCheck = graph_->CreateInstAnyTypeCheck(DataType::ANY, bcAddr, input, saveState, type);
877 AddInstruction(anyCheck);
878 return anyCheck;
879 }
880
881 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadStatic(const BytecodeInstruction * bcInst,DataType::Type type)882 void InstBuilder::BuildLoadStatic(const BytecodeInstruction *bcInst, DataType::Type type)
883 {
884 auto fieldIndex = bcInst->GetId(0).AsIndex();
885 auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), fieldIndex);
886 if (type != DataType::REFERENCE) {
887 type = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
888 }
889 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
890 AddInstruction(saveState);
891 Inst *inst = BuildLoadStaticInst(GetPc(bcInst->GetAddress()), type, fieldId, saveState);
892 AddInstruction(inst);
893 UpdateDefinitionAcc(inst);
894 }
895
896 // NOLINTNEXTLINE(readability-function-size,misc-definitions-in-headers)
BuildStoreStaticInst(const BytecodeInstruction * bcInst,DataType::Type type,uint32_t typeId,Inst * storeInput,Inst * saveState)897 Inst *InstBuilder::BuildStoreStaticInst(const BytecodeInstruction *bcInst, DataType::Type type, uint32_t typeId,
898 Inst *storeInput, Inst *saveState)
899 {
900 AddInstruction(saveState);
901
902 uint32_t classId;
903 auto field = GetRuntime()->ResolveField(GetMethod(), typeId, !GetGraph()->IsAotMode(), &classId);
904 auto pc = GetPc(bcInst->GetAddress());
905
906 if (field == nullptr || ForceUnresolved()) {
907 if (type == DataType::REFERENCE) {
908 // 1. Class initialization is needed.
909 // 2. GC Pre/Post write barriers may be needed.
910 // Just call runtime EntrypointId::UNRESOLVED_STORE_STATIC_BARRIERED,
911 // which performs all the necessary steps (see codegen.cpp for the details).
912 auto inst = graph_->CreateInstUnresolvedStoreStatic(type, pc, storeInput, saveState,
913 TypeIdMixin {typeId, GetGraph()->GetMethod()}, true);
914 return inst;
915 }
916 ASSERT(type != DataType::REFERENCE);
917 // 1. Create an instruction to resolve an object's static field.
918 // Its result is a static field memory address (REFERENCE)
919 auto resolveField = graph_->CreateInstResolveObjectFieldStatic(DataType::REFERENCE, pc, saveState,
920 TypeIdMixin {typeId, GetGraph()->GetMethod()});
921 AddInstruction(resolveField);
922 // 2. Create an instruction to store a value to the resolved static field address
923 auto storeField = graph_->CreateInstStoreResolvedObjectFieldStatic(
924 type, pc, resolveField, storeInput, TypeIdMixin {typeId, GetGraph()->GetMethod()});
925 if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
926 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), typeId,
927 UnresolvedTypesInterface::SlotKind::FIELD);
928 }
929 return storeField;
930 }
931
932 ASSERT(field != nullptr);
933 auto initClass = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, saveState,
934 TypeIdMixin {classId, GetGraph()->GetMethod()},
935 GetRuntime()->GetClassForField(field));
936 auto storeField =
937 graph_->CreateInstStoreStatic(type, pc, initClass, storeInput, TypeIdMixin {typeId, GetGraph()->GetMethod()},
938 field, GetRuntime()->IsFieldVolatile(field), type == DataType::REFERENCE);
939 AddInstruction(initClass);
940 return storeField;
941 }
942
943 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStoreStatic(const BytecodeInstruction * bcInst,DataType::Type type)944 void InstBuilder::BuildStoreStatic(const BytecodeInstruction *bcInst, DataType::Type type)
945 {
946 auto fieldIndex = bcInst->GetId(0).AsIndex();
947 auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), fieldIndex);
948 if (type != DataType::REFERENCE) {
949 type = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
950 }
951 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
952 Inst *storeInput = GetDefinitionAcc();
953 Inst *inst = BuildStoreStaticInst(bcInst, type, fieldId, storeInput, saveState);
954 AddInstruction(inst);
955 }
956
957 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildChecksBeforeArray(size_t pc,Inst * arrayRef,bool withNullcheck)958 std::tuple<SaveStateInst *, Inst *, LengthMethodInst *, BoundsCheckInst *> InstBuilder::BuildChecksBeforeArray(
959 size_t pc, Inst *arrayRef, bool withNullcheck)
960 {
961 // Create SaveState instruction
962 auto saveState = CreateSaveState(Opcode::SaveState, pc);
963
964 // Create NullCheck instruction
965 Inst *nullCheck = nullptr;
966 if (withNullcheck) {
967 nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, pc, arrayRef, saveState);
968 } else {
969 nullCheck = arrayRef;
970 }
971
972 // Create LenArray instruction
973 auto arrayLength = graph_->CreateInstLenArray(DataType::INT32, pc, nullCheck);
974
975 // Create BoundCheck instruction
976 auto boundsCheck = graph_->CreateInstBoundsCheck(DataType::INT32, pc, arrayLength, nullptr, saveState);
977
978 return std::make_tuple(saveState, nullCheck, arrayLength, boundsCheck);
979 }
980
981 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadArray(const BytecodeInstruction * bcInst,DataType::Type type)982 void InstBuilder::BuildLoadArray(const BytecodeInstruction *bcInst, DataType::Type type)
983 {
984 ASSERT(type != DataType::NO_TYPE);
985 auto pc = GetPc(bcInst->GetAddress());
986
987 auto [saveState, nullCheck, arrayLength, boundsCheck] =
988 BuildChecksBeforeArray(pc, GetDefinition(bcInst->GetVReg(0)));
989 ASSERT(saveState != nullptr && nullCheck != nullptr && arrayLength != nullptr && boundsCheck != nullptr);
990
991 // Create instruction
992 auto inst = graph_->CreateInstLoadArray(type, pc, nullCheck, boundsCheck);
993 boundsCheck->SetInput(1, GetDefinitionAcc());
994 AddInstruction(saveState, nullCheck, arrayLength, boundsCheck, inst);
995 UpdateDefinitionAcc(inst);
996 }
997
998 template <typename T>
BuildUnfoldLoadConstPrimitiveArray(const BytecodeInstruction * bcInst,DataType::Type type,const pandasm::LiteralArray & litArray,NewArrayInst * arrayInst)999 void InstBuilder::BuildUnfoldLoadConstPrimitiveArray(const BytecodeInstruction *bcInst, DataType::Type type,
1000 const pandasm::LiteralArray &litArray, NewArrayInst *arrayInst)
1001 {
1002 [[maybe_unused]] auto tag = litArray.literals[0].tag;
1003 auto arraySize = litArray.literals.size();
1004 for (size_t i = 0; i < arraySize; i++) {
1005 auto indexInst = graph_->FindOrCreateConstant(i);
1006 ConstantInst *valueInst;
1007 if constexpr (std::is_same_v<T, float>) {
1008 ASSERT(tag == panda_file::LiteralTag::ARRAY_F32);
1009 valueInst = FindOrCreateFloatConstant(std::get<T>(litArray.literals[i].value));
1010 } else if constexpr (std::is_same_v<T, double>) {
1011 ASSERT(tag == panda_file::LiteralTag::ARRAY_F64);
1012 valueInst = FindOrCreateDoubleConstant(std::get<T>(litArray.literals[i].value));
1013 } else if constexpr (std::is_same_v<T, bool>) {
1014 ASSERT(tag == panda_file::LiteralTag::ARRAY_U1);
1015 valueInst = FindOrCreateConstant(std::get<T>(litArray.literals[i].value));
1016 } else {
1017 auto lit = litArray.literals[i];
1018 T val = std::get<T>(lit.value);
1019 if (lit.IsSigned()) {
1020 valueInst = FindOrCreateConstant(static_cast<std::make_signed_t<T>>(val));
1021 } else {
1022 valueInst = FindOrCreateConstant(val);
1023 }
1024 }
1025
1026 BuildStoreArrayInst<false>(bcInst, type, arrayInst, indexInst, valueInst);
1027 }
1028 }
1029
1030 template <typename T>
BuildUnfoldLoadConstStringArray(const BytecodeInstruction * bcInst,DataType::Type type,const pandasm::LiteralArray & litArray,NewArrayInst * arrayInst)1031 void InstBuilder::BuildUnfoldLoadConstStringArray(const BytecodeInstruction *bcInst, DataType::Type type,
1032 const pandasm::LiteralArray &litArray, NewArrayInst *arrayInst)
1033 {
1034 auto method = GetGraph()->GetMethod();
1035 auto arraySize = litArray.literals.size();
1036 for (size_t i = 0; i < arraySize; i++) {
1037 auto indexInst = graph_->FindOrCreateConstant(i);
1038 auto save = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1039 auto typeId = static_cast<uint32_t>(std::get<T>(litArray.literals[i].value));
1040 auto loadStringInst = GetGraph()->CreateInstLoadString(DataType::REFERENCE, GetPc(bcInst->GetAddress()), save,
1041 TypeIdMixin {typeId, method});
1042 AddInstruction(save);
1043 AddInstruction(loadStringInst);
1044 if (GetGraph()->IsDynamicMethod()) {
1045 BuildCastToAnyString(bcInst);
1046 }
1047
1048 BuildStoreArrayInst<false>(bcInst, type, arrayInst, indexInst, loadStringInst);
1049 }
1050 }
1051
1052 template <typename T>
BuildUnfoldLoadConstArray(const BytecodeInstruction * bcInst,DataType::Type type,const pandasm::LiteralArray & litArray)1053 void InstBuilder::BuildUnfoldLoadConstArray(const BytecodeInstruction *bcInst, DataType::Type type,
1054 const pandasm::LiteralArray &litArray)
1055 {
1056 auto method = GetGraph()->GetMethod();
1057 auto arraySize = litArray.literals.size();
1058 auto typeId = GetRuntime()->GetLiteralArrayClassIdWithinFile(method, litArray.literals[0].tag);
1059
1060 // Create NewArray instruction
1061 auto sizeInst = graph_->FindOrCreateConstant(arraySize);
1062 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1063 auto negCheck = graph_->CreateInstNegativeCheck(DataType::INT32, GetPc(bcInst->GetAddress()), sizeInst, saveState);
1064 auto initClass = CreateLoadAndInitClassGeneric(typeId, GetPc(bcInst->GetAddress()));
1065 initClass->SetInput(0, saveState);
1066 auto arrayInst = graph_->CreateInstNewArray(DataType::REFERENCE, GetPc(bcInst->GetAddress()), initClass, negCheck,
1067 saveState, TypeIdMixin {typeId, GetGraph()->GetMethod()});
1068 AddInstruction(saveState);
1069 AddInstruction(initClass);
1070 AddInstruction(negCheck);
1071 AddInstruction(arrayInst);
1072 UpdateDefinition(bcInst->GetVReg(0), arrayInst);
1073
1074 if (arraySize > g_options.GetCompilerUnfoldConstArrayMaxSize()) {
1075 // Create LoadConstArray instruction
1076 auto ss = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1077 auto inst = GetGraph()->CreateInstFillConstArray(type, GetPc(bcInst->GetAddress()), arrayInst, ss,
1078 TypeIdMixin {bcInst->GetId(0).AsFileId().GetOffset(), method},
1079 arraySize);
1080 AddInstruction(ss);
1081 AddInstruction(inst);
1082 return;
1083 }
1084
1085 // Create instructions for array filling
1086 auto tag = litArray.literals[0].tag;
1087 if (tag != panda_file::LiteralTag::ARRAY_STRING) {
1088 BuildUnfoldLoadConstPrimitiveArray<T>(bcInst, type, litArray, arrayInst);
1089 return;
1090 }
1091
1092 [[maybe_unused]] auto arrayClass = GetRuntime()->ResolveType(method, typeId);
1093 ASSERT(GetRuntime()->CheckStoreArray(arrayClass, GetRuntime()->GetStringClass(method, nullptr)));
1094 // Special case for string array
1095 BuildUnfoldLoadConstStringArray<T>(bcInst, type, litArray, arrayInst);
1096 }
1097
1098 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadConstStringArray(const BytecodeInstruction * bcInst)1099 void InstBuilder::BuildLoadConstStringArray(const BytecodeInstruction *bcInst)
1100 {
1101 auto literalArrayIdx = bcInst->GetId(0).AsIndex();
1102 auto litArray = GetRuntime()->GetLiteralArray(GetMethod(), literalArrayIdx);
1103 auto arraySize = litArray.literals.size();
1104 ASSERT(arraySize > 0);
1105 if (arraySize > g_options.GetCompilerUnfoldConstArrayMaxSize()) {
1106 // Create LoadConstArray instruction for String array, because we calls runtime for the case.
1107 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1108 auto method = GetGraph()->GetMethod();
1109 auto inst = GetGraph()->CreateInstLoadConstArray(DataType::REFERENCE, GetPc(bcInst->GetAddress()), saveState,
1110 TypeIdMixin {literalArrayIdx, method});
1111 AddInstruction(saveState);
1112 AddInstruction(inst);
1113 UpdateDefinition(bcInst->GetVReg(0), inst);
1114 } else {
1115 BuildUnfoldLoadConstArray<uint32_t>(bcInst, DataType::REFERENCE, litArray);
1116 }
1117 }
1118
1119 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadConstArray(const BytecodeInstruction * bcInst)1120 void InstBuilder::BuildLoadConstArray(const BytecodeInstruction *bcInst)
1121 {
1122 auto literalArrayIdx = bcInst->GetId(0).AsIndex();
1123 auto litArray = GetRuntime()->GetLiteralArray(GetMethod(), literalArrayIdx);
1124 // Unfold LoadConstArray instruction
1125 auto tag = litArray.literals[0].tag;
1126 switch (tag) {
1127 case panda_file::LiteralTag::ARRAY_U1: {
1128 BuildUnfoldLoadConstArray<bool>(bcInst, DataType::INT8, litArray);
1129 break;
1130 }
1131 case panda_file::LiteralTag::ARRAY_I8:
1132 case panda_file::LiteralTag::ARRAY_U8: {
1133 BuildUnfoldLoadConstArray<uint8_t>(bcInst, DataType::INT8, litArray);
1134 break;
1135 }
1136 case panda_file::LiteralTag::ARRAY_I16:
1137 case panda_file::LiteralTag::ARRAY_U16: {
1138 BuildUnfoldLoadConstArray<uint16_t>(bcInst, DataType::INT16, litArray);
1139 break;
1140 }
1141 case panda_file::LiteralTag::ARRAY_I32:
1142 case panda_file::LiteralTag::ARRAY_U32: {
1143 BuildUnfoldLoadConstArray<uint32_t>(bcInst, DataType::INT32, litArray);
1144 break;
1145 }
1146 case panda_file::LiteralTag::ARRAY_I64:
1147 case panda_file::LiteralTag::ARRAY_U64: {
1148 BuildUnfoldLoadConstArray<uint64_t>(bcInst, DataType::INT64, litArray);
1149 break;
1150 }
1151 case panda_file::LiteralTag::ARRAY_F32: {
1152 BuildUnfoldLoadConstArray<float>(bcInst, DataType::FLOAT32, litArray);
1153 break;
1154 }
1155 case panda_file::LiteralTag::ARRAY_F64: {
1156 BuildUnfoldLoadConstArray<double>(bcInst, DataType::FLOAT64, litArray);
1157 break;
1158 }
1159 case panda_file::LiteralTag::ARRAY_STRING: {
1160 BuildLoadConstStringArray(bcInst);
1161 break;
1162 }
1163 default: {
1164 UNREACHABLE();
1165 break;
1166 }
1167 }
1168 }
1169
1170 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildStoreArray(const BytecodeInstruction * bcInst,DataType::Type type)1171 void InstBuilder::BuildStoreArray(const BytecodeInstruction *bcInst, DataType::Type type)
1172 {
1173 BuildStoreArrayInst<true>(bcInst, type, GetDefinition(bcInst->GetVReg(0)), GetDefinition(bcInst->GetVReg(1)),
1174 GetDefinitionAcc());
1175 }
1176
1177 // NOLINTNEXTLINE(misc-definitions-in-headers)
1178 template <bool CREATE_REF_CHECK>
BuildStoreArrayInst(const BytecodeInstruction * bcInst,DataType::Type type,Inst * arrayRef,Inst * index,Inst * value)1179 void InstBuilder::BuildStoreArrayInst(const BytecodeInstruction *bcInst, DataType::Type type, Inst *arrayRef,
1180 Inst *index, Inst *value)
1181 {
1182 ASSERT(type != DataType::NO_TYPE);
1183 Inst *refCheck = nullptr;
1184
1185 auto pc = GetPc(bcInst->GetAddress());
1186 auto [saveState, nullCheck, arrayLength, boundsCheck] = BuildChecksBeforeArray(pc, arrayRef);
1187 ASSERT(saveState != nullptr && nullCheck != nullptr && arrayLength != nullptr && boundsCheck != nullptr);
1188
1189 // Create instruction
1190 auto inst = graph_->CreateInstStoreArray(type, pc);
1191 boundsCheck->SetInput(1, index);
1192 auto storeDef = value;
1193 if (type == DataType::REFERENCE) {
1194 // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon)
1195 if constexpr (CREATE_REF_CHECK) {
1196 refCheck = graph_->CreateInstRefTypeCheck(DataType::REFERENCE, pc, nullCheck, storeDef, saveState);
1197 storeDef = refCheck;
1198 }
1199 inst->CastToStoreArray()->SetNeedBarrier(true);
1200 }
1201 inst->SetInput(0, nullCheck);
1202 inst->SetInput(1, boundsCheck);
1203 inst->SetInput(2U, storeDef);
1204 if (refCheck != nullptr) {
1205 AddInstruction(saveState, nullCheck, arrayLength, boundsCheck, refCheck, inst);
1206 } else {
1207 AddInstruction(saveState, nullCheck, arrayLength, boundsCheck, inst);
1208 }
1209 }
1210
1211 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLenArray(const BytecodeInstruction * bcInst)1212 void InstBuilder::BuildLenArray(const BytecodeInstruction *bcInst)
1213 {
1214 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1215 auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1216 nullCheck->SetInput(0, GetDefinition(bcInst->GetVReg(0)));
1217 nullCheck->SetInput(1, saveState);
1218 auto inst = graph_->CreateInstLenArray(DataType::INT32, GetPc(bcInst->GetAddress()), nullCheck);
1219 AddInstruction(saveState);
1220 AddInstruction(nullCheck);
1221 AddInstruction(inst);
1222 UpdateDefinitionAcc(inst);
1223 }
1224
1225 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildNewArray(const BytecodeInstruction * bcInst)1226 void InstBuilder::BuildNewArray(const BytecodeInstruction *bcInst)
1227 {
1228 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1229 auto negCheck = graph_->CreateInstNegativeCheck(DataType::INT32, GetPc(bcInst->GetAddress()),
1230 GetDefinition(bcInst->GetVReg(1)), saveState);
1231
1232 auto typeIndex = bcInst->GetId(0).AsIndex();
1233 auto typeId = GetRuntime()->ResolveTypeIndex(GetMethod(), typeIndex);
1234
1235 auto initClass = CreateLoadAndInitClassGeneric(typeId, GetPc(bcInst->GetAddress()));
1236 initClass->SetInput(0, saveState);
1237
1238 auto inst = graph_->CreateInstNewArray(DataType::REFERENCE, GetPc(bcInst->GetAddress()), initClass, negCheck,
1239 saveState, TypeIdMixin {typeId, GetGraph()->GetMethod()});
1240 AddInstruction(saveState, initClass, negCheck, inst);
1241 UpdateDefinition(bcInst->GetVReg(0), inst);
1242 }
1243
1244 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildNewObject(const BytecodeInstruction * bcInst)1245 void InstBuilder::BuildNewObject(const BytecodeInstruction *bcInst)
1246 {
1247 auto classId = GetRuntime()->ResolveTypeIndex(GetMethod(), bcInst->GetId(0).AsIndex());
1248 auto pc = GetPc(bcInst->GetAddress());
1249 auto saveState = CreateSaveState(Opcode::SaveState, pc);
1250 auto initClass = CreateLoadAndInitClassGeneric(classId, pc);
1251 auto inst = CreateNewObjectInst(pc, classId, saveState, initClass);
1252 initClass->SetInput(0, saveState);
1253 AddInstruction(saveState, initClass, inst);
1254 UpdateDefinition(bcInst->GetVReg(0), inst);
1255 }
1256
1257 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildMultiDimensionalArrayObject(const BytecodeInstruction * bcInst,bool isRange)1258 void InstBuilder::BuildMultiDimensionalArrayObject(const BytecodeInstruction *bcInst, bool isRange)
1259 {
1260 auto methodIndex = bcInst->GetId(0).AsIndex();
1261 auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
1262 auto pc = GetPc(bcInst->GetAddress());
1263 auto classId = GetRuntime()->GetClassIdForMethod(GetMethod(), methodId);
1264 auto saveState = CreateSaveState(Opcode::SaveState, pc);
1265 auto initClass = CreateLoadAndInitClassGeneric(classId, pc);
1266 size_t argsCount = GetMethodArgumentsCount(methodId);
1267 auto inst = GetGraph()->CreateInstMultiArray(DataType::REFERENCE, pc, methodId);
1268
1269 initClass->SetInput(0, saveState);
1270
1271 inst->ReserveInputs(ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1272 inst->AllocateInputTypes(GetGraph()->GetAllocator(), ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1273 inst->AppendInput(initClass);
1274 inst->AddInputType(DataType::REFERENCE);
1275
1276 AddInstruction(saveState, initClass);
1277
1278 if (isRange) {
1279 auto startReg = bcInst->GetVReg(0);
1280 for (size_t i = 0; i < argsCount; startReg++, i++) {
1281 auto negCheck = graph_->CreateInstNegativeCheck(DataType::INT32, pc, GetDefinition(startReg), saveState);
1282 AddInstruction(negCheck);
1283 inst->AppendInput(negCheck);
1284 inst->AddInputType(DataType::INT32);
1285 }
1286 } else {
1287 for (size_t i = 0; i < argsCount; i++) {
1288 auto negCheck =
1289 graph_->CreateInstNegativeCheck(DataType::INT32, pc, GetDefinition(bcInst->GetVReg(i)), saveState);
1290 AddInstruction(negCheck);
1291 inst->AppendInput(negCheck);
1292 inst->AddInputType(DataType::INT32);
1293 }
1294 }
1295 inst->AppendInput(saveState);
1296 inst->AddInputType(DataType::NO_TYPE);
1297 AddInstruction(inst);
1298 UpdateDefinitionAcc(inst);
1299 }
1300
1301 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildInitObjectMultiDimensionalArray(const BytecodeInstruction * bcInst,bool isRange)1302 void InstBuilder::BuildInitObjectMultiDimensionalArray(const BytecodeInstruction *bcInst, bool isRange)
1303 {
1304 auto pc = GetPc(bcInst->GetAddress());
1305 auto methodIndex = bcInst->GetId(0).AsIndex();
1306 auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
1307 auto classId = GetRuntime()->GetClassIdForMethod(GetMethod(), methodId);
1308 auto saveState = CreateSaveState(Opcode::SaveState, pc);
1309 auto initClass = graph_->CreateInstLoadAndInitClass(DataType::REFERENCE, pc, saveState,
1310 TypeIdMixin {classId, GetGraph()->GetMethod()},
1311 GetRuntime()->ResolveType(GetGraph()->GetMethod(), classId));
1312 auto inst = GetGraph()->CreateInstInitObject(DataType::REFERENCE, pc, methodId);
1313
1314 size_t argsCount = GetMethodArgumentsCount(methodId);
1315
1316 inst->ReserveInputs(ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1317 inst->AllocateInputTypes(GetGraph()->GetAllocator(), ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE);
1318 inst->AppendInput(initClass);
1319 inst->AddInputType(DataType::REFERENCE);
1320 if (isRange) {
1321 auto startReg = bcInst->GetVReg(0);
1322 for (size_t i = 0; i < argsCount; startReg++, i++) {
1323 inst->AppendInput(GetDefinition(startReg));
1324 inst->AddInputType(GetMethodArgumentType(methodId, i));
1325 }
1326 } else {
1327 for (size_t i = 0; i < argsCount; i++) {
1328 inst->AppendInput(GetDefinition(bcInst->GetVReg(i)));
1329 inst->AddInputType(GetMethodArgumentType(methodId, i));
1330 }
1331 }
1332 inst->AppendInput(saveState);
1333 inst->AddInputType(DataType::NO_TYPE);
1334 inst->SetCallMethod(GetRuntime()->GetMethodById(GetGraph()->GetMethod(), methodId));
1335
1336 AddInstruction(saveState, initClass, inst);
1337 UpdateDefinitionAcc(inst);
1338 }
1339
1340 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCallStaticForInitObject(const BytecodeInstruction * bcInst,uint32_t methodId,Inst ** resolver)1341 CallInst *InstBuilder::BuildCallStaticForInitObject(const BytecodeInstruction *bcInst, uint32_t methodId,
1342 Inst **resolver)
1343 {
1344 auto pc = GetPc(bcInst->GetAddress());
1345 size_t argsCount = GetMethodArgumentsCount(methodId);
1346 size_t inputsCount = ONE_FOR_OBJECT + argsCount + ONE_FOR_SSTATE;
1347 auto method = GetRuntime()->GetMethodById(graph_->GetMethod(), methodId);
1348 CallInst *call = nullptr;
1349 if (method == nullptr || ForceUnresolved()) {
1350 ResolveStaticInst *resolveStatic = graph_->CreateInstResolveStatic(DataType::POINTER, pc, methodId, nullptr);
1351 *resolver = resolveStatic;
1352 call = graph_->CreateInstCallResolvedStatic(GetMethodReturnType(methodId), pc, methodId);
1353 if (!graph_->IsAotMode() && !graph_->IsBytecodeOptimizer()) {
1354 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetMethod(), methodId,
1355 UnresolvedTypesInterface::SlotKind::METHOD);
1356 }
1357 inputsCount += 1; // resolver
1358 } else {
1359 call = graph_->CreateInstCallStatic(GetMethodReturnType(methodId), pc, methodId, method);
1360 }
1361 call->ReserveInputs(inputsCount);
1362 call->AllocateInputTypes(graph_->GetAllocator(), inputsCount);
1363 return call;
1364 }
1365
1366 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildInitString(const BytecodeInstruction * bcInst)1367 void InstBuilder::BuildInitString(const BytecodeInstruction *bcInst)
1368 {
1369 auto pc = GetPc(bcInst->GetAddress());
1370 auto saveState = CreateSaveState(Opcode::SaveState, pc);
1371 AddInstruction(saveState);
1372
1373 auto ctorMethodIndex = bcInst->GetId(0).AsIndex();
1374 auto ctorMethodId = GetRuntime()->ResolveMethodIndex(GetMethod(), ctorMethodIndex);
1375 size_t argsCount = GetMethodArgumentsCount(ctorMethodId);
1376
1377 Inst *inst = nullptr;
1378 if (argsCount == 0) {
1379 inst = GetGraph()->CreateInstInitEmptyString(DataType::REFERENCE, pc, saveState);
1380 } else {
1381 ASSERT(argsCount == 1);
1382 auto nullCheck =
1383 graph_->CreateInstNullCheck(DataType::REFERENCE, pc, GetDefinition(bcInst->GetVReg(0)), saveState);
1384 AddInstruction(nullCheck);
1385
1386 auto ctorMethod = GetRuntime()->GetMethodById(GetMethod(), ctorMethodId);
1387 auto ctorType = GetRuntime()->GetStringCtorType(ctorMethod);
1388 inst = GetGraph()->CreateInstInitString(DataType::REFERENCE, pc, nullCheck, saveState, ctorType);
1389 }
1390 AddInstruction(inst);
1391 UpdateDefinitionAcc(inst);
1392 }
1393
1394 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildInitObject(const BytecodeInstruction * bcInst,bool isRange)1395 void InstBuilder::BuildInitObject(const BytecodeInstruction *bcInst, bool isRange)
1396 {
1397 auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex());
1398 auto typeId = GetRuntime()->GetClassIdForMethod(GetMethod(), methodId);
1399 if (GetRuntime()->IsArrayClass(GetMethod(), typeId)) {
1400 if (GetGraph()->IsBytecodeOptimizer()) {
1401 BuildInitObjectMultiDimensionalArray(bcInst, isRange);
1402 } else {
1403 BuildMultiDimensionalArrayObject(bcInst, isRange);
1404 }
1405 return;
1406 }
1407
1408 if (GetRuntime()->IsStringClass(GetMethod(), typeId) && !GetGraph()->IsBytecodeOptimizer()) {
1409 BuildInitString(bcInst);
1410 return;
1411 }
1412
1413 auto pc = GetPc(bcInst->GetAddress());
1414 auto saveState = CreateSaveState(Opcode::SaveState, pc);
1415 auto initClass = CreateLoadAndInitClassGeneric(typeId, pc);
1416 initClass->SetInput(0, saveState);
1417 auto newObj = CreateNewObjectInst(pc, typeId, saveState, initClass);
1418 UpdateDefinitionAcc(newObj);
1419 Inst *resolver = nullptr;
1420 CallInst *call = BuildCallStaticForInitObject(bcInst, methodId, &resolver);
1421 if (resolver != nullptr) {
1422 call->AppendInput(resolver, DataType::POINTER);
1423 }
1424 call->AppendInput(newObj, DataType::REFERENCE);
1425
1426 size_t argsCount = GetMethodArgumentsCount(methodId);
1427 if (isRange) {
1428 auto startReg = bcInst->GetVReg(0);
1429 for (size_t i = 0; i < argsCount; startReg++, i++) {
1430 call->AppendInput(GetDefinition(startReg), GetMethodArgumentType(methodId, i));
1431 }
1432 } else {
1433 for (size_t i = 0; i < argsCount; i++) {
1434 call->AppendInput(GetDefinition(bcInst->GetVReg(i)), GetMethodArgumentType(methodId, i));
1435 }
1436 }
1437 auto saveStateForCall = CreateSaveState(Opcode::SaveState, pc);
1438 call->AppendInput(saveStateForCall, DataType::NO_TYPE);
1439 if (resolver != nullptr) {
1440 resolver->SetInput(0, saveStateForCall);
1441 AddInstruction(saveState, initClass, newObj, saveStateForCall, resolver, call);
1442 } else {
1443 AddInstruction(saveState, initClass, newObj, saveStateForCall, call);
1444 }
1445 }
1446
1447 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCheckCast(const BytecodeInstruction * bcInst)1448 void InstBuilder::BuildCheckCast(const BytecodeInstruction *bcInst)
1449 {
1450 auto typeIndex = bcInst->GetId(0).AsIndex();
1451 auto typeId = GetRuntime()->ResolveTypeIndex(GetMethod(), typeIndex);
1452 auto klassType = GetRuntime()->GetClassType(GetGraph()->GetMethod(), typeId);
1453 auto pc = GetPc(bcInst->GetAddress());
1454 auto saveState = CreateSaveState(Opcode::SaveState, pc);
1455 auto loadClass = BuildLoadClass(typeId, pc, saveState);
1456 auto inst = GetGraph()->CreateInstCheckCast(DataType::NO_TYPE, pc, GetDefinitionAcc(), loadClass, saveState,
1457 TypeIdMixin {typeId, GetGraph()->GetMethod()}, klassType);
1458 AddInstruction(saveState, loadClass, inst);
1459 }
1460
1461 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildIsInstance(const BytecodeInstruction * bcInst)1462 void InstBuilder::BuildIsInstance(const BytecodeInstruction *bcInst)
1463 {
1464 auto typeIndex = bcInst->GetId(0).AsIndex();
1465 auto typeId = GetRuntime()->ResolveTypeIndex(GetMethod(), typeIndex);
1466 auto klassType = GetRuntime()->GetClassType(GetGraph()->GetMethod(), typeId);
1467 auto pc = GetPc(bcInst->GetAddress());
1468 auto saveState = CreateSaveState(Opcode::SaveState, pc);
1469 auto loadClass = BuildLoadClass(typeId, pc, saveState);
1470 auto inst = GetGraph()->CreateInstIsInstance(DataType::BOOL, pc, GetDefinitionAcc(), loadClass, saveState,
1471 TypeIdMixin {typeId, GetGraph()->GetMethod()}, klassType);
1472 AddInstruction(saveState, loadClass, inst);
1473 UpdateDefinitionAcc(inst);
1474 }
1475
1476 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildLoadClass(RuntimeInterface::IdType typeId,size_t pc,Inst * saveState)1477 Inst *InstBuilder::BuildLoadClass(RuntimeInterface::IdType typeId, size_t pc, Inst *saveState)
1478 {
1479 auto inst = GetGraph()->CreateInstLoadClass(DataType::REFERENCE, pc, saveState,
1480 TypeIdMixin {typeId, GetGraph()->GetMethod()}, nullptr);
1481 auto klass = GetRuntime()->ResolveType(GetGraph()->GetMethod(), typeId);
1482 if (klass != nullptr) {
1483 inst->SetClass(klass);
1484 } else if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
1485 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(GetGraph()->GetMethod(), typeId,
1486 UnresolvedTypesInterface::SlotKind::CLASS);
1487 }
1488 return inst;
1489 }
1490
1491 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildThrow(const BytecodeInstruction * bcInst)1492 void InstBuilder::BuildThrow(const BytecodeInstruction *bcInst)
1493 {
1494 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1495 auto inst = graph_->CreateInstThrow(DataType::NO_TYPE, GetPc(bcInst->GetAddress()),
1496 GetDefinition(bcInst->GetVReg(0)), saveState);
1497 inst->SetCallMethod(GetMethod());
1498 AddInstruction(saveState);
1499 AddInstruction(inst);
1500 }
1501
1502 // NOLINTNEXTLINE(misc-definitions-in-headers)
1503 template <Opcode OPCODE>
BuildLoadFromPool(const BytecodeInstruction * bcInst)1504 void InstBuilder::BuildLoadFromPool(const BytecodeInstruction *bcInst)
1505 {
1506 auto method = GetGraph()->GetMethod();
1507 uint32_t typeId;
1508 Inst *inst;
1509 // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements)
1510 if constexpr (OPCODE == Opcode::LoadType) {
1511 auto typeIndex = bcInst->GetId(0).AsIndex();
1512 typeId = GetRuntime()->ResolveTypeIndex(method, typeIndex);
1513 if (GetRuntime()->ResolveType(method, typeId) == nullptr) {
1514 inst = GetGraph()->CreateInstUnresolvedLoadType(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1515 if (!GetGraph()->IsAotMode() && !GetGraph()->IsBytecodeOptimizer()) {
1516 GetRuntime()->GetUnresolvedTypes()->AddTableSlot(method, typeId,
1517 UnresolvedTypesInterface::SlotKind::MANAGED_CLASS);
1518 }
1519 } else {
1520 inst = GetGraph()->CreateInstLoadType(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1521 }
1522 // NOLINTNEXTLINE(readability-misleading-indentation)
1523 } else {
1524 // NOLINTNEXTLINE(readability-magic-numbers)
1525 static_assert(OPCODE == Opcode::LoadString);
1526 typeId = bcInst->GetId(0).AsFileId().GetOffset();
1527 if (!GetGraph()->IsDynamicMethod() || GetGraph()->IsBytecodeOptimizer()) {
1528 inst = GetGraph()->CreateInstLoadString(DataType::REFERENCE, GetPc(bcInst->GetAddress()));
1529 } else {
1530 inst = GetGraph()->CreateInstLoadFromConstantPool(DataType::ANY, GetPc(bcInst->GetAddress()));
1531 inst->CastToLoadFromConstantPool()->SetString(true);
1532 }
1533 }
1534 if (!GetGraph()->IsDynamicMethod() || GetGraph()->IsBytecodeOptimizer()) {
1535 // Create SaveState instruction
1536 auto saveState = CreateSaveState(Opcode::SaveState, GetPc(bcInst->GetAddress()));
1537 inst->SetInput(0, saveState);
1538 static_cast<LoadFromPool *>(inst)->SetTypeId(typeId);
1539 static_cast<LoadFromPool *>(inst)->SetMethod(method);
1540 AddInstruction(saveState);
1541 } else {
1542 inst->SetInput(0, GetEnvDefinition(CONST_POOL_IDX));
1543 inst->CastToLoadFromConstantPool()->SetTypeId(typeId);
1544 inst->CastToLoadFromConstantPool()->SetMethod(method);
1545 }
1546
1547 AddInstruction(inst);
1548 UpdateDefinitionAcc(inst);
1549 // NOLINTNEXTLINE(readability-magic-numbers,readability-braces-around-statements,bugprone-suspicious-semicolon)
1550 if constexpr (OPCODE == Opcode::LoadString) {
1551 if (GetGraph()->IsDynamicMethod() && GetGraph()->IsBytecodeOptimizer()) {
1552 BuildCastToAnyString(bcInst);
1553 }
1554 }
1555 }
1556
1557 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCastToAnyString(const BytecodeInstruction * bcInst)1558 void InstBuilder::BuildCastToAnyString(const BytecodeInstruction *bcInst)
1559 {
1560 auto input = GetDefinitionAcc();
1561 ASSERT(input->GetType() == DataType::REFERENCE);
1562
1563 auto language = GetRuntime()->GetMethodSourceLanguage(GetMethod());
1564 auto anyType = GetAnyStringType(language);
1565 ASSERT(anyType != AnyBaseType::UNDEFINED_TYPE);
1566
1567 auto box = graph_->CreateInstCastValueToAnyType(GetPc(bcInst->GetAddress()), anyType, input);
1568 UpdateDefinitionAcc(box);
1569 AddInstruction(box);
1570 }
1571
1572 // NOLINTNEXTLINE(misc-definitions-in-headers)
BuildCastToAnyNumber(const BytecodeInstruction * bcInst)1573 void InstBuilder::BuildCastToAnyNumber(const BytecodeInstruction *bcInst)
1574 {
1575 auto input = GetDefinitionAcc();
1576 auto type = input->GetType();
1577 if (input->IsConst() && !DataType::IsFloatType(type)) {
1578 auto constInsn = input->CastToConstant();
1579 if (constInsn->GetType() == DataType::INT64) {
1580 auto value = input->CastToConstant()->GetInt64Value();
1581 if (value == static_cast<uint32_t>(value)) {
1582 type = DataType::INT32;
1583 }
1584 }
1585 }
1586
1587 auto language = GetRuntime()->GetMethodSourceLanguage(GetMethod());
1588 auto anyType = NumericDataTypeToAnyType(type, language);
1589 ASSERT(anyType != AnyBaseType::UNDEFINED_TYPE);
1590
1591 auto box = graph_->CreateInstCastValueToAnyType(GetPc(bcInst->GetAddress()), anyType, input);
1592 UpdateDefinitionAcc(box);
1593 AddInstruction(box);
1594 }
1595
1596 // NOLINTNEXTLINE(misc-definitions-in-headers)
TryBuildStringCharAtIntrinsic(const BytecodeInstruction * bcInst,bool accRead)1597 bool InstBuilder::TryBuildStringCharAtIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
1598 {
1599 auto bcAddr = GetPc(bcInst->GetAddress());
1600 auto compressionEnabled = graph_->GetRuntime()->IsCompressedStringsEnabled();
1601 auto canEncodeCompressedStrCharAt = graph_->GetEncoder()->CanEncodeCompressedStringCharAt();
1602 if (compressionEnabled && !canEncodeCompressedStrCharAt) {
1603 return false;
1604 }
1605 auto saveStateNullcheck = CreateSaveState(Opcode::SaveState, bcAddr);
1606 auto nullCheck = graph_->CreateInstNullCheck(DataType::REFERENCE, bcAddr, GetArgDefinition(bcInst, 0, accRead),
1607 saveStateNullcheck);
1608 auto arrayLength = graph_->CreateInstLenArray(DataType::INT32, bcAddr, nullCheck, false);
1609
1610 AddInstruction(saveStateNullcheck);
1611 AddInstruction(nullCheck);
1612 AddInstruction(arrayLength);
1613
1614 Inst *stringLength = nullptr;
1615 if (compressionEnabled) {
1616 auto constOneInst = graph_->FindOrCreateConstant(1);
1617 stringLength = graph_->CreateInstShr(DataType::INT32, bcAddr, arrayLength, constOneInst);
1618 AddInstruction(stringLength);
1619 } else {
1620 stringLength = arrayLength;
1621 }
1622
1623 auto boundsCheck = graph_->CreateInstBoundsCheck(DataType::INT32, bcAddr, stringLength,
1624 GetArgDefinition(bcInst, 1, accRead), saveStateNullcheck, false);
1625 AddInstruction(boundsCheck);
1626
1627 Inst *inst = nullptr;
1628 if (compressionEnabled) {
1629 inst =
1630 graph_->CreateInstLoadCompressedStringChar(DataType::UINT16, bcAddr, nullCheck, boundsCheck, arrayLength);
1631 } else {
1632 inst = graph_->CreateInstLoadArray(DataType::UINT16, bcAddr, nullCheck, boundsCheck);
1633 }
1634
1635 AddInstruction(inst);
1636 UpdateDefinitionAcc(inst);
1637 return true;
1638 }
1639
1640 } // namespace ark::compiler
1641
1642 #endif // PANDA_INST_BUILDER_INL_H
1643