Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // This file is an internal atomic implementation, use base/atomicops.h instead.
      6 //
      7 // LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
      8 
      9 #ifndef BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
     10 #define BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
     11 #pragma once
     12 
     13 #define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
     14 
     15 namespace base {
     16 namespace subtle {
     17 
     18 // Atomically execute:
     19 //      result = *ptr;
     20 //      if (*ptr == old_value)
     21 //        *ptr = new_value;
     22 //      return result;
     23 //
     24 // I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
     25 // Always return the old value of "*ptr"
     26 //
     27 // This routine implies no memory barriers.
     28 inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
     29                                          Atomic32 old_value,
     30                                          Atomic32 new_value) {
     31   Atomic32 prev, tmp;
     32   __asm__ __volatile__(".set push\n"
     33                        ".set noreorder\n"
     34                        "1:\n"
     35                        "ll %0, %5\n"  // prev = *ptr
     36                        "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
     37                        "move %2, %4\n"  // tmp = new_value
     38                        "sc %2, %1\n"  // *ptr = tmp (with atomic check)
     39                        "beqz %2, 1b\n"  // start again on atomic error
     40                        "nop\n"  // delay slot nop
     41                        "2:\n"
     42                        ".set pop\n"
     43                        : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
     44                        : "Ir" (old_value), "r" (new_value), "m" (*ptr)
     45                        : "memory");
     46   return prev;
     47 }
     48 
     49 // Atomically store new_value into *ptr, returning the previous value held in
     50 // *ptr.  This routine implies no memory barriers.
     51 inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
     52                                          Atomic32 new_value) {
     53   Atomic32 temp, old;
     54   __asm__ __volatile__(".set push\n"
     55                        ".set noreorder\n"
     56                        "1:\n"
     57                        "ll %1, %2\n"  // old = *ptr
     58                        "move %0, %3\n"  // temp = new_value
     59                        "sc %0, %2\n"  // *ptr = temp (with atomic check)
     60                        "beqz %0, 1b\n"  // start again on atomic error
     61                        "nop\n"  // delay slot nop
     62                        ".set pop\n"
     63                        : "=&r" (temp), "=&r" (old), "=m" (*ptr)
     64                        : "r" (new_value), "m" (*ptr)
     65                        : "memory");
     66 
     67   return old;
     68 }
     69 
     70 // Atomically increment *ptr by "increment".  Returns the new value of
     71 // *ptr with the increment applied.  This routine implies no memory barriers.
     72 inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
     73                                           Atomic32 increment) {
     74   Atomic32 temp, temp2;
     75 
     76   __asm__ __volatile__(".set push\n"
     77                        ".set noreorder\n"
     78                        "1:\n"
     79                        "ll %0, %2\n"  // temp = *ptr
     80                        "addu %1, %0, %3\n"  // temp2 = temp + increment
     81                        "sc %1, %2\n"  // *ptr = temp2 (with atomic check)
     82                        "beqz %1, 1b\n"  // start again on atomic error
     83                        "addu %1, %0, %3\n"  // temp2 = temp + increment
     84                        ".set pop\n"
     85                        : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
     86                        : "Ir" (increment), "m" (*ptr)
     87                        : "memory");
     88   // temp2 now holds the final value.
     89   return temp2;
     90 }
     91 
     92 inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
     93                                         Atomic32 increment) {
     94   ATOMICOPS_COMPILER_BARRIER();
     95   Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
     96   ATOMICOPS_COMPILER_BARRIER();
     97   return res;
     98 }
     99 
    100 // "Acquire" operations
    101 // ensure that no later memory access can be reordered ahead of the operation.
    102 // "Release" operations ensure that no previous memory access can be reordered
    103 // after the operation.  "Barrier" operations have both "Acquire" and "Release"
    104 // semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
    105 // access.
    106 inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
    107                                        Atomic32 old_value,
    108                                        Atomic32 new_value) {
    109   ATOMICOPS_COMPILER_BARRIER();
    110   Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
    111   ATOMICOPS_COMPILER_BARRIER();
    112   return res;
    113 }
    114 
    115 inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
    116                                        Atomic32 old_value,
    117                                        Atomic32 new_value) {
    118   ATOMICOPS_COMPILER_BARRIER();
    119   Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
    120   ATOMICOPS_COMPILER_BARRIER();
    121   return res;
    122 }
    123 
    124 inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
    125   *ptr = value;
    126 }
    127 
    128 inline void MemoryBarrier() {
    129   __asm__ __volatile__("sync" : : : "memory");
    130 }
    131 
    132 inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
    133   *ptr = value;
    134   MemoryBarrier();
    135 }
    136 
    137 inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
    138   MemoryBarrier();
    139   *ptr = value;
    140 }
    141 
    142 inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
    143   return *ptr;
    144 }
    145 
    146 inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
    147   Atomic32 value = *ptr;
    148   MemoryBarrier();
    149   return value;
    150 }
    151 
    152 inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
    153   MemoryBarrier();
    154   return *ptr;
    155 }
    156 
    157 } // namespace base::subtle
    158 } // namespace base
    159 
    160 #undef ATOMICOPS_COMPILER_BARRIER
    161 
    162 #endif  // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
    163