~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/powerpc.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-2004 Hewlett-Packard Development Company, L.P.
 
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
 */
 
17
 
 
18
/* FIXME.  Incomplete.  No support for 64 bits.                         */
 
19
/* Memory model documented at http://www-106.ibm.com/developerworks/    */
 
20
/* eserver/articles/archguide.html and (clearer)                        */
 
21
/* http://www-106.ibm.com/developerworks/eserver/articles/powerpc.html. */
 
22
/* There appears to be no implicit ordering between any kind of         */
 
23
/* independent memory references.                                       */
 
24
/* Architecture enforces some ordering based on control dependence.     */
 
25
/* I don't know if that could help.                                     */
 
26
/* Data-dependent loads are always ordered.                             */
 
27
/* Based on the above references, eieio is intended for use on          */
 
28
/* uncached memory, which we don't support.  It does not order loads    */
 
29
/* from cached memory.                                                  */
 
30
/* Thanks to Maged Michael, Doug Lea, and Roger Hoover for helping to   */
 
31
/* track some of this down and correcting my misunderstandings. -HB     */
 
32
 
 
33
#include "../all_aligned_atomic_load_store.h"
 
34
 
 
35
#include "../test_and_set_t_is_ao_t.h"
 
36
        /* There seems to be no byte equivalent of lwarx, so this       */
 
37
        /* may really be what we want, at least in the 32-bit case.     */
 
38
 
 
39
AO_INLINE void
 
40
AO_nop_full()
 
41
{
 
42
  __asm__ __volatile__("sync" : : : "memory");
 
43
}
 
44
 
 
45
#define AO_HAVE_nop_full
 
46
 
 
47
/* lwsync apparently works for everything but a StoreLoad barrier.      */
 
48
AO_INLINE void
 
49
AO_lwsync()
 
50
{
 
51
  __asm__ __volatile__("lwsync" : : : "memory");
 
52
}
 
53
 
 
54
#define AO_nop_write() AO_lwsync()
 
55
#define AO_HAVE_nop_write
 
56
 
 
57
#define AO_nop_read() AO_lwsync()
 
58
#define AO_HAVE_nop_read
 
59
 
 
60
/* We explicitly specify load_acquire, since it is important, and can   */
 
61
/* be implemented relatively cheaply.  It could be implemented          */
 
62
/* with an ordinary load followed by a lwsync.  But the general wisdom  */
 
63
/* seems to be that a data dependent branch followed by an isync is     */
 
64
/* cheaper.  And the documentation is fairly explicit that this also    */
 
65
/* has acquire semantics.                                               */
 
66
/* ppc64 uses ld not lwz */
 
67
#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
 
68
AO_INLINE AO_t
 
69
AO_load_acquire(volatile AO_t *addr)
 
70
{
 
71
  AO_t result;
 
72
 
 
73
  /* FIXME: We should get gcc to allocate one of the condition  */
 
74
  /* registers.  I always got "impossible constraint" when I    */
 
75
  /* tried the "y" constraint.                                  */
 
76
  __asm__ __volatile__ (
 
77
    "ld %0,%1\n"
 
78
    "cmpw cr7,%0,%0\n"
 
79
    "bne- cr7,1f\n"
 
80
    "1: isync\n"
 
81
    : "=r" (result)
 
82
    : "m"(*addr) : "memory", "cc");
 
83
  return result;
 
84
}
 
85
#else
 
86
AO_INLINE AO_t
 
87
AO_load_acquire(volatile AO_t *addr)
 
88
{
 
89
  AO_t result;
 
90
 
 
91
  /* FIXME: We should get gcc to allocate one of the condition  */
 
92
  /* registers.  I always got "impossible constraint" when I    */
 
93
  /* tried the "y" constraint.                                  */
 
94
  __asm__ __volatile__ (
 
95
    "lwz%X1 %0,%1\n"
 
96
    "cmpw cr7,%0,%0\n"
 
97
    "bne- cr7,1f\n"
 
98
    "1: isync\n"
 
99
    : "=r" (result)
 
100
    : "m"(*addr) : "memory", "cc");
 
101
  return result;
 
102
}
 
103
#endif
 
104
#define AO_HAVE_load_acquire
 
105
 
 
106
/* We explicitly specify store_release, since it relies         */
 
107
/* on the fact that lwsync is also a LoadStore barrier.         */
 
108
AO_INLINE void
 
109
AO_store_release(volatile AO_t *addr, AO_t value)
 
110
{
 
111
  AO_lwsync();
 
112
  *addr = value;
 
113
}
 
114
 
 
115
#define AO_HAVE_load_acquire
 
116
 
 
117
/* This is similar to the code in the garbage collector.  Deleting      */
 
118
/* this and having it synthesized from compare_and_swap would probably  */
 
119
/* only cost us a load immediate instruction.                           */
 
120
#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
 
121
/* Completely untested.  And we should be using smaller objects anyway. */
 
122
AO_INLINE AO_TS_VAL_t
 
123
AO_test_and_set(volatile AO_TS_t *addr) {
 
124
  unsigned long oldval;
 
125
  unsigned long temp = 1; /* locked value */
 
126
 
 
127
  __asm__ __volatile__(
 
128
               "1:ldarx %0,0,%1\n"   /* load and reserve               */
 
129
               "cmpdi %0, 0\n"       /* if load is                     */
 
130
               "bne 2f\n"            /*   non-zero, return already set */
 
131
               "stdcx. %2,0,%1\n"    /* else store conditional         */
 
132
               "bne- 1b\n"           /* retry if lost reservation      */
 
133
               "2:\n"                /* oldval is zero if we set       */
 
134
              : "=&r"(oldval)
 
135
              : "r"(addr), "r"(temp)
 
136
              : "memory", "cc");
 
137
 
 
138
  return (AO_TS_VAL_t)oldval;
 
139
}
 
140
 
 
141
#else
 
142
 
 
143
AO_INLINE AO_TS_VAL_t
 
144
AO_test_and_set(volatile AO_TS_t *addr) {
 
145
  int oldval;
 
146
  int temp = 1; /* locked value */
 
147
 
 
148
  __asm__ __volatile__(
 
149
               "1:lwarx %0,0,%1\n"   /* load and reserve               */
 
150
               "cmpwi %0, 0\n"       /* if load is                     */
 
151
               "bne 2f\n"            /*   non-zero, return already set */
 
152
               "stwcx. %2,0,%1\n"    /* else store conditional         */
 
153
               "bne- 1b\n"           /* retry if lost reservation      */
 
154
               "2:\n"                /* oldval is zero if we set       */
 
155
              : "=&r"(oldval)
 
156
              : "r"(addr), "r"(temp)
 
157
              : "memory", "cc");
 
158
 
 
159
  return (AO_TS_VAL_t)oldval;
 
160
}
 
161
 
 
162
#endif
 
163
 
 
164
#define AO_have_test_and_set
 
165
 
 
166
AO_INLINE AO_TS_VAL_t
 
167
AO_test_and_set_acquire(volatile AO_TS_t *addr) {
 
168
  AO_TS_VAL_t result = AO_test_and_set(addr);
 
169
  AO_lwsync();
 
170
  return result;
 
171
}
 
172
 
 
173
#define AO_HAVE_test_and_set_acquire
 
174
 
 
175
AO_INLINE AO_TS_VAL_t
 
176
AO_test_and_set_release(volatile AO_TS_t *addr) {
 
177
  AO_lwsync();
 
178
  return AO_test_and_set(addr);
 
179
}
 
180
 
 
181
#define AO_HAVE_test_and_set_release
 
182
 
 
183
AO_INLINE AO_TS_VAL_t
 
184
AO_test_and_set_full(volatile AO_TS_t *addr) {
 
185
  AO_TS_VAL_t result;
 
186
  AO_lwsync();
 
187
  result = AO_test_and_set(addr);
 
188
  AO_lwsync();
 
189
  return result;
 
190
}
 
191
 
 
192
#define AO_HAVE_test_and_set_full
 
193
 
 
194
#if defined(__powerpc64__) || defined(__ppc64__) || defined(__64BIT__)
 
195
/* FIXME: Completely untested.  */
 
196
AO_INLINE int
 
197
AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {
 
198
  AO_t oldval;
 
199
  int result = 0;
 
200
 
 
201
  __asm__ __volatile__(
 
202
               "1:ldarx %0,0,%2\n"   /* load and reserve              */
 
203
               "cmpd %0, %4\n"      /* if load is not equal to  */
 
204
               "bne 2f\n"            /*   old, fail                     */
 
205
               "stdcx. %3,0,%2\n"    /* else store conditional         */
 
206
               "bne- 1b\n"           /* retry if lost reservation      */
 
207
               "li %1,1\n"           /* result = 1;                     */
 
208
               "2:\n"
 
209
              : "=&r"(oldval), "=&r"(result)
 
210
              : "r"(addr), "r"(new_val), "r"(old), "1"(result)
 
211
              : "memory", "cc");
 
212
 
 
213
  return result;
 
214
}
 
215
 
 
216
#else
 
217
 
 
218
AO_INLINE int
 
219
AO_compare_and_swap(volatile AO_t *addr, AO_t old, AO_t new_val) {
 
220
  AO_t oldval;
 
221
  int result = 0;
 
222
 
 
223
  __asm__ __volatile__(
 
224
               "1:lwarx %0,0,%2\n"   /* load and reserve              */
 
225
               "cmpw %0, %4\n"      /* if load is not equal to  */
 
226
               "bne 2f\n"            /*   old, fail                     */
 
227
               "stwcx. %3,0,%2\n"    /* else store conditional         */
 
228
               "bne- 1b\n"           /* retry if lost reservation      */
 
229
               "li %1,1\n"           /* result = 1;                     */
 
230
               "2:\n"
 
231
              : "=&r"(oldval), "=&r"(result)
 
232
              : "r"(addr), "r"(new_val), "r"(old), "1"(result)
 
233
              : "memory", "cc");
 
234
 
 
235
  return result;
 
236
}
 
237
#endif
 
238
 
 
239
#define AO_HAVE_compare_and_swap
 
240
 
 
241
AO_INLINE int
 
242
AO_compare_and_swap_acquire(volatile AO_t *addr, AO_t old, AO_t new_val) {
 
243
  int result = AO_compare_and_swap(addr, old, new_val);
 
244
  AO_lwsync();
 
245
  return result;
 
246
}
 
247
 
 
248
#define AO_HAVE_compare_and_swap_acquire
 
249
 
 
250
AO_INLINE int
 
251
AO_compare_and_swap_release(volatile AO_t *addr, AO_t old, AO_t new_val) {
 
252
  AO_lwsync();
 
253
  return AO_compare_and_swap(addr, old, new_val);
 
254
}
 
255
 
 
256
#define AO_HAVE_compare_and_swap_release
 
257
 
 
258
AO_INLINE int
 
259
AO_compare_and_swap_full(volatile AO_t *addr, AO_t old, AO_t new_val) {
 
260
  AO_t result;
 
261
  AO_lwsync();
 
262
  result = AO_compare_and_swap(addr, old, new_val);
 
263
  AO_lwsync();
 
264
  return result;
 
265
}
 
266
 
 
267
#define AO_HAVE_compare_and_swap_full
 
268
 
 
269
/* FIXME: We should also implement fetch_and_add and or primitives      */
 
270
/* directly.                                                            */