xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/builtins/aarch64/lse.S (revision 8a4dda33d67586ca2624f2a38417baa03a533a7f)
1e8d8bef9SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
2e8d8bef9SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
3e8d8bef9SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4e8d8bef9SDimitry Andric
5e8d8bef9SDimitry Andric#include "assembly.h"
6e8d8bef9SDimitry Andric
7e8d8bef9SDimitry Andric// Out-of-line LSE atomics helpers. Ported from libgcc library.
8e8d8bef9SDimitry Andric// N = {1, 2, 4, 8}
9e8d8bef9SDimitry Andric// M = {1, 2, 4, 8, 16}
10*8a4dda33SDimitry Andric// ORDER = {'relax', 'acq', 'rel', 'acq_rel', 'sync'}
11e8d8bef9SDimitry Andric// Routines implemented:
12e8d8bef9SDimitry Andric//
13e8d8bef9SDimitry Andric//  iM __aarch64_casM_ORDER(iM expected, iM desired, iM *ptr)
14e8d8bef9SDimitry Andric//  iN __aarch64_swpN_ORDER(iN val, iN *ptr)
15e8d8bef9SDimitry Andric//  iN __aarch64_ldaddN_ORDER(iN val, iN *ptr)
16e8d8bef9SDimitry Andric//  iN __aarch64_ldclrN_ORDER(iN val, iN *ptr)
17e8d8bef9SDimitry Andric//  iN __aarch64_ldeorN_ORDER(iN val, iN *ptr)
18e8d8bef9SDimitry Andric//  iN __aarch64_ldsetN_ORDER(iN val, iN *ptr)
19e8d8bef9SDimitry Andric//
20e8d8bef9SDimitry Andric// Routines may modify temporary registers tmp0, tmp1, tmp2,
21e8d8bef9SDimitry Andric// return value x0 and the flags only.
22e8d8bef9SDimitry Andric
23e8d8bef9SDimitry Andric#ifdef __aarch64__
24e8d8bef9SDimitry Andric
25e8d8bef9SDimitry Andric#ifdef HAS_ASM_LSE
26e8d8bef9SDimitry Andric.arch armv8-a+lse
27e8d8bef9SDimitry Andric#else
28e8d8bef9SDimitry Andric.arch armv8-a
29e8d8bef9SDimitry Andric#endif
30e8d8bef9SDimitry Andric
31e8d8bef9SDimitry Andric#if !defined(__APPLE__)
32e8d8bef9SDimitry AndricHIDDEN(__aarch64_have_lse_atomics)
33e8d8bef9SDimitry Andric#else
34e8d8bef9SDimitry AndricHIDDEN(___aarch64_have_lse_atomics)
35e8d8bef9SDimitry Andric#endif
36e8d8bef9SDimitry Andric
37e8d8bef9SDimitry Andric// Generate mnemonics for
38*8a4dda33SDimitry Andric// L_cas:                                 SIZE: 1,2,4,8,16 MODEL: 1,2,3,4,5
39*8a4dda33SDimitry Andric// L_swp L_ldadd L_ldclr L_ldeor L_ldset: SIZE: 1,2,4,8    MODEL: 1,2,3,4,5
40e8d8bef9SDimitry Andric
41e8d8bef9SDimitry Andric#if SIZE == 1
42e8d8bef9SDimitry Andric#define S b
43e8d8bef9SDimitry Andric#define UXT uxtb
44e8d8bef9SDimitry Andric#define B 0x00000000
45e8d8bef9SDimitry Andric#elif SIZE == 2
46e8d8bef9SDimitry Andric#define S h
47e8d8bef9SDimitry Andric#define UXT uxth
48e8d8bef9SDimitry Andric#define B 0x40000000
49e8d8bef9SDimitry Andric#elif SIZE == 4 || SIZE == 8 || SIZE == 16
50e8d8bef9SDimitry Andric#define S
51e8d8bef9SDimitry Andric#define UXT mov
52e8d8bef9SDimitry Andric#if SIZE == 4
53e8d8bef9SDimitry Andric#define B 0x80000000
54e8d8bef9SDimitry Andric#elif SIZE == 8
55e8d8bef9SDimitry Andric#define B 0xc0000000
56e8d8bef9SDimitry Andric#endif
57e8d8bef9SDimitry Andric#else
58e8d8bef9SDimitry Andric#error
59e8d8bef9SDimitry Andric#endif // SIZE
60e8d8bef9SDimitry Andric
61e8d8bef9SDimitry Andric#if MODEL == 1
62e8d8bef9SDimitry Andric#define SUFF _relax
63e8d8bef9SDimitry Andric#define A
64e8d8bef9SDimitry Andric#define L
65e8d8bef9SDimitry Andric#define M 0x000000
66e8d8bef9SDimitry Andric#define N 0x000000
67*8a4dda33SDimitry Andric#define BARRIER
68e8d8bef9SDimitry Andric#elif MODEL == 2
69e8d8bef9SDimitry Andric#define SUFF _acq
70e8d8bef9SDimitry Andric#define A a
71e8d8bef9SDimitry Andric#define L
72e8d8bef9SDimitry Andric#define M 0x400000
73e8d8bef9SDimitry Andric#define N 0x800000
74*8a4dda33SDimitry Andric#define BARRIER
75e8d8bef9SDimitry Andric#elif MODEL == 3
76e8d8bef9SDimitry Andric#define SUFF _rel
77e8d8bef9SDimitry Andric#define A
78e8d8bef9SDimitry Andric#define L l
79e8d8bef9SDimitry Andric#define M 0x008000
80e8d8bef9SDimitry Andric#define N 0x400000
81*8a4dda33SDimitry Andric#define BARRIER
82e8d8bef9SDimitry Andric#elif MODEL == 4
83e8d8bef9SDimitry Andric#define SUFF _acq_rel
84e8d8bef9SDimitry Andric#define A a
85e8d8bef9SDimitry Andric#define L l
86e8d8bef9SDimitry Andric#define M 0x408000
87e8d8bef9SDimitry Andric#define N 0xc00000
88*8a4dda33SDimitry Andric#define BARRIER
89*8a4dda33SDimitry Andric#elif MODEL == 5
90*8a4dda33SDimitry Andric#define SUFF _sync
91*8a4dda33SDimitry Andric#ifdef L_swp
92*8a4dda33SDimitry Andric// swp has _acq semantics.
93*8a4dda33SDimitry Andric#define A a
94*8a4dda33SDimitry Andric#define L
95*8a4dda33SDimitry Andric#define M 0x400000
96*8a4dda33SDimitry Andric#define N 0x800000
97*8a4dda33SDimitry Andric#else
98*8a4dda33SDimitry Andric// All other _sync functions have _seq semantics.
99*8a4dda33SDimitry Andric#define A a
100*8a4dda33SDimitry Andric#define L l
101*8a4dda33SDimitry Andric#define M 0x408000
102*8a4dda33SDimitry Andric#define N 0xc00000
103*8a4dda33SDimitry Andric#endif
104*8a4dda33SDimitry Andric#define BARRIER dmb ish
105e8d8bef9SDimitry Andric#else
106e8d8bef9SDimitry Andric#error
107e8d8bef9SDimitry Andric#endif // MODEL
108e8d8bef9SDimitry Andric
109e8d8bef9SDimitry Andric// Define register size.
110e8d8bef9SDimitry Andric#define x(N) GLUE2(x, N)
111e8d8bef9SDimitry Andric#define w(N) GLUE2(w, N)
112e8d8bef9SDimitry Andric#if SIZE < 8
113e8d8bef9SDimitry Andric#define s(N) w(N)
114e8d8bef9SDimitry Andric#else
115e8d8bef9SDimitry Andric#define s(N) x(N)
116e8d8bef9SDimitry Andric#endif
117e8d8bef9SDimitry Andric
118e8d8bef9SDimitry Andric#define NAME(BASE) GLUE4(__aarch64_, BASE, SIZE, SUFF)
119*8a4dda33SDimitry Andric#if MODEL == 5
120*8a4dda33SDimitry Andric// Drop A for _sync functions.
121*8a4dda33SDimitry Andric#define LDXR GLUE3(ld, xr, S)
122*8a4dda33SDimitry Andric#else
123e8d8bef9SDimitry Andric#define LDXR GLUE4(ld, A, xr, S)
124*8a4dda33SDimitry Andric#endif
125e8d8bef9SDimitry Andric#define STXR GLUE4(st, L, xr, S)
126e8d8bef9SDimitry Andric
127e8d8bef9SDimitry Andric// Define temporary registers.
128e8d8bef9SDimitry Andric#define tmp0 16
129e8d8bef9SDimitry Andric#define tmp1 17
130e8d8bef9SDimitry Andric#define tmp2 15
131e8d8bef9SDimitry Andric
132e8d8bef9SDimitry Andric// Macro for branch to label if no LSE available
133e8d8bef9SDimitry Andric.macro JUMP_IF_NOT_LSE label
134e8d8bef9SDimitry Andric#if !defined(__APPLE__)
135e8d8bef9SDimitry Andric        adrp    x(tmp0), __aarch64_have_lse_atomics
136e8d8bef9SDimitry Andric        ldrb    w(tmp0), [x(tmp0), :lo12:__aarch64_have_lse_atomics]
137e8d8bef9SDimitry Andric#else
138e8d8bef9SDimitry Andric        adrp    x(tmp0), ___aarch64_have_lse_atomics@page
139e8d8bef9SDimitry Andric        ldrb    w(tmp0), [x(tmp0), ___aarch64_have_lse_atomics@pageoff]
140e8d8bef9SDimitry Andric#endif
141e8d8bef9SDimitry Andric        cbz     w(tmp0), \label
142e8d8bef9SDimitry Andric.endm
143e8d8bef9SDimitry Andric
144e8d8bef9SDimitry Andric#ifdef L_cas
145e8d8bef9SDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(NAME(cas))
146e8d8bef9SDimitry Andric        JUMP_IF_NOT_LSE 8f
147e8d8bef9SDimitry Andric#if SIZE < 16
148e8d8bef9SDimitry Andric#ifdef HAS_ASM_LSE
149e8d8bef9SDimitry Andric#define CAS GLUE4(cas, A, L, S) s(0), s(1), [x2]
150e8d8bef9SDimitry Andric#else
151e8d8bef9SDimitry Andric#define CAS .inst 0x08a07c41 + B + M
152e8d8bef9SDimitry Andric#endif
153e8d8bef9SDimitry Andric        CAS    // s(0), s(1), [x2]
154e8d8bef9SDimitry Andric        ret
155e8d8bef9SDimitry Andric8:
156e8d8bef9SDimitry Andric        UXT    s(tmp0), s(0)
157e8d8bef9SDimitry Andric0:
158e8d8bef9SDimitry Andric        LDXR   s(0), [x2]
159e8d8bef9SDimitry Andric        cmp    s(0), s(tmp0)
160e8d8bef9SDimitry Andric        bne    1f
161e8d8bef9SDimitry Andric        STXR   w(tmp1), s(1), [x2]
162e8d8bef9SDimitry Andric        cbnz   w(tmp1), 0b
163e8d8bef9SDimitry Andric1:
164*8a4dda33SDimitry Andric        BARRIER
165e8d8bef9SDimitry Andric        ret
166e8d8bef9SDimitry Andric#else
167*8a4dda33SDimitry Andric#if MODEL == 5
168*8a4dda33SDimitry Andric// Drop A for _sync functions.
169*8a4dda33SDimitry Andric#define LDXP GLUE2(ld, xp)
170*8a4dda33SDimitry Andric#else
171e8d8bef9SDimitry Andric#define LDXP GLUE3(ld, A, xp)
172*8a4dda33SDimitry Andric#endif
173e8d8bef9SDimitry Andric#define STXP GLUE3(st, L, xp)
174e8d8bef9SDimitry Andric#ifdef HAS_ASM_LSE
175e8d8bef9SDimitry Andric#define CASP GLUE3(casp, A, L)  x0, x1, x2, x3, [x4]
176e8d8bef9SDimitry Andric#else
177e8d8bef9SDimitry Andric#define CASP .inst 0x48207c82 + M
178e8d8bef9SDimitry Andric#endif
179e8d8bef9SDimitry Andric
180e8d8bef9SDimitry Andric        CASP   // x0, x1, x2, x3, [x4]
181e8d8bef9SDimitry Andric        ret
182e8d8bef9SDimitry Andric8:
183e8d8bef9SDimitry Andric        mov    x(tmp0), x0
184e8d8bef9SDimitry Andric        mov    x(tmp1), x1
185e8d8bef9SDimitry Andric0:
186e8d8bef9SDimitry Andric        LDXP   x0, x1, [x4]
187e8d8bef9SDimitry Andric        cmp    x0, x(tmp0)
188e8d8bef9SDimitry Andric        ccmp   x1, x(tmp1), #0, eq
189e8d8bef9SDimitry Andric        bne    1f
190e8d8bef9SDimitry Andric        STXP   w(tmp2), x2, x3, [x4]
191e8d8bef9SDimitry Andric        cbnz   w(tmp2), 0b
192e8d8bef9SDimitry Andric1:
193*8a4dda33SDimitry Andric        BARRIER
194e8d8bef9SDimitry Andric        ret
195e8d8bef9SDimitry Andric#endif
196e8d8bef9SDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(NAME(cas))
197e8d8bef9SDimitry Andric#endif // L_cas
198e8d8bef9SDimitry Andric
199e8d8bef9SDimitry Andric#ifdef L_swp
200e8d8bef9SDimitry Andric#ifdef HAS_ASM_LSE
201e8d8bef9SDimitry Andric#define SWP GLUE4(swp, A, L, S)  s(0), s(0), [x1]
202e8d8bef9SDimitry Andric#else
203e8d8bef9SDimitry Andric#define SWP .inst 0x38208020 + B + N
204e8d8bef9SDimitry Andric#endif
205e8d8bef9SDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(NAME(swp))
206e8d8bef9SDimitry Andric        JUMP_IF_NOT_LSE 8f
207e8d8bef9SDimitry Andric        SWP    // s(0), s(0), [x1]
208e8d8bef9SDimitry Andric        ret
209e8d8bef9SDimitry Andric8:
210e8d8bef9SDimitry Andric        mov    s(tmp0), s(0)
211e8d8bef9SDimitry Andric0:
212e8d8bef9SDimitry Andric        LDXR   s(0), [x1]
213e8d8bef9SDimitry Andric        STXR   w(tmp1), s(tmp0), [x1]
214e8d8bef9SDimitry Andric        cbnz   w(tmp1), 0b
215*8a4dda33SDimitry Andric        BARRIER
216e8d8bef9SDimitry Andric        ret
217e8d8bef9SDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(NAME(swp))
218e8d8bef9SDimitry Andric#endif // L_swp
219e8d8bef9SDimitry Andric
220e8d8bef9SDimitry Andric#if defined(L_ldadd) || defined(L_ldclr) ||                                    \
221e8d8bef9SDimitry Andric    defined(L_ldeor) || defined(L_ldset)
222e8d8bef9SDimitry Andric
223e8d8bef9SDimitry Andric#ifdef L_ldadd
224e8d8bef9SDimitry Andric#define LDNM ldadd
225e8d8bef9SDimitry Andric#define OP add
226e8d8bef9SDimitry Andric#define OPN 0x0000
227e8d8bef9SDimitry Andric#elif defined(L_ldclr)
228e8d8bef9SDimitry Andric#define LDNM ldclr
229e8d8bef9SDimitry Andric#define OP bic
230e8d8bef9SDimitry Andric#define OPN 0x1000
231e8d8bef9SDimitry Andric#elif defined(L_ldeor)
232e8d8bef9SDimitry Andric#define LDNM ldeor
233e8d8bef9SDimitry Andric#define OP eor
234e8d8bef9SDimitry Andric#define OPN 0x2000
235e8d8bef9SDimitry Andric#elif defined(L_ldset)
236e8d8bef9SDimitry Andric#define LDNM ldset
237e8d8bef9SDimitry Andric#define OP orr
238e8d8bef9SDimitry Andric#define OPN 0x3000
239e8d8bef9SDimitry Andric#else
240e8d8bef9SDimitry Andric#error
241e8d8bef9SDimitry Andric#endif
242e8d8bef9SDimitry Andric
243e8d8bef9SDimitry Andric#ifdef HAS_ASM_LSE
244e8d8bef9SDimitry Andric#define LDOP GLUE4(LDNM, A, L, S) s(0), s(0), [x1]
245e8d8bef9SDimitry Andric#else
246e8d8bef9SDimitry Andric#define LDOP .inst 0x38200020 + OPN + B + N
247e8d8bef9SDimitry Andric#endif
248e8d8bef9SDimitry Andric
249e8d8bef9SDimitry AndricDEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(NAME(LDNM))
250e8d8bef9SDimitry Andric        JUMP_IF_NOT_LSE 8f
251e8d8bef9SDimitry Andric        LDOP // s(0), s(0), [x1]
252e8d8bef9SDimitry Andric        ret
253e8d8bef9SDimitry Andric8:
254e8d8bef9SDimitry Andric        mov    s(tmp0), s(0)
255e8d8bef9SDimitry Andric0:
256e8d8bef9SDimitry Andric        LDXR   s(0), [x1]
257e8d8bef9SDimitry Andric        OP     s(tmp1), s(0), s(tmp0)
258e8d8bef9SDimitry Andric        STXR   w(tmp2), s(tmp1), [x1]
259e8d8bef9SDimitry Andric        cbnz   w(tmp2), 0b
260*8a4dda33SDimitry Andric        BARRIER
261e8d8bef9SDimitry Andric        ret
262e8d8bef9SDimitry AndricEND_COMPILERRT_OUTLINE_FUNCTION(NAME(LDNM))
263e8d8bef9SDimitry Andric#endif // L_ldadd L_ldclr L_ldeor L_ldset
264e8d8bef9SDimitry Andric
265e8d8bef9SDimitry AndricNO_EXEC_STACK_DIRECTIVE
266e8d8bef9SDimitry Andric
267e8d8bef9SDimitry Andric// GNU property note for BTI and PAC
268e8d8bef9SDimitry AndricGNU_PROPERTY_BTI_PAC
269e8d8bef9SDimitry Andric
270e8d8bef9SDimitry Andric#endif // __aarch64__
271