v2 / vlib / x / atomics / atomics.i386.v
902 lines · 866 sloc · 16.9 KB · 1c4bb916e5cdf6aecbc6c6315f95453a9e8778f3
Raw
1module atomics
2
3// add_i32 atomically adds delta to the value at dest and returns the new value.
4// The operation is performed with sequential consistency.
5// Panics if dest is not 4-byte aligned.
6pub fn add_i32(dest &i32, delta i32) i32 {
7 mut result := i32(0)
8 asm volatile i386 {
9 mov edx, dest
10 test edx, 3
11 jz '1f'
12 call panicUnaligned
13 jmp '2f'
14 1:
15 mov eax, delta
16 lock xadd [edx], eax
17 add eax, delta
18 mov result, eax
19 2:
20 ; =r (result)
21 ; r (dest)
22 r (delta)
23 ; eax
24 edx
25 memory
26 }
27 return result
28}
29
30// swap_i32 atomically stores new value at dest and returns the old value.
31// The operation is performed with sequential consistency.
32// Panics if dest is not 4-byte aligned.
33pub fn swap_i32(dest &i32, new i32) i32 {
34 mut old := i32(0)
35 asm volatile i386 {
36 mov edx, dest
37 test edx, 3
38 jz '1f'
39 call panicUnaligned
40 jmp '2f'
41 1:
42 mov eax, new
43 xchg [edx], eax
44 mov old, eax
45 2:
46 ; =m (old)
47 ; r (dest)
48 r (new)
49 ; eax
50 edx
51 memory
52 }
53 return old
54}
55
56// store_i32 atomically stores value at dest.
57// The operation is performed with sequential consistency.
58// Panics if dest is not 4-byte aligned.
59pub fn store_i32(dest &i32, value i32) {
60 asm volatile i386 {
61 mov edx, dest
62 test edx, 3
63 jz '1f'
64 call panicUnaligned
65 jmp '2f'
66 1:
67 mov eax, value
68 xchg eax, [edx]
69 2:
70 ; ; r (dest)
71 r (value)
72 ; eax
73 edx
74 memory
75 }
76}
77
78// load_i32 atomically loads and returns the value at num.
79// The operation is performed with sequential consistency.
80// Panics if num is not 4-byte aligned.
81pub fn load_i32(num &i32) i32 {
82 mut out := i32(0)
83 asm volatile i386 {
84 mov edx, num
85 test edx, 3
86 jz '1f'
87 call panicUnaligned
88 jmp '2f'
89 1:
90 mov eax, [edx]
91 mov out, eax
92 2:
93 ; =r (out)
94 ; r (num)
95 ; eax
96 edx
97 memory
98 }
99 return out
100}
101
102// cas_i32 performs a compare-and-swap operation.
103// If the current value at addr equals old, it atomically stores new.
104// Returns true if the swap was performed, false otherwise.
105// The operation is performed with sequential consistency.
106// Panics if addr is not 4-byte aligned.
107pub fn cas_i32(addr &i32, old i32, new i32) bool {
108 mut swapped := false
109 asm volatile i386 {
110 mov edx, addr
111 test edx, 3
112 jz '1f'
113 call panicUnaligned
114 jmp '2f'
115 1:
116 mov eax, old
117 mov ecx, new
118 lock cmpxchg [edx], ecx
119 sete al
120 mov swapped, al
121 2:
122 ; =m (swapped)
123 ; r (addr)
124 r (old)
125 r (new)
126 ; eax
127 ecx
128 edx
129 memory
130 }
131 return swapped
132}
133
134// store_i64 atomically stores value at dest using MMX instructions.
135// The operation is performed with sequential consistency.
136// Requires MMX support. Panics if dest is not 8-byte aligned.
137pub fn store_i64(dest &i64, value i64) {
138 asm volatile i386 {
139 mov esi, dest
140 test esi, 7
141 jz '1f'
142 call panicUnaligned
143 jmp '2f'
144 1:
145 movq mm0, value
146 movq [esi], mm0
147 emms
148 xor eax, eax
149 lock xaddl [esp], eax
150 2:
151 ; ; r (dest)
152 m (value)
153 ; esi
154 eax
155 mm0
156 memory
157 }
158}
159
160// load_i64 atomically loads and returns the value at num using MMX instructions.
161// The operation is performed with sequential consistency.
162// Requires MMX support. Panics if num is not 8-byte aligned.
163pub fn load_i64(num &i64) i64 {
164 mut out := i64(0)
165 asm volatile i386 {
166 mov esi, num
167 test esi, 7
168 jz '1f'
169 call panicUnaligned
170 jmp '2f'
171 1:
172 movq mm0, [esi]
173 movq out, mm0
174 emms
175 2:
176 ; =m (out)
177 ; r (num)
178 ; esi
179 mm0
180 memory
181 }
182 return out
183}
184
185// add_i64 atomically adds delta to the value at dest and returns the new value.
186// Uses a compare-and-swap loop. The operation is performed with sequential consistency.
187// Panics if dest is not 8-byte aligned.
188pub fn add_i64(dest &i64, delta i64) i64 {
189 mut delta_lo := u32(u64(delta) & 0xFFFF_FFFF)
190 mut delta_hi := u32(u64(delta) >> 32)
191 mut res_lo := u32(0)
192 mut res_hi := u32(0)
193 asm volatile i386 {
194 mov esi, dest
195 test esi, 7
196 jz '1f'
197 call panicUnaligned
198 jmp '2f'
199 1:
200 3:
201 mov eax, [esi]
202 mov edx, [esi + 4]
203 mov ebx, eax
204 mov ecx, edx
205 add ebx, delta_lo
206 adc ecx, delta_hi
207 lock cmpxchg8b [esi]
208 jnz '3b'
209 mov res_lo, ebx
210 mov res_hi, ecx
211 2:
212 ; ; r (dest)
213 m (delta_lo)
214 m (delta_hi)
215 m (res_lo)
216 m (res_hi)
217 ; eax
218 ebx
219 ecx
220 edx
221 esi
222 memory
223 }
224 return i64(u64(res_lo) | (u64(res_hi) << 32))
225}
226
227// swap_i64 atomically stores value at dest and returns the old value.
228// Uses a compare-and-swap loop. The operation is performed with sequential consistency.
229// Panics if dest is not 8-byte aligned.
230pub fn swap_i64(dest &i64, value i64) i64 {
231 mut value_lo := u32(u64(value) & 0xFFFF_FFFF)
232 mut value_hi := u32(u64(value) >> 32)
233 asm volatile i386 {
234 mov esi, dest
235 test esi, 7
236 jz '1f'
237 call panicUnaligned
238 jmp '2f'
239 1:
240 3:
241 mov eax, [esi]
242 mov edx, [esi + 4]
243 mov ebx, value_lo
244 mov ecx, value_hi
245 lock cmpxchg8b [esi]
246 jnz '3b'
247 mov value_lo, eax
248 mov value_hi, edx
249 2:
250 ; ; r (dest)
251 m (value_lo)
252 m (value_hi)
253 ; eax
254 ebx
255 ecx
256 edx
257 esi
258 memory
259 }
260 return i64(u64(value_lo) | (u64(value_hi) << 32))
261}
262
263// cas_i64 performs a compare-and-swap operation.
264// If the current value at addr equals old, it atomically stores new.
265// Returns true if the swap was performed, false otherwise.
266// The operation is performed with sequential consistency.
267// Panics if addr is not 8-byte aligned.
268pub fn cas_i64(addr &i64, old i64, new i64) bool {
269 mut swapped := false
270 mut old_lo := u32(u64(old) & 0xFFFF_FFFF)
271 mut old_hi := u32(u64(old) >> 32)
272 mut new_lo := u32(u64(new) & 0xFFFF_FFFF)
273 mut new_hi := u32(u64(new) >> 32)
274 asm volatile i386 {
275 mov esi, addr
276 test esi, 7
277 jz '1f'
278 call panicUnaligned
279 jmp '2f'
280 1:
281 mov eax, old_lo
282 mov edx, old_hi
283 mov ebx, new_lo
284 mov ecx, new_hi
285 lock cmpxchg8b [esi]
286 sete al
287 mov swapped, al
288 2:
289 ; =m (swapped)
290 ; r (addr)
291 m (old_lo)
292 m (old_hi)
293 m (new_lo)
294 m (new_hi)
295 ; eax
296 ebx
297 ecx
298 edx
299 esi
300 memory
301 }
302 return swapped
303}
304
305// add_u32 atomically adds delta to the value at dest and returns the new value.
306// The operation is performed with sequential consistency.
307// Panics if dest is not 4-byte aligned.
308pub fn add_u32(dest &u32, delta u32) u32 {
309 mut result := u32(0)
310 asm volatile i386 {
311 mov edx, dest
312 test edx, 3
313 jz '1f'
314 call panicUnaligned
315 jmp '2f'
316 1:
317 mov eax, delta
318 lock xadd [edx], eax
319 add eax, delta
320 mov result, eax
321 2:
322 ; =r (result)
323 ; r (dest)
324 r (delta)
325 ; eax
326 edx
327 memory
328 }
329 return result
330}
331
332// swap_u32 atomically stores new value at dest and returns the old value.
333// The operation is performed with sequential consistency.
334// Panics if dest is not 4-byte aligned.
335pub fn swap_u32(dest &u32, new u32) u32 {
336 mut old := u32(0)
337 asm volatile i386 {
338 mov edx, dest
339 test edx, 3
340 jz '1f'
341 call panicUnaligned
342 jmp '2f'
343 1:
344 mov eax, new
345 xchg [edx], eax
346 mov old, eax
347 2:
348 ; =m (old)
349 ; r (dest)
350 r (new)
351 ; eax
352 edx
353 memory
354 }
355 return old
356}
357
358// store_u32 atomically stores value at dest.
359// The operation is performed with sequential consistency.
360// Panics if dest is not 4-byte aligned.
361pub fn store_u32(dest &u32, value u32) {
362 asm volatile i386 {
363 mov edx, dest
364 test edx, 3
365 jz '1f'
366 call panicUnaligned
367 jmp '2f'
368 1:
369 mov eax, value
370 xchg eax, [edx]
371 2:
372 ; ; r (dest)
373 r (value)
374 ; eax
375 edx
376 memory
377 }
378}
379
380// load_u32 atomically loads and returns the value at num.
381// The operation is performed with sequential consistency.
382// Panics if num is not 4-byte aligned.
383pub fn load_u32(num &u32) u32 {
384 mut out := u32(0)
385 asm volatile i386 {
386 mov edx, num
387 test edx, 3
388 jz '1f'
389 call panicUnaligned
390 jmp '2f'
391 1:
392 mov eax, [edx]
393 mov out, eax
394 2:
395 ; =r (out)
396 ; r (num)
397 ; eax
398 edx
399 memory
400 }
401 return out
402}
403
404// cas_u32 performs a compare-and-swap operation.
405// If the current value at addr equals old, it atomically stores new.
406// Returns true if the swap was performed, false otherwise.
407// The operation is performed with sequential consistency.
408// Panics if addr is not 4-byte aligned.
409pub fn cas_u32(addr &u32, old u32, new u32) bool {
410 mut swapped := false
411 asm volatile i386 {
412 mov edx, addr
413 test edx, 3
414 jz '1f'
415 call panicUnaligned
416 jmp '2f'
417 1:
418 mov eax, old
419 mov ecx, new
420 lock cmpxchg [edx], ecx
421 sete al
422 mov swapped, al
423 2:
424 ; =m (swapped)
425 ; r (addr)
426 r (old)
427 r (new)
428 ; eax
429 ecx
430 edx
431 memory
432 }
433 return swapped
434}
435
436// load_u64 atomically loads and returns the value at num using MMX instructions.
437// The operation is performed with sequential consistency.
438// Requires MMX support. Panics if num is not 8-byte aligned.
439pub fn load_u64(num &u64) u64 {
440 mut out := u64(0)
441 asm volatile i386 {
442 mov esi, num
443 test esi, 7
444 jz '1f'
445 call panicUnaligned
446 jmp '2f'
447 1:
448 movq mm0, [esi]
449 movq out, mm0
450 emms
451 2:
452 ; =m (out)
453 ; r (num)
454 ; esi
455 mm0
456 memory
457 }
458 return out
459}
460
461// store_u64 atomically stores value at dest using MMX instructions.
462// The operation is performed with sequential consistency.
463// Requires MMX support. Panics if dest is not 8-byte aligned.
464pub fn store_u64(dest &u64, value u64) {
465 asm volatile i386 {
466 mov esi, dest
467 test esi, 7
468 jz '1f'
469 call panicUnaligned
470 jmp '2f'
471 1:
472 movq mm0, value
473 movq [esi], mm0
474 emms
475 xor eax, eax
476 lock xaddl [esp], eax
477 2:
478 ; ; r (dest)
479 m (value)
480 ; eax
481 mm0
482 memory
483 }
484}
485
486// add_u64 atomically adds delta to the value at dest and returns the new value.
487// Uses a compare-and-swap loop. The operation is performed with sequential consistency.
488// Panics if dest is not 8-byte aligned.
489pub fn add_u64(dest &u64, delta u64) u64 {
490 mut delta_lo := u32(delta & 0xFFFF_FFFF)
491 mut delta_hi := u32(delta >> 32)
492 mut res_lo := u32(0)
493 mut res_hi := u32(0)
494 asm volatile i386 {
495 mov esi, dest
496 test esi, 7
497 jz '1f'
498 call panicUnaligned
499 jmp '2f'
500 1:
501 3:
502 mov eax, [esi]
503 mov edx, [esi + 4]
504 mov ebx, eax
505 mov ecx, edx
506 add ebx, delta_lo
507 adc ecx, delta_hi
508 lock cmpxchg8b [esi]
509 jnz '3b'
510 mov res_lo, ebx
511 mov res_hi, ecx
512 2:
513 ; ; r (dest)
514 m (delta_lo)
515 m (delta_hi)
516 m (res_lo)
517 m (res_hi)
518 ; eax
519 ebx
520 ecx
521 edx
522 esi
523 memory
524 }
525 return u64(res_lo) | (u64(res_hi) << 32)
526}
527
528// swap_u64 atomically stores value at dest and returns the old value.
529// Uses a compare-and-swap loop. The operation is performed with sequential consistency.
530// Panics if dest is not 8-byte aligned.
531pub fn swap_u64(dest &u64, value u64) u64 {
532 mut old := u64(0)
533 mut value_lo := u32(value & 0xFFFF_FFFF)
534 mut value_hi := u32(value >> 32)
535 asm volatile i386 {
536 mov esi, dest
537 test esi, 7
538 jz '1f'
539 call panicUnaligned
540 jmp '2f'
541 1:
542 3:
543 mov eax, [esi]
544 mov edx, [esi + 4]
545 mov ebx, value_lo
546 mov ecx, value_hi
547 lock cmpxchg8b [esi]
548 jnz '3b'
549 mov value_lo, eax
550 mov value_hi, edx
551 2:
552 ; ; r (dest)
553 m (value_lo)
554 m (value_hi)
555 ; eax
556 ebx
557 ecx
558 edx
559 esi
560 memory
561 }
562 old = u64(value_lo) | (u64(value_hi) << 32)
563 return old
564}
565
566// cas_u64 performs a compare-and-swap operation.
567// If the current value at addr equals old, it atomically stores new.
568// Returns true if the swap was performed, false otherwise.
569// The operation is performed with sequential consistency.
570// Panics if addr is not 8-byte aligned.
571pub fn cas_u64(addr &u64, old u64, new u64) bool {
572 mut swapped := false
573 mut old_lo := u32(old & 0xFFFF_FFFF)
574 mut old_hi := u32(old >> 32)
575 mut new_lo := u32(new & 0xFFFF_FFFF)
576 mut new_hi := u32(new >> 32)
577 asm volatile i386 {
578 mov esi, addr
579 test esi, 7
580 jz '1f'
581 call panicUnaligned
582 jmp '2f'
583 1:
584 mov eax, old_lo
585 mov edx, old_hi
586 mov ebx, new_lo
587 mov ecx, new_hi
588 lock cmpxchg8b [esi]
589 sete al
590 mov swapped, al
591 2:
592 ; =m (swapped)
593 ; r (addr)
594 m (old_lo)
595 m (old_hi)
596 m (new_lo)
597 m (new_hi)
598 ; eax
599 ebx
600 ecx
601 edx
602 esi
603 memory
604 }
605 return swapped
606}
607
608// and_i64 atomically performs a bitwise AND of the value at addr with mask and returns the old value.
609// The operation is performed with sequential consistency.
610// Panics if addr is not 8-byte aligned.
611pub fn and_i64(addr &i64, mask i64) i64 {
612 mask_lo := u32(u64(mask) & 0xFFFF_FFFF)
613 mask_hi := u32(u64(mask) >> 32)
614 mut old_lo := u32(0)
615 mut old_hi := u32(0)
616
617 asm volatile i386 {
618 mov esi, addr
619 test esi, 7
620 jz '1f'
621 call panicUnaligned
622 jmp '2f'
623 1:
624 mov eax, [esi]
625 mov edx, [esi + 4]
626 3:
627 mov ebx, eax
628 and ebx, mask_lo
629 mov ecx, edx
630 and ecx, mask_hi
631 lock cmpxchg8b [esi]
632 jnz '3b'
633 mov old_lo, eax
634 mov old_hi, edx
635 2:
636 ; =m (old_lo)
637 =m (old_hi)
638 ; m (mask_lo)
639 m (mask_hi)
640 r (addr)
641 ; eax
642 edx
643 ecx
644 ebx
645 esi
646 }
647 return i64(u64(old_lo) | (u64(old_hi) << 32))
648}
649
650// and_u64 atomically performs a bitwise AND of the value at addr with mask and returns the old value.
651// The operation is performed with sequential consistency.
652// Panics if addr is not 8-byte aligned.
653pub fn and_u64(addr &u64, mask u64) u64 {
654 mask_lo := u32(u64(mask) & 0xFFFF_FFFF)
655 mask_hi := u32(u64(mask) >> 32)
656 mut old_lo := u32(0)
657 mut old_hi := u32(0)
658
659 asm volatile i386 {
660 mov esi, addr
661 test esi, 7
662 jz '1f'
663 call panicUnaligned
664 jmp '2f'
665 1:
666 mov eax, [esi]
667 mov edx, [esi + 4]
668 3:
669 mov ebx, eax
670 and ebx, mask_lo
671 mov ecx, edx
672 and ecx, mask_hi
673 lock cmpxchg8b [esi]
674 jnz '3b'
675 mov old_lo, eax
676 mov old_hi, edx
677 2:
678 ; =m (old_lo)
679 =m (old_hi)
680 ; m (mask_lo)
681 m (mask_hi)
682 r (addr)
683 ; eax
684 edx
685 ecx
686 ebx
687 esi
688 }
689 return u64(old_lo) | (u64(old_hi) << 32)
690}
691
692// or_i64 atomically performs a bitwise OR of the value at addr with mask and returns the old value.
693// The operation is performed with sequential consistency.
694// Panics if addr is not 8-byte aligned.
695pub fn or_i64(addr &i64, mask i64) i64 {
696 mask_lo := u32(u64(mask) & 0xFFFF_FFFF)
697 mask_hi := u32(u64(mask) >> 32)
698 mut old_lo := u32(0)
699 mut old_hi := u32(0)
700
701 asm volatile i386 {
702 mov esi, addr
703 test esi, 7
704 jz '1f'
705 call panicUnaligned
706 jmp '2f'
707 1:
708 mov eax, [esi]
709 mov edx, [esi + 4]
710 3:
711 mov ebx, eax
712 or ebx, mask_lo
713 mov ecx, edx
714 or ecx, mask_hi
715 lock cmpxchg8b [esi]
716 jnz '3b'
717 mov old_lo, eax
718 mov old_hi, edx
719 2:
720 ; =m (old_lo)
721 =m (old_hi)
722 ; m (mask_lo)
723 m (mask_hi)
724 r (addr)
725 ; eax
726 edx
727 ecx
728 ebx
729 esi
730 }
731 return i64(u64(old_lo) | (u64(old_hi) << 32))
732}
733
734// or_u64 atomically performs a bitwise OR of the value at addr with mask and returns the old value.
735// The operation is performed with sequential consistency.
736// Panics if addr is not 8-byte aligned.
737pub fn or_u64(addr &u64, mask u64) u64 {
738 mask_lo := u32(u64(mask) & 0xFFFF_FFFF)
739 mask_hi := u32(u64(mask) >> 32)
740 mut old_lo := u32(0)
741 mut old_hi := u32(0)
742
743 asm volatile i386 {
744 mov esi, addr
745 test esi, 7
746 jz '1f'
747 call panicUnaligned
748 jmp '2f'
749 1:
750 mov eax, [esi]
751 mov edx, [esi + 4]
752 3:
753 mov ebx, eax
754 or ebx, mask_lo
755 mov ecx, edx
756 or ecx, mask_hi
757 lock cmpxchg8b [esi]
758 jnz '3b'
759 mov old_lo, eax
760 mov old_hi, edx
761 2:
762 ; =m (old_lo)
763 =m (old_hi)
764 ; m (mask_lo)
765 m (mask_hi)
766 r (addr)
767 ; eax
768 edx
769 ecx
770 ebx
771 esi
772 }
773 return u64(old_lo) | (u64(old_hi) << 32)
774}
775
776// and_u32 atomically performs a bitwise AND of the value at addr with mask and returns the old value.
777// The operation is performed with sequential consistency.
778// Panics if addr is not 4-byte aligned.
779pub fn and_u32(addr &u32, mask u32) u32 {
780 mut old := u32(0)
781
782 asm volatile i386 {
783 mov edx, addr
784 test edx, 3
785 jz '1f'
786 call panicUnaligned
787 jmp '2f'
788 1:
789 3:
790 mov eax, [edx]
791 mov ecx, eax
792 and ecx, mask
793 lock cmpxchgl [edx], ecx
794 jnz '3b'
795 mov old, eax
796 2:
797 ; =r (old)
798 ; r (addr)
799 r (mask)
800 ; edx
801 eax
802 ecx
803 memory
804 }
805 return old
806}
807
808// and_i32 atomically performs a bitwise AND of the value at addr with mask and returns the old value.
809// The operation is performed with sequential consistency.
810// Panics if addr is not 4-byte aligned.
811pub fn and_i32(addr &i32, mask i32) i32 {
812 mut old := i32(0)
813
814 asm volatile i386 {
815 mov edx, addr
816 test edx, 3
817 jz '1f'
818 call panicUnaligned
819 jmp '2f'
820 1:
821 3:
822 mov eax, [edx]
823 mov ecx, eax
824 and ecx, mask
825 lock cmpxchgl [edx], ecx
826 jnz '3b'
827 mov old, eax
828 2:
829 ; =r (old)
830 ; r (addr)
831 r (mask)
832 ; edx
833 eax
834 ecx
835 memory
836 }
837 return old
838}
839
840// or_i32 atomically performs a bitwise OR of the value at addr with mask and returns the old value.
841// The operation is performed with sequential consistency.
842// Panics if addr is not 4-byte aligned.
843pub fn or_i32(addr &i32, mask i32) i32 {
844 mut old := i32(0)
845
846 asm volatile i386 {
847 mov edx, addr
848 test edx, 3
849 jz '1f'
850 call panicUnaligned
851 jmp '2f'
852 1:
853 3:
854 mov eax, [edx]
855 mov ecx, eax
856 or ecx, mask
857 lock cmpxchgl [edx], ecx
858 jnz '3b'
859 mov old, eax
860 2:
861 ; =r (old)
862 ; r (addr)
863 r (mask)
864 ; edx
865 eax
866 ecx
867 memory
868 }
869 return old
870}
871
872// or_u32 atomically performs a bitwise OR of the value at addr with mask and returns the old value.
873// The operation is performed with sequential consistency.
874// Panics if addr is not 4-byte aligned.
875pub fn or_u32(addr &u32, mask u32) u32 {
876 mut old := u32(0)
877
878 asm volatile i386 {
879 mov edx, addr
880 test edx, 3
881 jz '1f'
882 call panicUnaligned
883 jmp '2f'
884 1:
885 3:
886 mov eax, [edx]
887 mov ecx, eax
888 or ecx, mask
889 lock cmpxchgl [edx], ecx
890 jnz '3b'
891 mov old, eax
892 2:
893 ; =r (old)
894 ; r (addr)
895 r (mask)
896 ; edx
897 eax
898 ecx
899 memory
900 }
901 return old
902}
903