1/*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 * Atomic store insert into 128-bit, AArch64 version.
4 *
5 * Copyright (C) 2023 Linaro, Ltd.
6 */
7
8#ifndef AARCH64_STORE_INSERT_AL16_H
9#define AARCH64_STORE_INSERT_AL16_H
10
11/**
12 * store_atom_insert_al16:
13 * @p: host address
14 * @val: shifted value to store
15 * @msk: mask for value to store
16 *
17 * Atomically store @val to @p masked by @msk.
18 */
19static inline void ATTRIBUTE_ATOMIC128_OPT
20store_atom_insert_al16(Int128 *ps, Int128 val, Int128 msk)
21{
22    /*
23     * GCC only implements __sync* primitives for int128 on aarch64.
24     * We can do better without the barriers, and integrating the
25     * arithmetic into the load-exclusive/store-conditional pair.
26     */
27    uint64_t tl, th, vl, vh, ml, mh;
28    uint32_t fail;
29
30    qemu_build_assert(!HOST_BIG_ENDIAN);
31    vl = int128_getlo(val);
32    vh = int128_gethi(val);
33    ml = int128_getlo(msk);
34    mh = int128_gethi(msk);
35
36    asm("0: ldxp %[l], %[h], %[mem]\n\t"
37        "bic %[l], %[l], %[ml]\n\t"
38        "bic %[h], %[h], %[mh]\n\t"
39        "orr %[l], %[l], %[vl]\n\t"
40        "orr %[h], %[h], %[vh]\n\t"
41        "stxp %w[f], %[l], %[h], %[mem]\n\t"
42        "cbnz %w[f], 0b\n"
43        : [mem] "+Q"(*ps), [f] "=&r"(fail), [l] "=&r"(tl), [h] "=&r"(th)
44        : [vl] "r"(vl), [vh] "r"(vh), [ml] "r"(ml), [mh] "r"(mh));
45}
46
47#endif /* AARCH64_STORE_INSERT_AL16_H */
48