1 //===-- sync-ops.h - --===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements outline macros for the __sync_fetch_and_*
10 // operations. Different instantiations will generate appropriate assembly for
11 // ARM and Thumb-2 versions of the functions.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "../assembly.h"
16 
17 #if __ARM_ARCH >= 7
18 #define DMB dmb
19 #elif __ARM_ARCH >= 6
20 #define DMB mcr p15, #0, r0, c7, c10, #5
21 #else
22 #error DMB is only supported on ARMv6+
23 #endif
24 
25 #define SYNC_OP_4(op)                                                          \
26   .p2align 2;                                                                  \
27   .syntax unified;                                                             \
28   DEFINE_COMPILERRT_FUNCTION(__sync_fetch_and_##op)                            \
29   DMB;                                                                         \
30   mov r12, r0;                                                                 \
31   LOCAL_LABEL(tryatomic_##op) : ldrex r0, [r12];                               \
32   op(r2, r0, r1);                                                              \
33   strex r3, r2, [r12];                                                         \
34   cmp r3, #0;                                                                  \
35   bne LOCAL_LABEL(tryatomic_##op);                                             \
36   DMB;                                                                         \
37   bx lr
38 
39 #define SYNC_OP_8(op)                                                          \
40   .p2align 2;                                                                  \
41   .syntax unified;                                                             \
42   DEFINE_COMPILERRT_FUNCTION(__sync_fetch_and_##op)                            \
43   push {r4, r5, r6, lr};                                                       \
44   DMB;                                                                         \
45   mov r12, r0;                                                                 \
46   LOCAL_LABEL(tryatomic_##op) : ldrexd r0, r1, [r12];                          \
47   op(r4, r5, r0, r1, r2, r3);                                                  \
48   strexd r6, r4, r5, [r12];                                                    \
49   cmp r6, #0;                                                                  \
50   bne LOCAL_LABEL(tryatomic_##op);                                             \
51   DMB;                                                                         \
52   pop { r4, r5, r6, pc }
53 
54 #define MINMAX_4(rD, rN, rM, cmp_kind)                                         \
55   cmp rN, rM;                                                                  \
56   mov rD, rM;                                                                  \
57   it cmp_kind;                                                                 \
58   mov##cmp_kind rD, rN
59 
60 #define MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, cmp_kind)           \
61   cmp rN_LO, rM_LO;                                                            \
62   sbcs rN_HI, rM_HI;                                                           \
63   mov rD_LO, rM_LO;                                                            \
64   mov rD_HI, rM_HI;                                                            \
65   itt cmp_kind;                                                                \
66   mov##cmp_kind rD_LO, rN_LO;                                                  \
67   mov##cmp_kind rD_HI, rN_HI
68