Daily bump.
[official-gcc.git] / libgcc / config / arm / freebsd-atomic.c
bloba3a55e5d8ab04786a8da04e25ec1789a8e369ee1
1 /* FreeBSD specific atomic operations for ARM EABI.
2 Copyright (C) 2015 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 #include <sys/types.h>
27 #define HIDDEN __attribute__ ((visibility ("hidden")))
29 #define ARM_VECTORS_HIGH 0xffff0000U
30 #define ARM_TP_ADDRESS (ARM_VECTORS_HIGH + 0x1000)
31 #define ARM_RAS_START (ARM_TP_ADDRESS + 4)
33 void HIDDEN
34 __sync_synchronize (void)
36 #if defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) \
37 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__) \
38 || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__) \
39 || defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
40 #if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
41 __asm __volatile ("dmb" : : : "memory");
42 #else
43 __asm __volatile ("mcr p15, 0, r0, c7, c10, 5" : : : "memory");
44 #endif
45 #else
46 __asm __volatile ("nop" : : : "memory");
47 #endif
50 #if defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) \
51 || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__) \
52 || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__) \
53 || defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
55 /* These systems should be supported by the compiler. */
57 #else /* __ARM_ARCH_5__ */
59 #define SYNC_LOCK_TEST_AND_SET_N(N, TYPE, LDR, STR) \
60 TYPE HIDDEN \
61 __sync_lock_test_and_set_##N (TYPE *mem, TYPE val) \
62 { \
63 unsigned int old, temp, ras_start; \
65 ras_start = ARM_RAS_START; \
66 __asm volatile ( \
67 /* Set up Restartable Atomic Sequence. */ \
68 "1:" \
69 "\tadr %2, 1b\n" \
70 "\tstr %2, [%5]\n" \
71 "\tadr %2, 2f\n" \
72 "\tstr %2, [%5, #4]\n" \
74 "\t"LDR" %0, %4\n" /* Load old value. */ \
75 "\t"STR" %3, %1\n" /* Store new value. */ \
77 /* Tear down Restartable Atomic Sequence. */ \
78 "2:" \
79 "\tmov %2, #0x00000000\n" \
80 "\tstr %2, [%5]\n" \
81 "\tmov %2, #0xffffffff\n" \
82 "\tstr %2, [%5, #4]\n" \
83 : "=&r" (old), "=m" (*mem), "=&r" (temp) \
84 : "r" (val), "m" (*mem), "r" (ras_start)); \
85 return (old); \
88 #define SYNC_LOCK_RELEASE_N(N, TYPE) \
89 void HIDDEN \
90 __sync_lock_release_##N (TYPE *ptr) \
91 { \
92 /* All writes before this point must be seen before we release \
93 the lock itself. */ \
94 __sync_synchronize (); \
95 *ptr = 0; \
98 #define SYNC_VAL_CAS_N(N, TYPE, LDR, STREQ) \
99 TYPE HIDDEN \
100 __sync_val_compare_and_swap_##N (TYPE *mem, TYPE expected, \
101 TYPE desired) \
103 unsigned int old, temp, ras_start; \
105 ras_start = ARM_RAS_START; \
106 __asm volatile ( \
107 /* Set up Restartable Atomic Sequence. */ \
108 "1:" \
109 "\tadr %2, 1b\n" \
110 "\tstr %2, [%6]\n" \
111 "\tadr %2, 2f\n" \
112 "\tstr %2, [%6, #4]\n" \
114 "\t"LDR" %0, %5\n" /* Load old value. */ \
115 "\tcmp %0, %3\n" /* Compare to expected value. */\
116 "\t"STREQ" %4, %1\n" /* Store new value. */ \
118 /* Tear down Restartable Atomic Sequence. */ \
119 "2:" \
120 "\tmov %2, #0x00000000\n" \
121 "\tstr %2, [%6]\n" \
122 "\tmov %2, #0xffffffff\n" \
123 "\tstr %2, [%6, #4]\n" \
124 : "=&r" (old), "=m" (*mem), "=&r" (temp) \
125 : "r" (expected), "r" (desired), "m" (*mem), \
126 "r" (ras_start)); \
127 return (old); \
130 typedef unsigned char bool;
132 #define SYNC_BOOL_CAS_N(N, TYPE) \
133 bool HIDDEN \
134 __sync_bool_compare_and_swap_##N (TYPE *ptr, TYPE oldval, \
135 TYPE newval) \
137 TYPE actual_oldval \
138 = __sync_val_compare_and_swap_##N (ptr, oldval, newval); \
139 return (oldval == actual_oldval); \
142 #define SYNC_FETCH_AND_OP_N(N, TYPE, LDR, STR, NAME, OP) \
143 TYPE HIDDEN \
144 __sync_fetch_and_##NAME##_##N (TYPE *mem, TYPE val) \
146 unsigned int old, temp, ras_start; \
148 ras_start = ARM_RAS_START; \
149 __asm volatile ( \
150 /* Set up Restartable Atomic Sequence. */ \
151 "1:" \
152 "\tadr %2, 1b\n" \
153 "\tstr %2, [%5]\n" \
154 "\tadr %2, 2f\n" \
155 "\tstr %2, [%5, #4]\n" \
157 "\t"LDR" %0, %4\n" /* Load old value. */ \
158 "\t"OP" %2, %0, %3\n" /* Calculate new value. */ \
159 "\t"STR" %2, %1\n" /* Store new value. */ \
161 /* Tear down Restartable Atomic Sequence. */ \
162 "2:" \
163 "\tmov %2, #0x00000000\n" \
164 "\tstr %2, [%5]\n" \
165 "\tmov %2, #0xffffffff\n" \
166 "\tstr %2, [%5, #4]\n" \
167 : "=&r" (old), "=m" (*mem), "=&r" (temp) \
168 : "r" (val), "m" (*mem), "r" (ras_start)); \
169 return (old); \
172 #define SYNC_OP_AND_FETCH_N(N, TYPE, LDR, STR, NAME, OP) \
173 TYPE HIDDEN \
174 __sync_##NAME##_and_fetch_##N (TYPE *mem, TYPE val) \
176 unsigned int old, temp, ras_start; \
178 ras_start = ARM_RAS_START; \
179 __asm volatile ( \
180 /* Set up Restartable Atomic Sequence. */ \
181 "1:" \
182 "\tadr %2, 1b\n" \
183 "\tstr %2, [%5]\n" \
184 "\tadr %2, 2f\n" \
185 "\tstr %2, [%5, #4]\n" \
187 "\t"LDR" %0, %4\n" /* Load old value. */ \
188 "\t"OP" %2, %0, %3\n" /* Calculate new value. */ \
189 "\t"STR" %2, %1\n" /* Store new value. */ \
191 /* Tear down Restartable Atomic Sequence. */ \
192 "2:" \
193 "\tmov %2, #0x00000000\n" \
194 "\tstr %2, [%5]\n" \
195 "\tmov %2, #0xffffffff\n" \
196 "\tstr %2, [%5, #4]\n" \
197 : "=&r" (old), "=m" (*mem), "=&r" (temp) \
198 : "r" (val), "m" (*mem), "r" (ras_start)); \
199 return (old); \
202 #define EMIT_ALL_OPS_N(N, TYPE, LDR, STR, STREQ) \
203 SYNC_LOCK_TEST_AND_SET_N (N, TYPE, LDR, STR) \
204 SYNC_LOCK_RELEASE_N (N, TYPE) \
205 SYNC_VAL_CAS_N (N, TYPE, LDR, STREQ) \
206 SYNC_BOOL_CAS_N (N, TYPE) \
207 SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, add, "add") \
208 SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, and, "and") \
209 SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, or, "orr") \
210 SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, sub, "sub") \
211 SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, xor, "eor") \
212 SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, add, "add") \
213 SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, and, "and") \
214 SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, or, "orr") \
215 SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, sub, "sub") \
216 SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, xor, "eor")
220 EMIT_ALL_OPS_N (1, unsigned char, "ldrb", "strb", "streqb")
221 EMIT_ALL_OPS_N (2, unsigned short, "ldrh", "strh", "streqh")
222 EMIT_ALL_OPS_N (4, unsigned int, "ldr", "str", "streq")
224 #endif