replace sparc-specific Int64 code with calls to platform-independent macros
[ghc-hetmet.git] / includes / stg / SMP.h
1 /* ----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 2005-2008
4  *
5  * Macros for multi-CPU support
6  *
7  * -------------------------------------------------------------------------- */
8
9 #ifndef SMP_H
10 #define SMP_H
11
12 #if defined(THREADED_RTS)
13
14 /* ----------------------------------------------------------------------------
15    Atomic operations
16    ------------------------------------------------------------------------- */
17    
18 #if !IN_STG_CODE || IN_STGCRUN
19 // We only want the barriers, e.g. write_barrier(), declared in .hc
20 // files.  Defining the other inline functions here causes type
21 // mismatch errors from gcc, because the generated C code is assuming
22 // that there are no prototypes in scope.
23
24 /* 
25  * The atomic exchange operation: xchg(p,w) exchanges the value
26  * pointed to by p with the value w, returning the old value.
27  *
28  * Used for locking closures during updates (see lockClosure() below)
29  * and the MVar primops.
30  */
31 EXTERN_INLINE StgWord xchg(StgPtr p, StgWord w);
32
33 /* 
34  * Compare-and-swap.  Atomically does this:
35  *
36  * cas(p,o,n) { 
37  *    r = *p; 
38  *    if (r == o) { *p = n }; 
39  *    return r;
40  * }
41  */
42 EXTERN_INLINE StgWord cas(StgVolatilePtr p, StgWord o, StgWord n);
43
44 /*
45  * Atomic increment
46  *
47  * atomic_inc(p) {
48  *   return ++(*p);
49  * }
50  */
51 EXTERN_INLINE StgWord atomic_inc(StgVolatilePtr p);
52
53 /*
54  * Atomic decrement
55  *
56  * atomic_dec(p) {
57  *   return --(*p);
58  * }
59  */
60 EXTERN_INLINE StgWord atomic_dec(StgVolatilePtr p);
61
62 #endif // !IN_STG_CODE
63
64 /*
65  * Various kinds of memory barrier.
66  *  write_barrier: prevents future stores occurring before prededing stores.
67  *  store_load_barrier: prevents future loads occurring before preceding stores.
68  *  load_load_barrier: prevents future loads occurring before earlier stores.
69  *
70  * Reference for these: "The JSR-133 Cookbook for Compiler Writers"
71  * http://gee.cs.oswego.edu/dl/jmm/cookbook.html
72  *
73  * To check whether you got these right, try the test in 
74  *   testsuite/tests/ghc-regress/rts/testwsdeque.c
75  * This tests the work-stealing deque implementation, which relies on
76  * properly working store_load and load_load memory barriers.
77  */ 
78 EXTERN_INLINE void write_barrier(void);
79 EXTERN_INLINE void store_load_barrier(void);
80 EXTERN_INLINE void load_load_barrier(void);
81
82 /* ----------------------------------------------------------------------------
83    Implementations
84    ------------------------------------------------------------------------- */
85
86 #if !IN_STG_CODE || IN_STGCRUN
87
88 EXTERN_INLINE StgWord
89 xchg(StgPtr p, StgWord w)
90 {
91     StgWord result;
92 #if i386_HOST_ARCH || x86_64_HOST_ARCH
93     result = w;
94     __asm__ __volatile__ (
95         // NB: the xchg instruction is implicitly locked, so we do not
96         // need a lock prefix here.
97           "xchg %1,%0"
98           :"+r" (result), "+m" (*p)
99           : /* no input-only operands */
100         );
101 #elif powerpc_HOST_ARCH
102     __asm__ __volatile__ (
103         "1:     lwarx     %0, 0, %2\n"
104         "       stwcx.    %1, 0, %2\n"
105         "       bne-      1b"
106         :"=&r" (result)
107         :"r" (w), "r" (p)
108     );
109 #elif sparc_HOST_ARCH
110     result = w;
111     __asm__ __volatile__ (
112         "swap %1,%0"
113         : "+r" (result), "+m" (*p)
114         : /* no input-only operands */
115       );
116 #elif !defined(WITHSMP)
117     result = *p;
118     *p = w;
119 #else
120 #error xchg() unimplemented on this architecture
121 #endif
122     return result;
123 }
124
125 /* 
126  * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used 
127  * in the STM implementation.
128  */
129 EXTERN_INLINE StgWord
130 cas(StgVolatilePtr p, StgWord o, StgWord n)
131 {
132 #if i386_HOST_ARCH || x86_64_HOST_ARCH
133     __asm__ __volatile__ (
134           "lock\ncmpxchg %3,%1"
135           :"=a"(o), "=m" (*(volatile unsigned int *)p) 
136           :"0" (o), "r" (n));
137     return o;
138 #elif powerpc_HOST_ARCH
139     StgWord result;
140     __asm__ __volatile__ (
141         "1:     lwarx     %0, 0, %3\n"
142         "       cmpw      %0, %1\n"
143         "       bne       2f\n"
144         "       stwcx.    %2, 0, %3\n"
145         "       bne-      1b\n"
146         "2:"
147         :"=&r" (result)
148         :"r" (o), "r" (n), "r" (p)
149         :"cc", "memory"
150     );
151     return result;
152 #elif sparc_HOST_ARCH
153     __asm__ __volatile__ (
154         "cas [%1], %2, %0"
155         : "+r" (n)
156         : "r" (p), "r" (o)
157         : "memory"
158     );
159     return n;
160 #elif !defined(WITHSMP)
161     StgWord result;
162     result = *p;
163     if (result == o) {
164         *p = n;
165     }
166     return result;
167 #else
168 #error cas() unimplemented on this architecture
169 #endif
170 }
171
172 EXTERN_INLINE StgWord
173 atomic_inc(StgVolatilePtr p)
174 {
175 #if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)
176     StgWord r;
177     r = 1;
178     __asm__ __volatile__ (
179         "lock\nxadd %0,%1":
180             "+r" (r), "+m" (*p):
181     );
182     return r+1;
183 #else
184     StgWord old, new;
185     do {
186         old = *p;
187         new = old + 1;
188     } while (cas(p, old, new) != old);
189     return new;
190 #endif
191 }
192
193 EXTERN_INLINE StgWord
194 atomic_dec(StgVolatilePtr p)
195 {
196 #if defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)
197     StgWord r;
198     r = (StgWord)-1;
199     __asm__ __volatile__ (
200         "lock\nxadd %0,%1":
201             "+r" (r), "+m" (*p):
202     );
203     return r-1;
204 #else
205     StgWord old, new;
206     do {
207         old = *p;
208         new = old - 1;
209     } while (cas(p, old, new) != old);
210     return new;
211 #endif
212 }
213
214 #endif // !IN_STG_CODE
215
216 /*
217  * We need to tell both the compiler AND the CPU about the barriers.
218  * It's no good preventing the CPU from reordering the operations if
219  * the compiler has already done so - hence the "memory" restriction
220  * on each of the barriers below.
221  */
222 EXTERN_INLINE void
223 write_barrier(void) {
224 #if i386_HOST_ARCH || x86_64_HOST_ARCH
225     __asm__ __volatile__ ("" : : : "memory");
226 #elif powerpc_HOST_ARCH
227     __asm__ __volatile__ ("lwsync" : : : "memory");
228 #elif sparc_HOST_ARCH
229     /* Sparc in TSO mode does not require store/store barriers. */
230     __asm__ __volatile__ ("" : : : "memory");
231 #elif !defined(WITHSMP)
232     return;
233 #else
234 #error memory barriers unimplemented on this architecture
235 #endif
236 }
237
238 EXTERN_INLINE void
239 store_load_barrier(void) {
240 #if i386_HOST_ARCH
241     __asm__ __volatile__ ("lock; addl $0,0(%%esp)" : : : "memory");
242 #elif x86_64_HOST_ARCH
243     __asm__ __volatile__ ("lock; addq $0,0(%%rsp)" : : : "memory");
244 #elif powerpc_HOST_ARCH
245     __asm__ __volatile__ ("sync" : : : "memory");
246 #elif sparc_HOST_ARCH
247     __asm__ __volatile__ ("membar #StoreLoad" : : : "memory");
248 #elif !defined(WITHSMP)
249     return;
250 #else
251 #error memory barriers unimplemented on this architecture
252 #endif
253 }
254
255 EXTERN_INLINE void
256 load_load_barrier(void) {
257 #if i386_HOST_ARCH
258     __asm__ __volatile__ ("" : : : "memory");
259 #elif x86_64_HOST_ARCH
260     __asm__ __volatile__ ("" : : : "memory");
261 #elif powerpc_HOST_ARCH
262     __asm__ __volatile__ ("lwsync" : : : "memory");
263 #elif sparc_HOST_ARCH
264     /* Sparc in TSO mode does not require load/load barriers. */
265     __asm__ __volatile__ ("" : : : "memory");
266 #elif !defined(WITHSMP)
267     return;
268 #else
269 #error memory barriers unimplemented on this architecture
270 #endif
271 }
272
273 /* ---------------------------------------------------------------------- */
274 #else /* !THREADED_RTS */
275
276 #define write_barrier()      /* nothing */
277 #define store_load_barrier() /* nothing */
278 #define load_load_barrier()  /* nothing */
279
280 INLINE_HEADER StgWord
281 xchg(StgPtr p, StgWord w)
282 {
283     StgWord old = *p;
284     *p = w;
285     return old;
286 }
287
288 STATIC_INLINE StgWord
289 cas(StgVolatilePtr p, StgWord o, StgWord n)
290 {
291     StgWord result;
292     result = *p;
293     if (result == o) {
294         *p = n;
295     }
296     return result;
297 }
298
299 INLINE_HEADER StgWord
300 atomic_inc(StgVolatilePtr p)
301 {
302     return ++(*p);
303 }
304
305 INLINE_HEADER StgWord
306 atomic_dec(StgVolatilePtr p)
307 {
308     return --(*p);
309 }
310
311 #endif /* !THREADED_RTS */
312
313 #endif /* SMP_H */