1 /**
2 * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "optimizer/code_generator/encode.h"
17 #include "optimizer/ir_builder/inst_builder.h"
18 #include "bytecode_instruction-inl.h"
19
20 namespace ark::compiler {
21 /*
22 FMOV: f -> n
23 return CMP(AND(SHR(n, FP_FRACT_SIZE), FP_EXP_MASK), FP_EXP_MASK)
24
25 1. bitcast f1
26 2. shr v1, FP_FRACT_SIZE
27 3. and v2, FP_EXP_MASK
28 4. compare v3, FP_EXP_MASK
29
30 fraction size is 23 bits for floats and 52 bits for doubles
31 exponent mask is 0xff (8 bits) for floats and 0x7ff (11 bits) for doubles
32 */
BuildIsFiniteIntrinsic(const BytecodeInstruction * bcInst,bool accRead)33 void InstBuilder::BuildIsFiniteIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
34 {
35 auto methodIndex = bcInst->GetId(0).AsIndex();
36 auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
37 auto type = GetMethodArgumentType(methodId, 0);
38 auto itype = type == DataType::FLOAT32 ? DataType::INT32 : DataType::INT64;
39 // NOLINTNEXTLINE(readability-magic-numbers)
40 auto fpFractSize = type == DataType::FLOAT32 ? 23 : 52;
41 // NOLINTNEXTLINE(readability-magic-numbers)
42 auto fpExpMask = type == DataType::FLOAT32 ? 0xff : 0x7ff;
43
44 auto bitcast =
45 GetGraph()->CreateInstBitcast(itype, GetPc(bcInst->GetAddress()), GetArgDefinition(bcInst, 0, accRead), type);
46 auto shift =
47 GetGraph()->CreateInstShr(itype, GetPc(bcInst->GetAddress()), bitcast, FindOrCreateConstant(fpFractSize));
48 auto mask = GetGraph()->CreateInstAnd(itype, GetPc(bcInst->GetAddress()), shift, FindOrCreateConstant(fpExpMask));
49 auto cmp = GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), mask,
50 FindOrCreateConstant(fpExpMask), itype, ConditionCode::CC_NE);
51
52 AddInstruction(bitcast, shift, mask, cmp);
53 UpdateDefinitionAcc(cmp);
54 }
55
BuildStdRuntimeEquals(const BytecodeInstruction * bcInst,bool accRead)56 void InstBuilder::BuildStdRuntimeEquals(const BytecodeInstruction *bcInst, bool accRead)
57 {
58 auto cmp =
59 GetGraph()->CreateInstCompare(DataType::BOOL, GetPc(bcInst->GetAddress()), GetArgDefinition(bcInst, 0, accRead),
60 GetArgDefinition(bcInst, 1, accRead), DataType::REFERENCE, ConditionCode::CC_EQ);
61 AddInstruction(cmp);
62 UpdateDefinitionAcc(cmp);
63 }
64
BuildSignbitIntrinsic(const BytecodeInstruction * bcInst,bool accRead)65 void InstBuilder::BuildSignbitIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
66 {
67 auto bitcast = GetGraph()->CreateInstBitcast(DataType::INT64, GetPc(bcInst->GetAddress()),
68 GetArgDefinition(bcInst, 0, accRead), DataType::FLOAT64);
69 constexpr auto SHIFT = 63;
70 auto res =
71 GetGraph()->CreateInstShr(DataType::INT64, GetPc(bcInst->GetAddress()), bitcast, FindOrCreateConstant(SHIFT));
72 AddInstruction(bitcast, res);
73 UpdateDefinitionAcc(res);
74 }
75
BuildUint8ClampedArraySetIntrinsic(const BytecodeInstruction * bcInst,ark::compiler::DataType::Type type,bool accRead)76 void InstBuilder::BuildUint8ClampedArraySetIntrinsic(const BytecodeInstruction *bcInst,
77 ark::compiler::DataType::Type type, bool accRead)
78 {
79 constexpr auto MAX_VALUE = 255;
80 auto bcAddr = GetPc(bcInst->GetAddress());
81 auto *value = GetArgDefinition(bcInst, 2, accRead);
82 auto *graph = GetGraph();
83 auto *clamped0 = graph->CreateInstMax(DataType::INT32, bcAddr);
84 clamped0->SetInput(0, value);
85 clamped0->SetInput(1, graph->FindOrCreateConstant(0));
86 AddInstruction(clamped0);
87 auto *clamped = graph->CreateInstMin(DataType::INT32, bcAddr);
88 clamped->SetInput(0, clamped0);
89 clamped->SetInput(1, graph->FindOrCreateConstant(MAX_VALUE));
90 AddInstruction(clamped);
91 BuildTypedUnsignedArraySetIntrinsic(bcInst, clamped, type, accRead);
92 }
93
BuildTypedArraySetIntrinsic(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead)94 void InstBuilder::BuildTypedArraySetIntrinsic(const BytecodeInstruction *bcInst, DataType::Type type, bool accRead)
95 {
96 ASSERT(type != DataType::INT64);
97 auto [loadDataInst, dataOffsetInst] = BuildTypedArrayLoadDataAndOffset(bcInst, type, accRead, true);
98 auto *value = GetArgDefinition(bcInst, 2, accRead);
99 BuildTypedArraySet(bcInst, value, type, loadDataInst, dataOffsetInst);
100 }
101
BuildTypedUnsignedArraySetIntrinsic(const BytecodeInstruction * bcInst,Inst * value,DataType::Type type,bool accRead)102 void InstBuilder::BuildTypedUnsignedArraySetIntrinsic(const BytecodeInstruction *bcInst, Inst *value,
103 DataType::Type type, bool accRead)
104 {
105 ASSERT(type != DataType::INT64);
106 auto [loadDataInst, dataOffsetInst] = BuildTypedUnsignedArrayLoadDataAndOffset(bcInst, type, accRead, true);
107 BuildTypedArraySet(bcInst, value, type, loadDataInst, dataOffsetInst);
108 }
109
BuildTypedUnsignedArraySetIntrinsic(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead)110 void InstBuilder::BuildTypedUnsignedArraySetIntrinsic(const BytecodeInstruction *bcInst, DataType::Type type,
111 bool accRead)
112 {
113 ASSERT(type != DataType::INT64);
114 auto *value = GetArgDefinition(bcInst, 2, accRead);
115 BuildTypedUnsignedArraySetIntrinsic(bcInst, value, type, accRead);
116 }
117
BuildTypedArraySet(const BytecodeInstruction * bcInst,Inst * value,ark::compiler::DataType::Type type,Inst * loadDataInst,Inst * dataOffsetInst)118 void InstBuilder::BuildTypedArraySet(const BytecodeInstruction *bcInst, Inst *value, ark::compiler::DataType::Type type,
119 Inst *loadDataInst, Inst *dataOffsetInst)
120 {
121 const size_t valueIndex = 2;
122 auto bcAddr = GetPc(bcInst->GetAddress());
123 auto *storeInst = GetGraph()->CreateInstStoreNative(type, bcAddr);
124 storeInst->SetInput(0, loadDataInst);
125 storeInst->SetInput(1, dataOffsetInst);
126 storeInst->SetInput(valueIndex, value);
127 AddInstruction(storeInst);
128 }
129
BuildBigInt64ArraySetIntrinsic(const BytecodeInstruction * bcInst,bool accRead)130 void InstBuilder::BuildBigInt64ArraySetIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
131 {
132 auto [loadDataInst, dataOffsetInst] = BuildTypedArrayLoadDataAndOffset(bcInst, DataType::INT64, accRead, true);
133 auto *value = GetArgDefinition(bcInst, 2, accRead);
134 if (value->GetType() != DataType::INT64) {
135 auto bcAddr = GetPc(bcInst->GetAddress());
136 auto *cast = GetGraph()->CreateInstCast(DataType::INT64, bcAddr, value, value->GetType());
137 AddInstruction(cast);
138 value = cast;
139 }
140 BuildTypedArraySet(bcInst, value, DataType::INT64, loadDataInst, dataOffsetInst);
141 }
142
BuildBigUint64ArraySetIntrinsic(const BytecodeInstruction * bcInst,bool accRead)143 void InstBuilder::BuildBigUint64ArraySetIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
144 {
145 auto [loadDataInst, dataOffsetInst] =
146 BuildTypedUnsignedArrayLoadDataAndOffset(bcInst, DataType::INT64, accRead, true);
147 auto *value = GetArgDefinition(bcInst, 2, accRead);
148 if (value->GetType() != DataType::INT64) {
149 auto bcAddr = GetPc(bcInst->GetAddress());
150 auto *cast = GetGraph()->CreateInstCast(DataType::INT64, bcAddr, value, value->GetType());
151 AddInstruction(cast);
152 value = cast;
153 }
154 BuildTypedArraySet(bcInst, value, DataType::INT64, loadDataInst, dataOffsetInst);
155 }
156
BuildTypedArrayGetIntrinsic(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead)157 void InstBuilder::BuildTypedArrayGetIntrinsic(const BytecodeInstruction *bcInst, DataType::Type type, bool accRead)
158 {
159 ASSERT(type != DataType::INT64);
160 auto bcAddr = GetPc(bcInst->GetAddress());
161 auto [loadDataInst, dataOffsetInst] = BuildTypedArrayLoadDataAndOffset(bcInst, type, accRead, true);
162 auto *loadInst = BuildTypedArrayGet(bcInst, type, loadDataInst, dataOffsetInst);
163 auto result = GetGraph()->CreateInstCast(DataType::FLOAT64, bcAddr, loadInst, loadInst->GetType());
164 AddInstruction(result);
165 UpdateDefinitionAcc(result);
166 }
167
BuildTypedArrayGetUnsafeIntrinsic(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead)168 void InstBuilder::BuildTypedArrayGetUnsafeIntrinsic(const BytecodeInstruction *bcInst, DataType::Type type,
169 bool accRead)
170 {
171 ASSERT(type != DataType::INT64);
172 auto [loadDataInst, dataOffsetInst] = BuildTypedArrayLoadDataAndOffset(bcInst, type, accRead, false);
173 auto *loadInst = BuildTypedArrayGet(bcInst, type, loadDataInst, dataOffsetInst);
174 UpdateDefinitionAcc(loadInst);
175 }
176
BuildTypedUnsignedArrayGetIntrinsic(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead)177 void InstBuilder::BuildTypedUnsignedArrayGetIntrinsic(const BytecodeInstruction *bcInst, DataType::Type type,
178 bool accRead)
179 {
180 ASSERT(type != DataType::INT64);
181 auto bcAddr = GetPc(bcInst->GetAddress());
182 auto [loadDataInst, dataOffsetInst] = BuildTypedUnsignedArrayLoadDataAndOffset(bcInst, type, accRead, true);
183 auto *loadInst = BuildTypedArrayGet(bcInst, type, loadDataInst, dataOffsetInst);
184 auto result = GetGraph()->CreateInstCast(DataType::FLOAT64, bcAddr, loadInst, loadInst->GetType());
185 AddInstruction(result);
186 UpdateDefinitionAcc(result);
187 }
188
BuildTypedUnsignedArrayGetUnsafeIntrinsic(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead)189 void InstBuilder::BuildTypedUnsignedArrayGetUnsafeIntrinsic(const BytecodeInstruction *bcInst, DataType::Type type,
190 bool accRead)
191 {
192 ASSERT(type != DataType::INT64);
193 auto [loadDataInst, dataOffsetInst] = BuildTypedUnsignedArrayLoadDataAndOffset(bcInst, type, accRead, false);
194 auto *loadInst = BuildTypedArrayGet(bcInst, type, loadDataInst, dataOffsetInst);
195 UpdateDefinitionAcc(loadInst);
196 }
197
BuildUint32ArrayGetUnsafeIntrinsic(const BytecodeInstruction * bcInst,bool accRead)198 void InstBuilder::BuildUint32ArrayGetUnsafeIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
199 {
200 auto bcAddr = GetPc(bcInst->GetAddress());
201 auto [loadDataInst, dataOffsetInst] =
202 BuildTypedUnsignedArrayLoadDataAndOffset(bcInst, DataType::UINT32, accRead, false);
203 auto *loadInst = BuildTypedArrayGet(bcInst, DataType::UINT32, loadDataInst, dataOffsetInst);
204 auto result = GetGraph()->CreateInstCast(DataType::INT64, bcAddr, loadInst, loadInst->GetType());
205 AddInstruction(result);
206 UpdateDefinitionAcc(result);
207 }
208
BuildTypedArrayGet(const BytecodeInstruction * bcInst,DataType::Type type,Inst * loadDataInst,Inst * dataOffsetInst)209 Inst *InstBuilder::BuildTypedArrayGet(const BytecodeInstruction *bcInst, DataType::Type type, Inst *loadDataInst,
210 Inst *dataOffsetInst)
211 {
212 auto bcAddr = GetPc(bcInst->GetAddress());
213 auto *loadInst = GetGraph()->CreateInstLoadNative(type, bcAddr);
214 loadInst->SetInput(0, loadDataInst);
215 loadInst->SetInput(1, dataOffsetInst);
216 AddInstruction(loadInst);
217 return loadInst;
218 }
219
BuildBigInt64ArrayGetIntrinsic(const BytecodeInstruction * bcInst,bool accRead,bool needBoundCheck)220 void InstBuilder::BuildBigInt64ArrayGetIntrinsic(const BytecodeInstruction *bcInst, bool accRead, bool needBoundCheck)
221 {
222 auto [loadDataInst, dataOffsetInst] =
223 BuildTypedArrayLoadDataAndOffset(bcInst, DataType::INT64, accRead, needBoundCheck);
224 auto *loadInst = BuildTypedArrayGet(bcInst, DataType::INT64, loadDataInst, dataOffsetInst);
225 UpdateDefinitionAcc(loadInst);
226 }
227
BuildBigUint64ArrayGetIntrinsic(const BytecodeInstruction * bcInst,bool accRead,bool needBoundCheck)228 void InstBuilder::BuildBigUint64ArrayGetIntrinsic(const BytecodeInstruction *bcInst, bool accRead, bool needBoundCheck)
229 {
230 auto [loadDataInst, dataOffsetInst] =
231 BuildTypedUnsignedArrayLoadDataAndOffset(bcInst, DataType::INT64, accRead, needBoundCheck);
232 auto *loadInst = BuildTypedArrayGet(bcInst, DataType::INT64, loadDataInst, dataOffsetInst);
233 UpdateDefinitionAcc(loadInst);
234 }
235
236 /*
237 1. typedArray
238 2. pos
239 3. NullCheck v1
240 5. LoadNative v3, TYPED_ARRAY_BUFFER_OFFSET
241 6. LoadNative v5, ARRAY_BUFFER_DATA_OFFSET
242 7. DeoptimizeIf v6 == 0
243 9. LoadNative v3, TYPED_ARRAY_BUFFER_BYTE_OFFSET_OFFSET
244 10. Cast FLOAT64->INT32 v9
245 11. LoadNative v3, TYPED_ARRAY_LENGTH_OFFSET
246 12. DeoptimizeIf v2 CC_AE v11
247 13. Add v2, ARRAY_DATA_OFFSET
248 14. Add v13, v10
249 Returns (v6, v14)
250 */
BuildTypedArrayLoadDataAndOffset(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead,bool needBoundCheck)251 std::tuple<Inst *, Inst *> InstBuilder::BuildTypedArrayLoadDataAndOffset(const BytecodeInstruction *bcInst,
252 DataType::Type type, bool accRead,
253 bool needBoundCheck)
254 {
255 ASSERT(DataType::IsTypeSigned(type));
256 auto bcAddr = GetPc(bcInst->GetAddress());
257 auto *obj = GetArgDefinition(bcInst, 0, accRead);
258 auto *pos = GetArgDefinition(bcInst, 1, accRead);
259 auto saveState = CreateSaveState(Opcode::SaveState, bcAddr);
260 AddInstruction(saveState);
261 auto *graph = GetGraph();
262 auto arch = graph->GetArch();
263 auto *nullCheck = graph->CreateInstNullCheck(DataType::REFERENCE, bcAddr, obj, saveState);
264 AddInstruction(nullCheck);
265
266 auto *loadBufferInst =
267 graph->CreateInstLoadNative(DataType::REFERENCE, bcAddr, nullCheck,
268 graph->FindOrCreateConstant(ark::cross_values::GetTypedArrayBufferOffset(arch)));
269 AddInstruction(loadBufferInst);
270
271 auto *loadDataInst =
272 graph->CreateInstLoadNative(DataType::REFERENCE, bcAddr, loadBufferInst,
273 graph->FindOrCreateConstant(ark::cross_values::GetArrayBufferDataOffset(arch)));
274 AddInstruction(loadDataInst);
275
276 BuildTypedArrayDeoptimizeIfExternalData(loadDataInst, bcAddr, saveState);
277
278 auto *loadDataOffsetFloat64Inst = graph->CreateInstLoadNative(
279 DataType::FLOAT64, bcAddr, nullCheck,
280 graph->FindOrCreateConstant(ark::cross_values::GetTypedArrayByteOffsetOffset(arch)));
281 AddInstruction(loadDataOffsetFloat64Inst);
282 auto *loadDataOffsetInst =
283 graph->CreateInstCast(DataType::INT32, bcAddr, loadDataOffsetFloat64Inst, loadDataOffsetFloat64Inst->GetType());
284 AddInstruction(loadDataOffsetInst);
285
286 if (needBoundCheck) {
287 auto *loadLengthInst = graph->CreateInstLoadNative(
288 DataType::INT32, bcAddr, nullCheck,
289 graph->FindOrCreateConstant(ark::cross_values::GetTypedArrayLengthOffset(arch)));
290 AddInstruction(loadLengthInst);
291 BuildTypedArrayDeoptimizeIfOutOfRange(pos, loadLengthInst, bcAddr, saveState);
292 }
293
294 auto *arrayDataOffset = graph->FindOrCreateConstant(ark::cross_values::GetCoretypesArrayDataOffset(arch));
295 auto scale = DataType::ShiftByType(type, graph->GetArch());
296 auto *scaledPos = graph->CreateInstShl(DataType::INT32, bcAddr, pos, graph->FindOrCreateConstant(scale));
297 AddInstruction(scaledPos);
298 auto *dataOffsetInst = graph->CreateInstAdd(DataType::INT32, bcAddr, scaledPos, arrayDataOffset);
299 AddInstruction(dataOffsetInst);
300 dataOffsetInst = graph->CreateInstAdd(DataType::INT32, bcAddr, dataOffsetInst, loadDataOffsetInst);
301 AddInstruction(dataOffsetInst);
302
303 return std::make_tuple(loadDataInst, dataOffsetInst);
304 }
305
BuildTypedArrayDeoptimizeIfExternalData(Inst * dataInst,size_t bcAddr,SaveStateInst * saveState)306 void InstBuilder::BuildTypedArrayDeoptimizeIfExternalData(Inst *dataInst, size_t bcAddr, SaveStateInst *saveState)
307 {
308 auto *graph = GetGraph();
309 auto *nullPtrInst = graph->GetOrCreateNullPtr();
310 auto *isExternalInst = graph->CreateInstCompare(DataType::BOOL, bcAddr, dataInst, nullPtrInst, DataType::REFERENCE,
311 ConditionCode::CC_EQ);
312 AddInstruction(isExternalInst);
313 auto *deoptIsExternalInst =
314 graph->CreateInstDeoptimizeIf(bcAddr, isExternalInst, saveState, DeoptimizeType::ZERO_CHECK);
315 AddInstruction(deoptIsExternalInst);
316 }
317
BuildTypedArrayDeoptimizeIfOutOfRange(Inst * posInst,Inst * lengthInst,size_t bcAddr,SaveStateInst * saveState)318 void InstBuilder::BuildTypedArrayDeoptimizeIfOutOfRange(Inst *posInst, Inst *lengthInst, size_t bcAddr,
319 SaveStateInst *saveState)
320 {
321 auto *graph = GetGraph();
322 auto *boundsCheck =
323 graph->CreateInstCompare(DataType::BOOL, bcAddr, posInst, lengthInst, DataType::INT32, ConditionCode::CC_AE);
324 AddInstruction(boundsCheck);
325
326 auto *deoptRangeError = graph->CreateInstDeoptimizeIf(bcAddr, boundsCheck, saveState, DeoptimizeType::BOUNDS_CHECK);
327 AddInstruction(deoptRangeError);
328 }
329
330 /*
331 1. typedUArray
332 2. pos
333 3. NullCheck v1
334 5. LoadNative v3, TYPED_U_ARRAY_BUFFER_OFFSET
335 6. LoadNative v5, ARRAY_BUFFER_DATA_OFFSET
336 7. DeoptimizeIf v6 == 0
337 9. LoadNative v3, TYPED_U_ARRAY_BUFFER_BYTE_OFFSET_OFFSET
338 11. LoadNative v3, TYPED_U_ARRAY_LENGTH_OFFSET
339 12. DeoptimizeIf v2 CC_AE v11
340 13. Add v2, ARRAY_DATA_OFFSET
341 14. Add v13, v9
342 Returns (v6, v14)
343 */
BuildTypedUnsignedArrayLoadDataAndOffset(const BytecodeInstruction * bcInst,DataType::Type type,bool accRead,bool needBoundCheck)344 std::tuple<Inst *, Inst *> InstBuilder::BuildTypedUnsignedArrayLoadDataAndOffset(const BytecodeInstruction *bcInst,
345 DataType::Type type, bool accRead,
346 bool needBoundCheck)
347 {
348 auto bcAddr = GetPc(bcInst->GetAddress());
349 auto *obj = GetArgDefinition(bcInst, 0, accRead);
350 auto *pos = GetArgDefinition(bcInst, 1, accRead);
351 auto saveState = CreateSaveState(Opcode::SaveState, bcAddr);
352 AddInstruction(saveState);
353 auto *graph = GetGraph();
354 auto arch = graph->GetArch();
355 auto *nullCheck = graph->CreateInstNullCheck(DataType::REFERENCE, bcAddr, obj, saveState);
356 AddInstruction(nullCheck);
357
358 auto *loadBufferInst = graph->CreateInstLoadNative(
359 DataType::REFERENCE, bcAddr, nullCheck,
360 graph->FindOrCreateConstant(ark::cross_values::GetTypedUnsignedArrayBufferOffset(arch)));
361 AddInstruction(loadBufferInst);
362
363 auto *loadDataInst =
364 graph->CreateInstLoadNative(DataType::REFERENCE, bcAddr, loadBufferInst,
365 graph->FindOrCreateConstant(ark::cross_values::GetArrayBufferDataOffset(arch)));
366 AddInstruction(loadDataInst);
367
368 BuildTypedArrayDeoptimizeIfExternalData(loadDataInst, bcAddr, saveState);
369
370 auto *loadDataOffsetInst = graph->CreateInstLoadNative(
371 DataType::INT32, bcAddr, nullCheck,
372 graph->FindOrCreateConstant(ark::cross_values::GetTypedUnsignedArrayByteOffsetOffset(arch)));
373 AddInstruction(loadDataOffsetInst);
374
375 if (needBoundCheck) {
376 auto *loadLengthInst = graph->CreateInstLoadNative(
377 DataType::INT32, bcAddr, nullCheck,
378 graph->FindOrCreateConstant(ark::cross_values::GetTypedUnsignedArrayLengthOffset(arch)));
379 AddInstruction(loadLengthInst);
380 BuildTypedArrayDeoptimizeIfOutOfRange(pos, loadLengthInst, bcAddr, saveState);
381 }
382
383 auto *arrayDataOffset = graph->FindOrCreateConstant(ark::cross_values::GetCoretypesArrayDataOffset(arch));
384 auto scale = DataType::ShiftByType(type, graph->GetArch());
385 auto *scaledPos = graph->CreateInstShl(DataType::INT32, bcAddr, pos, graph->FindOrCreateConstant(scale));
386 AddInstruction(scaledPos);
387 auto *dataOffsetInst = graph->CreateInstAdd(DataType::INT32, bcAddr, scaledPos, arrayDataOffset);
388 AddInstruction(dataOffsetInst);
389 dataOffsetInst = graph->CreateInstAdd(DataType::INT32, bcAddr, dataOffsetInst, loadDataOffsetInst);
390 AddInstruction(dataOffsetInst);
391
392 return std::make_tuple(loadDataInst, dataOffsetInst);
393 }
394
395 template <bool LOAD>
BuildUnsafeIntrinsic(const BytecodeInstruction * bcInst,bool accRead)396 void InstBuilder::BuildUnsafeIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
397 {
398 /* ensure the boot context of the caller */
399 if (!IsInBootContext()) {
400 failed_ = true;
401 return;
402 }
403
404 auto bcAddr = GetPc(bcInst->GetAddress());
405 auto methodIndex = bcInst->GetId(0).AsIndex();
406 auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), methodIndex);
407
408 auto type = LOAD ? GetMethodReturnType(methodId) : GetMethodArgumentType(methodId, 1);
409 ASSERT(type == DataType::INT8 || type == DataType::INT16 || type == DataType::INT32 || type == DataType::INT64 ||
410 type == DataType::BOOL || type == DataType::FLOAT32 || type == DataType::FLOAT64);
411
412 auto raw = GetArgDefinition(bcInst, 0, accRead);
413 auto addr = GetGraph()->CreateInstCast(DataType::POINTER, bcAddr, raw, DataType::INT64);
414 auto zero = FindOrCreateConstant(0);
415 AddInstruction(addr);
416
417 if (LOAD) {
418 auto ld = GetGraph()->CreateInstLoadNative(type, bcAddr, addr, zero);
419 AddInstruction(ld);
420 UpdateDefinitionAcc(ld);
421 } else {
422 auto val = GetArgDefinition(bcInst, 1, accRead);
423 auto st = GetGraph()->CreateInstStoreNative(type, bcAddr, addr, zero, val);
424 AddInstruction(st);
425 }
426 }
427
BuildUnsafeLoadIntrinsic(const BytecodeInstruction * bcInst,bool accRead)428 void InstBuilder::BuildUnsafeLoadIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
429 {
430 BuildUnsafeIntrinsic<true>(bcInst, accRead);
431 }
432
BuildUnsafeStoreIntrinsic(const BytecodeInstruction * bcInst,bool accRead)433 void InstBuilder::BuildUnsafeStoreIntrinsic(const BytecodeInstruction *bcInst, bool accRead)
434 {
435 BuildUnsafeIntrinsic<false>(bcInst, accRead);
436 }
437
BuildStringSizeInBytes(const BytecodeInstruction * bcInst,bool accRead)438 void InstBuilder::BuildStringSizeInBytes(const BytecodeInstruction *bcInst, bool accRead)
439 {
440 /* ensure the boot context of the caller */
441 if (!IsInBootContext()) {
442 failed_ = true;
443 return;
444 }
445
446 auto bcAddr = GetPc(bcInst->GetAddress());
447 auto str = GetArgDefinition(bcInst, 0, accRead);
448 auto runtime = GetRuntime();
449 auto graph = GetGraph();
450 auto offset = FindOrCreateConstant(runtime->GetStringLengthOffset(graph->GetArch()));
451 auto one = FindOrCreateConstant(1U);
452
453 auto len = graph->CreateInstLoadNative(DataType::INT32, bcAddr, str, offset);
454 auto size = graph->CreateInstShr(DataType::INT32, bcAddr, len, one);
455 auto shift = graph->CreateInstAnd(DataType::INT32, bcAddr, len, one);
456 auto add = graph->CreateInstAdd(DataType::INT32, bcAddr, size, shift);
457 auto result = graph->CreateInstShl(DataType::INT32, bcAddr, add, shift);
458
459 AddInstruction(len, size, shift, add, result);
460 UpdateDefinitionAcc(result);
461 }
462
463 } // namespace ark::compiler
464