~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc/x86_64.h

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
 
3
 * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
 
4
 * Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
 
5
 *
 
6
 *
 
7
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 
8
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 
9
 *
 
10
 * Permission is hereby granted to use or copy this program
 
11
 * for any purpose,  provided the above notices are retained on all copies.
 
12
 * Permission to modify the code and to distribute modified code is granted,
 
13
 * provided the above notices are retained, and a notice that the code was
 
14
 * modified is included with the above copyright notice.
 
15
 *
 
16
 * Some of the machine specific code was borrowed from our GC distribution.
 
17
 */
 
18
 
 
19
/* The following really assume we have a 486 or better.  Unfortunately  */
 
20
/* gcc doesn't define a suitable feature test macro based on command    */
 
21
/* line options.                                                        */
 
22
/* We should perhaps test dynamically.                                  */
 
23
 
 
24
#include "../all_aligned_atomic_load_store.h"
 
25
 
 
26
/* Real X86 implementations, except for some old WinChips, appear       */
 
27
/* to enforce ordering between memory operations, EXCEPT that a later   */
 
28
/* read can pass earlier writes, presumably due to the visible          */
 
29
/* presence of store buffers.                                           */
 
30
/* We ignore both the WinChips, and the fact that the official specs    */
 
31
/* seem to be much weaker (and arguably too weak to be usable).         */
 
32
 
 
33
#include "../ordered_except_wr.h"
 
34
 
 
35
#include "../test_and_set_t_is_char.h"
 
36
 
 
37
#include "../standard_ao_double_t.h"
 
38
 
 
39
#if defined(AO_USE_PENTIUM4_INSTRS)
 
40
AO_INLINE void
 
41
AO_nop_full()
 
42
{
 
43
  __asm__ __volatile__("mfence" : : : "memory");
 
44
}
 
45
 
 
46
#define AO_HAVE_nop_full
 
47
 
 
48
#else
 
49
 
 
50
/* We could use the cpuid instruction.  But that seems to be slower     */
 
51
/* than the default implementation based on test_and_set_full.  Thus    */
 
52
/* we omit that bit of misinformation here.                             */
 
53
 
 
54
#endif
 
55
 
 
56
/* As far as we can tell, the lfence and sfence instructions are not    */
 
57
/* currently needed or useful for cached memory accesses.               */
 
58
 
 
59
/* Really only works for 486 and later */
 
60
AO_INLINE AO_t
 
61
AO_fetch_and_add_full (volatile AO_t *p, AO_t incr)
 
62
{
 
63
  AO_t result;
 
64
 
 
65
  __asm__ __volatile__ ("lock; xaddq %0, %1" :
 
66
                        "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
 
67
                        : "memory");
 
68
  return result;
 
69
}
 
70
 
 
71
#define AO_HAVE_fetch_and_add_full
 
72
 
 
73
AO_INLINE unsigned char
 
74
AO_char_fetch_and_add_full (volatile unsigned char *p, unsigned char incr)
 
75
{
 
76
  unsigned char result;
 
77
 
 
78
  __asm__ __volatile__ ("lock; xaddb %0, %1" :
 
79
                        "=q" (result), "=m" (*p) : "0" (incr), "m" (*p)
 
80
                        : "memory");
 
81
  return result;
 
82
}
 
83
 
 
84
#define AO_HAVE_char_fetch_and_add_full
 
85
 
 
86
AO_INLINE unsigned short
 
87
AO_short_fetch_and_add_full (volatile unsigned short *p, unsigned short incr)
 
88
{
 
89
  unsigned short result;
 
90
 
 
91
  __asm__ __volatile__ ("lock; xaddw %0, %1" :
 
92
                        "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
 
93
                        : "memory");
 
94
  return result;
 
95
}
 
96
 
 
97
#define AO_HAVE_short_fetch_and_add_full
 
98
 
 
99
AO_INLINE unsigned short
 
100
AO_int_fetch_and_add_full (volatile unsigned int *p, unsigned int incr)
 
101
{
 
102
  unsigned int result;
 
103
 
 
104
  __asm__ __volatile__ ("lock; xaddl %0, %1" :
 
105
                        "=r" (result), "=m" (*p) : "0" (incr), "m" (*p)
 
106
                        : "memory");
 
107
  return result;
 
108
}
 
109
 
 
110
#define AO_HAVE_int_fetch_and_add_full
 
111
 
 
112
/* Really only works for 486 and later */
 
113
AO_INLINE void
 
114
AO_or_full (volatile AO_t *p, AO_t incr)
 
115
{
 
116
  __asm__ __volatile__ ("lock; orq %1, %0" :
 
117
                        "=m" (*p) : "r" (incr), "m" (*p) : "memory");
 
118
}
 
119
 
 
120
#define AO_HAVE_or_full
 
121
 
 
122
AO_INLINE AO_TS_VAL_t
 
123
AO_test_and_set_full(volatile AO_TS_t *addr)
 
124
{
 
125
  unsigned char oldval;
 
126
  /* Note: the "xchg" instruction does not need a "lock" prefix */
 
127
  __asm__ __volatile__("xchgb %0, %1"
 
128
                : "=q"(oldval), "=m"(*addr)
 
129
                : "0"(0xff), "m"(*addr) : "memory");
 
130
  return (AO_TS_VAL_t)oldval;
 
131
}
 
132
 
 
133
#define AO_HAVE_test_and_set_full
 
134
 
 
135
/* Returns nonzero if the comparison succeeded. */
 
136
AO_INLINE int
 
137
AO_compare_and_swap_full(volatile AO_t *addr,
 
138
                         AO_t old, AO_t new_val) 
 
139
{
 
140
  char result;
 
141
  __asm__ __volatile__("lock; cmpxchgq %3, %0; setz %1"
 
142
                       : "=m"(*addr), "=q"(result)
 
143
                       : "m"(*addr), "r" (new_val), "a"(old) : "memory");
 
144
  return (int) result;
 
145
}
 
146
 
 
147
#define AO_HAVE_compare_and_swap_full
 
148
 
 
149
#ifdef AO_CMPXCHG16B_AVAILABLE
 
150
/* NEC LE-IT: older AMD Opterons are missing this instruction.
 
151
 * On these machines SIGILL will be thrown. Define AO_CASDOUBLE_MISSING
 
152
 * to have an emulated (lock based) version available */ 
 
153
/* HB: Changed this to not define either by default.  There are
 
154
 * enough machines and tool chains around on which cmpxchg16b
 
155
 * doesn't work.  And the emulation is unsafe by our usual rules.
 
156
 * Hoewever both are clearly useful in certain cases.
 
157
 */
 
158
AO_INLINE int
 
159
AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
 
160
                                       AO_t old_val1, AO_t old_val2,
 
161
                                       AO_t new_val1, AO_t new_val2)
 
162
{
 
163
  char result;
 
164
  __asm__ __volatile__("lock; cmpxchg16b %0; setz %1"
 
165
                                : "=m"(*addr), "=q"(result)
 
166
                                        : "m"(*addr),
 
167
                                          "d" (old_val1),
 
168
                                          "a" (old_val2),
 
169
                                          "c" (new_val1),
 
170
                                          "b" (new_val2)  : "memory");
 
171
  return (int) result;
 
172
}
 
173
#define AO_HAVE_compare_double_and_swap_double_full
 
174
#else
 
175
/* this one provides spinlock based emulation of CAS implemented in     */
 
176
/* atomic_ops.c.  We probably do not want to do this here, since it is  */
 
177
/* not attomic with respect to other kinds of updates of *addr.  On the */
 
178
/* other hand, this may be a useful facility on occasion.               */
 
179
#ifdef AO_WEAK_DOUBLE_CAS_EMULATION
 
180
int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *addr,
 
181
                                                AO_t old_val1, AO_t old_val2,
 
182
                                                AO_t new_val1, AO_t new_val2);
 
183
 
 
184
AO_INLINE int
 
185
AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
 
186
                                       AO_t old_val1, AO_t old_val2,
 
187
                                       AO_t new_val1, AO_t new_val2)
 
188
{
 
189
        return AO_compare_double_and_swap_double_emulation(addr,
 
190
                                                           old_val1, old_val2,
 
191
                                                           new_val1, new_val2);
 
192
}
 
193
#define AO_HAVE_compare_double_and_swap_double_full
 
194
#endif /* AO_WEAK_DOUBLE_CAS_EMULATION */
 
195
#endif /* AO_CMPXCHG16B_AVAILABLE */