ipc/chromium/src/base/atomicops_internals_x86_gcc.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/base/atomicops_internals_x86_gcc.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,259 @@
     1.4 +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
     1.5 +// Use of this source code is governed by a BSD-style license that can be
     1.6 +// found in the LICENSE file.
     1.7 +
     1.8 +// This file is an internal atomic implementation, use base/atomicops.h instead.
     1.9 +
    1.10 +#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
    1.11 +#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
    1.12 +
    1.13 +// This struct is not part of the public API of this module; clients may not
    1.14 +// use it.
    1.15 +// Features of this x86.  Values may not be correct before main() is run,
    1.16 +// but are set conservatively.
    1.17 +struct AtomicOps_x86CPUFeatureStruct {
    1.18 +  bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
    1.19 +                            // after acquire compare-and-swap.
    1.20 +  bool has_sse2;            // Processor has SSE2.
    1.21 +};
    1.22 +extern struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures;
    1.23 +
    1.24 +#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
    1.25 +
    1.26 +namespace base {
    1.27 +namespace subtle {
    1.28 +
    1.29 +// 32-bit low-level operations on any platform.
    1.30 +
    1.31 +inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
    1.32 +                                         Atomic32 old_value,
    1.33 +                                         Atomic32 new_value) {
    1.34 +  Atomic32 prev;
    1.35 +  __asm__ __volatile__("lock; cmpxchgl %1,%2"
    1.36 +                       : "=a" (prev)
    1.37 +                       : "q" (new_value), "m" (*ptr), "0" (old_value)
    1.38 +                       : "memory");
    1.39 +  return prev;
    1.40 +}
    1.41 +
    1.42 +inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
    1.43 +                                         Atomic32 new_value) {
    1.44 +  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
    1.45 +                       : "=r" (new_value)
    1.46 +                       : "m" (*ptr), "0" (new_value)
    1.47 +                       : "memory");
    1.48 +  return new_value;  // Now it's the previous value.
    1.49 +}
    1.50 +
    1.51 +inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
    1.52 +                                          Atomic32 increment) {
    1.53 +  Atomic32 temp = increment;
    1.54 +  __asm__ __volatile__("lock; xaddl %0,%1"
    1.55 +                       : "+r" (temp), "+m" (*ptr)
    1.56 +                       : : "memory");
    1.57 +  // temp now holds the old value of *ptr
    1.58 +  return temp + increment;
    1.59 +}
    1.60 +
    1.61 +inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
    1.62 +                                        Atomic32 increment) {
    1.63 +  Atomic32 temp = increment;
    1.64 +  __asm__ __volatile__("lock; xaddl %0,%1"
    1.65 +                       : "+r" (temp), "+m" (*ptr)
    1.66 +                       : : "memory");
    1.67 +  // temp now holds the old value of *ptr
    1.68 +  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
    1.69 +    __asm__ __volatile__("lfence" : : : "memory");
    1.70 +  }
    1.71 +  return temp + increment;
    1.72 +}
    1.73 +
    1.74 +inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
    1.75 +                                       Atomic32 old_value,
    1.76 +                                       Atomic32 new_value) {
    1.77 +  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
    1.78 +  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
    1.79 +    __asm__ __volatile__("lfence" : : : "memory");
    1.80 +  }
    1.81 +  return x;
    1.82 +}
    1.83 +
    1.84 +inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
    1.85 +                                       Atomic32 old_value,
    1.86 +                                       Atomic32 new_value) {
    1.87 +  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
    1.88 +}
    1.89 +
    1.90 +inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
    1.91 +  *ptr = value;
    1.92 +}
    1.93 +
    1.94 +#if defined(__x86_64__)
    1.95 +
    1.96 +// 64-bit implementations of memory barrier can be simpler, because it
    1.97 +// "mfence" is guaranteed to exist.
    1.98 +inline void MemoryBarrier() {
    1.99 +  __asm__ __volatile__("mfence" : : : "memory");
   1.100 +}
   1.101 +
   1.102 +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
   1.103 +  *ptr = value;
   1.104 +  MemoryBarrier();
   1.105 +}
   1.106 +
   1.107 +#else
   1.108 +
   1.109 +inline void MemoryBarrier() {
   1.110 +  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
   1.111 +    __asm__ __volatile__("mfence" : : : "memory");
   1.112 +  } else { // mfence is faster but not present on PIII
   1.113 +    Atomic32 x = 0;
   1.114 +    NoBarrier_AtomicExchange(&x, 0);  // acts as a barrier on PIII
   1.115 +  }
   1.116 +}
   1.117 +
   1.118 +inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
   1.119 +  if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
   1.120 +    *ptr = value;
   1.121 +    __asm__ __volatile__("mfence" : : : "memory");
   1.122 +  } else {
   1.123 +    NoBarrier_AtomicExchange(ptr, value);
   1.124 +                          // acts as a barrier on PIII
   1.125 +  }
   1.126 +}
   1.127 +#endif
   1.128 +
   1.129 +inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
   1.130 +  ATOMICOPS_COMPILER_BARRIER();
   1.131 +  *ptr = value; // An x86 store acts as a release barrier.
   1.132 +  // See comments in Atomic64 version of Release_Store(), below.
   1.133 +}
   1.134 +
   1.135 +inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
   1.136 +  return *ptr;
   1.137 +}
   1.138 +
   1.139 +inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
   1.140 +  Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
   1.141 +  // See comments in Atomic64 version of Release_Store(), below.
   1.142 +  ATOMICOPS_COMPILER_BARRIER();
   1.143 +  return value;
   1.144 +}
   1.145 +
   1.146 +inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
   1.147 +  MemoryBarrier();
   1.148 +  return *ptr;
   1.149 +}
   1.150 +
   1.151 +#if defined(__x86_64__)
   1.152 +
   1.153 +// 64-bit low-level operations on 64-bit platform.
   1.154 +
   1.155 +inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
   1.156 +                                         Atomic64 old_value,
   1.157 +                                         Atomic64 new_value) {
   1.158 +  Atomic64 prev;
   1.159 +  __asm__ __volatile__("lock; cmpxchgq %1,%2"
   1.160 +                       : "=a" (prev)
   1.161 +                       : "q" (new_value), "m" (*ptr), "0" (old_value)
   1.162 +                       : "memory");
   1.163 +  return prev;
   1.164 +}
   1.165 +
   1.166 +inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
   1.167 +                                         Atomic64 new_value) {
   1.168 +  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
   1.169 +                       : "=r" (new_value)
   1.170 +                       : "m" (*ptr), "0" (new_value)
   1.171 +                       : "memory");
   1.172 +  return new_value;  // Now it's the previous value.
   1.173 +}
   1.174 +
   1.175 +inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
   1.176 +                                          Atomic64 increment) {
   1.177 +  Atomic64 temp = increment;
   1.178 +  __asm__ __volatile__("lock; xaddq %0,%1"
   1.179 +                       : "+r" (temp), "+m" (*ptr)
   1.180 +                       : : "memory");
   1.181 +  // temp now contains the previous value of *ptr
   1.182 +  return temp + increment;
   1.183 +}
   1.184 +
   1.185 +inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
   1.186 +                                        Atomic64 increment) {
   1.187 +  Atomic64 temp = increment;
   1.188 +  __asm__ __volatile__("lock; xaddq %0,%1"
   1.189 +                       : "+r" (temp), "+m" (*ptr)
   1.190 +                       : : "memory");
   1.191 +  // temp now contains the previous value of *ptr
   1.192 +  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
   1.193 +    __asm__ __volatile__("lfence" : : : "memory");
   1.194 +  }
   1.195 +  return temp + increment;
   1.196 +}
   1.197 +
   1.198 +inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
   1.199 +  *ptr = value;
   1.200 +}
   1.201 +
   1.202 +inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
   1.203 +                                       Atomic64 old_value,
   1.204 +                                       Atomic64 new_value) {
   1.205 +  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
   1.206 +  /* XXX/cjones: no idea if this is necessary... */
   1.207 +  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
   1.208 +    __asm__ __volatile__("lfence" : : : "memory");
   1.209 +  }
   1.210 +  return x;
   1.211 +}
   1.212 +
   1.213 +inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
   1.214 +  *ptr = value;
   1.215 +  MemoryBarrier();
   1.216 +}
   1.217 +
   1.218 +inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
   1.219 +  ATOMICOPS_COMPILER_BARRIER();
   1.220 +
   1.221 +  *ptr = value; // An x86 store acts as a release barrier
   1.222 +                // for current AMD/Intel chips as of Jan 2008.
   1.223 +                // See also Acquire_Load(), below.
   1.224 +
   1.225 +  // When new chips come out, check:
   1.226 +  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
   1.227 +  //  System Programming Guide, Chatper 7: Multiple-processor management,
   1.228 +  //  Section 7.2, Memory Ordering.
   1.229 +  // Last seen at:
   1.230 +  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
   1.231 +  //
   1.232 +  // x86 stores/loads fail to act as barriers for a few instructions (clflush
   1.233 +  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
   1.234 +  // not generated by the compiler, and are rare.  Users of these instructions
   1.235 +  // need to know about cache behaviour in any case since all of these involve
   1.236 +  // either flushing cache lines or non-temporal cache hints.
   1.237 +}
   1.238 +
   1.239 +inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
   1.240 +  return *ptr;
   1.241 +}
   1.242 +
   1.243 +inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
   1.244 +  Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
   1.245 +                         // for current AMD/Intel chips as of Jan 2008.
   1.246 +                         // See also Release_Store(), above.
   1.247 +  ATOMICOPS_COMPILER_BARRIER();
   1.248 +  return value;
   1.249 +}
   1.250 +
   1.251 +inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
   1.252 +  MemoryBarrier();
   1.253 +  return *ptr;
   1.254 +}
   1.255 +#endif  // defined(__x86_64__)
   1.256 +
   1.257 +} // namespace base::subtle
   1.258 +} // namespace base
   1.259 +
   1.260 +#undef ATOMICOPS_COMPILER_BARRIER
   1.261 +
   1.262 +#endif  // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_

mercurial