diff --git a/compiler/optimizer/code_generator/codegen.cpp b/compiler/optimizer/code_generator/codegen.cpp index 2816515b3c1c622f0c1ce97693e6471d916eb606..2f0c3189b39e0cbbcef73b80d2ec99a72c9b1fe6 100644 --- a/compiler/optimizer/code_generator/codegen.cpp +++ b/compiler/optimizer/code_generator/codegen.cpp @@ -4621,6 +4621,47 @@ void Codegen::CreateStringFromStringTlab(IntrinsicInst *inst, Reg dst, SRCREGS s auto src_str = src[FIRST_OPERAND]; CallFastPath(inst, entry_id, dst, RegMask::GetZeroMask(), src_str); } +#if 1 +void Codegen::CreateArrayCopyTo(IntrinsicInst *inst, [[maybe_unused]] Reg dst, SRCREGS src) +{ + auto entrypoint_id = EntrypointId::COUNT; + + switch (inst->GetIntrinsicId()) { + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_BOOL_COPY_TO: + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_BYTE_COPY_TO: + entrypoint_id = EntrypointId::ARRAY_COPY_TO_1B; + break; + + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_CHAR_COPY_TO: + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_SHORT_COPY_TO: + entrypoint_id = EntrypointId::ARRAY_COPY_TO_2B; + break; + + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_INT_COPY_TO: + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_FLOAT_COPY_TO: + entrypoint_id = EntrypointId::ARRAY_COPY_TO_4B; + break; + + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_LONG_COPY_TO: + case RuntimeInterface::IntrinsicId::INTRINSIC_STD_CORE_DOUBLE_COPY_TO: + entrypoint_id = EntrypointId::ARRAY_COPY_TO_8B; + break; + + default: + break; + } + + ASSERT(entrypoint_id != EntrypointId::COUNT); + + auto src_obj = src[FIRST_OPERAND]; + auto dst_obj = src[SECOND_OPERAND]; + auto dst_start = src[THIRD_OPERAND]; + auto src_start = src[FOURTH_OPERAND]; + auto src_end = src[FIFTH_OPERAND]; + CallFastPath(inst, entrypoint_id, INVALID_REGISTER, RegMask::GetZeroMask(), src_obj, dst_obj, dst_start, src_start, + src_end); +} +#endif #include "intrinsics_codegen.inl" diff --git a/irtoc/BUILD.gn b/irtoc/BUILD.gn index 703e28c541dcb71b3a9d80e0bfd503d250595859..879cf3fffc701c53bd001c830ec051914f8b42fd 100644 --- a/irtoc/BUILD.gn +++ b/irtoc/BUILD.gn @@ -39,6 +39,7 @@ irtoc_scripts = [ "scripts/gc.irt", "scripts/strings.irt", "scripts/string_builder.irt", + "scripts/arrays.irt", ] irtoc_scripts += plugin_irtoc_scripts diff --git a/irtoc/scripts/arrays.irt b/irtoc/scripts/arrays.irt new file mode 100644 index 0000000000000000000000000000000000000000..0f2382f0793b6bbbb04e3952e55c3dc76d6bf562 --- /dev/null +++ b/irtoc/scripts/arrays.irt @@ -0,0 +1,345 @@ +#!/usr/bin/env ruby + +# Copyright (c) 2021-2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +include_relative 'common.irt' + +macro(:full_unroll_small) do |el_size| + # copy small (<= 8 bytes) + if el_size < 2 + compare := Compare(len_bytes, 2).LT.b + IfImm(compare).Imm(0).NE.b { + # 1 byte + tmp := LoadI(src_data).Imm(0).u8 + StoreI(dst_data, tmp).Imm(0).u8 + Goto(:End) + } + end + if el_size < 4 + compare := Compare(len_bytes, 2).EQ.b + IfImm(compare).Imm(0).NE.b { + # 2 bytes + tmp := LoadI(src_data).Imm(0).u16 + StoreI(dst_data, tmp).Imm(0).u16 + Goto(:End) + } + + compare := Compare(len_bytes, 4).LT.b + IfImm(compare).Imm(0).NE.b { + # 3 bytes + tmp2 := LoadI(src_data).Imm(0).u16 + tmp1 := LoadI(src_data).Imm(2).u8 + StoreI(dst_data, tmp2).Imm(0).u16 + StoreI(dst_data, tmp1).Imm(2).u8 + Goto(:End) + } + end + if el_size < 8 + compare := Compare(len_bytes, 4).EQ.b + IfImm(compare).Imm(0).NE.b { + # 4 bytes + tmp := LoadI(src_data).Imm(0).u32 + StoreI(dst_data, tmp).Imm(0).u32 + Goto(:End) + } + + compare := Compare(len_bytes, 8).LT.b + IfImm(compare).Imm(0).NE.b { + # 5-7 bytes + src_right := Add(src_data, len_word).ptr + dst_right := Add(dst_data, len_word).ptr + + tmp_left4 := LoadI(src_data).Imm(0).u32 + tmp_right4 := LoadI(src_right).Imm(-4).u32 + StoreI(dst_data, tmp_left4).Imm(0).u32 + StoreI(dst_right, tmp_right4).Imm(-4).u32 + Goto(:End) + } + end + + # 8 bytes + tmp := LoadI(src_data).Imm(0).u64 + StoreI(dst_data, tmp).Imm(0).u64 +end + +# while integer parameters for the function are declared +# as signed types there is no case when this is valid for +# them to be negative, since bitwise arithmetics does better +# with unsigned values we treat them as such +def GenerateArrayCopy(el_size, el_log_size) + suffix = el_size.to_s + "B" + function("ArrayCopyTo#{suffix}".to_sym, + params: {src_obj: 'ref', dst_obj: 'ref', dst_start: 'u32', src_start: 'u32', src_end: 'u32'}, + regmap: $full_regmap, + regalloc_set: $panda_mask, + mode: [:FastPath]) { + + # Arm32 is not supported + if Options.arch == :arm32 + Intrinsic(:UNREACHABLE).void.Terminator + next + end + + # range checks: we don't do early exit as early exit means + # an exception and we have no intention of optimizing the + # exceptional case + src_size := LoadI(src_obj).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 + dst_size := LoadI(dst_obj).Imm(Constants::ARRAY_LENGTH_OFFSET).u32 + len := Sub(src_end, src_start).u32; + + # ((src_start - src_end) | (src_end - len ) | src_start) & 0x80000000) == 0 + compare := Compare(src_start, src_end).GT.b + IfImm(compare).Imm(0).NE.b { + Goto(:FallToIntrinsic) + } + compare := Compare(src_end, src_size).GT.b + IfImm(compare).Imm(0).NE.b { + Goto(:FallToIntrinsic) + } + + If(src_start, 0).GT.b { + Goto(:FallToIntrinsic) + } + + If(dst_start, 0).LT.b { + Goto(:FallToIntrinsic) + } + count1 := Sub(src_end, src_end).u32 + count2 := Sub(dst_size, dst_start).u32 + compare := Compare(count1, count2).GT.b + IfImm(compare).Imm(0).NE.b { + Goto(:FallToIntrinsic) + } + + # if len == 0 then do nothing + If(len, 0).EQ.Unlikely.b { + Goto(:End) + } + + src_from_bytes := ShlI(src_start).Imm(el_log_size).u32 + dst_from_bytes := ShlI(dst_start).Imm(el_log_size).u32 + + src_data := AddI(Cast(src_obj).ptr).Imm(Constants::ARRAY_DATA_OFFSET).ptr + src_data := Add(src_data, Cast(src_from_bytes).word).ptr + + dst_data := AddI(Cast(dst_obj).ptr).Imm(Constants::ARRAY_DATA_OFFSET).ptr + dst_data := Add(dst_data, Cast(dst_from_bytes).word).ptr + + # if src_data == dst_data then do nothing + If(src_data, dst_data).EQ.Unlikely.b { + Goto(:End) + } + + ### Start copy + len_bytes := ShlI(len).Imm(el_log_size).u32 + len_word := Cast(len_bytes).word + + compare := Compare(len_bytes, 8).GT.b + IfImm(compare).Imm(0).NE.b { + Goto(:BigCopy) + } + + full_unroll_small(el_size) + Goto(:End) + +Label(:BigCopy) +# # if bytes size > 4096 bytes, copy via system routine +# upper_limit := 4096 +# compare := Compare(len_bytes, upper_limit).GT.b +# IfImm(compare).Imm(0).NE.Unlikely.b { +# Call(dst_data, src_data, len_bytes).Method("memmove").void +# Intrinsic(:UNREACHABLE).Terminator.void if defines.DEBUG +# } +# + If(src_data, dst_data).CC(:CC_A).b { + Goto(:ForwardCopy) + } + + gap := Sub(dst_data, src_data).word + If(gap, len_word).AE.b { + Goto(:ForwardCopy) + } + + # BackwardCopy + compare := Compare(len_bytes, 64).GE.b + IfImm(compare).Imm(0).NE.b { + Goto(:BackwardCopy64) + } + + idx := Sub(len_bytes, 8).i32 + buf := Load(src_data, idx).u64 + +Label(:BackwardCopyLoop) + idx := Phi(idx, idx_prev).i32 + buf := Phi(buf, buf_prev).u64 + compare := Compare(idx, 8).LE.b + IfImm(compare).Imm(0).NE.Unlikely.b { + Goto(:BackwardCopyTail) + } + Store(dst_data, idx, buf).u64 + idx_prev := Sub(idx, 8).i32 + buf_prev := Load(src_data, idx_prev).u64 + Goto(:BackwardCopyLoop) + +Label(:BackwardCopyTail) + buf1 := LoadI(src_data).Imm(0).u64 + Store(dst_data, idx, buf).u64 + StoreI(dst_data, buf1).Imm(0).u64 + Goto(:End) + +Label(:BackwardCopy64) + # This is naive x6 loop unroll for 64+ bytes + # TODO (asidorov): remove when LoopUnroll pass added in Irtoc + first_buf0 := LoadI(src_data).Imm(0).u64 + first_buf1 := LoadI(src_data).Imm(8).u64 + first_buf2 := LoadI(src_data).Imm(16).u64 + first_buf3 := LoadI(src_data).Imm(24).u64 + first_buf4 := LoadI(src_data).Imm(32).u64 + first_buf5 := LoadI(src_data).Imm(40).u64 + len_tail := SubI(len_word).Imm(48).word + src_ptr_init := Add(src_data, len_tail).ptr + dst_ptr_init := Add(dst_data, len_tail).ptr + +Label(:BackwardCopyLoop64) + src_ptr := Phi(src_ptr_init, prev_src_ptr).ptr + dst_ptr := Phi(dst_ptr_init, prev_dst_ptr).ptr + + buf5 := LoadI(src_ptr).Imm(40).u64 + buf4 := LoadI(src_ptr).Imm(32).u64 + buf3 := LoadI(src_ptr).Imm(24).u64 + buf2 := LoadI(src_ptr).Imm(16).u64 + buf1 := LoadI(src_ptr).Imm(8).u64 + buf0 := LoadI(src_ptr).Imm(0).u64 + + StoreI(dst_ptr, buf5).Imm(40).u64 + StoreI(dst_ptr, buf4).Imm(32).u64 + StoreI(dst_ptr, buf3).Imm(24).u64 + StoreI(dst_ptr, buf2).Imm(16).u64 + StoreI(dst_ptr, buf1).Imm(8).u64 + StoreI(dst_ptr, buf0).Imm(0).u64 + + prev_src_ptr := SubI(src_ptr).Imm(48).ptr + prev_dst_ptr := SubI(dst_ptr).Imm(48).ptr + If(prev_src_ptr, src_data).CC(:CC_B).Unlikely.b { + Goto(:BackwardCopyTail64) + } Else { + Goto(:BackwardCopyLoop64) + } + +Label(:BackwardCopyTail64) + StoreI(dst_data, first_buf5).Imm(40).u64 + StoreI(dst_data, first_buf4).Imm(32).u64 + StoreI(dst_data, first_buf3).Imm(24).u64 + StoreI(dst_data, first_buf2).Imm(16).u64 + StoreI(dst_data, first_buf1).Imm(8).u64 + StoreI(dst_data, first_buf0).Imm(0).u64 + Goto(:End) + +Label(:ForwardCopy) + compare := Compare(len_bytes, 64).GE.b + IfImm(compare).Imm(0).NE.b { + Goto(:ForwardCopy64) + } + + # ForwardCopy + len_bytes := Sub(len_bytes, 16).i32 + idx := 0 + buf := Load(src_data, idx).u64 + +Label(:ForwardCopyLoop) + idx := Phi(idx, idx_next).i32 + buf := Phi(buf, buf_next).u64 + If(idx, len_bytes).GE.Unlikely.b { + Goto(:ForwardCopyTail) + } + Store(dst_data, idx, buf).u64 + idx_next := Add(idx, 8).i32 + buf_next := Load(src_data, idx_next).u64 + Goto(:ForwardCopyLoop) + +Label(:ForwardCopyTail) + len_bytes := Add(len_bytes, 8).i32 + buf1 := Load(src_data, len_bytes).u64 + Store(dst_data, idx, buf).u64 + Store(dst_data, len_bytes, buf1).u64 + + Goto(:End) + +Label(:ForwardCopy64) + # This is naive x6 loop unroll for 64+ bytes + # TODO (asidorov): remove when LoopUnroll pass added in Irtoc + len_tail := SubI(len_word).Imm(48).word + src_end_data := Add(src_data, len_tail).ptr + last_buf0 := LoadI(src_end_data).Imm(0).u64 + last_buf1 := LoadI(src_end_data).Imm(8).u64 + last_buf2 := LoadI(src_end_data).Imm(16).u64 + last_buf3 := LoadI(src_end_data).Imm(24).u64 + last_buf4 := LoadI(src_end_data).Imm(32).u64 + last_buf5 := LoadI(src_end_data).Imm(40).u64 + +Label(:ForwardCopyLoop64) + src_ptr := Phi(src_data, next_src_ptr).ptr + dst_ptr := Phi(dst_data, next_dst_ptr).ptr + + buf0 := LoadI(src_ptr).Imm(0).u64 + buf1 := LoadI(src_ptr).Imm(8).u64 + buf2 := LoadI(src_ptr).Imm(16).u64 + buf3 := LoadI(src_ptr).Imm(24).u64 + buf4 := LoadI(src_ptr).Imm(32).u64 + buf5 := LoadI(src_ptr).Imm(40).u64 + + StoreI(dst_ptr, buf0).Imm(0).u64 + StoreI(dst_ptr, buf1).Imm(8).u64 + StoreI(dst_ptr, buf2).Imm(16).u64 + StoreI(dst_ptr, buf3).Imm(24).u64 + StoreI(dst_ptr, buf4).Imm(32).u64 + StoreI(dst_ptr, buf5).Imm(40).u64 + + next_src_ptr := AddI(src_ptr).Imm(48).ptr + next_dst_ptr := AddI(dst_ptr).Imm(48).ptr + If(next_src_ptr, src_end_data).AE.Unlikely.b { + Goto(:ForwardCopyTail64) + } Else { + Goto(:ForwardCopyLoop64) + } + +Label(:ForwardCopyTail64) + dst_end_data := Add(dst_data, len_tail).ptr + + StoreI(dst_end_data, last_buf0).Imm(0).u64 + StoreI(dst_end_data, last_buf1).Imm(8).u64 + StoreI(dst_end_data, last_buf2).Imm(16).u64 + StoreI(dst_end_data, last_buf3).Imm(24).u64 + StoreI(dst_end_data, last_buf4).Imm(32).u64 + StoreI(dst_end_data, last_buf5).Imm(40).u64 + Goto(:End) + ### End copy + +Label(:FallToIntrinsic) + # call Intrinsic + id1 = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::ARRAY_COPY_TO#{suffix}_SLOW_PATH)" + id2 = "cross_values::GetManagedThreadEntrypointOffset(GetArch(), EntrypointId::ARRAY_COPY_TO#{suffix}_ODD_SAVED)" + Intrinsic(:SLOW_PATH_ENTRY, src_obj, dst_obj, dst_start, src_start, src_end).AddImm(id1).AddImm(id2).Terminator.ptr + Intrinsic(:UNREACHABLE).Terminator.void if defines.DEBUG + +Label(:End) + ReturnVoid().void +} +end + +GenerateArrayCopy(1, 0) +GenerateArrayCopy(2, 1) +GenerateArrayCopy(4, 2) +GenerateArrayCopy(8, 3) + diff --git a/plugins/ets/runtime/CMakeLists.txt b/plugins/ets/runtime/CMakeLists.txt index 38e46f8d00847c0e393688a5d3ae06332f6b77ad..8185f769c2f09ab2df47e865d6250f8998d597c4 100644 --- a/plugins/ets/runtime/CMakeLists.txt +++ b/plugins/ets/runtime/CMakeLists.txt @@ -47,6 +47,7 @@ set(ETS_RUNTIME_SOURCES ${ETS_EXT_SOURCES}/intrinsics/std_core_TypeCreator.cpp ${ETS_EXT_SOURCES}/intrinsics/std_core_Method.cpp ${ETS_EXT_SOURCES}/intrinsics/std_core_Value.cpp + ${ETS_EXT_SOURCES}/intrinsics/std_core_Arrays.cpp ${ETS_EXT_SOURCES}/intrinsics/escompat_Atomics.cpp ${ETS_EXT_SOURCES}/intrinsics/std_math.cpp ${ETS_EXT_SOURCES}/intrinsics/escompat_JSON.cpp diff --git a/plugins/ets/runtime/ets_entrypoints.yaml b/plugins/ets/runtime/ets_entrypoints.yaml index 7a8e080b55c3238f4c46cfa91f22addaba3ad368..62b010ebff23156d7b4ed69f2f751ce658af2f1b 100644 --- a/plugins/ets/runtime/ets_entrypoints.yaml +++ b/plugins/ets/runtime/ets_entrypoints.yaml @@ -62,3 +62,100 @@ - panda::ObjectHeader* - uint64_t* - panda::ObjectHeader* + +- name: ArrayCopyTo1bSlowPath + entrypoint: StdCoreByteCopyTo + bridge: slow_path + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo2bSlowPath + entrypoint: StdCoreShortCopyTo + bridge: slow_path + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo4bSlowPath + entrypoint: StdCoreIntCopyTo + bridge: slow_path + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo8bSlowPath + entrypoint: StdCoreLongCopyTo + bridge: slow_path + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo1bOddSaved + entrypoint: StdCoreByteCopyTo + bridge: odd_saved + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo2bOddSaved + entrypoint: StdCoreShortCopyTo + bridge: odd_saved + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo4bOddSaved + entrypoint: StdCoreIntCopyTo + bridge: odd_saved + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo8bOddSaved + entrypoint: StdCoreLongCopyTo + bridge: odd_saved + properties: [intrinsic] + signature: + - void + - void* + - void* + - int32_t + - int32_t + - int32_t + diff --git a/plugins/ets/runtime/ets_libbase_runtime.yaml b/plugins/ets/runtime/ets_libbase_runtime.yaml index dd96ec4845dcf3744aa4c74a1cd6e57219c767f6..a4ba89a40416fe9847517f2d54cf94945898306c 100644 --- a/plugins/ets/runtime/ets_libbase_runtime.yaml +++ b/plugins/ets/runtime/ets_libbase_runtime.yaml @@ -1195,6 +1195,153 @@ intrinsics: codegen_func: CreateFloatIsSafeInteger clear_flags: [ no_dce, no_hoist, no_cse, barrier, require_state, runtime_call ] +############ +# std.core # +############ + - name: StdCoreBoolCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - u1\[ + - u1\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreBoolCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + + - name: StdCoreCharCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - u16\[ + - u16\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreCharCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + + - name: StdCoreByteCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - i8\[ + - i8\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreByteCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + + - name: StdCoreShortCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - i16\[ + - i16\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreShortCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + + - name: StdCoreIntCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - i32\[ + - i32\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreIntCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + + - name: StdCoreLongCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - i64\[ + - i64\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreLongCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + + - name: StdCoreFloatCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - f32\[ + - f32\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreFloatCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + + - name: StdCoreDoubleCopyTo + space: ets + class_name: std.core.ETSGLOBAL + method_name: copyTo + static: true + signature: + ret: std.core.void + args: + - f64\[ + - f64\[ + - i32 + - i32 + - i32 + impl: panda::ets::intrinsics::StdCoreDoubleCopyTo + set_flags: [can_throw] + codegen_arch: [arm64, amd64] + codegen_func: CreateArrayCopyTo + ############ # std.core # ############ @@ -2236,8 +2383,6 @@ intrinsics: impl: panda::ets::intrinsics::ValueAPIGetFieldDouble clear_flags: [ ] - - - name: ValueAPISetFieldObject space: ets class_name: std.core.ETSGLOBAL diff --git a/plugins/ets/runtime/intrinsics/std_core_Arrays.cpp b/plugins/ets/runtime/intrinsics/std_core_Arrays.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cea5a6ed83015507e393fb44a8542b92a00345fc --- /dev/null +++ b/plugins/ets/runtime/intrinsics/std_core_Arrays.cpp @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "intrinsics.h" +#include "libpandabase/utils/logger.h" +#include "runtime/handle_scope-inl.h" +#include "runtime/entrypoints/string_index_of.h" +#include "plugins/ets/runtime/types/ets_string.h" +#include "plugins/ets/runtime/ets_exceptions.h" +#include "plugins/ets/runtime/ets_language_context.h" +#include "plugins/ets/runtime/ets_panda_file_items.h" + +namespace panda::ets::intrinsics { + +template +static EtsVoid *StdCoreCopyTo(coretypes::Array *src, coretypes::Array *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + auto src_len = static_cast(src->GetLength()); + auto dst_len = static_cast(dst->GetLength()); + const char *err_msg = nullptr; + + if (src_start < 0 || src_start > src_end || src_end > src_len) { + err_msg = "copyTo: src bounds verification failed"; + } else if (dst_start < 0 || dst_start > dst_len) { + err_msg = "copyTo: dst bounds verification failed"; + } else if ((src_end - src_start) > (dst_len - dst_start)) { + err_msg = "copyTo: Destination array doesn't have enough space"; + } + + if (err_msg == nullptr) { + auto src_addr = ToVoidPtr(ToUintPtr(src->GetData()) + src_start * sizeof(T)); + auto dst_addr = ToVoidPtr(ToUintPtr(dst->GetData()) + dst_start * sizeof(T)); + auto size = static_cast((src_end - src_start) * sizeof(T)); + std::memmove(dst_addr, src_addr, size); + } else { + auto *coroutine = EtsCoroutine::GetCurrent(); + ThrowEtsException(coroutine, panda_file_items::class_descriptors::ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION, err_msg); + std::cout << "StdCoreCopyTo: ArrayIndexOutOfBoundsException thrown\n"; + } + + return static_cast(nullptr); +} + +extern "C" EtsVoid *StdCoreBoolCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +extern "C" EtsVoid *StdCoreCharCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +extern "C" EtsVoid *StdCoreShortCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +extern "C" EtsVoid *StdCoreByteCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +extern "C" EtsVoid *StdCoreIntCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +extern "C" EtsVoid *StdCoreLongCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +extern "C" EtsVoid *StdCoreFloatCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +extern "C" EtsVoid *StdCoreDoubleCopyTo(EtsCharArray *src, EtsCharArray *dst, int32_t dst_start, int32_t src_start, + int32_t src_end) +{ + return StdCoreCopyTo(src->GetCoreType(), dst->GetCoreType(), dst_start, src_start, src_end); +} + +} // namespace panda::ets::intrinsics diff --git a/plugins/ets/subproject_sources.gn b/plugins/ets/subproject_sources.gn index 1a5a6d275fa43d6bf21014f981e481b8e644bea9..843c78665e6ce99fb8611c9b69c4e4e19759a819 100644 --- a/plugins/ets/subproject_sources.gn +++ b/plugins/ets/subproject_sources.gn @@ -86,6 +86,7 @@ srcs_runtime = [ "runtime/intrinsics/escompat_JSON.cpp", "runtime/intrinsics/std_core.cpp", "runtime/intrinsics/std_core_Char.cpp", + "runtime/intrinsics/std_core_Arrays.cpp", "runtime/intrinsics/std_core_Console.cpp", "runtime/intrinsics/std_core_Double.cpp", "runtime/intrinsics/std_core_Float.cpp", diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 36c1c5586526b441a6320fc3ff9abd0507205c28..146ba7e5af41eb67062308a3daa2e49d72ea27a9 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -395,6 +395,7 @@ if(NOT (CMAKE_CROSSCOMPILING OR PANDA_TARGET_OHOS)) ${IRTOC_SOURCE_DIR}/scripts/strings.irt ${IRTOC_SOURCE_DIR}/scripts/string_builder.irt ${IRTOC_SOURCE_DIR}/scripts/string_helpers.irt + ${IRTOC_SOURCE_DIR}/scripts/arrays.irt TARGET_VARIABLE IRTOC_FASTPATH_OBJ TARGET_VARIABLE_LLVM IRTOC_FASTPATH_LLVM_OBJ SKIP_VALIDATION ${skip_fastpath_validation}) diff --git a/runtime/entrypoints/entrypoints.yaml b/runtime/entrypoints/entrypoints.yaml index e793a8ef0936b52143ecc24f29268a2dce897b49..c7a08481aec77894f39471c069fe6af44579d6b8 100644 --- a/runtime/entrypoints/entrypoints.yaml +++ b/runtime/entrypoints/entrypoints.yaml @@ -1230,3 +1230,52 @@ entrypoints: - uint32_t # length - panda::ObjectHeader* # u16 array - panda::ObjectHeader* # string class pointer + +- name: ArrayCopyTo_1b + entrypoint: ArrayCopyTo1B + bridge: none + properties: [irtoc] + signature: + - void + - panda::ObjectHeader* + - panda::ObjectHeader* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo_2b + entrypoint: ArrayCopyTo2B + bridge: none + properties: [irtoc] + signature: + - void + - panda::ObjectHeader* + - panda::ObjectHeader* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo_4b + entrypoint: ArrayCopyTo4B + bridge: none + properties: [irtoc] + signature: + - void + - panda::ObjectHeader* + - panda::ObjectHeader* + - int32_t + - int32_t + - int32_t + +- name: ArrayCopyTo_8b + entrypoint: ArrayCopyTo8B + bridge: none + properties: [irtoc] + signature: + - void + - panda::ObjectHeader* + - panda::ObjectHeader* + - int32_t + - int32_t + - int32_t +