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