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