Skip to content

Commit bf7d643

Browse files
dcharkesCommit Queue
authored and
Commit Queue
committed
[vm/test] MemoryCopyInstr unit tests
TEST=runtime/vm/compiler/backend/memory_copy_test.cc Bug: #51031 Change-Id: I6b0b2eb63f97ae9d7d3c9c80d998929f657ef482 Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-riscv64-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-android-debug-arm-try,vm-kernel-nnbd-mac-debug-arm64-try,vm-kernel-nnbd-win-debug-x64-try,vm-kernel-win-debug-x64c-try,vm-kernel-win-debug-ia32-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-reload-rollback-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279387 Reviewed-by: Alexander Markov <[email protected]>
1 parent 10953e2 commit bf7d643

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
#include <vector>
6+
7+
#include "vm/compiler/backend/il.h"
8+
#include "vm/compiler/backend/il_printer.h"
9+
#include "vm/compiler/backend/il_test_helper.h"
10+
#include "vm/compiler/call_specializer.h"
11+
#include "vm/compiler/compiler_pass.h"
12+
#include "vm/object.h"
13+
#include "vm/unit_test.h"
14+
15+
namespace dart {
16+
17+
extern const char* pointer_prefix;
18+
19+
static const intptr_t kMemoryTestLength = 1024;
20+
static const uint8_t kUnInitialized = 0xFE;
21+
22+
static classid_t TypedDataCidForElementSize(intptr_t elem_size) {
23+
switch (elem_size) {
24+
case 1:
25+
return kTypedDataUint8ArrayCid;
26+
case 2:
27+
return kTypedDataUint16ArrayCid;
28+
case 4:
29+
return kTypedDataUint32ArrayCid;
30+
case 8:
31+
return kTypedDataUint64ArrayCid;
32+
case 16:
33+
return kTypedDataInt32x4ArrayCid;
34+
default:
35+
break;
36+
}
37+
UNIMPLEMENTED();
38+
}
39+
40+
static void RunMemoryCopyInstrTest(intptr_t src_start,
41+
intptr_t dest_start,
42+
intptr_t length,
43+
intptr_t elem_size) {
44+
OS::Print("==================================================\n");
45+
OS::Print("RunMemoryCopyInstrTest src_start %" Pd " dest_start %" Pd
46+
" length "
47+
"%" Pd " elem_size %" Pd "\n",
48+
src_start, dest_start, length, elem_size);
49+
OS::Print("==================================================\n");
50+
classid_t cid = TypedDataCidForElementSize(elem_size);
51+
52+
intptr_t dest_copied_start = dest_start * elem_size;
53+
intptr_t dest_copied_end = dest_copied_start + length * elem_size;
54+
ASSERT(dest_copied_end < kMemoryTestLength);
55+
intptr_t expect_diff = (dest_start - src_start) * elem_size;
56+
57+
uint8_t* ptr = reinterpret_cast<uint8_t*>(malloc(kMemoryTestLength));
58+
uint8_t* ptr2 = reinterpret_cast<uint8_t*>(malloc(kMemoryTestLength));
59+
for (intptr_t i = 0; i < kMemoryTestLength; i++) {
60+
ptr[i] = 1 + i % 100; // Initialized.
61+
ptr2[i] = kUnInitialized; // Emtpy.
62+
}
63+
64+
OS::Print("&ptr %p &ptr2 %p\n", ptr, ptr2);
65+
66+
// clang-format off
67+
auto kScript = Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
68+
import 'dart:ffi';
69+
70+
void myFunction() {
71+
final pointer = Pointer<Uint8>.fromAddress(%s%p);
72+
final pointer2 = Pointer<Uint8>.fromAddress(%s%p);
73+
anotherFunction();
74+
}
75+
76+
void anotherFunction() {}
77+
)", pointer_prefix, ptr, pointer_prefix, ptr2), std::free);
78+
// clang-format on
79+
80+
const auto& root_library = Library::Handle(LoadTestScript(kScript.get()));
81+
Invoke(root_library, "myFunction");
82+
// Running this should be a no-op on the memory.
83+
for (intptr_t i = 0; i < kMemoryTestLength; i++) {
84+
EXPECT_EQ(1 + i % 100, static_cast<intptr_t>(ptr[i]));
85+
EXPECT_EQ(kUnInitialized, static_cast<intptr_t>(ptr2[i]));
86+
}
87+
88+
const auto& my_function =
89+
Function::Handle(GetFunction(root_library, "myFunction"));
90+
91+
TestPipeline pipeline(my_function, CompilerPass::kJIT);
92+
FlowGraph* flow_graph = pipeline.RunPasses({
93+
CompilerPass::kComputeSSA,
94+
});
95+
96+
StaticCallInstr* pointer = nullptr;
97+
StaticCallInstr* pointer2 = nullptr;
98+
StaticCallInstr* another_function_call = nullptr;
99+
{
100+
ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
101+
102+
EXPECT(cursor.TryMatch({
103+
kMoveGlob,
104+
{kMatchAndMoveStaticCall, &pointer},
105+
{kMatchAndMoveStaticCall, &pointer2},
106+
{kMatchAndMoveStaticCall, &another_function_call},
107+
}));
108+
}
109+
110+
Zone* const zone = Thread::Current()->zone();
111+
112+
auto* const src_start_constant_instr = flow_graph->GetConstant(
113+
Integer::ZoneHandle(zone, Integer::New(src_start, Heap::kOld)), kTagged);
114+
115+
auto* const dest_start_constant_instr = flow_graph->GetConstant(
116+
Integer::ZoneHandle(zone, Integer::New(dest_start, Heap::kOld)), kTagged);
117+
118+
auto* const length_constant_instr = flow_graph->GetConstant(
119+
Integer::ZoneHandle(zone, Integer::New(length, Heap::kOld)), kTagged);
120+
121+
auto* const memory_copy_instr = new (zone)
122+
MemoryCopyInstr(new (zone) Value(pointer), new (zone) Value(pointer2),
123+
new (zone) Value(src_start_constant_instr),
124+
new (zone) Value(dest_start_constant_instr),
125+
new (zone) Value(length_constant_instr),
126+
/*src_cid=*/cid,
127+
/*dest_cid=*/cid);
128+
flow_graph->InsertBefore(another_function_call, memory_copy_instr, nullptr,
129+
FlowGraph::kEffect);
130+
131+
another_function_call->RemoveFromGraph();
132+
133+
{
134+
// Check we constructed the right graph.
135+
ILMatcher cursor(flow_graph, flow_graph->graph_entry()->normal_entry());
136+
EXPECT(cursor.TryMatch({
137+
kMoveGlob,
138+
kMatchAndMoveStaticCall,
139+
kMatchAndMoveStaticCall,
140+
kMatchAndMoveMemoryCopy,
141+
}));
142+
}
143+
144+
{
145+
#if !defined(PRODUCT)
146+
SetFlagScope<bool> sfs(&FLAG_disassemble_optimized, true);
147+
#endif
148+
149+
pipeline.RunForcedOptimizedAfterSSAPasses();
150+
pipeline.CompileGraphAndAttachFunction();
151+
}
152+
153+
// Run the mem copy.
154+
Invoke(root_library, "myFunction");
155+
for (intptr_t i = 0; i < kMemoryTestLength; i++) {
156+
EXPECT_EQ(1 + i % 100, static_cast<intptr_t>(ptr[i]));
157+
if (dest_copied_start <= i && i < dest_copied_end) {
158+
// Copied.
159+
EXPECT_EQ(1 + (i - expect_diff) % 100, static_cast<intptr_t>(ptr2[i]));
160+
} else {
161+
// Untouched.
162+
EXPECT_EQ(kUnInitialized, static_cast<intptr_t>(ptr2[i]));
163+
}
164+
}
165+
free(ptr);
166+
free(ptr2);
167+
}
168+
169+
#define MEMORY_COPY_TEST(src_start, dest_start, length, elem_size) \
170+
ISOLATE_UNIT_TEST_CASE( \
171+
IRTest_MemoryCopy_##src_start##_##dest_start##_##length##_##elem_size) { \
172+
RunMemoryCopyInstrTest(src_start, dest_start, length, elem_size); \
173+
}
174+
175+
// No offset, varying length.
176+
MEMORY_COPY_TEST(0, 0, 1, 1)
177+
MEMORY_COPY_TEST(0, 0, 2, 1)
178+
MEMORY_COPY_TEST(0, 0, 3, 1)
179+
MEMORY_COPY_TEST(0, 0, 4, 1)
180+
MEMORY_COPY_TEST(0, 0, 5, 1)
181+
MEMORY_COPY_TEST(0, 0, 6, 1)
182+
MEMORY_COPY_TEST(0, 0, 7, 1)
183+
MEMORY_COPY_TEST(0, 0, 8, 1)
184+
MEMORY_COPY_TEST(0, 0, 16, 1)
185+
186+
// Offsets.
187+
MEMORY_COPY_TEST(2, 2, 1, 1)
188+
MEMORY_COPY_TEST(2, 17, 3, 1)
189+
MEMORY_COPY_TEST(20, 5, 17, 1)
190+
191+
// Other element sizes.
192+
MEMORY_COPY_TEST(0, 0, 1, 2)
193+
MEMORY_COPY_TEST(0, 0, 1, 4)
194+
MEMORY_COPY_TEST(0, 0, 1, 8)
195+
MEMORY_COPY_TEST(0, 0, 2, 2)
196+
MEMORY_COPY_TEST(0, 0, 2, 4)
197+
MEMORY_COPY_TEST(0, 0, 2, 8)
198+
MEMORY_COPY_TEST(0, 0, 4, 2)
199+
MEMORY_COPY_TEST(0, 0, 4, 4)
200+
MEMORY_COPY_TEST(0, 0, 4, 8)
201+
MEMORY_COPY_TEST(0, 0, 8, 2)
202+
MEMORY_COPY_TEST(0, 0, 8, 4)
203+
MEMORY_COPY_TEST(0, 0, 8, 8)
204+
// TODO(http://dartbug.com/51237): Fix arm64 issue.
205+
#if !defined(TARGET_ARCH_ARM64)
206+
MEMORY_COPY_TEST(0, 0, 2, 16)
207+
MEMORY_COPY_TEST(0, 0, 4, 16)
208+
MEMORY_COPY_TEST(0, 0, 8, 16)
209+
#endif
210+
211+
// Other element sizes with offsets.
212+
MEMORY_COPY_TEST(1, 1, 2, 2)
213+
MEMORY_COPY_TEST(0, 1, 4, 2)
214+
MEMORY_COPY_TEST(1, 2, 3, 2)
215+
MEMORY_COPY_TEST(123, 2, 4, 4)
216+
MEMORY_COPY_TEST(5, 72, 1, 8)
217+
218+
// TODO(http://dartbug.com/51229): Fix arm issue.
219+
// TODO(http://dartbug.com/51237): Fix arm64 issue.
220+
#if !defined(TARGET_ARCH_ARM) && !defined(TARGET_ARCH_ARM64)
221+
MEMORY_COPY_TEST(13, 14, 15, 16)
222+
#endif
223+
224+
} // namespace dart

runtime/vm/compiler/compiler_sources.gni

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ compiler_sources_tests = [
172172
"backend/inliner_test.cc",
173173
"backend/locations_helpers_test.cc",
174174
"backend/loops_test.cc",
175+
"backend/memory_copy_test.cc",
175176
"backend/range_analysis_test.cc",
176177
"backend/reachability_fence_test.cc",
177178
"backend/redundancy_elimination_test.cc",

0 commit comments

Comments
 (0)