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
17namespace __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.
23static void __spin_lock(volatile int *lock) {
24  while (__sync_lock_test_and_set(lock, 1))
25    while (*lock) {
26    }
27}
28
29static 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.
34static struct {
35  int lock;
36  char pad[32 - sizeof(int)];
37} __attribute__((aligned(32))) lock = {0, {0}};
38
39template <>
40inline 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
57template <>
58inline 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
64template <>
65inline 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
89template <>
90inline 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
102template <>
103inline 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
118