15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Protocol Buffers - Google's data interchange format
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2012 Google Inc.  All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://code.google.com/p/protobuf/
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met:
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions of source code must retain the above copyright
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions in binary form must reproduce the above
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Neither the name of Google Inc. nor the names of its
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is an internal atomic implementation, use atomicops.h instead.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace google {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace protobuf {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This struct is not part of the public API of this module; clients may not
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use it.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Features of this x86.  Values may not be correct before main() is run,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but are set conservatively.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct AtomicOps_x86CPUFeatureStruct {
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_amd_lock_mb_bug;  // Processor has AMD memory-barrier bug; do lfence
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             // after acquire compare-and-swap.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_sse2;             // Processor has SSE2.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 32-bit low-level operations on any platform.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         Atomic32 old_value,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         Atomic32 new_value) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic32 prev;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("lock; cmpxchgl %1,%2"
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "=a" (prev)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "q" (new_value), "m" (*ptr), "0" (old_value)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "memory");
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return prev;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         Atomic32 new_value) {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "=r" (new_value)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "m" (*ptr), "0" (new_value)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "memory");
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new_value;  // Now it's the previous value.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          Atomic32 increment) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic32 temp = increment;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("lock; xaddl %0,%1"
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "+r" (temp), "+m" (*ptr)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : : "memory");
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // temp now holds the old value of *ptr
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return temp + increment;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        Atomic32 increment) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic32 temp = increment;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("lock; xaddl %0,%1"
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "+r" (temp), "+m" (*ptr)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : : "memory");
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // temp now holds the old value of *ptr
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __asm__ __volatile__("lfence" : : : "memory");
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return temp + increment;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic32 old_value,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic32 new_value) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __asm__ __volatile__("lfence" : : : "memory");
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return x;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic32 old_value,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic32 new_value) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = value;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__x86_64__)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 64-bit implementations of memory barrier can be simpler, because it
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "mfence" is guaranteed to exist.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void MemoryBarrier() {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("mfence" : : : "memory");
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = value;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryBarrier();
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void MemoryBarrier() {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __asm__ __volatile__("mfence" : : : "memory");
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {  // mfence is faster but not present on PIII
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Atomic32 x = 0;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NoBarrier_AtomicExchange(&x, 0);  // acts as a barrier on PIII
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *ptr = value;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __asm__ __volatile__("mfence" : : : "memory");
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NoBarrier_AtomicExchange(ptr, value);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          // acts as a barrier on PIII
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ATOMICOPS_COMPILER_BARRIER();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = value;  // An x86 store acts as a release barrier.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See comments in Atomic64 version of Release_Store(), below.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *ptr;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic32 value = *ptr;  // An x86 load acts as a acquire barrier.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // See comments in Atomic64 version of Release_Store(), below.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ATOMICOPS_COMPILER_BARRIER();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryBarrier();
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *ptr;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(__x86_64__)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 64-bit low-level operations on 64-bit platform.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         Atomic64 old_value,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         Atomic64 new_value) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic64 prev;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("lock; cmpxchgq %1,%2"
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "=a" (prev)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "q" (new_value), "m" (*ptr), "0" (old_value)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "memory");
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return prev;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         Atomic64 new_value) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "=r" (new_value)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "m" (*ptr), "0" (new_value)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "memory");
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new_value;  // Now it's the previous value.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          Atomic64 increment) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic64 temp = increment;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("lock; xaddq %0,%1"
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "+r" (temp), "+m" (*ptr)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : : "memory");
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // temp now contains the previous value of *ptr
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return temp + increment;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        Atomic64 increment) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic64 temp = increment;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __asm__ __volatile__("lock; xaddq %0,%1"
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : "+r" (temp), "+m" (*ptr)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       : : "memory");
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // temp now contains the previous value of *ptr
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __asm__ __volatile__("lfence" : : : "memory");
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return temp + increment;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = value;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = value;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryBarrier();
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ATOMICOPS_COMPILER_BARRIER();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr = value;  // An x86 store acts as a release barrier
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 // for current AMD/Intel chips as of Jan 2008.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 // See also Acquire_Load(), below.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When new chips come out, check:
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  System Programming Guide, Chatper 7: Multiple-processor management,
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //  Section 7.2, Memory Ordering.
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Last seen at:
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // x86 stores/loads fail to act as barriers for a few instructions (clflush
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not generated by the compiler, and are rare.  Users of these instructions
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // need to know about cache behaviour in any case since all of these involve
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // either flushing cache lines or non-temporal cache hints.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *ptr;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic64 value = *ptr;  // An x86 load acts as a acquire barrier,
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          // for current AMD/Intel chips as of Jan 2008.
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          // See also Release_Store(), above.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ATOMICOPS_COMPILER_BARRIER();
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return value;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MemoryBarrier();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return *ptr;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic64 old_value,
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic64 new_value) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    __asm__ __volatile__("lfence" : : : "memory");
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return x;
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic64 old_value,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       Atomic64 new_value) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(__x86_64__)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace protobuf
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace google
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef ATOMICOPS_COMPILER_BARRIER
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
294