1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "test/cctest/wasm/wasm-atomics-utils.h"
6 #include "test/common/wasm/wasm-macro-gen.h"
7 
8 namespace v8 {
9 namespace internal {
10 namespace wasm {
11 namespace test_run_wasm_atomics_64 {
12 
RunU64BinOp(TestExecutionTier execution_tier,WasmOpcode wasm_op,Uint64BinOp expected_op)13 void RunU64BinOp(TestExecutionTier execution_tier, WasmOpcode wasm_op,
14                  Uint64BinOp expected_op) {
15   EXPERIMENTAL_FLAG_SCOPE(threads);
16   WasmRunner<uint64_t, uint64_t> r(execution_tier);
17   uint64_t* memory =
18       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
19   r.builder().SetHasSharedMemory();
20 
21   BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_LOCAL_GET(0),
22                               MachineRepresentation::kWord64));
23 
24   FOR_UINT64_INPUTS(i) {
25     uint64_t initial = i;
26     FOR_UINT64_INPUTS(j) {
27       r.builder().WriteMemory(&memory[0], initial);
28       CHECK_EQ(initial, r.Call(j));
29       uint64_t expected = expected_op(i, j);
30       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
31     }
32   }
33 }
34 
35 #define TEST_OPERATION(Name)                                 \
36   WASM_EXEC_TEST(I64Atomic##Name) {                          \
37     RunU64BinOp(execution_tier, kExprI64Atomic##Name, Name); \
38   }
OPERATION_LIST(TEST_OPERATION)39 OPERATION_LIST(TEST_OPERATION)
40 #undef TEST_OPERATION
41 
42 void RunU32BinOp(TestExecutionTier execution_tier, WasmOpcode wasm_op,
43                  Uint32BinOp expected_op) {
44   EXPERIMENTAL_FLAG_SCOPE(threads);
45   WasmRunner<uint64_t, uint64_t> r(execution_tier);
46   uint32_t* memory =
47       r.builder().AddMemoryElems<uint32_t>(kWasmPageSize / sizeof(uint32_t));
48   r.builder().SetHasSharedMemory();
49 
50   BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_LOCAL_GET(0),
51                               MachineRepresentation::kWord32));
52 
53   FOR_UINT32_INPUTS(i) {
54     uint32_t initial = i;
55     FOR_UINT32_INPUTS(j) {
56       r.builder().WriteMemory(&memory[0], initial);
57       CHECK_EQ(initial, r.Call(j));
58       uint32_t expected = expected_op(i, j);
59       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
60     }
61   }
62 }
63 
64 #define TEST_OPERATION(Name)                                      \
65   WASM_EXEC_TEST(I64Atomic##Name##32U) {                          \
66     RunU32BinOp(execution_tier, kExprI64Atomic##Name##32U, Name); \
67   }
OPERATION_LIST(TEST_OPERATION)68 OPERATION_LIST(TEST_OPERATION)
69 #undef TEST_OPERATION
70 
71 void RunU16BinOp(TestExecutionTier tier, WasmOpcode wasm_op,
72                  Uint16BinOp expected_op) {
73   EXPERIMENTAL_FLAG_SCOPE(threads);
74   WasmRunner<uint64_t, uint64_t> r(tier);
75   r.builder().SetHasSharedMemory();
76   uint16_t* memory =
77       r.builder().AddMemoryElems<uint16_t>(kWasmPageSize / sizeof(uint16_t));
78 
79   BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_LOCAL_GET(0),
80                               MachineRepresentation::kWord16));
81 
82   FOR_UINT16_INPUTS(i) {
83     uint16_t initial = i;
84     FOR_UINT16_INPUTS(j) {
85       r.builder().WriteMemory(&memory[0], initial);
86       CHECK_EQ(initial, r.Call(j));
87       uint16_t expected = expected_op(i, j);
88       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
89     }
90   }
91 }
92 
93 #define TEST_OPERATION(Name)                                      \
94   WASM_EXEC_TEST(I64Atomic##Name##16U) {                          \
95     RunU16BinOp(execution_tier, kExprI64Atomic##Name##16U, Name); \
96   }
OPERATION_LIST(TEST_OPERATION)97 OPERATION_LIST(TEST_OPERATION)
98 #undef TEST_OPERATION
99 
100 void RunU8BinOp(TestExecutionTier execution_tier, WasmOpcode wasm_op,
101                 Uint8BinOp expected_op) {
102   EXPERIMENTAL_FLAG_SCOPE(threads);
103   WasmRunner<uint64_t, uint64_t> r(execution_tier);
104   r.builder().SetHasSharedMemory();
105   uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(kWasmPageSize);
106 
107   BUILD(r, WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_LOCAL_GET(0),
108                               MachineRepresentation::kWord8));
109 
110   FOR_UINT8_INPUTS(i) {
111     uint8_t initial = i;
112     FOR_UINT8_INPUTS(j) {
113       r.builder().WriteMemory(&memory[0], initial);
114       CHECK_EQ(initial, r.Call(j));
115       uint8_t expected = expected_op(i, j);
116       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
117     }
118   }
119 }
120 
121 #define TEST_OPERATION(Name)                                    \
122   WASM_EXEC_TEST(I64Atomic##Name##8U) {                         \
123     RunU8BinOp(execution_tier, kExprI64Atomic##Name##8U, Name); \
124   }
125 OPERATION_LIST(TEST_OPERATION)
126 #undef TEST_OPERATION
127 
WASM_EXEC_TEST(I64AtomicCompareExchange)128 WASM_EXEC_TEST(I64AtomicCompareExchange) {
129   EXPERIMENTAL_FLAG_SCOPE(threads);
130   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
131   r.builder().SetHasSharedMemory();
132   uint64_t* memory =
133       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
134   BUILD(r, WASM_ATOMICS_TERNARY_OP(
135                kExprI64AtomicCompareExchange, WASM_I32V_1(0), WASM_LOCAL_GET(0),
136                WASM_LOCAL_GET(1), MachineRepresentation::kWord64));
137 
138   FOR_UINT64_INPUTS(i) {
139     uint64_t initial = i;
140     FOR_UINT64_INPUTS(j) {
141       r.builder().WriteMemory(&memory[0], initial);
142       CHECK_EQ(initial, r.Call(i, j));
143       uint64_t expected = CompareExchange(initial, i, j);
144       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
145     }
146   }
147 }
148 
WASM_EXEC_TEST(I64AtomicCompareExchange32U)149 WASM_EXEC_TEST(I64AtomicCompareExchange32U) {
150   EXPERIMENTAL_FLAG_SCOPE(threads);
151   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
152   r.builder().SetHasSharedMemory();
153   uint32_t* memory =
154       r.builder().AddMemoryElems<uint32_t>(kWasmPageSize / sizeof(uint32_t));
155   BUILD(r, WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange32U,
156                                    WASM_I32V_1(0), WASM_LOCAL_GET(0),
157                                    WASM_LOCAL_GET(1),
158                                    MachineRepresentation::kWord32));
159 
160   FOR_UINT32_INPUTS(i) {
161     uint32_t initial = i;
162     FOR_UINT32_INPUTS(j) {
163       r.builder().WriteMemory(&memory[0], initial);
164       CHECK_EQ(initial, r.Call(i, j));
165       uint32_t expected = CompareExchange(initial, i, j);
166       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
167     }
168   }
169 }
170 
WASM_EXEC_TEST(I64AtomicCompareExchange16U)171 WASM_EXEC_TEST(I64AtomicCompareExchange16U) {
172   EXPERIMENTAL_FLAG_SCOPE(threads);
173   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
174   r.builder().SetHasSharedMemory();
175   uint16_t* memory =
176       r.builder().AddMemoryElems<uint16_t>(kWasmPageSize / sizeof(uint16_t));
177   BUILD(r, WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange16U,
178                                    WASM_I32V_1(0), WASM_LOCAL_GET(0),
179                                    WASM_LOCAL_GET(1),
180                                    MachineRepresentation::kWord16));
181 
182   FOR_UINT16_INPUTS(i) {
183     uint16_t initial = i;
184     FOR_UINT16_INPUTS(j) {
185       r.builder().WriteMemory(&memory[0], initial);
186       CHECK_EQ(initial, r.Call(i, j));
187       uint16_t expected = CompareExchange(initial, i, j);
188       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
189     }
190   }
191 }
192 
WASM_EXEC_TEST(I32AtomicCompareExchange8U)193 WASM_EXEC_TEST(I32AtomicCompareExchange8U) {
194   EXPERIMENTAL_FLAG_SCOPE(threads);
195   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
196   r.builder().SetHasSharedMemory();
197   uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(kWasmPageSize);
198   BUILD(r,
199         WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange8U, WASM_I32V_1(0),
200                                 WASM_LOCAL_GET(0), WASM_LOCAL_GET(1),
201                                 MachineRepresentation::kWord8));
202   FOR_UINT8_INPUTS(i) {
203     uint8_t initial = i;
204     FOR_UINT8_INPUTS(j) {
205       r.builder().WriteMemory(&memory[0], initial);
206       CHECK_EQ(initial, r.Call(i, j));
207       uint8_t expected = CompareExchange(initial, i, j);
208       CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
209     }
210   }
211 }
212 
WASM_EXEC_TEST(I64AtomicLoad)213 WASM_EXEC_TEST(I64AtomicLoad) {
214   EXPERIMENTAL_FLAG_SCOPE(threads);
215   WasmRunner<uint64_t> r(execution_tier);
216   r.builder().SetHasSharedMemory();
217   uint64_t* memory =
218       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
219   BUILD(r, WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad, WASM_ZERO,
220                                 MachineRepresentation::kWord64));
221 
222   FOR_UINT64_INPUTS(i) {
223     uint64_t expected = i;
224     r.builder().WriteMemory(&memory[0], expected);
225     CHECK_EQ(expected, r.Call());
226   }
227 }
228 
WASM_EXEC_TEST(I64AtomicLoad32U)229 WASM_EXEC_TEST(I64AtomicLoad32U) {
230   EXPERIMENTAL_FLAG_SCOPE(threads);
231   WasmRunner<uint64_t> r(execution_tier);
232   r.builder().SetHasSharedMemory();
233   uint32_t* memory =
234       r.builder().AddMemoryElems<uint32_t>(kWasmPageSize / sizeof(uint32_t));
235   BUILD(r, WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad32U, WASM_ZERO,
236                                 MachineRepresentation::kWord32));
237 
238   FOR_UINT32_INPUTS(i) {
239     uint32_t expected = i;
240     r.builder().WriteMemory(&memory[0], expected);
241     CHECK_EQ(expected, r.Call());
242   }
243 }
244 
WASM_EXEC_TEST(I64AtomicLoad16U)245 WASM_EXEC_TEST(I64AtomicLoad16U) {
246   EXPERIMENTAL_FLAG_SCOPE(threads);
247   WasmRunner<uint64_t> r(execution_tier);
248   r.builder().SetHasSharedMemory();
249   uint16_t* memory =
250       r.builder().AddMemoryElems<uint16_t>(kWasmPageSize / sizeof(uint16_t));
251   BUILD(r, WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad16U, WASM_ZERO,
252                                 MachineRepresentation::kWord16));
253 
254   FOR_UINT16_INPUTS(i) {
255     uint16_t expected = i;
256     r.builder().WriteMemory(&memory[0], expected);
257     CHECK_EQ(expected, r.Call());
258   }
259 }
260 
WASM_EXEC_TEST(I64AtomicLoad8U)261 WASM_EXEC_TEST(I64AtomicLoad8U) {
262   EXPERIMENTAL_FLAG_SCOPE(threads);
263   WasmRunner<uint64_t> r(execution_tier);
264   r.builder().SetHasSharedMemory();
265   uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(kWasmPageSize);
266   BUILD(r, WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad8U, WASM_ZERO,
267                                 MachineRepresentation::kWord8));
268 
269   FOR_UINT8_INPUTS(i) {
270     uint8_t expected = i;
271     r.builder().WriteMemory(&memory[0], expected);
272     CHECK_EQ(expected, r.Call());
273   }
274 }
275 
WASM_EXEC_TEST(I64AtomicStoreLoad)276 WASM_EXEC_TEST(I64AtomicStoreLoad) {
277   EXPERIMENTAL_FLAG_SCOPE(threads);
278   WasmRunner<uint64_t, uint64_t> r(execution_tier);
279   r.builder().SetHasSharedMemory();
280   uint64_t* memory =
281       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
282 
283   BUILD(r,
284         WASM_ATOMICS_STORE_OP(kExprI64AtomicStore, WASM_ZERO, WASM_LOCAL_GET(0),
285                               MachineRepresentation::kWord64),
286         WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad, WASM_ZERO,
287                              MachineRepresentation::kWord64));
288 
289   FOR_UINT64_INPUTS(i) {
290     uint64_t expected = i;
291     CHECK_EQ(expected, r.Call(i));
292     CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
293   }
294 }
295 
WASM_EXEC_TEST(I64AtomicStoreLoad32U)296 WASM_EXEC_TEST(I64AtomicStoreLoad32U) {
297   EXPERIMENTAL_FLAG_SCOPE(threads);
298   WasmRunner<uint64_t, uint64_t> r(execution_tier);
299   r.builder().SetHasSharedMemory();
300   uint32_t* memory =
301       r.builder().AddMemoryElems<uint32_t>(kWasmPageSize / sizeof(uint32_t));
302 
303   BUILD(
304       r,
305       WASM_ATOMICS_STORE_OP(kExprI64AtomicStore32U, WASM_ZERO,
306                             WASM_LOCAL_GET(0), MachineRepresentation::kWord32),
307       WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad32U, WASM_ZERO,
308                            MachineRepresentation::kWord32));
309 
310   FOR_UINT32_INPUTS(i) {
311     uint32_t expected = i;
312     CHECK_EQ(expected, r.Call(i));
313     CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
314   }
315 }
316 
WASM_EXEC_TEST(I64AtomicStoreLoad16U)317 WASM_EXEC_TEST(I64AtomicStoreLoad16U) {
318   EXPERIMENTAL_FLAG_SCOPE(threads);
319   WasmRunner<uint64_t, uint64_t> r(execution_tier);
320   r.builder().SetHasSharedMemory();
321   uint16_t* memory =
322       r.builder().AddMemoryElems<uint16_t>(kWasmPageSize / sizeof(uint16_t));
323 
324   BUILD(
325       r,
326       WASM_ATOMICS_STORE_OP(kExprI64AtomicStore16U, WASM_ZERO,
327                             WASM_LOCAL_GET(0), MachineRepresentation::kWord16),
328       WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad16U, WASM_ZERO,
329                            MachineRepresentation::kWord16));
330 
331   FOR_UINT16_INPUTS(i) {
332     uint16_t expected = i;
333     CHECK_EQ(expected, r.Call(i));
334     CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
335   }
336 }
337 
WASM_EXEC_TEST(I64AtomicStoreLoad8U)338 WASM_EXEC_TEST(I64AtomicStoreLoad8U) {
339   EXPERIMENTAL_FLAG_SCOPE(threads);
340   WasmRunner<uint64_t, uint64_t> r(execution_tier);
341   r.builder().SetHasSharedMemory();
342   uint8_t* memory = r.builder().AddMemoryElems<uint8_t>(kWasmPageSize);
343 
344   BUILD(r,
345         WASM_ATOMICS_STORE_OP(kExprI64AtomicStore8U, WASM_ZERO,
346                               WASM_LOCAL_GET(0), MachineRepresentation::kWord8),
347         WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad8U, WASM_ZERO,
348                              MachineRepresentation::kWord8));
349 
350   FOR_UINT8_INPUTS(i) {
351     uint8_t expected = i;
352     CHECK_EQ(expected, r.Call(i));
353     CHECK_EQ(i, r.builder().ReadMemory(&memory[0]));
354   }
355 }
356 
357 // Drop tests verify atomic operations are run correctly when the
358 // entire 64-bit output is optimized out
RunDropTest(TestExecutionTier execution_tier,WasmOpcode wasm_op,Uint64BinOp op)359 void RunDropTest(TestExecutionTier execution_tier, WasmOpcode wasm_op,
360                  Uint64BinOp op) {
361   EXPERIMENTAL_FLAG_SCOPE(threads);
362   WasmRunner<uint64_t, uint64_t> r(execution_tier);
363   uint64_t* memory =
364       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
365   r.builder().SetHasSharedMemory();
366 
367   BUILD(r,
368         WASM_ATOMICS_BINOP(wasm_op, WASM_I32V_1(0), WASM_LOCAL_GET(0),
369                            MachineRepresentation::kWord64),
370         WASM_DROP, WASM_LOCAL_GET(0));
371 
372   uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
373   r.builder().WriteMemory(&memory[0], initial);
374   CHECK_EQ(local, r.Call(local));
375   uint64_t expected = op(initial, local);
376   CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
377 }
378 
379 #define TEST_OPERATION(Name)                                 \
380   WASM_EXEC_TEST(I64Atomic##Name##Drop) {                    \
381     RunDropTest(execution_tier, kExprI64Atomic##Name, Name); \
382   }
383 OPERATION_LIST(TEST_OPERATION)
384 #undef TEST_OPERATION
385 
WASM_EXEC_TEST(I64AtomicSub16UDrop)386 WASM_EXEC_TEST(I64AtomicSub16UDrop) {
387   EXPERIMENTAL_FLAG_SCOPE(threads);
388   WasmRunner<uint64_t, uint64_t> r(execution_tier);
389   uint16_t* memory =
390       r.builder().AddMemoryElems<uint16_t>(kWasmPageSize / sizeof(uint16_t));
391   r.builder().SetHasSharedMemory();
392 
393   BUILD(r,
394         WASM_ATOMICS_BINOP(kExprI64AtomicSub16U, WASM_I32V_1(0),
395                            WASM_LOCAL_GET(0), MachineRepresentation::kWord16),
396         WASM_DROP, WASM_LOCAL_GET(0));
397 
398   uint16_t initial = 0x7, local = 0xffe0;
399   r.builder().WriteMemory(&memory[0], initial);
400   CHECK_EQ(local, r.Call(local));
401   uint16_t expected = Sub(initial, local);
402   CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
403 }
404 
WASM_EXEC_TEST(I64AtomicCompareExchangeDrop)405 WASM_EXEC_TEST(I64AtomicCompareExchangeDrop) {
406   EXPERIMENTAL_FLAG_SCOPE(threads);
407   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
408   r.builder().SetHasSharedMemory();
409   uint64_t* memory =
410       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
411   BUILD(r,
412         WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange, WASM_I32V_1(0),
413                                 WASM_LOCAL_GET(0), WASM_LOCAL_GET(1),
414                                 MachineRepresentation::kWord64),
415         WASM_DROP, WASM_LOCAL_GET(1));
416 
417   uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
418   r.builder().WriteMemory(&memory[0], initial);
419   CHECK_EQ(local, r.Call(initial, local));
420   uint64_t expected = CompareExchange(initial, initial, local);
421   CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
422 }
423 
WASM_EXEC_TEST(I64AtomicStoreLoadDrop)424 WASM_EXEC_TEST(I64AtomicStoreLoadDrop) {
425   EXPERIMENTAL_FLAG_SCOPE(threads);
426   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
427   r.builder().SetHasSharedMemory();
428   uint64_t* memory =
429       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
430 
431   BUILD(r,
432         WASM_ATOMICS_STORE_OP(kExprI64AtomicStore, WASM_ZERO, WASM_LOCAL_GET(0),
433                               MachineRepresentation::kWord64),
434         WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad, WASM_ZERO,
435                              MachineRepresentation::kWord64),
436         WASM_DROP, WASM_LOCAL_GET(1));
437 
438   uint64_t store_value = 0x1111111111111111, expected = 0xC0DE;
439   CHECK_EQ(expected, r.Call(store_value, expected));
440   CHECK_EQ(store_value, r.builder().ReadMemory(&memory[0]));
441 }
442 
WASM_EXEC_TEST(I64AtomicAddConvertDrop)443 WASM_EXEC_TEST(I64AtomicAddConvertDrop) {
444   EXPERIMENTAL_FLAG_SCOPE(threads);
445   WasmRunner<uint64_t, uint64_t> r(execution_tier);
446   uint64_t* memory =
447       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
448   r.builder().SetHasSharedMemory();
449 
450   BUILD(r,
451         WASM_ATOMICS_BINOP(kExprI64AtomicAdd, WASM_I32V_1(0), WASM_LOCAL_GET(0),
452                            MachineRepresentation::kWord64),
453         kExprI32ConvertI64, WASM_DROP, WASM_LOCAL_GET(0));
454 
455   uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
456   r.builder().WriteMemory(&memory[0], initial);
457   CHECK_EQ(local, r.Call(local));
458   uint64_t expected = Add(initial, local);
459   CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
460 }
461 
WASM_EXEC_TEST(I64AtomicLoadConvertDrop)462 WASM_EXEC_TEST(I64AtomicLoadConvertDrop) {
463   EXPERIMENTAL_FLAG_SCOPE(threads);
464   WasmRunner<uint32_t, uint64_t> r(execution_tier);
465   uint64_t* memory =
466       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
467   r.builder().SetHasSharedMemory();
468 
469   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_LOAD_OP(
470                kExprI64AtomicLoad, WASM_ZERO, MachineRepresentation::kWord64)));
471 
472   uint64_t initial = 0x1111222233334444;
473   r.builder().WriteMemory(&memory[0], initial);
474   CHECK_EQ(static_cast<uint32_t>(initial), r.Call(initial));
475 }
476 
477 // Convert tests verify atomic operations are run correctly when the
478 // upper half of the 64-bit output is optimized out
RunConvertTest(TestExecutionTier execution_tier,WasmOpcode wasm_op,Uint64BinOp op)479 void RunConvertTest(TestExecutionTier execution_tier, WasmOpcode wasm_op,
480                     Uint64BinOp op) {
481   EXPERIMENTAL_FLAG_SCOPE(threads);
482   WasmRunner<uint32_t, uint64_t> r(execution_tier);
483   uint64_t* memory =
484       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
485   r.builder().SetHasSharedMemory();
486 
487   BUILD(r, WASM_I32_CONVERT_I64(
488                WASM_ATOMICS_BINOP(wasm_op, WASM_ZERO, WASM_LOCAL_GET(0),
489                                   MachineRepresentation::kWord64)));
490 
491   uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
492   r.builder().WriteMemory(&memory[0], initial);
493   CHECK_EQ(static_cast<uint32_t>(initial), r.Call(local));
494   uint64_t expected = op(initial, local);
495   CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
496 }
497 
498 #define TEST_OPERATION(Name)                                    \
499   WASM_EXEC_TEST(I64AtomicConvert##Name) {                      \
500     RunConvertTest(execution_tier, kExprI64Atomic##Name, Name); \
501   }
502 OPERATION_LIST(TEST_OPERATION)
503 #undef TEST_OPERATION
504 
WASM_EXEC_TEST(I64AtomicConvertCompareExchange)505 WASM_EXEC_TEST(I64AtomicConvertCompareExchange) {
506   EXPERIMENTAL_FLAG_SCOPE(threads);
507   WasmRunner<uint32_t, uint64_t, uint64_t> r(execution_tier);
508   uint64_t* memory =
509       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
510   r.builder().SetHasSharedMemory();
511 
512   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_TERNARY_OP(
513                kExprI64AtomicCompareExchange, WASM_I32V_1(0), WASM_LOCAL_GET(0),
514                WASM_LOCAL_GET(1), MachineRepresentation::kWord64)));
515 
516   uint64_t initial = 0x1111222233334444, local = 0x1111111111111111;
517   r.builder().WriteMemory(&memory[0], initial);
518   CHECK_EQ(static_cast<uint32_t>(initial), r.Call(initial, local));
519   uint64_t expected = CompareExchange(initial, initial, local);
520   CHECK_EQ(expected, r.builder().ReadMemory(&memory[0]));
521 }
522 
523 // The WASM_I64_EQ operation is used here to test that the index node
524 // is lowered correctly.
RunNonConstIndexTest(TestExecutionTier execution_tier,WasmOpcode wasm_op,Uint64BinOp op)525 void RunNonConstIndexTest(TestExecutionTier execution_tier, WasmOpcode wasm_op,
526                           Uint64BinOp op) {
527   EXPERIMENTAL_FLAG_SCOPE(threads);
528   WasmRunner<uint32_t, uint64_t> r(execution_tier);
529   uint64_t* memory =
530       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
531   r.builder().SetHasSharedMemory();
532 
533   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_BINOP(
534                wasm_op, WASM_I64_EQ(WASM_I64V(1), WASM_I64V(0)),
535                WASM_LOCAL_GET(0), MachineRepresentation::kWord32)));
536 
537   uint64_t initial = 0x1111222233334444, local = 0x5555666677778888;
538   r.builder().WriteMemory(&memory[0], initial);
539   CHECK_EQ(static_cast<uint32_t>(initial), r.Call(local));
540   CHECK_EQ(static_cast<uint32_t>(op(initial, local)),
541            static_cast<uint32_t>(r.builder().ReadMemory(&memory[0])));
542 }
543 
544 // Test a set of Narrow operations
545 #define TEST_OPERATION(Name)                                               \
546   WASM_EXEC_TEST(I64AtomicConstIndex##Name##Narrow) {                      \
547     RunNonConstIndexTest(execution_tier, kExprI64Atomic##Name##32U, Name); \
548   }
549 OPERATION_LIST(TEST_OPERATION)
550 #undef TEST_OPERATION
551 
552 // Test a set of Regular operations
553 #define TEST_OPERATION(Name)                                          \
554   WASM_EXEC_TEST(I64AtomicConstIndex##Name) {                         \
555     RunNonConstIndexTest(execution_tier, kExprI64Atomic##Name, Name); \
556   }
OPERATION_LIST(TEST_OPERATION)557 OPERATION_LIST(TEST_OPERATION)
558 #undef TEST_OPERATION
559 
560 WASM_EXEC_TEST(I64AtomicNonConstIndexCompareExchangeNarrow) {
561   EXPERIMENTAL_FLAG_SCOPE(threads);
562   WasmRunner<uint32_t, uint64_t, uint64_t> r(execution_tier);
563   uint64_t* memory =
564       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
565   r.builder().SetHasSharedMemory();
566 
567   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_TERNARY_OP(
568                kExprI64AtomicCompareExchange16U,
569                WASM_I64_EQ(WASM_I64V(1), WASM_I64V(0)), WASM_LOCAL_GET(0),
570                WASM_LOCAL_GET(1), MachineRepresentation::kWord16)));
571 
572   uint64_t initial = 0x4444333322221111, local = 0x9999888877776666;
573   r.builder().WriteMemory(&memory[0], initial);
574   CHECK_EQ(static_cast<uint16_t>(initial), r.Call(initial, local));
575   CHECK_EQ(static_cast<uint16_t>(CompareExchange(initial, initial, local)),
576            static_cast<uint16_t>(r.builder().ReadMemory(&memory[0])));
577 }
578 
WASM_EXEC_TEST(I64AtomicNonConstIndexCompareExchange)579 WASM_EXEC_TEST(I64AtomicNonConstIndexCompareExchange) {
580   EXPERIMENTAL_FLAG_SCOPE(threads);
581   WasmRunner<uint32_t, uint64_t, uint64_t> r(execution_tier);
582   uint64_t* memory =
583       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
584   r.builder().SetHasSharedMemory();
585 
586   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_TERNARY_OP(
587                kExprI64AtomicCompareExchange,
588                WASM_I64_EQ(WASM_I64V(1), WASM_I64V(0)), WASM_LOCAL_GET(0),
589                WASM_LOCAL_GET(1), MachineRepresentation::kWord16)));
590 
591   uint64_t initial = 4444333322221111, local = 0x9999888877776666;
592   r.builder().WriteMemory(&memory[0], initial);
593   CHECK_EQ(static_cast<uint32_t>(initial), r.Call(initial, local));
594   CHECK_EQ(CompareExchange(initial, initial, local),
595            r.builder().ReadMemory(&memory[0]));
596 }
597 
WASM_EXEC_TEST(I64AtomicNonConstIndexLoad8U)598 WASM_EXEC_TEST(I64AtomicNonConstIndexLoad8U) {
599   EXPERIMENTAL_FLAG_SCOPE(threads);
600   WasmRunner<uint32_t> r(execution_tier);
601   r.builder().SetHasSharedMemory();
602   uint64_t* memory =
603       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
604   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_LOAD_OP(
605                kExprI64AtomicLoad8U, WASM_I64_EQ(WASM_I64V(1), WASM_I64V(0)),
606                MachineRepresentation::kWord8)));
607 
608   uint64_t expected = 0xffffeeeeddddcccc;
609   r.builder().WriteMemory(&memory[0], expected);
610   CHECK_EQ(static_cast<uint8_t>(expected), r.Call());
611 }
612 
WASM_EXEC_TEST(I64AtomicCompareExchangeFail)613 WASM_EXEC_TEST(I64AtomicCompareExchangeFail) {
614   EXPERIMENTAL_FLAG_SCOPE(threads);
615   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
616   r.builder().SetHasSharedMemory();
617   uint64_t* memory =
618       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
619   BUILD(r, WASM_ATOMICS_TERNARY_OP(
620                kExprI64AtomicCompareExchange, WASM_I32V_1(0), WASM_LOCAL_GET(0),
621                WASM_LOCAL_GET(1), MachineRepresentation::kWord64));
622 
623   uint64_t initial = 0x1111222233334444, local = 0x1111111111111111,
624            test = 0x2222222222222222;
625   r.builder().WriteMemory(&memory[0], initial);
626   CHECK_EQ(initial, r.Call(test, local));
627   // No memory change on failed compare exchange
628   CHECK_EQ(initial, r.builder().ReadMemory(&memory[0]));
629 }
630 
WASM_EXEC_TEST(I64AtomicCompareExchange32UFail)631 WASM_EXEC_TEST(I64AtomicCompareExchange32UFail) {
632   EXPERIMENTAL_FLAG_SCOPE(threads);
633   WasmRunner<uint64_t, uint64_t, uint64_t> r(execution_tier);
634   r.builder().SetHasSharedMemory();
635   uint64_t* memory =
636       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
637   BUILD(r, WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange32U,
638                                    WASM_I32V_1(0), WASM_LOCAL_GET(0),
639                                    WASM_LOCAL_GET(1),
640                                    MachineRepresentation::kWord32));
641 
642   uint64_t initial = 0x1111222233334444, test = 0xffffffff, local = 0xeeeeeeee;
643   r.builder().WriteMemory(&memory[0], initial);
644   CHECK_EQ(static_cast<uint32_t>(initial), r.Call(test, local));
645   // No memory change on failed compare exchange
646   CHECK_EQ(initial, r.builder().ReadMemory(&memory[0]));
647 }
648 
WASM_EXEC_TEST(AtomicStoreNoConsideredEffectful)649 WASM_EXEC_TEST(AtomicStoreNoConsideredEffectful) {
650   EXPERIMENTAL_FLAG_SCOPE(threads);
651   // Use {Load} instead of {ProtectedLoad}.
652   FLAG_SCOPE(wasm_enforce_bounds_checks);
653   WasmRunner<uint32_t> r(execution_tier);
654   r.builder().AddMemoryElems<int64_t>(kWasmPageSize / sizeof(int64_t));
655   r.builder().SetHasSharedMemory();
656   BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
657         WASM_ATOMICS_STORE_OP(kExprI64AtomicStore, WASM_ZERO, WASM_I64V(20),
658                               MachineRepresentation::kWord64),
659         kExprI64Eqz);
660   CHECK_EQ(1, r.Call());
661 }
662 
RunNoEffectTest(TestExecutionTier execution_tier,WasmOpcode wasm_op)663 void RunNoEffectTest(TestExecutionTier execution_tier, WasmOpcode wasm_op) {
664   EXPERIMENTAL_FLAG_SCOPE(threads);
665   // Use {Load} instead of {ProtectedLoad}.
666   FLAG_SCOPE(wasm_enforce_bounds_checks);
667   WasmRunner<uint32_t> r(execution_tier);
668   r.builder().AddMemoryElems<int64_t>(kWasmPageSize / sizeof(int64_t));
669   r.builder().SetHasSharedMemory();
670   BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
671         WASM_ATOMICS_BINOP(wasm_op, WASM_ZERO, WASM_I64V(20),
672                            MachineRepresentation::kWord64),
673         WASM_DROP, kExprI64Eqz);
674   CHECK_EQ(1, r.Call());
675 }
676 
WASM_EXEC_TEST(AtomicAddNoConsideredEffectful)677 WASM_EXEC_TEST(AtomicAddNoConsideredEffectful) {
678   RunNoEffectTest(execution_tier, kExprI64AtomicAdd);
679 }
680 
WASM_EXEC_TEST(AtomicExchangeNoConsideredEffectful)681 WASM_EXEC_TEST(AtomicExchangeNoConsideredEffectful) {
682   RunNoEffectTest(execution_tier, kExprI64AtomicExchange);
683 }
684 
WASM_EXEC_TEST(AtomicCompareExchangeNoConsideredEffectful)685 WASM_EXEC_TEST(AtomicCompareExchangeNoConsideredEffectful) {
686   EXPERIMENTAL_FLAG_SCOPE(threads);
687   // Use {Load} instead of {ProtectedLoad}.
688   FLAG_SCOPE(wasm_enforce_bounds_checks);
689   WasmRunner<uint32_t> r(execution_tier);
690   r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
691   r.builder().SetHasSharedMemory();
692   BUILD(r, WASM_LOAD_MEM(MachineType::Int64(), WASM_ZERO),
693         WASM_ATOMICS_TERNARY_OP(kExprI64AtomicCompareExchange, WASM_ZERO,
694                                 WASM_I64V(0), WASM_I64V(30),
695                                 MachineRepresentation::kWord64),
696         WASM_DROP, kExprI64Eqz);
697   CHECK_EQ(1, r.Call());
698 }
699 
WASM_EXEC_TEST(I64AtomicLoadUseOnlyLowWord)700 WASM_EXEC_TEST(I64AtomicLoadUseOnlyLowWord) {
701   EXPERIMENTAL_FLAG_SCOPE(threads);
702   WasmRunner<uint32_t> r(execution_tier);
703   uint64_t* memory =
704       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
705   memory[1] = 0x1234567890abcdeful;
706   r.builder().SetHasSharedMemory();
707   // Test that we can use just the low word of an I64AtomicLoad.
708   BUILD(r,
709         WASM_I32_CONVERT_I64(WASM_ATOMICS_LOAD_OP(
710             kExprI64AtomicLoad, WASM_I32V(8), MachineRepresentation::kWord64)));
711   CHECK_EQ(0x90abcdef, r.Call());
712 }
713 
WASM_EXEC_TEST(I64AtomicLoadUseOnlyHighWord)714 WASM_EXEC_TEST(I64AtomicLoadUseOnlyHighWord) {
715   EXPERIMENTAL_FLAG_SCOPE(threads);
716   WasmRunner<uint32_t> r(execution_tier);
717   uint64_t* memory =
718       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
719   memory[1] = 0x1234567890abcdeful;
720   r.builder().SetHasSharedMemory();
721   // Test that we can use just the high word of an I64AtomicLoad.
722   BUILD(r, WASM_I32_CONVERT_I64(WASM_I64_ROR(
723                WASM_ATOMICS_LOAD_OP(kExprI64AtomicLoad, WASM_I32V(8),
724                                     MachineRepresentation::kWord64),
725                WASM_I64V(32))));
726   CHECK_EQ(0x12345678, r.Call());
727 }
728 
WASM_EXEC_TEST(I64AtomicAddUseOnlyLowWord)729 WASM_EXEC_TEST(I64AtomicAddUseOnlyLowWord) {
730   EXPERIMENTAL_FLAG_SCOPE(threads);
731   WasmRunner<uint32_t> r(execution_tier);
732   uint64_t* memory =
733       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
734   memory[1] = 0x1234567890abcdeful;
735   r.builder().SetHasSharedMemory();
736   // Test that we can use just the low word of an I64AtomicLoad.
737   BUILD(r, WASM_I32_CONVERT_I64(
738                WASM_ATOMICS_BINOP(kExprI64AtomicAdd, WASM_I32V(8), WASM_I64V(1),
739                                   MachineRepresentation::kWord64)));
740   CHECK_EQ(0x90abcdef, r.Call());
741 }
742 
WASM_EXEC_TEST(I64AtomicAddUseOnlyHighWord)743 WASM_EXEC_TEST(I64AtomicAddUseOnlyHighWord) {
744   EXPERIMENTAL_FLAG_SCOPE(threads);
745   WasmRunner<uint32_t> r(execution_tier);
746   uint64_t* memory =
747       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
748   memory[1] = 0x1234567890abcdeful;
749   r.builder().SetHasSharedMemory();
750   // Test that we can use just the high word of an I64AtomicLoad.
751   BUILD(r, WASM_I32_CONVERT_I64(WASM_I64_ROR(
752                WASM_ATOMICS_BINOP(kExprI64AtomicAdd, WASM_I32V(8), WASM_I64V(1),
753                                   MachineRepresentation::kWord64),
754                WASM_I64V(32))));
755   CHECK_EQ(0x12345678, r.Call());
756 }
757 
WASM_EXEC_TEST(I64AtomicCompareExchangeUseOnlyLowWord)758 WASM_EXEC_TEST(I64AtomicCompareExchangeUseOnlyLowWord) {
759   EXPERIMENTAL_FLAG_SCOPE(threads);
760   WasmRunner<uint32_t> r(execution_tier);
761   uint64_t* memory =
762       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
763   memory[1] = 0x1234567890abcdeful;
764   r.builder().SetHasSharedMemory();
765   // Test that we can use just the low word of an I64AtomicLoad.
766   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_TERNARY_OP(
767                kExprI64AtomicCompareExchange, WASM_I32V(8), WASM_I64V(1),
768                WASM_I64V(memory[1]), MachineRepresentation::kWord64)));
769   CHECK_EQ(0x90abcdef, r.Call());
770 }
771 
WASM_EXEC_TEST(I64AtomicCompareExchangeUseOnlyHighWord)772 WASM_EXEC_TEST(I64AtomicCompareExchangeUseOnlyHighWord) {
773   EXPERIMENTAL_FLAG_SCOPE(threads);
774   WasmRunner<uint32_t> r(execution_tier);
775   uint64_t* memory =
776       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
777   memory[1] = 0x1234567890abcdeful;
778   r.builder().SetHasSharedMemory();
779   // Test that we can use just the high word of an I64AtomicLoad.
780   BUILD(r, WASM_I32_CONVERT_I64(WASM_I64_ROR(
781                WASM_ATOMICS_TERNARY_OP(
782                    kExprI64AtomicCompareExchange, WASM_I32V(8), WASM_I64V(1),
783                    WASM_I64V(memory[1]), MachineRepresentation::kWord64),
784                WASM_I64V(32))));
785   CHECK_EQ(0x12345678, r.Call());
786 }
787 
WASM_EXEC_TEST(I64AtomicExchangeUseOnlyLowWord)788 WASM_EXEC_TEST(I64AtomicExchangeUseOnlyLowWord) {
789   EXPERIMENTAL_FLAG_SCOPE(threads);
790   WasmRunner<uint32_t> r(execution_tier);
791   uint64_t* memory =
792       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
793   memory[1] = 0x1234567890abcdeful;
794   r.builder().SetHasSharedMemory();
795   // Test that we can use just the low word of an I64AtomicLoad.
796   BUILD(r, WASM_I32_CONVERT_I64(WASM_ATOMICS_BINOP(
797                kExprI64AtomicExchange, WASM_I32V(8), WASM_I64V(1),
798                MachineRepresentation::kWord64)));
799   CHECK_EQ(0x90abcdef, r.Call());
800 }
801 
WASM_EXEC_TEST(I64AtomicExchangeUseOnlyHighWord)802 WASM_EXEC_TEST(I64AtomicExchangeUseOnlyHighWord) {
803   EXPERIMENTAL_FLAG_SCOPE(threads);
804   WasmRunner<uint32_t> r(execution_tier);
805   uint64_t* memory =
806       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
807   memory[1] = 0x1234567890abcdeful;
808   r.builder().SetHasSharedMemory();
809   // Test that we can use just the high word of an I64AtomicLoad.
810   BUILD(r, WASM_I32_CONVERT_I64(WASM_I64_ROR(
811                WASM_ATOMICS_BINOP(kExprI64AtomicExchange, WASM_I32V(8),
812                                   WASM_I64V(1), MachineRepresentation::kWord64),
813                WASM_I64V(32))));
814   CHECK_EQ(0x12345678, r.Call());
815 }
816 
WASM_EXEC_TEST(I64AtomicCompareExchange32UZeroExtended)817 WASM_EXEC_TEST(I64AtomicCompareExchange32UZeroExtended) {
818   EXPERIMENTAL_FLAG_SCOPE(threads);
819   WasmRunner<uint32_t> r(execution_tier);
820   uint64_t* memory =
821       r.builder().AddMemoryElems<uint64_t>(kWasmPageSize / sizeof(uint64_t));
822   memory[1] = 0;
823   r.builder().SetHasSharedMemory();
824   // Test that the high word of the expected value is cleared in the return
825   // value.
826   BUILD(r, WASM_I64_EQZ(WASM_ATOMICS_TERNARY_OP(
827                kExprI64AtomicCompareExchange32U, WASM_I32V(8),
828                WASM_I64V(0x1234567800000000), WASM_I64V(0),
829                MachineRepresentation::kWord32)));
830   CHECK_EQ(1, r.Call());
831 }
832 
833 }  // namespace test_run_wasm_atomics_64
834 }  // namespace wasm
835 }  // namespace internal
836 }  // namespace v8
837