build fix: add -I../rts/parallel
[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  * Prevents write operations from moving across this call in either
59  * direction.
60  */ 
61 EXTERN_INLINE void write_barrier(void);
62
63 /*
64  * Prevents loads from moving before earlier stores.
65  */
66 EXTERN_INLINE void store_load_barrier(void);
67
68 /* ----------------------------------------------------------------------------
69    Implementations
70    ------------------------------------------------------------------------- */
71
72 #if !IN_STG_CODE
73
74 /* 
75  * NB: the xchg instruction is implicitly locked, so we do not need
76  * a lock prefix here. 
77  */
78 EXTERN_INLINE StgWord
79 xchg(StgPtr p, StgWord w)
80 {
81     StgWord result;
82 #if i386_HOST_ARCH || x86_64_HOST_ARCH
83     result = w;
84     __asm__ __volatile__ (
85           "xchg %1,%0"
86           :"+r" (result), "+m" (*p)
87           : /* no input-only operands */
88         );
89 #elif powerpc_HOST_ARCH
90     __asm__ __volatile__ (
91         "1:     lwarx     %0, 0, %2\n"
92         "       stwcx.    %1, 0, %2\n"
93         "       bne-      1b"
94         :"=&r" (result)
95         :"r" (w), "r" (p)
96     );
97 #elif sparc_HOST_ARCH
98     result = w;
99     __asm__ __volatile__ (
100         "swap %1,%0"
101         : "+r" (result), "+m" (*p)
102         : /* no input-only operands */
103       );
104 #elif !defined(WITHSMP)
105     result = *p;
106     *p = w;
107 #else
108 #error xchg() unimplemented on this architecture
109 #endif
110     return result;
111 }
112
113 /* 
114  * CMPXCHG - the single-word atomic compare-and-exchange instruction.  Used 
115  * in the STM implementation.
116  */
117 EXTERN_INLINE StgWord
118 cas(StgVolatilePtr p, StgWord o, StgWord n)
119 {
120 #if i386_HOST_ARCH || x86_64_HOST_ARCH
121     __asm__ __volatile__ (
122           "lock\ncmpxchg %3,%1"
123           :"=a"(o), "=m" (*(volatile unsigned int *)p) 
124           :"0" (o), "r" (n));
125     return o;
126 #elif powerpc_HOST_ARCH
127     StgWord result;
128     __asm__ __volatile__ (
129         "1:     lwarx     %0, 0, %3\n"
130         "       cmpw      %0, %1\n"
131         "       bne       2f\n"
132         "       stwcx.    %2, 0, %3\n"
133         "       bne-      1b\n"
134         "2:"
135         :"=&r" (result)
136         :"r" (o), "r" (n), "r" (p)
137         :"cc", "memory"
138     );
139     return result;
140 #elif sparc_HOST_ARCH
141     __asm__ __volatile__ (
142         "cas [%1], %2, %0"
143         : "+r" (n)
144         : "r" (p), "r" (o)
145         : "memory"
146     );
147     return n;
148 #elif !defined(WITHSMP)
149     StgWord result;
150     result = *p;
151     if (result == o) {
152         *p = n;
153     }
154     return result;
155 #else
156 #error cas() unimplemented on this architecture
157 #endif
158 }
159
160 #endif // !IN_STG_CODE
161
162 /*
163  * Write barrier - ensure that all preceding writes have happened
164  * before all following writes.  
165  *
166  * We need to tell both the compiler AND the CPU about the barrier.
167  * This is a brute force solution; better results might be obtained by
168  * using volatile type declarations to get fine-grained ordering
169  * control in C, and optionally a memory barrier instruction on CPUs
170  * that require it (not x86 or x86_64).
171  */
172 EXTERN_INLINE void
173 write_barrier(void) {
174 #if i386_HOST_ARCH || x86_64_HOST_ARCH
175     __asm__ __volatile__ ("" : : : "memory");
176 #elif powerpc_HOST_ARCH
177     __asm__ __volatile__ ("lwsync" : : : "memory");
178 #elif sparc_HOST_ARCH
179     /* Sparc in TSO mode does not require write/write barriers. */
180     __asm__ __volatile__ ("" : : : "memory");
181 #elif !defined(WITHSMP)
182     return;
183 #else
184 #error memory barriers unimplemented on this architecture
185 #endif
186 }
187
188 EXTERN_INLINE void
189 store_load_barrier(void) {
190 #if i386_HOST_ARCH
191     __asm__ __volatile__ ("lock; addl $0,0(%%esp)" : : : "memory");
192 #elif x86_64_HOST_ARCH
193     __asm__ __volatile__ ("lock; addq $0,0(%%rsp)" : : : "memory");
194 #elif powerpc_HOST_ARCH
195     __asm__ __volatile__ ("msync" : : : "memory");
196 #elif sparc_HOST_ARCH
197     /* Sparc in TSO mode does not require write/write barriers. */
198     __asm__ __volatile__ ("membar" : : : "memory");
199 #elif !defined(WITHSMP)
200     return;
201 #else
202 #error memory barriers unimplemented on this architecture
203 #endif
204 }
205
206 /* ---------------------------------------------------------------------- */
207 #else /* !THREADED_RTS */
208
209 #define write_barrier() /* nothing */
210
211 #define store_load_barrier() /* nothing */
212
213 INLINE_HEADER StgWord
214 xchg(StgPtr p, StgWord w)
215 {
216     StgWord old = *p;
217     *p = w;
218     return old;
219 }
220
221 STATIC_INLINE StgWord
222 cas(StgVolatilePtr p, StgWord o, StgWord n)
223 {
224     StgWord result;
225     result = *p;
226     if (result == o) {
227         *p = n;
228     }
229     return result;
230 }
231
232 #endif /* !THREADED_RTS */
233
234 #endif /* SMP_H */