update Sparc store/load barrier (#3019), and fix comments
[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 store/store 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     __asm__ __volatile__ ("membar #StoreLoad" : : : "memory");
201 #elif !defined(WITHSMP)
202     return;
203 #else
204 #error memory barriers unimplemented on this architecture
205 #endif
206 }
207
208 EXTERN_INLINE void
209 load_load_barrier(void) {
210 #if i386_HOST_ARCH
211     __asm__ __volatile__ ("" : : : "memory");
212 #elif x86_64_HOST_ARCH
213     __asm__ __volatile__ ("" : : : "memory");
214 #elif powerpc_HOST_ARCH
215     __asm__ __volatile__ ("lwsync" : : : "memory");
216 #elif sparc_HOST_ARCH
217     /* Sparc in TSO mode does not require load/load barriers. */
218     __asm__ __volatile__ ("" : : : "memory");
219 #elif !defined(WITHSMP)
220     return;
221 #else
222 #error memory barriers unimplemented on this architecture
223 #endif
224 }
225
226 /* ---------------------------------------------------------------------- */
227 #else /* !THREADED_RTS */
228
229 #define write_barrier()      /* nothing */
230 #define store_load_barrier() /* nothing */
231 #define load_load_barrier()  /* nothing */
232
233 INLINE_HEADER StgWord
234 xchg(StgPtr p, StgWord w)
235 {
236     StgWord old = *p;
237     *p = w;
238     return old;
239 }
240
241 STATIC_INLINE StgWord
242 cas(StgVolatilePtr p, StgWord o, StgWord n)
243 {
244     StgWord result;
245     result = *p;
246     if (result == o) {
247         *p = n;
248     }
249     return result;
250 }
251
252 #endif /* !THREADED_RTS */
253
254 #endif /* SMP_H */