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