Split testb3 into multiple files
[WebKit-https.git] / Source / JavaScriptCore / b3 / testb3_8.cpp
1 /*
2  * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "testb3.h"
28
29 #if ENABLE(B3_JIT)
30
31 template<typename T>
32 void testAtomicWeakCAS()
33 {
34     Type type = NativeTraits<T>::type;
35     Width width = NativeTraits<T>::width;
36
37     auto checkMyDisassembly = [&] (Compilation& compilation, bool fenced) {
38         if (isX86()) {
39             checkUsesInstruction(compilation, "lock");
40             checkUsesInstruction(compilation, "cmpxchg");
41         } else {
42             if (fenced) {
43                 checkUsesInstruction(compilation, "ldax");
44                 checkUsesInstruction(compilation, "stlx");
45             } else {
46                 checkUsesInstruction(compilation, "ldx");
47                 checkUsesInstruction(compilation, "stx");
48             }
49         }
50     };
51
52     {
53         Procedure proc;
54         BasicBlock* root = proc.addBlock();
55         BasicBlock* reloop = proc.addBlock();
56         BasicBlock* done = proc.addBlock();
57     
58         Value* ptr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
59         root->appendNew<Value>(proc, Jump, Origin());
60         root->setSuccessors(reloop);
61     
62         reloop->appendNew<Value>(
63             proc, Branch, Origin(),
64             reloop->appendNew<AtomicValue>(
65                 proc, AtomicWeakCAS, Origin(), width,
66                 reloop->appendIntConstant(proc, Origin(), type, 42),
67                 reloop->appendIntConstant(proc, Origin(), type, 0xbeef),
68                 ptr));
69         reloop->setSuccessors(done, reloop);
70     
71         done->appendNew<Value>(proc, Return, Origin());
72     
73         auto code = compileProc(proc);
74         T value[2];
75         value[0] = 42;
76         value[1] = 13;
77         invoke<void>(*code, value);
78         CHECK_EQ(value[0], static_cast<T>(0xbeef));
79         CHECK_EQ(value[1], 13);
80         checkMyDisassembly(*code, true);
81     }
82
83     {
84         Procedure proc;
85         BasicBlock* root = proc.addBlock();
86         BasicBlock* reloop = proc.addBlock();
87         BasicBlock* done = proc.addBlock();
88     
89         Value* ptr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
90         root->appendNew<Value>(proc, Jump, Origin());
91         root->setSuccessors(reloop);
92     
93         reloop->appendNew<Value>(
94             proc, Branch, Origin(),
95             reloop->appendNew<AtomicValue>(
96                 proc, AtomicWeakCAS, Origin(), width,
97                 reloop->appendIntConstant(proc, Origin(), type, 42),
98                 reloop->appendIntConstant(proc, Origin(), type, 0xbeef),
99                 ptr, 0, HeapRange(42), HeapRange()));
100         reloop->setSuccessors(done, reloop);
101     
102         done->appendNew<Value>(proc, Return, Origin());
103     
104         auto code = compileProc(proc);
105         T value[2];
106         value[0] = 42;
107         value[1] = 13;
108         invoke<void>(*code, value);
109         CHECK_EQ(value[0], static_cast<T>(0xbeef));
110         CHECK_EQ(value[1], 13);
111         checkMyDisassembly(*code, false);
112     }
113
114     {
115         Procedure proc;
116         BasicBlock* root = proc.addBlock();
117         BasicBlock* succ = proc.addBlock();
118         BasicBlock* fail = proc.addBlock();
119     
120         Value* ptr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
121         root->appendNew<Value>(
122             proc, Branch, Origin(),
123             root->appendNew<AtomicValue>(
124                 proc, AtomicWeakCAS, Origin(), width,
125                 root->appendIntConstant(proc, Origin(), type, 42),
126                 root->appendIntConstant(proc, Origin(), type, 0xbeef),
127                 ptr));
128         root->setSuccessors(succ, fail);
129     
130         succ->appendNew<MemoryValue>(
131             proc, storeOpcode(GP, width), Origin(),
132             succ->appendIntConstant(proc, Origin(), type, 100),
133             ptr);
134         succ->appendNew<Value>(proc, Return, Origin());
135     
136         fail->appendNew<Value>(proc, Return, Origin());
137     
138         auto code = compileProc(proc);
139         T value[2];
140         value[0] = 42;
141         value[1] = 13;
142         while (value[0] == 42)
143             invoke<void>(*code, value);
144         CHECK_EQ(value[0], static_cast<T>(100));
145         CHECK_EQ(value[1], 13);
146         value[0] = static_cast<T>(300);
147         invoke<void>(*code, value);
148         CHECK_EQ(value[0], static_cast<T>(300));
149         CHECK_EQ(value[1], 13);
150         checkMyDisassembly(*code, true);
151     }
152
153     {
154         Procedure proc;
155         BasicBlock* root = proc.addBlock();
156         BasicBlock* succ = proc.addBlock();
157         BasicBlock* fail = proc.addBlock();
158     
159         Value* ptr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
160         root->appendNew<Value>(
161             proc, Branch, Origin(),
162             root->appendNew<Value>(
163                 proc, Equal, Origin(),
164                 root->appendNew<AtomicValue>(
165                     proc, AtomicWeakCAS, Origin(), width,
166                     root->appendIntConstant(proc, Origin(), type, 42),
167                     root->appendIntConstant(proc, Origin(), type, 0xbeef),
168                     ptr),
169                 root->appendIntConstant(proc, Origin(), Int32, 0)));
170         root->setSuccessors(fail, succ);
171     
172         succ->appendNew<MemoryValue>(
173             proc, storeOpcode(GP, width), Origin(),
174             succ->appendIntConstant(proc, Origin(), type, 100),
175             ptr);
176         succ->appendNew<Value>(proc, Return, Origin());
177     
178         fail->appendNew<Value>(proc, Return, Origin());
179     
180         auto code = compileProc(proc);
181         T value[2];
182         value[0] = 42;
183         value[1] = 13;
184         while (value[0] == 42)
185             invoke<void>(*code, value);
186         CHECK_EQ(value[0], static_cast<T>(100));
187         CHECK_EQ(value[1], 13);
188         value[0] = static_cast<T>(300);
189         invoke<void>(*code, value);
190         CHECK_EQ(value[0], static_cast<T>(300));
191         CHECK_EQ(value[1], 13);
192         checkMyDisassembly(*code, true);
193     }
194
195     {
196         Procedure proc;
197         BasicBlock* root = proc.addBlock();
198         root->appendNew<Value>(
199             proc, Return, Origin(),
200             root->appendNew<AtomicValue>(
201                 proc, AtomicWeakCAS, Origin(), width,
202                 root->appendIntConstant(proc, Origin(), type, 42),
203                 root->appendIntConstant(proc, Origin(), type, 0xbeef),
204                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
205     
206         auto code = compileProc(proc);
207         T value[2];
208         value[0] = 42;
209         value[1] = 13;
210         while (!invoke<bool>(*code, value)) { }
211         CHECK_EQ(value[0], static_cast<T>(0xbeef));
212         CHECK_EQ(value[1], 13);
213     
214         value[0] = static_cast<T>(300);
215         CHECK(!invoke<bool>(*code, value));
216         CHECK_EQ(value[0], static_cast<T>(300));
217         CHECK_EQ(value[1], 13);
218         checkMyDisassembly(*code, true);
219     }
220
221     {
222         Procedure proc;
223         BasicBlock* root = proc.addBlock();
224         root->appendNew<Value>(
225             proc, Return, Origin(),
226             root->appendNew<Value>(
227                 proc, Equal, Origin(),
228                 root->appendNew<AtomicValue>(
229                     proc, AtomicWeakCAS, Origin(), width,
230                     root->appendIntConstant(proc, Origin(), type, 42),
231                     root->appendIntConstant(proc, Origin(), type, 0xbeef),
232                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
233                 root->appendNew<Const32Value>(proc, Origin(), 0)));
234     
235         auto code = compileProc(proc);
236         T value[2];
237         value[0] = 42;
238         value[1] = 13;
239         while (invoke<bool>(*code, value)) { }
240         CHECK_EQ(value[0], static_cast<T>(0xbeef));
241         CHECK_EQ(value[1], 13);
242     
243         value[0] = static_cast<T>(300);
244         CHECK(invoke<bool>(*code, value));
245         CHECK_EQ(value[0], static_cast<T>(300));
246         CHECK_EQ(value[1], 13);
247         checkMyDisassembly(*code, true);
248     }
249
250     {
251         Procedure proc;
252         BasicBlock* root = proc.addBlock();
253         root->appendNew<Value>(
254             proc, Return, Origin(),
255             root->appendNew<AtomicValue>(
256                 proc, AtomicWeakCAS, Origin(), width,
257                 root->appendIntConstant(proc, Origin(), type, 42),
258                 root->appendIntConstant(proc, Origin(), type, 0xbeef),
259                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
260                 42));
261     
262         auto code = compileProc(proc);
263         T value[2];
264         value[0] = 42;
265         value[1] = 13;
266         while (!invoke<bool>(*code, bitwise_cast<intptr_t>(value) - 42)) { }
267         CHECK_EQ(value[0], static_cast<T>(0xbeef));
268         CHECK_EQ(value[1], 13);
269     
270         value[0] = static_cast<T>(300);
271         CHECK(!invoke<bool>(*code, bitwise_cast<intptr_t>(value) - 42));
272         CHECK_EQ(value[0], static_cast<T>(300));
273         CHECK_EQ(value[1], 13);
274         checkMyDisassembly(*code, true);
275     }
276 }
277
278 template<typename T>
279 void testAtomicStrongCAS()
280 {
281     Type type = NativeTraits<T>::type;
282     Width width = NativeTraits<T>::width;
283
284     auto checkMyDisassembly = [&] (Compilation& compilation, bool fenced) {
285         if (isX86()) {
286             checkUsesInstruction(compilation, "lock");
287             checkUsesInstruction(compilation, "cmpxchg");
288         } else {
289             if (fenced) {
290                 checkUsesInstruction(compilation, "ldax");
291                 checkUsesInstruction(compilation, "stlx");
292             } else {
293                 checkUsesInstruction(compilation, "ldx");
294                 checkUsesInstruction(compilation, "stx");
295             }
296         }
297     };
298
299     {
300         Procedure proc;
301         BasicBlock* root = proc.addBlock();
302         BasicBlock* succ = proc.addBlock();
303         BasicBlock* fail = proc.addBlock();
304     
305         Value* ptr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
306         root->appendNew<Value>(
307             proc, Branch, Origin(),
308             root->appendNew<Value>(
309                 proc, Equal, Origin(),
310                 root->appendNew<AtomicValue>(
311                     proc, AtomicStrongCAS, Origin(), width,
312                     root->appendIntConstant(proc, Origin(), type, 42),
313                     root->appendIntConstant(proc, Origin(), type, 0xbeef),
314                     ptr),
315                 root->appendIntConstant(proc, Origin(), type, 42)));
316         root->setSuccessors(succ, fail);
317     
318         succ->appendNew<MemoryValue>(
319             proc, storeOpcode(GP, width), Origin(),
320             succ->appendIntConstant(proc, Origin(), type, 100),
321             ptr);
322         succ->appendNew<Value>(proc, Return, Origin());
323     
324         fail->appendNew<Value>(proc, Return, Origin());
325     
326         auto code = compileProc(proc);
327         T value[2];
328         value[0] = 42;
329         value[1] = 13;
330         invoke<void>(*code, value);
331         CHECK_EQ(value[0], static_cast<T>(100));
332         CHECK_EQ(value[1], 13);
333         value[0] = static_cast<T>(300);
334         invoke<void>(*code, value);
335         CHECK_EQ(value[0], static_cast<T>(300));
336         CHECK_EQ(value[1], 13);
337         checkMyDisassembly(*code, true);
338     }
339
340     {
341         Procedure proc;
342         BasicBlock* root = proc.addBlock();
343         BasicBlock* succ = proc.addBlock();
344         BasicBlock* fail = proc.addBlock();
345     
346         Value* ptr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
347         root->appendNew<Value>(
348             proc, Branch, Origin(),
349             root->appendNew<Value>(
350                 proc, Equal, Origin(),
351                 root->appendNew<AtomicValue>(
352                     proc, AtomicStrongCAS, Origin(), width,
353                     root->appendIntConstant(proc, Origin(), type, 42),
354                     root->appendIntConstant(proc, Origin(), type, 0xbeef),
355                     ptr, 0, HeapRange(42), HeapRange()),
356                 root->appendIntConstant(proc, Origin(), type, 42)));
357         root->setSuccessors(succ, fail);
358     
359         succ->appendNew<MemoryValue>(
360             proc, storeOpcode(GP, width), Origin(),
361             succ->appendIntConstant(proc, Origin(), type, 100),
362             ptr);
363         succ->appendNew<Value>(proc, Return, Origin());
364     
365         fail->appendNew<Value>(proc, Return, Origin());
366     
367         auto code = compileProc(proc);
368         T value[2];
369         value[0] = 42;
370         value[1] = 13;
371         invoke<void>(*code, value);
372         CHECK_EQ(value[0], static_cast<T>(100));
373         CHECK_EQ(value[1], 13);
374         value[0] = static_cast<T>(300);
375         invoke<void>(*code, value);
376         CHECK_EQ(value[0], static_cast<T>(300));
377         CHECK_EQ(value[1], 13);
378         checkMyDisassembly(*code, false);
379     }
380
381     {
382         Procedure proc;
383         BasicBlock* root = proc.addBlock();
384         BasicBlock* succ = proc.addBlock();
385         BasicBlock* fail = proc.addBlock();
386     
387         Value* ptr = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
388         root->appendNew<Value>(
389             proc, Branch, Origin(),
390             root->appendNew<Value>(
391                 proc, NotEqual, Origin(),
392                 root->appendNew<AtomicValue>(
393                     proc, AtomicStrongCAS, Origin(), width,
394                     root->appendIntConstant(proc, Origin(), type, 42),
395                     root->appendIntConstant(proc, Origin(), type, 0xbeef),
396                     ptr),
397                 root->appendIntConstant(proc, Origin(), type, 42)));
398         root->setSuccessors(fail, succ);
399     
400         succ->appendNew<MemoryValue>(
401             proc, storeOpcode(GP, width), Origin(),
402             succ->appendIntConstant(proc, Origin(), type, 100),
403             ptr);
404         succ->appendNew<Value>(proc, Return, Origin());
405     
406         fail->appendNew<Value>(proc, Return, Origin());
407     
408         auto code = compileProc(proc);
409         T value[2];
410         value[0] = 42;
411         value[1] = 13;
412         invoke<void>(*code, value);
413         CHECK_EQ(value[0], static_cast<T>(100));
414         CHECK_EQ(value[1], 13);
415         value[0] = static_cast<T>(300);
416         invoke<void>(*code, value);
417         CHECK_EQ(value[0], static_cast<T>(300));
418         CHECK_EQ(value[1], 13);
419         checkMyDisassembly(*code, true);
420     }
421
422     {
423         Procedure proc;
424         BasicBlock* root = proc.addBlock();
425         root->appendNew<Value>(
426             proc, Return, Origin(),
427             root->appendNew<AtomicValue>(
428                 proc, AtomicStrongCAS, Origin(), width,
429                 root->appendIntConstant(proc, Origin(), type, 42),
430                 root->appendIntConstant(proc, Origin(), type, 0xbeef),
431                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
432     
433         auto code = compileProc(proc);
434         T value[2];
435         value[0] = 42;
436         value[1] = 13;
437         CHECK_EQ(invoke<typename NativeTraits<T>::CanonicalType>(*code, value), 42);
438         CHECK_EQ(value[0], static_cast<T>(0xbeef));
439         CHECK_EQ(value[1], 13);
440         value[0] = static_cast<T>(300);
441         CHECK_EQ(invoke<typename NativeTraits<T>::CanonicalType>(*code, value), static_cast<typename NativeTraits<T>::CanonicalType>(static_cast<T>(300)));
442         CHECK_EQ(value[0], static_cast<T>(300));
443         CHECK_EQ(value[1], 13);
444         value[0] = static_cast<T>(-1);
445         CHECK_EQ(invoke<typename NativeTraits<T>::CanonicalType>(*code, value), static_cast<typename NativeTraits<T>::CanonicalType>(static_cast<T>(-1)));
446         CHECK_EQ(value[0], static_cast<T>(-1));
447         CHECK_EQ(value[1], 13);
448         checkMyDisassembly(*code, true);
449     }
450
451     {
452         // Test for https://bugs.webkit.org/show_bug.cgi?id=169867.
453     
454         Procedure proc;
455         BasicBlock* root = proc.addBlock();
456         root->appendNew<Value>(
457             proc, Return, Origin(),
458             root->appendNew<Value>(
459                 proc, BitXor, Origin(),
460                 root->appendNew<AtomicValue>(
461                     proc, AtomicStrongCAS, Origin(), width,
462                     root->appendIntConstant(proc, Origin(), type, 42),
463                     root->appendIntConstant(proc, Origin(), type, 0xbeef),
464                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
465                 root->appendIntConstant(proc, Origin(), type, 1)));
466     
467         typename NativeTraits<T>::CanonicalType one = 1;
468     
469         auto code = compileProc(proc);
470         T value[2];
471         value[0] = 42;
472         value[1] = 13;
473         CHECK_EQ(invoke<typename NativeTraits<T>::CanonicalType>(*code, value), 42 ^ one);
474         CHECK_EQ(value[0], static_cast<T>(0xbeef));
475         CHECK_EQ(value[1], 13);
476         value[0] = static_cast<T>(300);
477         CHECK_EQ(invoke<typename NativeTraits<T>::CanonicalType>(*code, value), static_cast<typename NativeTraits<T>::CanonicalType>(static_cast<T>(300)) ^ one);
478         CHECK_EQ(value[0], static_cast<T>(300));
479         CHECK_EQ(value[1], 13);
480         value[0] = static_cast<T>(-1);
481         CHECK_EQ(invoke<typename NativeTraits<T>::CanonicalType>(*code, value), static_cast<typename NativeTraits<T>::CanonicalType>(static_cast<T>(-1)) ^ one);
482         CHECK_EQ(value[0], static_cast<T>(-1));
483         CHECK_EQ(value[1], 13);
484         checkMyDisassembly(*code, true);
485     }
486
487     {
488         Procedure proc;
489         BasicBlock* root = proc.addBlock();
490         root->appendNew<Value>(
491             proc, Return, Origin(),
492             root->appendNew<Value>(
493                 proc, Equal, Origin(),
494                 root->appendNew<AtomicValue>(
495                     proc, AtomicStrongCAS, Origin(), width,
496                     root->appendIntConstant(proc, Origin(), type, 42),
497                     root->appendIntConstant(proc, Origin(), type, 0xbeef),
498                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
499                 root->appendIntConstant(proc, Origin(), type, 42)));
500     
501         auto code = compileProc(proc);
502         T value[2];
503         value[0] = 42;
504         value[1] = 13;
505         CHECK(invoke<bool>(*code, value));
506         CHECK_EQ(value[0], static_cast<T>(0xbeef));
507         CHECK_EQ(value[1], 13);
508         value[0] = static_cast<T>(300);
509         CHECK(!invoke<bool>(*code, value));
510         CHECK_EQ(value[0], static_cast<T>(300));
511         CHECK_EQ(value[1], 13);
512         checkMyDisassembly(*code, true);
513     }
514
515     {
516         Procedure proc;
517         BasicBlock* root = proc.addBlock();
518         root->appendNew<Value>(
519             proc, Return, Origin(),
520             root->appendNew<Value>(
521                 proc, Equal, Origin(),
522                 root->appendNew<Value>(
523                     proc, NotEqual, Origin(),
524                     root->appendNew<AtomicValue>(
525                         proc, AtomicStrongCAS, Origin(), width,
526                         root->appendIntConstant(proc, Origin(), type, 42),
527                         root->appendIntConstant(proc, Origin(), type, 0xbeef),
528                         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)),
529                     root->appendIntConstant(proc, Origin(), type, 42)),
530                 root->appendNew<Const32Value>(proc, Origin(), 0)));
531         
532         auto code = compileProc(proc);
533         T value[2];
534         value[0] = 42;
535         value[1] = 13;
536         CHECK(invoke<bool>(*code, value));
537         CHECK_EQ(value[0], static_cast<T>(0xbeef));
538         CHECK_EQ(value[1], 13);
539         value[0] = static_cast<T>(300);
540         CHECK(!invoke<bool>(*code, &value));
541         CHECK_EQ(value[0], static_cast<T>(300));
542         CHECK_EQ(value[1], 13);
543         checkMyDisassembly(*code, true);
544     }
545 }
546
547 template<typename T>
548 void testAtomicXchg(B3::Opcode opcode)
549 {
550     Type type = NativeTraits<T>::type;
551     Width width = NativeTraits<T>::width;
552
553     auto doTheMath = [&] (T& memory, T operand) -> T {
554         T oldValue = memory;
555         switch (opcode) {
556         case AtomicXchgAdd:
557             memory += operand;
558             break;
559         case AtomicXchgAnd:
560             memory &= operand;
561             break;
562         case AtomicXchgOr:
563             memory |= operand;
564             break;
565         case AtomicXchgSub:
566             memory -= operand;
567             break;
568         case AtomicXchgXor:
569             memory ^= operand;
570             break;
571         case AtomicXchg:
572             memory = operand;
573             break;
574         default:
575             RELEASE_ASSERT_NOT_REACHED();
576         }
577         return oldValue;
578     };
579
580     auto oldValue = [&] (T memory, T operand) -> T {
581         return doTheMath(memory, operand);
582     };
583
584     auto newValue = [&] (T memory, T operand) -> T {
585         doTheMath(memory, operand);
586         return memory;
587     };
588
589     auto checkMyDisassembly = [&] (Compilation& compilation, bool fenced) {
590         if (isX86())
591             checkUsesInstruction(compilation, "lock");
592         else {
593             if (fenced) {
594                 checkUsesInstruction(compilation, "ldax");
595                 checkUsesInstruction(compilation, "stlx");
596             } else {
597                 checkUsesInstruction(compilation, "ldx");
598                 checkUsesInstruction(compilation, "stx");
599             }
600         }
601     };
602
603     {
604         Procedure proc;
605         BasicBlock* root = proc.addBlock();
606         root->appendNew<Value>(
607             proc, Return, Origin(),
608             root->appendNew<AtomicValue>(
609                 proc, opcode, Origin(), width,
610                 root->appendIntConstant(proc, Origin(), type, 1),
611                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
612
613         auto code = compileProc(proc);
614         T value[2];
615         value[0] = 5;
616         value[1] = 100;
617         CHECK_EQ(invoke<T>(*code, value), oldValue(5, 1));
618         CHECK_EQ(value[0], newValue(5, 1));
619         CHECK_EQ(value[1], 100);
620         checkMyDisassembly(*code, true);
621     }
622
623     {
624         Procedure proc;
625         BasicBlock* root = proc.addBlock();
626         root->appendNew<Value>(
627             proc, Return, Origin(),
628             root->appendNew<AtomicValue>(
629                 proc, opcode, Origin(), width,
630                 root->appendIntConstant(proc, Origin(), type, 42),
631                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
632
633         auto code = compileProc(proc);
634         T value[2];
635         value[0] = 5;
636         value[1] = 100;
637         CHECK_EQ(invoke<T>(*code, value), oldValue(5, 42));
638         CHECK_EQ(value[0], newValue(5, 42));
639         CHECK_EQ(value[1], 100);
640         checkMyDisassembly(*code, true);
641     }
642
643     {
644         Procedure proc;
645         BasicBlock* root = proc.addBlock();
646         root->appendNew<AtomicValue>(
647             proc, opcode, Origin(), width,
648             root->appendIntConstant(proc, Origin(), type, 42),
649             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
650         root->appendNew<Value>(proc, Return, Origin());
651
652         auto code = compileProc(proc);
653         T value[2];
654         value[0] = 5;
655         value[1] = 100;
656         invoke<T>(*code, value);
657         CHECK_EQ(value[0], newValue(5, 42));
658         CHECK_EQ(value[1], 100);
659         checkMyDisassembly(*code, true);
660     }
661
662     {
663         Procedure proc;
664         BasicBlock* root = proc.addBlock();
665         root->appendNew<AtomicValue>(
666             proc, opcode, Origin(), width,
667             root->appendIntConstant(proc, Origin(), type, 42),
668             root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
669             0, HeapRange(42), HeapRange());
670         root->appendNew<Value>(proc, Return, Origin());
671
672         auto code = compileProc(proc);
673         T value[2];
674         value[0] = 5;
675         value[1] = 100;
676         invoke<T>(*code, value);
677         CHECK_EQ(value[0], newValue(5, 42));
678         CHECK_EQ(value[1], 100);
679         checkMyDisassembly(*code, false);
680     }
681 }
682
683 void addAtomicTests(const char* filter, Deque<RefPtr<SharedTask<void()>>>& tasks)
684 {
685     RUN(testAtomicWeakCAS<int8_t>());
686     RUN(testAtomicWeakCAS<int16_t>());
687     RUN(testAtomicWeakCAS<int32_t>());
688     RUN(testAtomicWeakCAS<int64_t>());
689     RUN(testAtomicStrongCAS<int8_t>());
690     RUN(testAtomicStrongCAS<int16_t>());
691     RUN(testAtomicStrongCAS<int32_t>());
692     RUN(testAtomicStrongCAS<int64_t>());
693     RUN(testAtomicXchg<int8_t>(AtomicXchgAdd));
694     RUN(testAtomicXchg<int16_t>(AtomicXchgAdd));
695     RUN(testAtomicXchg<int32_t>(AtomicXchgAdd));
696     RUN(testAtomicXchg<int64_t>(AtomicXchgAdd));
697     RUN(testAtomicXchg<int8_t>(AtomicXchgAnd));
698     RUN(testAtomicXchg<int16_t>(AtomicXchgAnd));
699     RUN(testAtomicXchg<int32_t>(AtomicXchgAnd));
700     RUN(testAtomicXchg<int64_t>(AtomicXchgAnd));
701     RUN(testAtomicXchg<int8_t>(AtomicXchgOr));
702     RUN(testAtomicXchg<int16_t>(AtomicXchgOr));
703     RUN(testAtomicXchg<int32_t>(AtomicXchgOr));
704     RUN(testAtomicXchg<int64_t>(AtomicXchgOr));
705     RUN(testAtomicXchg<int8_t>(AtomicXchgSub));
706     RUN(testAtomicXchg<int16_t>(AtomicXchgSub));
707     RUN(testAtomicXchg<int32_t>(AtomicXchgSub));
708     RUN(testAtomicXchg<int64_t>(AtomicXchgSub));
709     RUN(testAtomicXchg<int8_t>(AtomicXchgXor));
710     RUN(testAtomicXchg<int16_t>(AtomicXchgXor));
711     RUN(testAtomicXchg<int32_t>(AtomicXchgXor));
712     RUN(testAtomicXchg<int64_t>(AtomicXchgXor));
713     RUN(testAtomicXchg<int8_t>(AtomicXchg));
714     RUN(testAtomicXchg<int16_t>(AtomicXchg));
715     RUN(testAtomicXchg<int32_t>(AtomicXchg));
716     RUN(testAtomicXchg<int64_t>(AtomicXchg));
717 }
718
719 template<B3::Type type, typename CType, typename InputType>
720 void testLoad(B3::Opcode opcode, InputType value)
721 {
722     // Simple load from an absolute address.
723     {
724         Procedure proc;
725         BasicBlock* root = proc.addBlock();
726
727         root->appendNewControlValue(
728             proc, Return, Origin(),
729             root->appendNew<MemoryValue>(
730                 proc, opcode, type, Origin(),
731                 root->appendNew<ConstPtrValue>(proc, Origin(), &value)));
732
733         CHECK(isIdentical(compileAndRun<CType>(proc), modelLoad<CType>(value)));
734     }
735
736     // Simple load from an address in a register.
737     {
738         Procedure proc;
739         BasicBlock* root = proc.addBlock();
740
741         root->appendNewControlValue(
742             proc, Return, Origin(),
743             root->appendNew<MemoryValue>(
744                 proc, opcode, type, Origin(),
745                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0)));
746
747         CHECK(isIdentical(compileAndRun<CType>(proc, &value), modelLoad<CType>(value)));
748     }
749
750     // Simple load from an address in a register, at an offset.
751     {
752         Procedure proc;
753         BasicBlock* root = proc.addBlock();
754
755         root->appendNewControlValue(
756             proc, Return, Origin(),
757             root->appendNew<MemoryValue>(
758                 proc, opcode, type, Origin(),
759                 root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
760                 static_cast<int32_t>(sizeof(InputType))));
761
762         CHECK(isIdentical(compileAndRun<CType>(proc, &value - 1), modelLoad<CType>(value)));
763     }
764
765     // Load from a simple base-index with various scales.
766     for (unsigned logScale = 0; logScale <= 3; ++logScale) {
767         Procedure proc;
768         BasicBlock* root = proc.addBlock();
769
770         root->appendNewControlValue(
771             proc, Return, Origin(),
772             root->appendNew<MemoryValue>(
773                 proc, opcode, type, Origin(),
774                 root->appendNew<Value>(
775                     proc, Add, Origin(),
776                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
777                     root->appendNew<Value>(
778                         proc, Shl, Origin(),
779                         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
780                         root->appendNew<Const32Value>(proc, Origin(), logScale)))));
781
782         CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value)));
783     }
784
785     // Load from a simple base-index with various scales, but commuted.
786     for (unsigned logScale = 0; logScale <= 3; ++logScale) {
787         Procedure proc;
788         BasicBlock* root = proc.addBlock();
789
790         root->appendNewControlValue(
791             proc, Return, Origin(),
792             root->appendNew<MemoryValue>(
793                 proc, opcode, type, Origin(),
794                 root->appendNew<Value>(
795                     proc, Add, Origin(),
796                     root->appendNew<Value>(
797                         proc, Shl, Origin(),
798                         root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1),
799                         root->appendNew<Const32Value>(proc, Origin(), logScale)),
800                     root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0))));
801
802         CHECK(isIdentical(compileAndRun<CType>(proc, &value - 2, (sizeof(InputType) * 2) >> logScale), modelLoad<CType>(value)));
803     }
804 }
805
806 template<typename T>
807 void testLoad(B3::Opcode opcode, int32_t value)
808 {
809     return testLoad<Int32, T>(opcode, value);
810 }
811
812 template<B3::Type type, typename T>
813 void testLoad(T value)
814 {
815     return testLoad<type, T>(Load, value);
816 }
817
818 void addLoadTests(const char* filter, Deque<RefPtr<SharedTask<void()>>>& tasks)
819 {
820     RUN(testLoad<Int32>(60));
821     RUN(testLoad<Int32>(-60));
822     RUN(testLoad<Int32>(1000));
823     RUN(testLoad<Int32>(-1000));
824     RUN(testLoad<Int32>(1000000));
825     RUN(testLoad<Int32>(-1000000));
826     RUN(testLoad<Int32>(1000000000));
827     RUN(testLoad<Int32>(-1000000000));
828     RUN_UNARY(testLoad<Int64>, int64Operands());
829     RUN_UNARY(testLoad<Float>, floatingPointOperands<float>());
830     RUN_UNARY(testLoad<Double>, floatingPointOperands<double>());
831     
832     RUN(testLoad<int8_t>(Load8S, 60));
833     RUN(testLoad<int8_t>(Load8S, -60));
834     RUN(testLoad<int8_t>(Load8S, 1000));
835     RUN(testLoad<int8_t>(Load8S, -1000));
836     RUN(testLoad<int8_t>(Load8S, 1000000));
837     RUN(testLoad<int8_t>(Load8S, -1000000));
838     RUN(testLoad<int8_t>(Load8S, 1000000000));
839     RUN(testLoad<int8_t>(Load8S, -1000000000));
840     
841     RUN(testLoad<uint8_t>(Load8Z, 60));
842     RUN(testLoad<uint8_t>(Load8Z, -60));
843     RUN(testLoad<uint8_t>(Load8Z, 1000));
844     RUN(testLoad<uint8_t>(Load8Z, -1000));
845     RUN(testLoad<uint8_t>(Load8Z, 1000000));
846     RUN(testLoad<uint8_t>(Load8Z, -1000000));
847     RUN(testLoad<uint8_t>(Load8Z, 1000000000));
848     RUN(testLoad<uint8_t>(Load8Z, -1000000000));
849     
850     RUN(testLoad<int16_t>(Load16S, 60));
851     RUN(testLoad<int16_t>(Load16S, -60));
852     RUN(testLoad<int16_t>(Load16S, 1000));
853     RUN(testLoad<int16_t>(Load16S, -1000));
854     RUN(testLoad<int16_t>(Load16S, 1000000));
855     RUN(testLoad<int16_t>(Load16S, -1000000));
856     RUN(testLoad<int16_t>(Load16S, 1000000000));
857     RUN(testLoad<int16_t>(Load16S, -1000000000));
858     
859     RUN(testLoad<uint16_t>(Load16Z, 60));
860     RUN(testLoad<uint16_t>(Load16Z, -60));
861     RUN(testLoad<uint16_t>(Load16Z, 1000));
862     RUN(testLoad<uint16_t>(Load16Z, -1000));
863     RUN(testLoad<uint16_t>(Load16Z, 1000000));
864     RUN(testLoad<uint16_t>(Load16Z, -1000000));
865     RUN(testLoad<uint16_t>(Load16Z, 1000000000));
866     RUN(testLoad<uint16_t>(Load16Z, -1000000000));
867 }
868
869 #endif // ENABLE(B3_JIT)