PostgreSQL Source Code  git master
arch-ppc.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * arch-ppc.h
4  * Atomic operations considerations specific to PowerPC
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * NOTES:
10  *
11  * src/include/port/atomics/arch-ppc.h
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #if defined(__GNUC__)
17 
18 /*
19  * lwsync orders loads with respect to each other, and similarly with stores.
20  * But a load can be performed before a subsequent store, so sync must be used
21  * for a full memory barrier.
22  */
23 #define pg_memory_barrier_impl() __asm__ __volatile__ ("sync" : : : "memory")
24 #define pg_read_barrier_impl() __asm__ __volatile__ ("lwsync" : : : "memory")
25 #define pg_write_barrier_impl() __asm__ __volatile__ ("lwsync" : : : "memory")
26 #endif
27 
28 #define PG_HAVE_ATOMIC_U32_SUPPORT
29 typedef struct pg_atomic_uint32
30 {
31  volatile uint32 value;
33 
34 /* 64bit atomics are only supported in 64bit mode */
35 #ifdef __64BIT__
36 #define PG_HAVE_ATOMIC_U64_SUPPORT
37 typedef struct pg_atomic_uint64
38 {
39  volatile uint64 value pg_attribute_aligned(8);
41 
42 #endif /* __64BIT__ */
43 
44 /*
45  * This mimics gcc __atomic_compare_exchange_n(..., __ATOMIC_SEQ_CST), but
46  * code generation differs at the end. __atomic_compare_exchange_n():
47  * 100: isync
48  * 104: mfcr r3
49  * 108: rlwinm r3,r3,3,31,31
50  * 10c: bne 120 <.eb+0x10>
51  * 110: clrldi r3,r3,63
52  * 114: addi r1,r1,112
53  * 118: blr
54  * 11c: nop
55  * 120: clrldi r3,r3,63
56  * 124: stw r9,0(r4)
57  * 128: addi r1,r1,112
58  * 12c: blr
59  *
60  * This:
61  * f0: isync
62  * f4: mfcr r9
63  * f8: rldicl. r3,r9,35,63
64  * fc: bne 104 <.eb>
65  * 100: stw r10,0(r4)
66  * 104: addi r1,r1,112
67  * 108: blr
68  *
69  * This implementation may or may not have materially different performance.
70  * It's not exploiting the fact that cr0 still holds the relevant comparison
71  * bits, set during the __asm__. One could fix that by moving more code into
72  * the __asm__. (That would remove the freedom to eliminate dead stores when
73  * the caller ignores "expected", but few callers do.)
74  *
75  * The cmpwi variant may be dead code. In gcc 7.2.0,
76  * __builtin_constant_p(*expected) always reports false.
77  * __atomic_compare_exchange_n() does use cmpwi when its second argument
78  * points to a constant. Hence, using this instead of
79  * __atomic_compare_exchange_n() nominally penalizes the generic.h
80  * pg_atomic_test_set_flag_impl(). Modern GCC will use the generic-gcc.h
81  * version, making the penalty theoretical only.
82  *
83  * Recognizing constant "newval" would be superfluous, because there's no
84  * immediate-operand version of stwcx.
85  */
86 #define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U32
87 static inline bool
89  uint32 *expected, uint32 newval)
90 {
91  uint32 found;
92  uint32 condition_register;
93  bool ret;
94 
95 #ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
96  if (__builtin_constant_p(*expected) &&
97  *expected <= PG_INT16_MAX && *expected >= PG_INT16_MIN)
98  __asm__ __volatile__(
99  " sync \n"
100  " lwarx %0,0,%5 \n"
101  " cmpwi %0,%3 \n"
102  " bne $+12 \n" /* branch to isync */
103  " stwcx. %4,0,%5 \n"
104  " bne $-16 \n" /* branch to lwarx */
105  " isync \n"
106  " mfcr %1 \n"
107 : "=&r"(found), "=r"(condition_register), "+m"(ptr->value)
108 : "i"(*expected), "r"(newval), "r"(&ptr->value)
109 : "memory", "cc");
110  else
111 #endif
112  __asm__ __volatile__(
113  " sync \n"
114  " lwarx %0,0,%5 \n"
115  " cmpw %0,%3 \n"
116  " bne $+12 \n" /* branch to isync */
117  " stwcx. %4,0,%5 \n"
118  " bne $-16 \n" /* branch to lwarx */
119  " isync \n"
120  " mfcr %1 \n"
121 : "=&r"(found), "=r"(condition_register), "+m"(ptr->value)
122 : "r"(*expected), "r"(newval), "r"(&ptr->value)
123 : "memory", "cc");
124 
125  ret = (condition_register >> 29) & 1; /* test eq bit of cr0 */
126  if (!ret)
127  *expected = found;
128  return ret;
129 }
130 
131 /*
132  * This mirrors gcc __sync_fetch_and_add().
133  *
134  * Like tas(), use constraint "=&b" to avoid allocating r0.
135  */
136 #define PG_HAVE_ATOMIC_FETCH_ADD_U32
137 static inline uint32
139 {
140  uint32 _t;
141  uint32 res;
142 
143 #ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
144  if (__builtin_constant_p(add_) &&
145  add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)
146  __asm__ __volatile__(
147  " sync \n"
148  " lwarx %1,0,%4 \n"
149  " addi %0,%1,%3 \n"
150  " stwcx. %0,0,%4 \n"
151  " bne $-12 \n" /* branch to lwarx */
152  " isync \n"
153 : "=&r"(_t), "=&b"(res), "+m"(ptr->value)
154 : "i"(add_), "r"(&ptr->value)
155 : "memory", "cc");
156  else
157 #endif
158  __asm__ __volatile__(
159  " sync \n"
160  " lwarx %1,0,%4 \n"
161  " add %0,%1,%3 \n"
162  " stwcx. %0,0,%4 \n"
163  " bne $-12 \n" /* branch to lwarx */
164  " isync \n"
165 : "=&r"(_t), "=&r"(res), "+m"(ptr->value)
166 : "r"(add_), "r"(&ptr->value)
167 : "memory", "cc");
168 
169  return res;
170 }
171 
172 #ifdef PG_HAVE_ATOMIC_U64_SUPPORT
173 
174 #define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64
175 static inline bool
177  uint64 *expected, uint64 newval)
178 {
179  uint64 found;
180  uint32 condition_register;
181  bool ret;
182 
183  /* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/; s/cmpw/cmpd/ */
184 #ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
185  if (__builtin_constant_p(*expected) &&
186  *expected <= PG_INT16_MAX && *expected >= PG_INT16_MIN)
187  __asm__ __volatile__(
188  " sync \n"
189  " ldarx %0,0,%5 \n"
190  " cmpdi %0,%3 \n"
191  " bne $+12 \n" /* branch to isync */
192  " stdcx. %4,0,%5 \n"
193  " bne $-16 \n" /* branch to ldarx */
194  " isync \n"
195  " mfcr %1 \n"
196 : "=&r"(found), "=r"(condition_register), "+m"(ptr->value)
197 : "i"(*expected), "r"(newval), "r"(&ptr->value)
198 : "memory", "cc");
199  else
200 #endif
201  __asm__ __volatile__(
202  " sync \n"
203  " ldarx %0,0,%5 \n"
204  " cmpd %0,%3 \n"
205  " bne $+12 \n" /* branch to isync */
206  " stdcx. %4,0,%5 \n"
207  " bne $-16 \n" /* branch to ldarx */
208  " isync \n"
209  " mfcr %1 \n"
210 : "=&r"(found), "=r"(condition_register), "+m"(ptr->value)
211 : "r"(*expected), "r"(newval), "r"(&ptr->value)
212 : "memory", "cc");
213 
214  ret = (condition_register >> 29) & 1; /* test eq bit of cr0 */
215  if (!ret)
216  *expected = found;
217  return ret;
218 }
219 
220 #define PG_HAVE_ATOMIC_FETCH_ADD_U64
221 static inline uint64
222 pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
223 {
224  uint64 _t;
225  uint64 res;
226 
227  /* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/ */
228 #ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P
229  if (__builtin_constant_p(add_) &&
230  add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)
231  __asm__ __volatile__(
232  " sync \n"
233  " ldarx %1,0,%4 \n"
234  " addi %0,%1,%3 \n"
235  " stdcx. %0,0,%4 \n"
236  " bne $-12 \n" /* branch to ldarx */
237  " isync \n"
238 : "=&r"(_t), "=&b"(res), "+m"(ptr->value)
239 : "i"(add_), "r"(&ptr->value)
240 : "memory", "cc");
241  else
242 #endif
243  __asm__ __volatile__(
244  " sync \n"
245  " ldarx %1,0,%4 \n"
246  " add %0,%1,%3 \n"
247  " stdcx. %0,0,%4 \n"
248  " bne $-12 \n" /* branch to ldarx */
249  " isync \n"
250 : "=&r"(_t), "=&r"(res), "+m"(ptr->value)
251 : "r"(add_), "r"(&ptr->value)
252 : "memory", "cc");
253 
254  return res;
255 }
256 
257 #endif /* PG_HAVE_ATOMIC_U64_SUPPORT */
258 
259 /* per architecture manual doubleword accesses have single copy atomicity */
260 #define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY
static bool pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval)
Definition: arch-ppc.h:88
struct pg_atomic_uint32 pg_atomic_uint32
static uint32 pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)
Definition: arch-ppc.h:138
bool pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr, uint64 *expected, uint64 newval)
Definition: atomics.c:200
struct pg_atomic_uint64 pg_atomic_uint64
volatile uint32 value
Definition: arch-ppc.h:31
signed int int32
Definition: c.h:347
uint64 pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)
Definition: atomics.c:228
unsigned int uint32
Definition: c.h:359
volatile uint64 value
Definition: fallback.h:119
#define PG_INT16_MIN
Definition: c.h:438
#define newval