codekingpro/portable-devtools
114k
1/*-------------------------------------------------------------------------2 *3 * arch-ppc.h4 * Atomic operations considerations specific to PowerPC5 *6 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group7 * Portions Copyright (c) 1994, Regents of the University of California8 *9 * NOTES:10 *11 * src/include/port/atomics/arch-ppc.h12 *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 used21 * 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#endif27 28#define PG_HAVE_ATOMIC_U32_SUPPORT29typedef struct pg_atomic_uint3230{31 volatile uint32 value;32} pg_atomic_uint32;33 34/* 64bit atomics are only supported in 64bit mode */35#if SIZEOF_VOID_P >= 836#define PG_HAVE_ATOMIC_U64_SUPPORT37typedef struct pg_atomic_uint6438{39 volatile uint64 value pg_attribute_aligned(8);40} pg_atomic_uint64;41 42#endif43 44/*45 * This mimics gcc __atomic_compare_exchange_n(..., __ATOMIC_SEQ_CST), but46 * code generation differs at the end. __atomic_compare_exchange_n():47 * 100: isync48 * 104: mfcr r349 * 108: rlwinm r3,r3,3,31,3150 * 10c: bne 120 <.eb+0x10>51 * 110: clrldi r3,r3,6352 * 114: addi r1,r1,11253 * 118: blr54 * 11c: nop55 * 120: clrldi r3,r3,6356 * 124: stw r9,0(r4)57 * 128: addi r1,r1,11258 * 12c: blr59 *60 * This:61 * f0: isync62 * f4: mfcr r963 * f8: rldicl. r3,r9,35,6364 * fc: bne 104 <.eb>65 * 100: stw r10,0(r4)66 * 104: addi r1,r1,11267 * 108: blr68 *69 * This implementation may or may not have materially different performance.70 * It's not exploiting the fact that cr0 still holds the relevant comparison71 * bits, set during the __asm__. One could fix that by moving more code into72 * the __asm__. (That would remove the freedom to eliminate dead stores when73 * the caller ignores "expected", but few callers do.)74 *75 * Recognizing constant "newval" would be superfluous, because there's no76 * immediate-operand version of stwcx.77 */78#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U3279static inline bool80pg_atomic_compare_exchange_u32_impl(volatile pg_atomic_uint32 *ptr,81 uint32 *expected, uint32 newval)82{83 uint32 found;84 uint32 condition_register;85 bool ret;86 87#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P88 if (__builtin_constant_p(*expected) &&89 (int32) *expected <= PG_INT16_MAX &&90 (int32) *expected >= PG_INT16_MIN)91 __asm__ __volatile__(92 " sync \n"93 " lwarx %0,0,%5,1 \n"94 " cmpwi %0,%3 \n"95 " bne $+12 \n" /* branch to lwsync */96 " stwcx. %4,0,%5 \n"97 " bne $-16 \n" /* branch to lwarx */98 " lwsync \n"99 " mfcr %1 \n"100: "=&r"(found), "=r"(condition_register), "+m"(ptr->value)101: "i"(*expected), "r"(newval), "r"(&ptr->value)102: "memory", "cc");103 else104#endif105 __asm__ __volatile__(106 " sync \n"107 " lwarx %0,0,%5,1 \n"108 " cmpw %0,%3 \n"109 " bne $+12 \n" /* branch to lwsync */110 " stwcx. %4,0,%5 \n"111 " bne $-16 \n" /* branch to lwarx */112 " lwsync \n"113 " mfcr %1 \n"114: "=&r"(found), "=r"(condition_register), "+m"(ptr->value)115: "r"(*expected), "r"(newval), "r"(&ptr->value)116: "memory", "cc");117 118 ret = (condition_register >> 29) & 1; /* test eq bit of cr0 */119 if (!ret)120 *expected = found;121 return ret;122}123 124/*125 * This mirrors gcc __sync_fetch_and_add().126 *127 * Like tas(), use constraint "=&b" to avoid allocating r0.128 */129#define PG_HAVE_ATOMIC_FETCH_ADD_U32130static inline uint32131pg_atomic_fetch_add_u32_impl(volatile pg_atomic_uint32 *ptr, int32 add_)132{133 uint32 _t;134 uint32 res;135 136#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P137 if (__builtin_constant_p(add_) &&138 add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)139 __asm__ __volatile__(140 " sync \n"141 " lwarx %1,0,%4,1 \n"142 " addi %0,%1,%3 \n"143 " stwcx. %0,0,%4 \n"144 " bne $-12 \n" /* branch to lwarx */145 " lwsync \n"146: "=&r"(_t), "=&b"(res), "+m"(ptr->value)147: "i"(add_), "r"(&ptr->value)148: "memory", "cc");149 else150#endif151 __asm__ __volatile__(152 " sync \n"153 " lwarx %1,0,%4,1 \n"154 " add %0,%1,%3 \n"155 " stwcx. %0,0,%4 \n"156 " bne $-12 \n" /* branch to lwarx */157 " lwsync \n"158: "=&r"(_t), "=&r"(res), "+m"(ptr->value)159: "r"(add_), "r"(&ptr->value)160: "memory", "cc");161 162 return res;163}164 165#ifdef PG_HAVE_ATOMIC_U64_SUPPORT166 167#define PG_HAVE_ATOMIC_COMPARE_EXCHANGE_U64168static inline bool169pg_atomic_compare_exchange_u64_impl(volatile pg_atomic_uint64 *ptr,170 uint64 *expected, uint64 newval)171{172 uint64 found;173 uint32 condition_register;174 bool ret;175 176 /* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/; s/cmpw/cmpd/ */177#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P178 if (__builtin_constant_p(*expected) &&179 (int64) *expected <= PG_INT16_MAX &&180 (int64) *expected >= PG_INT16_MIN)181 __asm__ __volatile__(182 " sync \n"183 " ldarx %0,0,%5,1 \n"184 " cmpdi %0,%3 \n"185 " bne $+12 \n" /* branch to lwsync */186 " stdcx. %4,0,%5 \n"187 " bne $-16 \n" /* branch to ldarx */188 " lwsync \n"189 " mfcr %1 \n"190: "=&r"(found), "=r"(condition_register), "+m"(ptr->value)191: "i"(*expected), "r"(newval), "r"(&ptr->value)192: "memory", "cc");193 else194#endif195 __asm__ __volatile__(196 " sync \n"197 " ldarx %0,0,%5,1 \n"198 " cmpd %0,%3 \n"199 " bne $+12 \n" /* branch to lwsync */200 " stdcx. %4,0,%5 \n"201 " bne $-16 \n" /* branch to ldarx */202 " lwsync \n"203 " mfcr %1 \n"204: "=&r"(found), "=r"(condition_register), "+m"(ptr->value)205: "r"(*expected), "r"(newval), "r"(&ptr->value)206: "memory", "cc");207 208 ret = (condition_register >> 29) & 1; /* test eq bit of cr0 */209 if (!ret)210 *expected = found;211 return ret;212}213 214#define PG_HAVE_ATOMIC_FETCH_ADD_U64215static inline uint64216pg_atomic_fetch_add_u64_impl(volatile pg_atomic_uint64 *ptr, int64 add_)217{218 uint64 _t;219 uint64 res;220 221 /* Like u32, but s/lwarx/ldarx/; s/stwcx/stdcx/ */222#ifdef HAVE_I_CONSTRAINT__BUILTIN_CONSTANT_P223 if (__builtin_constant_p(add_) &&224 add_ <= PG_INT16_MAX && add_ >= PG_INT16_MIN)225 __asm__ __volatile__(226 " sync \n"227 " ldarx %1,0,%4,1 \n"228 " addi %0,%1,%3 \n"229 " stdcx. %0,0,%4 \n"230 " bne $-12 \n" /* branch to ldarx */231 " lwsync \n"232: "=&r"(_t), "=&b"(res), "+m"(ptr->value)233: "i"(add_), "r"(&ptr->value)234: "memory", "cc");235 else236#endif237 __asm__ __volatile__(238 " sync \n"239 " ldarx %1,0,%4,1 \n"240 " add %0,%1,%3 \n"241 " stdcx. %0,0,%4 \n"242 " bne $-12 \n" /* branch to ldarx */243 " lwsync \n"244: "=&r"(_t), "=&r"(res), "+m"(ptr->value)245: "r"(add_), "r"(&ptr->value)246: "memory", "cc");247 248 return res;249}250 251#endif /* PG_HAVE_ATOMIC_U64_SUPPORT */252 253/* per architecture manual doubleword accesses have single copy atomicity */254#define PG_HAVE_8BYTE_SINGLE_COPY_ATOMICITY255 