(root)/
gcc-13.2.0/
libsanitizer/
sanitizer_common/
sanitizer_atomic_clang_mips.h
       1  //===-- sanitizer_atomic_clang_mips.h ---------------------------*- C++ -*-===//
       2  //
       3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
       4  // See https://llvm.org/LICENSE.txt for license information.
       5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
       6  //
       7  //===----------------------------------------------------------------------===//
       8  //
       9  // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
      10  // Not intended for direct inclusion. Include sanitizer_atomic.h.
      11  //
      12  //===----------------------------------------------------------------------===//
      13  
      14  #ifndef SANITIZER_ATOMIC_CLANG_MIPS_H
      15  #define SANITIZER_ATOMIC_CLANG_MIPS_H
      16  
      17  namespace __sanitizer {
      18  
      19  // MIPS32 does not support atomics > 4 bytes. To address this lack of
      20  // functionality, the sanitizer library provides helper methods which use an
      21  // internal spin lock mechanism to emulate atomic operations when the size is
      22  // 8 bytes.
      23  static void __spin_lock(volatile int *lock) {
      24    while (__sync_lock_test_and_set(lock, 1))
      25      while (*lock) {
      26      }
      27  }
      28  
      29  static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); }
      30  
      31  // Make sure the lock is on its own cache line to prevent false sharing.
      32  // Put it inside a struct that is aligned and padded to the typical MIPS
      33  // cacheline which is 32 bytes.
      34  static struct {
      35    int lock;
      36    char pad[32 - sizeof(int)];
      37  } __attribute__((aligned(32))) lock = {0, {0}};
      38  
      39  template <>
      40  inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
      41                                                atomic_uint64_t::Type val,
      42                                                memory_order mo) {
      43    DCHECK(mo &
      44           (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
      45    DCHECK(!((uptr)ptr % sizeof(*ptr)));
      46  
      47    atomic_uint64_t::Type ret;
      48  
      49    __spin_lock(&lock.lock);
      50    ret = *(const_cast<atomic_uint64_t::Type volatile *>(&ptr->val_dont_use));
      51    ptr->val_dont_use = ret + val;
      52    __spin_unlock(&lock.lock);
      53  
      54    return ret;
      55  }
      56  
      57  template <>
      58  inline atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr,
      59                                                atomic_uint64_t::Type val,
      60                                                memory_order mo) {
      61    return atomic_fetch_add(ptr, -val, mo);
      62  }
      63  
      64  template <>
      65  inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
      66                                             atomic_uint64_t::Type *cmp,
      67                                             atomic_uint64_t::Type xchg,
      68                                             memory_order mo) {
      69    DCHECK(mo &
      70           (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
      71    DCHECK(!((uptr)ptr % sizeof(*ptr)));
      72  
      73    typedef atomic_uint64_t::Type Type;
      74    Type cmpv = *cmp;
      75    Type prev;
      76    bool ret = false;
      77  
      78    __spin_lock(&lock.lock);
      79    prev = *(const_cast<Type volatile *>(&ptr->val_dont_use));
      80    if (prev == cmpv) {
      81      ret = true;
      82      ptr->val_dont_use = xchg;
      83    }
      84    __spin_unlock(&lock.lock);
      85  
      86    return ret;
      87  }
      88  
      89  template <>
      90  inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
      91                                           memory_order mo) {
      92    DCHECK(mo &
      93           (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
      94    DCHECK(!((uptr)ptr % sizeof(*ptr)));
      95  
      96    atomic_uint64_t::Type zero = 0;
      97    volatile atomic_uint64_t *Newptr =
      98        const_cast<volatile atomic_uint64_t *>(ptr);
      99    return atomic_fetch_add(Newptr, zero, mo);
     100  }
     101  
     102  template <>
     103  inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
     104                           memory_order mo) {
     105    DCHECK(mo &
     106           (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
     107    DCHECK(!((uptr)ptr % sizeof(*ptr)));
     108  
     109    __spin_lock(&lock.lock);
     110    ptr->val_dont_use = v;
     111    __spin_unlock(&lock.lock);
     112  }
     113  
     114  }  // namespace __sanitizer
     115  
     116  #endif  // SANITIZER_ATOMIC_CLANG_MIPS_H
     117