atomic.c 7.93 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
#include "Rts.h"

// Fallbacks for atomic primops on byte arrays. The builtins used
// below are supported on both GCC and LLVM.
//
// Ideally these function would take StgWord8, StgWord16, etc but
// older GCC versions incorrectly assume that the register that the
// argument is passed in has been zero extended, which is incorrect
// according to the ABI and is not what GHC does when it generates
// calls to these functions.

// FetchAddByteArrayOp_Int

14
extern StgWord hs_atomic_add8(StgWord x, StgWord val);
15
StgWord
16
hs_atomic_add8(StgWord x, StgWord val)
17
{
18
  return __sync_fetch_and_add((volatile StgWord8 *) x, (StgWord8) val);
19 20
}

21
extern StgWord hs_atomic_add16(StgWord x, StgWord val);
22
StgWord
23
hs_atomic_add16(StgWord x, StgWord val)
24
{
25
  return __sync_fetch_and_add((volatile StgWord16 *) x, (StgWord16) val);
26 27
}

28
extern StgWord hs_atomic_add32(StgWord x, StgWord val);
29
StgWord
30
hs_atomic_add32(StgWord x, StgWord val)
31
{
32
  return __sync_fetch_and_add((volatile StgWord32 *) x, (StgWord32) val);
33 34
}

35
#if WORD_SIZE_IN_BITS == 64
36
extern StgWord64 hs_atomic_add64(StgWord x, StgWord64 val);
37
StgWord64
38
hs_atomic_add64(StgWord x, StgWord64 val)
39
{
40
  return __sync_fetch_and_add((volatile StgWord64 *) x, val);
41
}
42
#endif
43 44 45

// FetchSubByteArrayOp_Int

46
extern StgWord hs_atomic_sub8(StgWord x, StgWord val);
47
StgWord
48
hs_atomic_sub8(StgWord x, StgWord val)
49
{
50
  return __sync_fetch_and_sub((volatile StgWord8 *) x, (StgWord8) val);
51 52
}

53
extern StgWord hs_atomic_sub16(StgWord x, StgWord val);
54
StgWord
55
hs_atomic_sub16(StgWord x, StgWord val)
56
{
57
  return __sync_fetch_and_sub((volatile StgWord16 *) x, (StgWord16) val);
58 59
}

60
extern StgWord hs_atomic_sub32(StgWord x, StgWord val);
61
StgWord
62
hs_atomic_sub32(StgWord x, StgWord val)
63
{
64
  return __sync_fetch_and_sub((volatile StgWord32 *) x, (StgWord32) val);
65 66
}

67
#if WORD_SIZE_IN_BITS == 64
68
extern StgWord64 hs_atomic_sub64(StgWord x, StgWord64 val);
69
StgWord64
70
hs_atomic_sub64(StgWord x, StgWord64 val)
71
{
72
  return __sync_fetch_and_sub((volatile StgWord64 *) x, val);
73
}
74
#endif
75 76 77

// FetchAndByteArrayOp_Int

78
extern StgWord hs_atomic_and8(StgWord x, StgWord val);
79
StgWord
80
hs_atomic_and8(StgWord x, StgWord val)
81
{
82
  return __sync_fetch_and_and((volatile StgWord8 *) x, (StgWord8) val);
83 84
}

85
extern StgWord hs_atomic_and16(StgWord x, StgWord val);
86
StgWord
87
hs_atomic_and16(StgWord x, StgWord val)
88
{
89
  return __sync_fetch_and_and((volatile StgWord16 *) x, (StgWord16) val);
90 91
}

92
extern StgWord hs_atomic_and32(StgWord x, StgWord val);
93
StgWord
94
hs_atomic_and32(StgWord x, StgWord val)
95
{
96
  return __sync_fetch_and_and((volatile StgWord32 *) x, (StgWord32) val);
97 98
}

99
#if WORD_SIZE_IN_BITS == 64
100
extern StgWord64 hs_atomic_and64(StgWord x, StgWord64 val);
101
StgWord64
102
hs_atomic_and64(StgWord x, StgWord64 val)
103
{
104
  return __sync_fetch_and_and((volatile StgWord64 *) x, val);
105
}
106
#endif
107 108 109 110 111 112 113 114 115 116 117 118 119

// FetchNandByteArrayOp_Int

// Workaround for http://llvm.org/bugs/show_bug.cgi?id=8842
#define CAS_NAND(x, val)                                            \
  {                                                                 \
    __typeof__ (*(x)) tmp = *(x);                                   \
    while (!__sync_bool_compare_and_swap(x, tmp, ~(tmp & (val)))) { \
      tmp = *(x);                                                   \
    }                                                               \
    return tmp;                                                     \
  }

120
extern StgWord hs_atomic_nand8(StgWord x, StgWord val);
121
StgWord
122
hs_atomic_nand8(StgWord x, StgWord val)
123 124
{
#ifdef __clang__
125
  CAS_NAND((volatile StgWord8 *) x, (StgWord8) val)
126
#else
127
  return __sync_fetch_and_nand((volatile StgWord8 *) x, (StgWord8) val);
128 129 130
#endif
}

131
extern StgWord hs_atomic_nand16(StgWord x, StgWord val);
132
StgWord
133
hs_atomic_nand16(StgWord x, StgWord val)
134 135
{
#ifdef __clang__
136
  CAS_NAND((volatile StgWord16 *) x, (StgWord16) val);
137
#else
138
  return __sync_fetch_and_nand((volatile StgWord16 *) x, (StgWord16) val);
139 140 141
#endif
}

142
extern StgWord hs_atomic_nand32(StgWord x, StgWord val);
143
StgWord
144
hs_atomic_nand32(StgWord x, StgWord val)
145 146
{
#ifdef __clang__
147
  CAS_NAND((volatile StgWord32 *) x, (StgWord32) val);
148
#else
149
  return __sync_fetch_and_nand((volatile StgWord32 *) x, (StgWord32) val);
150 151 152
#endif
}

153
#if WORD_SIZE_IN_BITS == 64
154
extern StgWord64 hs_atomic_nand64(StgWord x, StgWord64 val);
155
StgWord64
156
hs_atomic_nand64(StgWord x, StgWord64 val)
157 158
{
#ifdef __clang__
159
  CAS_NAND((volatile StgWord64 *) x, val);
160
#else
161
  return __sync_fetch_and_nand((volatile StgWord64 *) x, val);
162 163
#endif
}
164
#endif
165 166 167

// FetchOrByteArrayOp_Int

168
extern StgWord hs_atomic_or8(StgWord x, StgWord val);
169
StgWord
170
hs_atomic_or8(StgWord x, StgWord val)
171
{
172
  return __sync_fetch_and_or((volatile StgWord8 *) x, (StgWord8) val);
173 174
}

175
extern StgWord hs_atomic_or16(StgWord x, StgWord val);
176
StgWord
177
hs_atomic_or16(StgWord x, StgWord val)
178
{
179
  return __sync_fetch_and_or((volatile StgWord16 *) x, (StgWord16) val);
180 181
}

182
extern StgWord hs_atomic_or32(StgWord x, StgWord val);
183
StgWord
184
hs_atomic_or32(StgWord x, StgWord val)
185
{
186
  return __sync_fetch_and_or((volatile StgWord32 *) x, (StgWord32) val);
187 188
}

189
#if WORD_SIZE_IN_BITS == 64
190
extern StgWord64 hs_atomic_or64(StgWord x, StgWord64 val);
191
StgWord64
192
hs_atomic_or64(StgWord x, StgWord64 val)
193
{
194
  return __sync_fetch_and_or((volatile StgWord64 *) x, val);
195
}
196
#endif
197 198 199

// FetchXorByteArrayOp_Int

200
extern StgWord hs_atomic_xor8(StgWord x, StgWord val);
201
StgWord
202
hs_atomic_xor8(StgWord x, StgWord val)
203
{
204
  return __sync_fetch_and_xor((volatile StgWord8 *) x, (StgWord8) val);
205 206
}

207
extern StgWord hs_atomic_xor16(StgWord x, StgWord val);
208
StgWord
209
hs_atomic_xor16(StgWord x, StgWord val)
210
{
211
  return __sync_fetch_and_xor((volatile StgWord16 *) x, (StgWord16) val);
212 213
}

214
extern StgWord hs_atomic_xor32(StgWord x, StgWord val);
215
StgWord
216
hs_atomic_xor32(StgWord x, StgWord val)
217
{
218
  return __sync_fetch_and_xor((volatile StgWord32 *) x, (StgWord32) val);
219 220
}

221
#if WORD_SIZE_IN_BITS == 64
222
extern StgWord64 hs_atomic_xor64(StgWord x, StgWord64 val);
223
StgWord64
224
hs_atomic_xor64(StgWord x, StgWord64 val)
225
{
226
  return __sync_fetch_and_xor((volatile StgWord64 *) x, val);
227
}
228
#endif
229 230 231

// CasByteArrayOp_Int

232
extern StgWord hs_cmpxchg8(StgWord x, StgWord old, StgWord new);
233
StgWord
234
hs_cmpxchg8(StgWord x, StgWord old, StgWord new)
235
{
236
  return __sync_val_compare_and_swap((volatile StgWord8 *) x, (StgWord8) old, (StgWord8) new);
237 238
}

239
extern StgWord hs_cmpxchg16(StgWord x, StgWord old, StgWord new);
240
StgWord
241
hs_cmpxchg16(StgWord x, StgWord old, StgWord new)
242
{
243
  return __sync_val_compare_and_swap((volatile StgWord16 *) x, (StgWord16) old, (StgWord16) new);
244 245
}

246
extern StgWord hs_cmpxchg32(StgWord x, StgWord old, StgWord new);
247
StgWord
248
hs_cmpxchg32(StgWord x, StgWord old, StgWord new)
249
{
250
  return __sync_val_compare_and_swap((volatile StgWord32 *) x, (StgWord32) old, (StgWord32) new);
251 252
}

253
#if WORD_SIZE_IN_BITS == 64
254
extern StgWord hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new);
255
StgWord
256
hs_cmpxchg64(StgWord x, StgWord64 old, StgWord64 new)
257
{
258
  return __sync_val_compare_and_swap((volatile StgWord64 *) x, old, new);
259
}
260
#endif
261 262 263

// AtomicReadByteArrayOp_Int

264
extern StgWord hs_atomicread8(StgWord x);
265
StgWord
266
hs_atomicread8(StgWord x)
267
{
268
  return *(volatile StgWord8 *) x;
269 270
}

271
extern StgWord hs_atomicread16(StgWord x);
272
StgWord
273
hs_atomicread16(StgWord x)
274
{
275
  return *(volatile StgWord16 *) x;
276 277
}

278
extern StgWord hs_atomicread32(StgWord x);
279
StgWord
280
hs_atomicread32(StgWord x)
281
{
282
  return *(volatile StgWord32 *) x;
283 284
}

285
extern StgWord64 hs_atomicread64(StgWord x);
286
StgWord64
287
hs_atomicread64(StgWord x)
288
{
289
  return *(volatile StgWord64 *) x;
290 291 292 293
}

// AtomicWriteByteArrayOp_Int

294
extern void hs_atomicwrite8(StgWord x, StgWord val);
295
void
296
hs_atomicwrite8(StgWord x, StgWord val)
297
{
298
  *(volatile StgWord8 *) x = (StgWord8) val;
299 300
}

301
extern void hs_atomicwrite16(StgWord x, StgWord val);
302
void
303
hs_atomicwrite16(StgWord x, StgWord val)
304
{
305
  *(volatile StgWord16 *) x = (StgWord16) val;
306 307
}

308
extern void hs_atomicwrite32(StgWord x, StgWord val);
309
void
310
hs_atomicwrite32(StgWord x, StgWord val)
311
{
312
  *(volatile StgWord32 *) x = (StgWord32) val;
313 314
}

315
extern void hs_atomicwrite64(StgWord x, StgWord64 val);
316
void
317
hs_atomicwrite64(StgWord x, StgWord64 val)
318
{
319
  *(volatile StgWord64 *) x = (StgWord64) val;
320
}