799722aa37c8ee888a6a5380b70fa447c7a3e356
[cacao.git] / src / mm / boehm-gc / libatomic_ops-1.2 / src / atomic_ops / sysdeps / gcc / powerpc.h
1 /* 
2  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
3  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
4  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
5  *
6  *
7  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
9  *
10  * Permission is hereby granted to use or copy this program
11  * for any purpose,  provided the above notices are retained on all copies.
12  * Permission to modify the code and to distribute modified code is granted,
13  * provided the above notices are retained, and a notice that the code was
14  * modified is included with the above copyright notice.
15  *
16  */
17
18 /* FIXME.  Incomplete.  No support for 64 bits.                         */
19 /* Memory model documented at http://www-106.ibm.com/developerworks/    */
20 /* eserver/articles/archguide.html and (clearer)                        */
21 /* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */
22 /* There appears to be no implicit ordering between any kind of         */
23 /* independent memory references.                                       */
24 /* Architecture enforces some ordering based on control dependence.     */
25 /* I don't know if that could help.                                     */
26 /* Data-dependent loads are always ordered.                             */
27 /* Based on the above references, eieio is intended for use on          */
28 /* uncached memory, which we don't support.  It does not order loads    */
29 /* from cached memory.                                                  */
30 /* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to   */
31 /* track some of this down and correcting my misunderstandings. -HB     */
32
33 #include "../all_aligned_atomic_load_store.h"
34
35 #include "../test_and_set_t_is_ao_t.h"
36         /* There seems to be no byte equivalent of lwarx, so this       */
37         /* may really be what we want, at least in the 32-bit case.     */
38
39 AO_INLINE void
40 AO_nop_full()
41 {
42   __asm__ __volatile__("sync" : : : "memory");
43 }
44
45 #define AO_HAVE_nop_full
46
47 /* lwsync apparently works for everything but a StoreLoad barrier.      */
48 AO_INLINE void
49 AO_lwsync()
50 {
51   __asm__ __volatile__("lwsync" : : : "memory");
52 }
53
54 #define AO_nop_write() AO_lwsync()
55 #define AO_HAVE_nop_write
56
57 #define AO_nop_read() AO_lwsync()
58 #define AO_HAVE_nop_read
59
60 /* We explicitly specify load_acquire, since it is important, and can   */
61 /* be implemented relatively cheaply.  It could be implemented          */
62 /* with an ordinary load followed by a lwsync.  But the general wisdom  */
63 /* seems to be that a data dependent branch followed by an isync is     */
64 /* cheaper.  And the documentation is fairly explicit that this also    */
65 /* has acquire semantics.                                               */
66 /* ppc64 uses ld not lwz */
67 #if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
68 AO_INLINE AO_t
69 AO_load_acquire(volatile AO_t *addr)
70 {
71   AO_t result;
72
73   /* FIXME: We should get gcc to allocate one of the condition  */
74   /* registers.  I always got "impossible constraint" when I    */
75   /* tried the "y" constraint.                                  */
76   __asm__ __volatile__ (
77     "ld %0,%1\n"
78     "cmpw cr7,%0,%0\n"
79     "bne- cr7,1f\n"
80     "1: isync\n"
81     : "=r" (result)
82     : "m"(*addr) : "memory", "cc");
83   return result;
84 }
85 #else
86 AO_INLINE AO_t
87 AO_load_acquire(volatile AO_t *addr)
88 {
89   AO_t result;
90
91   /* FIXME: We should get gcc to allocate one of the condition  */
92   /* registers.  I always got "impossible constraint" when I    */
93   /* tried the "y" constraint.                                  */
94   __asm__ __volatile__ (
95     "lwz%X1 %0,%1\n"
96     "cmpw cr7,%0,%0\n"
97     "bne- cr7,1f\n"
98     "1: isync\n"
99     : "=r" (result)
100     : "m"(*addr) : "memory", "cc");
101   return result;
102 }
103 #endif
104 #define AO_HAVE_load_acquire
105
106 /* We explicitly specify store_release, since it relies         */
107 /* on the fact that lwsync is also a LoadStore barrier.         */
108 AO_INLINE void
109 AO_store_release(volatile AO_t *addr, AO_t value)
110 {
111   AO_lwsync();
112   *addr = value;
113 }
114
115 #define AO_HAVE_load_acquire
116
117 /* This is similar to the code in the garbage collector.  Deleting      */
118 /* this and having it synthesized from compare_and_swap would probably  */
119 /* only cost us a load immediate instruction.                           */
120 #if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
121 /* Completely untested.  And we should be using smaller objects anyway. */
122 AO_INLINE AO_TS_VAL_t
123 AO_test_and_set(volatile AO_TS_t *addr) {
124   unsigned long oldval;
125   unsigned long temp = 1; /* locked value */
126
127   __asm__ __volatile__(
128                "1:ldarx %0,0,%1\n"   /* load and reserve               */
129                "cmpdi %0, 0\n"       /* if load is                     */
130                "bne 2f\n"            /*   non-zero, return already set */
131                "stdcx. %2,0,%1\n"    /* else store conditional         */
132                "bne- 1b\n"           /* retry if lost reservation      */
133                "2:\n"                /* oldval is zero if we set       */
134               : "=&r"(oldval)
135               : "r"(addr), "r"(temp)
136               : "memory", "cc");
137
138   return (AO_TS_VAL_t)oldval;
139 }
140
141 #else
142
143 AO_INLINE AO_TS_VAL_t
144 AO_test_and_set(volatile AO_TS_t *addr) {
145   int oldval;
146   int temp = 1; /* locked value */
147
148   __asm__ __volatile__(
149                "1:lwarx %0,0,%1\n"   /* load and reserve               */
150                "cmpwi %0, 0\n"       /* if load is                     */
151                "bne 2f\n"            /*   non-zero, return already set */
152                "stwcx. %2,0,%1\n"    /* else store conditional         */
153                "bne- 1b\n"           /* retry if lost reservation      */
154                "2:\n"                /* oldval is zero if we set       */
155               : "=&r"(oldval)
156               : "r"(addr), "r"(temp)
157               : "memory", "cc");
158
159   return (AO_TS_VAL_t)oldval;
160 }
161
162 #endif
163
164 #define AO_have_test_and_set
165
166 AO_INLINE AO_TS_VAL_t
167 AO_test_and_set_acquire(volatile AO_TS_t *addr) {
168   AO_TS_VAL_t result = AO_test_and_set(addr);
169   AO_lwsync();
170   return result;
171 }
172
173 #define AO_HAVE_test_and_set_acquire
174
175 AO_INLINE AO_TS_VAL_t
176 AO_test_and_set_release(volatile AO_TS_t *addr) {
177   AO_lwsync();
178   return AO_test_and_set(addr);
179 }
180
181 #define AO_HAVE_test_and_set_release
182
183 AO_INLINE AO_TS_VAL_t
184 AO_test_and_set_full(volatile AO_TS_t *addr) {
185   AO_TS_VAL_t result;
186   AO_lwsync();
187   result = AO_test_and_set(addr);
188   AO_lwsync();
189   return result;
190 }
191
192 #define AO_HAVE_test_and_set_full
193
194 #if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
195 /* FIXME: Completely untested.  */
196 AO_INLINE int
197 AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {
198   AO_t oldval;
199   int result = 0;
200
201   __asm__ __volatile__(
202                "1:ldarx %0,0,%2\n"   /* load and reserve              */
203                "cmpd %0, %4\n"      /* if load is not equal to  */
204                "bne 2f\n"            /*   old, fail                     */
205                "stdcx. %3,0,%2\n"    /* else store conditional         */
206                "bne- 1b\n"           /* retry if lost reservation      */
207                "li %1,1\n"           /* result = 1;                     */
208                "2:\n"
209               : "=&r"(oldval), "=&r"(result)
210               : "r"(addr), "r"(new_val), "r"(old), "1"(result)
211               : "memory", "cc");
212
213   return result;
214 }
215
216 #else
217
218 AO_INLINE int
219 AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {
220   AO_t oldval;
221   int result = 0;
222
223   __asm__ __volatile__(
224                "1:lwarx %0,0,%2\n"   /* load and reserve              */
225                "cmpw %0, %4\n"      /* if load is not equal to  */
226                "bne 2f\n"            /*   old, fail                     */
227                "stwcx. %3,0,%2\n"    /* else store conditional         */
228                "bne- 1b\n"           /* retry if lost reservation      */
229                "li %1,1\n"           /* result = 1;                     */
230                "2:\n"
231               : "=&r"(oldval), "=&r"(result)
232               : "r"(addr), "r"(new_val), "r"(old), "1"(result)
233               : "memory", "cc");
234
235   return result;
236 }
237 #endif
238
239 #define AO_HAVE_compare_and_swap
240
241 AO_INLINE int
242 AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {
243   int result = AO_compare_and_swap(addr, old, new_val);
244   AO_lwsync();
245   return result;
246 }
247
248 #define AO_HAVE_compare_and_swap_acquire
249
250 AO_INLINE int
251 AO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {
252   AO_lwsync();
253   return AO_compare_and_swap(addr, old, new_val);
254 }
255
256 #define AO_HAVE_compare_and_swap_release
257
258 AO_INLINE int
259 AO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {
260   AO_t result;
261   AO_lwsync();
262   result = AO_compare_and_swap(addr, old, new_val);
263   AO_lwsync();
264   return result;
265 }
266
267 #define AO_HAVE_compare_and_swap_full
268
269 /* FIXME: We should also implement fetch_and_add and or primitives      */
270 /* directly.                                                            */