• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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