1 /*
2  * SPDX-License-Identifier: GPL-2.0-or-later
3  * Load/store for 128-bit atomic operations, LoongArch version.
4  *
5  * See docs/devel/atomics.rst for discussion about the guarantees each
6  * atomic primitive is meant to provide.
7  */
8 
9 #ifndef LOONGARCH_ATOMIC128_LDST_H
10 #define LOONGARCH_ATOMIC128_LDST_H
11 
12 #include "host/cpuinfo.h"
13 #include "tcg/debug-assert.h"
14 
15 #define HAVE_ATOMIC128_RO  likely(cpuinfo & CPUINFO_LSX)
16 #define HAVE_ATOMIC128_RW  HAVE_ATOMIC128_RO
17 
18 /*
19  * As of gcc 13 and clang 16, there is no compiler support for LSX at all.
20  * Use inline assembly throughout.
21  */
22 
23 static inline Int128 atomic16_read_ro(const Int128 *ptr)
24 {
25     uint64_t l, h;
26 
27     tcg_debug_assert(HAVE_ATOMIC128_RO);
28     asm("vld $vr0, %2, 0\n\t"
29         "vpickve2gr.d %0, $vr0, 0\n\t"
30         "vpickve2gr.d %1, $vr0, 1"
31 	: "=r"(l), "=r"(h) : "r"(ptr), "m"(*ptr) : "f0");
32 
33     return int128_make128(l, h);
34 }
35 
36 static inline Int128 atomic16_read_rw(Int128 *ptr)
37 {
38     return atomic16_read_ro(ptr);
39 }
40 
41 static inline void atomic16_set(Int128 *ptr, Int128 val)
42 {
43     uint64_t l = int128_getlo(val), h = int128_gethi(val);
44 
45     tcg_debug_assert(HAVE_ATOMIC128_RW);
46     asm("vinsgr2vr.d $vr0, %1, 0\n\t"
47         "vinsgr2vr.d $vr0, %2, 1\n\t"
48         "vst $vr0, %3, 0"
49 	: "=m"(*ptr) : "r"(l), "r"(h), "r"(ptr) : "f0");
50 }
51 
52 #endif /* LOONGARCH_ATOMIC128_LDST_H */
53