diff options
-rw-r--r-- | compiler/optimizing/code_generator_riscv64.h | 3 | ||||
-rw-r--r-- | compiler/optimizing/intrinsics_riscv64.cc | 285 | ||||
-rw-r--r-- | test/011-array-copy2/expected-stderr.txt | 0 | ||||
-rw-r--r-- | test/011-array-copy2/expected-stdout.txt | 3 | ||||
-rw-r--r-- | test/011-array-copy2/info.txt | 1 | ||||
-rw-r--r-- | test/011-array-copy2/src/Main.java | 483 |
6 files changed, 770 insertions, 5 deletions
diff --git a/compiler/optimizing/code_generator_riscv64.h b/compiler/optimizing/code_generator_riscv64.h index 227882e7b8..6664614e5a 100644 --- a/compiler/optimizing/code_generator_riscv64.h +++ b/compiler/optimizing/code_generator_riscv64.h @@ -56,9 +56,6 @@ static_assert(kQuietNaN == 0x200); static constexpr int32_t kFClassNaNMinValue = 0x100; #define UNIMPLEMENTED_INTRINSIC_LIST_RISCV64(V) \ - V(SystemArrayCopyByte) \ - V(SystemArrayCopyChar) \ - V(SystemArrayCopyInt) \ V(FP16Ceil) \ V(FP16Compare) \ V(FP16Floor) \ diff --git a/compiler/optimizing/intrinsics_riscv64.cc b/compiler/optimizing/intrinsics_riscv64.cc index b71232b4e4..9f1ac08a26 100644 --- a/compiler/optimizing/intrinsics_riscv64.cc +++ b/compiler/optimizing/intrinsics_riscv64.cc @@ -1569,8 +1569,9 @@ static void GenSystemArrayCopyAddresses(CodeGeneratorRISCV64* codegen, XRegister src_base, XRegister dst_base, XRegister src_end) { - // This routine is used by the SystemArrayCopy and the SystemArrayCopyChar intrinsics. - DCHECK(type == DataType::Type::kReference || type == DataType::Type::kUint16) + // This routine is used by the SystemArrayCopyX intrinsics. + DCHECK(type == DataType::Type::kReference || type == DataType::Type::kInt8 || + type == DataType::Type::kUint16 || type == DataType::Type::kInt32) << "Unexpected element type: " << type; const int32_t element_size = DataType::Size(type); const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value(); @@ -1921,6 +1922,286 @@ void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopy(HInvoke* invoke) { __ Bind(intrinsic_slow_path->GetExitLabel()); } +// This value is in bytes and greater than ARRAYCOPY_SHORT_XXX_ARRAY_THRESHOLD +// in libcore, so if we choose to jump to the slow path we will end up +// in the native implementation. +static constexpr int32_t kSystemArrayCopyPrimThreshold = 384; + +static void CreateSystemArrayCopyLocations(HInvoke* invoke, DataType::Type type) { + int32_t copy_threshold = kSystemArrayCopyPrimThreshold / DataType::Size(type); + + // Check to see if we have known failures that will cause us to have to bail out + // to the runtime, and just generate the runtime call directly. + HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstantOrNull(); + HIntConstant* dst_pos = invoke->InputAt(3)->AsIntConstantOrNull(); + + // The positions must be non-negative. + if ((src_pos != nullptr && src_pos->GetValue() < 0) || + (dst_pos != nullptr && dst_pos->GetValue() < 0)) { + // We will have to fail anyways. + return; + } + + // The length must be >= 0 and not so long that we would (currently) prefer libcore's + // native implementation. + HIntConstant* length = invoke->InputAt(4)->AsIntConstantOrNull(); + if (length != nullptr) { + int32_t len = length->GetValue(); + if (len < 0 || len > copy_threshold) { + // Just call as normal. + return; + } + } + + ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator(); + LocationSummary* locations = + new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified); + // arraycopy(char[] src, int src_pos, char[] dst, int dst_pos, int length). + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, LocationForSystemArrayCopyInput(invoke->InputAt(1))); + locations->SetInAt(2, Location::RequiresRegister()); + locations->SetInAt(3, LocationForSystemArrayCopyInput(invoke->InputAt(3))); + locations->SetInAt(4, LocationForSystemArrayCopyInput(invoke->InputAt(4))); + + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); +} + +void IntrinsicLocationsBuilderRISCV64::VisitSystemArrayCopyByte(HInvoke* invoke) { + CreateSystemArrayCopyLocations(invoke, DataType::Type::kInt8); +} + +void IntrinsicLocationsBuilderRISCV64::VisitSystemArrayCopyChar(HInvoke* invoke) { + CreateSystemArrayCopyLocations(invoke, DataType::Type::kUint16); +} + +void IntrinsicLocationsBuilderRISCV64::VisitSystemArrayCopyInt(HInvoke* invoke) { + CreateSystemArrayCopyLocations(invoke, DataType::Type::kInt32); +} + +static void GenerateUnsignedLoad( + Riscv64Assembler* assembler, XRegister rd, XRegister rs1, int32_t offset, size_t type_size) { + switch (type_size) { + case 1: + __ Lbu(rd, rs1, offset); + break; + case 2: + __ Lhu(rd, rs1, offset); + break; + case 4: + __ Lwu(rd, rs1, offset); + break; + case 8: + __ Ld(rd, rs1, offset); + break; + default: + LOG(FATAL) << "Unexpected data type"; + } +} + +static void GenerateStore( + Riscv64Assembler* assembler, XRegister rs2, XRegister rs1, int32_t offset, size_t type_size) { + switch (type_size) { + case 1: + __ Sb(rs2, rs1, offset); + break; + case 2: + __ Sh(rs2, rs1, offset); + break; + case 4: + __ Sw(rs2, rs1, offset); + break; + case 8: + __ Sd(rs2, rs1, offset); + break; + default: + LOG(FATAL) << "Unexpected data type"; + } +} + +static void SystemArrayCopyPrimitive(HInvoke* invoke, + CodeGeneratorRISCV64* codegen, + DataType::Type type) { + Riscv64Assembler* assembler = codegen->GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + XRegister src = locations->InAt(0).AsRegister<XRegister>(); + Location src_pos = locations->InAt(1); + XRegister dst = locations->InAt(2).AsRegister<XRegister>(); + Location dst_pos = locations->InAt(3); + Location length = locations->InAt(4); + + SlowPathCodeRISCV64* slow_path = + new (codegen->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke); + codegen->AddSlowPath(slow_path); + + SystemArrayCopyOptimizations optimizations(invoke); + + // If source and destination are the same, take the slow path. Overlapping copy regions must be + // copied in reverse and we can't know in all cases if it's needed. + __ Beq(src, dst, slow_path->GetEntryLabel()); + + if (!optimizations.GetSourceIsNotNull()) { + // Bail out if the source is null. + __ Beqz(src, slow_path->GetEntryLabel()); + } + + if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) { + // Bail out if the destination is null. + __ Beqz(dst, slow_path->GetEntryLabel()); + } + + int32_t copy_threshold = kSystemArrayCopyPrimThreshold / DataType::Size(type); + XRegister tmp = locations->GetTemp(0).AsRegister<XRegister>(); + if (!length.IsConstant()) { + // Merge the following two comparisons into one: + // If the length is negative, bail out (delegate to libcore's native implementation). + // If the length >= kSystemArrayCopyPrimThreshold then (currently) prefer libcore's + // native implementation. + __ Li(tmp, copy_threshold); + __ Bgeu(length.AsRegister<XRegister>(), tmp, slow_path->GetEntryLabel()); + } else { + // We have already checked in the LocationsBuilder for the constant case. + DCHECK_GE(length.GetConstant()->AsIntConstant()->GetValue(), 0); + DCHECK_LE(length.GetConstant()->AsIntConstant()->GetValue(), copy_threshold); + } + + XRegister src_curr_addr = locations->GetTemp(1).AsRegister<XRegister>(); + XRegister dst_curr_addr = locations->GetTemp(2).AsRegister<XRegister>(); + + CheckSystemArrayCopyPosition(assembler, + src, + src_pos, + length, + slow_path, + src_curr_addr, + dst_curr_addr, + /*length_is_array_length=*/ false, + /*position_sign_checked=*/ false); + + CheckSystemArrayCopyPosition(assembler, + dst, + dst_pos, + length, + slow_path, + src_curr_addr, + dst_curr_addr, + /*length_is_array_length=*/ false, + /*position_sign_checked=*/ false); + + const int32_t element_size = DataType::Size(type); + const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value(); + + GenArrayAddress(codegen, src_curr_addr, src, src_pos, type, data_offset); + GenArrayAddress(codegen, dst_curr_addr, dst, dst_pos, type, data_offset); + + // We split processing of the array in two parts: head and tail. + // A first loop handles the head by copying a block of elements per + // iteration (see: elements_per_block). + // A second loop handles the tail by copying the remaining elements. + // If the copy length is not constant, we copy them one-by-one. + // + // Both loops are inverted for better performance, meaning they are + // implemented as conditional do-while loops. + // Here, the loop condition is first checked to determine if there are + // sufficient elements to run an iteration, then we enter the do-while: an + // iteration is performed followed by a conditional branch only if another + // iteration is necessary. As opposed to a standard while-loop, this inversion + // can save some branching (e.g. we don't branch back to the initial condition + // at the end of every iteration only to potentially immediately branch + // again). + // + // A full block of elements is subtracted and added before and after the head + // loop, respectively. This ensures that any remaining length after each + // head loop iteration means there is a full block remaining, reducing the + // number of conditional checks required on every iteration. + ScratchRegisterScope temps(assembler); + constexpr int32_t bytes_copied_per_iteration = 16; + DCHECK_EQ(bytes_copied_per_iteration % element_size, 0); + int32_t elements_per_block = bytes_copied_per_iteration / element_size; + Riscv64Label done; + + XRegister length_tmp = temps.AllocateXRegister(); + + auto emit_head_loop = [&]() { + ScratchRegisterScope local_temps(assembler); + XRegister tmp2 = local_temps.AllocateXRegister(); + + Riscv64Label loop; + __ Bind(&loop); + __ Ld(tmp, src_curr_addr, 0); + __ Ld(tmp2, src_curr_addr, 8); + __ Sd(tmp, dst_curr_addr, 0); + __ Sd(tmp2, dst_curr_addr, 8); + __ Addi(length_tmp, length_tmp, -elements_per_block); + __ Addi(src_curr_addr, src_curr_addr, bytes_copied_per_iteration); + __ Addi(dst_curr_addr, dst_curr_addr, bytes_copied_per_iteration); + __ Bgez(length_tmp, &loop); + }; + + auto emit_tail_loop = [&]() { + Riscv64Label loop; + __ Bind(&loop); + GenerateUnsignedLoad(assembler, tmp, src_curr_addr, 0, element_size); + GenerateStore(assembler, tmp, dst_curr_addr, 0, element_size); + __ Addi(length_tmp, length_tmp, -1); + __ Addi(src_curr_addr, src_curr_addr, element_size); + __ Addi(dst_curr_addr, dst_curr_addr, element_size); + __ Bgtz(length_tmp, &loop); + }; + + auto emit_unrolled_tail_loop = [&](int32_t tail_length) { + DCHECK_LT(tail_length, elements_per_block); + + int32_t length_in_bytes = tail_length * element_size; + size_t offset = 0; + for (size_t operation_size = 8; operation_size > 0; operation_size >>= 1) { + if ((length_in_bytes & operation_size) != 0) { + GenerateUnsignedLoad(assembler, tmp, src_curr_addr, offset, operation_size); + GenerateStore(assembler, tmp, dst_curr_addr, offset, operation_size); + offset += operation_size; + } + } + }; + + if (length.IsConstant()) { + const int32_t constant_length = length.GetConstant()->AsIntConstant()->GetValue(); + if (constant_length >= elements_per_block) { + __ Li(length_tmp, constant_length - elements_per_block); + emit_head_loop(); + } + emit_unrolled_tail_loop(constant_length % elements_per_block); + } else { + Riscv64Label tail_loop; + XRegister length_reg = length.AsRegister<XRegister>(); + __ Addi(length_tmp, length_reg, -elements_per_block); + __ Bltz(length_tmp, &tail_loop); + + emit_head_loop(); + + __ Bind(&tail_loop); + __ Addi(length_tmp, length_tmp, elements_per_block); + __ Beqz(length_tmp, &done); + + emit_tail_loop(); + } + + __ Bind(&done); + __ Bind(slow_path->GetExitLabel()); +} + +void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopyByte(HInvoke* invoke) { + SystemArrayCopyPrimitive(invoke, codegen_, DataType::Type::kInt8); +} + +void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopyChar(HInvoke* invoke) { + SystemArrayCopyPrimitive(invoke, codegen_, DataType::Type::kUint16); +} + +void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopyInt(HInvoke* invoke) { + SystemArrayCopyPrimitive(invoke, codegen_, DataType::Type::kInt32); +} + enum class GetAndUpdateOp { kSet, kAdd, diff --git a/test/011-array-copy2/expected-stderr.txt b/test/011-array-copy2/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/011-array-copy2/expected-stderr.txt diff --git a/test/011-array-copy2/expected-stdout.txt b/test/011-array-copy2/expected-stdout.txt new file mode 100644 index 0000000000..203323f75a --- /dev/null +++ b/test/011-array-copy2/expected-stdout.txt @@ -0,0 +1,3 @@ +[ByteArrayTests]: passed +[CharArrayTests]: passed +[IntArrayTests]: passed diff --git a/test/011-array-copy2/info.txt b/test/011-array-copy2/info.txt new file mode 100644 index 0000000000..540486c134 --- /dev/null +++ b/test/011-array-copy2/info.txt @@ -0,0 +1 @@ +Test additional corner cases of SystemArrayCopy. diff --git a/test/011-array-copy2/src/Main.java b/test/011-array-copy2/src/Main.java new file mode 100644 index 0000000000..fd8f9a1451 --- /dev/null +++ b/test/011-array-copy2/src/Main.java @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * 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. + */ + +class Main { + + private static class ByteArrayTests { + public static byte[] init(byte[] arr) { + for (byte i = 0; i < arr.length; i++) { + arr[i] = (byte) i; + } + return arr; + } + + public static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new Error("Expected " + expected + ", got " + actual); + } + } + + public static byte[] createArrayOfZeroes(int size) { + byte[] arr = new byte[size]; + return arr; + } + + public static byte[] createIncrementedArray(int size) { + byte[] arr = new byte[size]; + init(arr); + return arr; + } + + public static void checkIncrementedArray(byte[] dst) { + for (byte i = 0; i < dst.length; i++) { + assertEquals(i, dst[i]); + } + } + + public static void $noinline$test1(byte[] src, byte[] dst) { + System.arraycopy(src, 0, dst, 0, 15); + } + + public static void $noinline$test2(byte[] src, byte[] dst) { + System.arraycopy(src, 0, dst, 0, 127); + } + + public static byte[] $noinline$test3() { + byte size = 15; + byte[] src = new byte[size]; + src = init(src); + byte[] dst = new byte[size]; + + System.arraycopy(src, 0, dst, 0, size); + return dst; + } + + public static byte[] $noinline$test4() { + int size = 127; + byte[] src = new byte[size]; + src = init(src); + byte[] dst = new byte[size]; + + System.arraycopy(src, 0, dst, 0, size); + return dst; + } + + public static byte[] $noinline$test5() { + byte[] src = new byte[80]; + src = init(src); + byte[] dst = new byte[80]; + + System.arraycopy(src, 0, dst, 0, 80); + return dst; + } + + public static byte[] $noinline$test6() { + byte[] src = new byte[127]; + src = init(src); + byte[] dst = new byte[127]; + + System.arraycopy(src, 0, dst, 100, 27); + return dst; + } + public static void check6(byte[] dst) { + for (byte i = 0; i < 100; i++) { + assertEquals(0, dst[i]); + } + for (byte i = 100; i < 127; i++) { + assertEquals(i - 100, dst[i]); + } + } + + public static byte[] $noinline$test7() { + byte[] src = new byte[127]; + src = init(src); + + System.arraycopy(src, 0, src, 100, 27); + return src; + } + public static void check7(byte[] dst) { + for (byte i = 0; i < 100; i++) { + assertEquals(i, dst[i]); + } + for (byte i = 100; i < 127; i++) { + assertEquals(i - 100, dst[i]); + } + } + + public static byte[] $noinline$test8() { + byte[] src = new byte[127]; + src = init(src); + + System.arraycopy(src, 100, src, 0, 27); + return src; + } + public static void check8(byte[] dst) { + for (byte i = 0; i < 27; i++) { + assertEquals(100 + i, dst[i]); + } + for (byte i = 27; i < 127; i++) { + assertEquals(i, dst[i]); + } + } + + public static void $noinline$test9(byte[] src, byte[] dst, byte i) { + System.arraycopy(src, 0, dst, 0, i); + } + + public static void runTests() { + System.out.print("[ByteArrayTests]: "); + + byte[] src15 = createIncrementedArray(15); + byte[] dst15 = createArrayOfZeroes(15); + $noinline$test1(src15, dst15); + checkIncrementedArray(dst15); + + byte[] src150 = createIncrementedArray(127); + byte[] dst150 = createArrayOfZeroes(127); + $noinline$test2(src150, dst150); + checkIncrementedArray(dst150); + + checkIncrementedArray($noinline$test3()); + checkIncrementedArray($noinline$test4()); + checkIncrementedArray($noinline$test5()); + + check6($noinline$test6()); + check7($noinline$test7()); + check8($noinline$test8()); + + for (byte i = 1; i < 127; i++) { + byte[] src = createIncrementedArray(i); + byte[] dst = createArrayOfZeroes(i); + $noinline$test9(src, dst, i); + checkIncrementedArray(dst); + } + System.out.println("passed"); + } + } + + private static class CharArrayTests { + + public static char[] init(char[] arr) { + for (int i = 0; i < arr.length; i++) { + arr[i] = (char) i; + } + return arr; + } + + public static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new Error("Expected " + expected + ", got " + actual); + } + } + + public static char[] createArrayOfZeroes(int size) { + char[] arr = new char[size]; + return arr; + } + + public static char[] createIncrementedArray(int size) { + char[] arr = new char[size]; + init(arr); + return arr; + } + + public static void checkIncrementedArray(char[] dst) { + for (int i = 0; i < dst.length; i++) { + assertEquals(i, dst[i]); + } + } + + public static void $noinline$test1(char[] src, char[] dst) { + System.arraycopy(src, 0, dst, 0, 15); + } + + public static void $noinline$test2(char[] src, char[] dst) { + System.arraycopy(src, 0, dst, 0, 150); + } + + public static char[] $noinline$test3() { + int size = 15; + char[] src = new char[size]; + src = init(src); + char[] dst = new char[size]; + + System.arraycopy(src, 0, dst, 0, size); + return dst; + } + + public static char[] $noinline$test4() { + int size = 150; + char[] src = new char[size]; + src = init(src); + char[] dst = new char[size]; + + System.arraycopy(src, 0, dst, 0, size); + return dst; + } + + public static char[] $noinline$test5() { + char[] src = new char[80]; + src = init(src); + char[] dst = new char[80]; + + System.arraycopy(src, 0, dst, 0, 80); + return dst; + } + + public static char[] $noinline$test6() { + char[] src = new char[150]; + src = init(src); + char[] dst = new char[150]; + + System.arraycopy(src, 0, dst, 100, 50); + return dst; + } + public static void check6(char[] dst) { + for (int i = 0; i < 100; i++) { + assertEquals(0, dst[i]); + } + for (int i = 100; i < 150; i++) { + assertEquals(i-100, dst[i]); + } + } + + public static char[] $noinline$test7() { + char[] src = new char[150]; + src = init(src); + + System.arraycopy(src, 0, src, 100, 50); + return src; + } + public static void check7(char[] dst) { + for (int i = 0; i < 100; i++) { + assertEquals(i, dst[i]); + } + for (int i = 100; i < 150; i++) { + assertEquals(i - 100, dst[i]); + } + } + + public static char[] $noinline$test8() { + char[] src = new char[150]; + src = init(src); + + System.arraycopy(src, 100, src, 0, 50); + return src; + } + public static void check8(char[] dst) { + for (int i = 0; i < 50; i++) { + assertEquals(100 + i, dst[i]); + } + for (int i = 50; i < 150; i++) { + assertEquals(i, dst[i]); + } + } + + public static void $noinline$test9(char[] src, char[] dst, int i) { + System.arraycopy(src, 0, dst, 0, i); + } + + public static void runTests() { + System.out.print("[CharArrayTests]: "); + + char[] src15 = createIncrementedArray(15); + char[] dst15 = createArrayOfZeroes(15); + $noinline$test1(src15, dst15); + checkIncrementedArray(dst15); + + char[] src150 = createIncrementedArray(150); + char[] dst150 = createArrayOfZeroes(150); + $noinline$test2(src150, dst150); + checkIncrementedArray(dst150); + + checkIncrementedArray($noinline$test3()); + checkIncrementedArray($noinline$test4()); + checkIncrementedArray($noinline$test5()); + + check6($noinline$test6()); + check7($noinline$test7()); + check8($noinline$test8()); + + for (int i = 1; i < 256; i++) { + char[] src = createIncrementedArray(i); + char[] dst = createArrayOfZeroes(i); + $noinline$test9(src, dst, i); + checkIncrementedArray(dst); + } + + System.out.println("passed"); + } + } + + private static class IntArrayTests { + public static int[] init(int[] arr) { + for (int i = 0; i < arr.length; i++) { + arr[i] = (int) i; + } + return arr; + } + + public static void assertEquals(int expected, int actual) { + if (expected != actual) { + throw new Error("Expected " + expected + ", got " + actual); + } + } + + public static int[] createArrayOfZeroes(int size) { + int[] arr = new int[size]; + return arr; + } + + public static int[] createIncrementedArray(int size) { + int[] arr = new int[size]; + init(arr); + return arr; + } + + public static void checkIncrementedArray(int[] dst) { + for (int i = 0; i < dst.length; i++) { + assertEquals(i, dst[i]); + } + } + + public static void $noinline$test1(int[] src, int[] dst) { + System.arraycopy(src, 0, dst, 0, 15); + } + + public static void $noinline$test2(int[] src, int[] dst) { + System.arraycopy(src, 0, dst, 0, 150); + } + + public static int[] $noinline$test3() { + int size = 15; + int[] src = new int[size]; + src = init(src); + int[] dst = new int[size]; + + System.arraycopy(src, 0, dst, 0, size); + return dst; + } + + public static int[] $noinline$test4() { + int size = 150; + int[] src = new int[size]; + src = init(src); + int[] dst = new int[size]; + + System.arraycopy(src, 0, dst, 0, size); + return dst; + } + + public static int[] $noinline$test5() { + int[] src = new int[80]; + src = init(src); + int[] dst = new int[80]; + + System.arraycopy(src, 0, dst, 0, 80); + return dst; + } + + public static int[] $noinline$test6() { + int[] src = new int[150]; + src = init(src); + int[] dst = new int[150]; + + System.arraycopy(src, 0, dst, 100, 50); + return dst; + } + public static void check6(int[] dst) { + for (int i = 0; i < 100; i++) { + assertEquals(0, dst[i]); + } + for (int i = 100; i < 150; i++) { + assertEquals(i-100, dst[i]); + } + } + + public static int[] $noinline$test7() { + int[] src = new int[150]; + src = init(src); + + System.arraycopy(src, 0, src, 100, 50); + return src; + } + public static void check7(int[] dst) { + for (int i = 0; i < 100; i++) { + assertEquals(i, dst[i]); + } + for (int i = 100; i < 150; i++) { + assertEquals(i - 100, dst[i]); + } + } + + public static int[] $noinline$test8() { + int[] src = new int[150]; + src = init(src); + + System.arraycopy(src, 100, src, 0, 50); + return src; + } + public static void check8(int[] dst) { + for (int i = 0; i < 50; i++) { + assertEquals(100 + i, dst[i]); + } + for (int i = 50; i < 150; i++) { + assertEquals(i, dst[i]); + } + } + + public static void $noinline$test9(int[] src, int[] dst, int i) { + System.arraycopy(src, 0, dst, 0, i); + } + + public static void runTests() { + System.out.print("[IntArrayTests]: "); + + int[] src15 = createIncrementedArray(15); + int[] dst15 = createArrayOfZeroes(15); + $noinline$test1(src15, dst15); + checkIncrementedArray(dst15); + + int[] src150 = createIncrementedArray(150); + int[] dst150 = createArrayOfZeroes(150); + $noinline$test2(src150, dst150); + checkIncrementedArray(dst150); + + checkIncrementedArray($noinline$test3()); + checkIncrementedArray($noinline$test4()); + checkIncrementedArray($noinline$test5()); + + check6($noinline$test6()); + check7($noinline$test7()); + check8($noinline$test8()); + + for (int i = 1; i < 256; i++) { + int[] src = createIncrementedArray(i); + int[] dst = createArrayOfZeroes(i); + $noinline$test9(src, dst, i); + checkIncrementedArray(dst); + } + + System.out.println("passed"); + } + } + + public static void main(String[] args) { + ByteArrayTests.runTests(); + CharArrayTests.runTests(); + IntArrayTests.runTests(); + } +} |