1b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//===-- sanitizer_atomic_clang.h --------------------------------*- C++ -*-===//
2b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//
3b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//                     The LLVM Compiler Infrastructure
4b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//
5b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov// This file is distributed under the University of Illinois Open Source
6b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov// License. See LICENSE.TXT for details.
7b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//
8b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//===----------------------------------------------------------------------===//
9b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//
10b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
11b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov// Not intended for direct inclusion. Include sanitizer_atomic.h.
12b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//
13b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov//===----------------------------------------------------------------------===//
14b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
15b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov#ifndef SANITIZER_ATOMIC_CLANG_H
16b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov#define SANITIZER_ATOMIC_CLANG_H
17b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
182d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#if defined(__i386__) || defined(__x86_64__)
192d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines# include "sanitizer_atomic_clang_x86.h"
202d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#else
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines# include "sanitizer_atomic_clang_other.h"
222d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#endif
232d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
24b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukovnamespace __sanitizer {
25b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
262d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// We would like to just use compiler builtin atomic operations
272d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// for loads and stores, but they are mostly broken in clang:
282d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// - they lead to vastly inefficient code generation
292d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// (http://llvm.org/bugs/show_bug.cgi?id=17281)
302d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// - 64-bit atomic operations are not implemented on x86_32
312d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// (http://llvm.org/bugs/show_bug.cgi?id=15034)
322d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// - they are not implemented on ARM
332d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// error: undefined reference to '__atomic_load_4'
342d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
352d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
362d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines// for mappings of the memory model to different processors.
372d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
38b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry VyukovINLINE void atomic_signal_fence(memory_order) {
39b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  __asm__ __volatile__("" ::: "memory");
40b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}
41b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
42b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry VyukovINLINE void atomic_thread_fence(memory_order) {
43b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  __sync_synchronize();
44b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}
45b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
46b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukovtemplate<typename T>
47b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry VyukovINLINE typename T::Type atomic_fetch_add(volatile T *a,
48b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov    typename T::Type v, memory_order mo) {
49b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  (void)mo;
50b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  DCHECK(!((uptr)a % sizeof(*a)));
51b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  return __sync_fetch_and_add(&a->val_dont_use, v);
52b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}
53b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
54b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukovtemplate<typename T>
55b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry VyukovINLINE typename T::Type atomic_fetch_sub(volatile T *a,
56b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov    typename T::Type v, memory_order mo) {
57b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  (void)mo;
58b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  DCHECK(!((uptr)a % sizeof(*a)));
59b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  return __sync_fetch_and_add(&a->val_dont_use, -v);
60b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}
61b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
62b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukovtemplate<typename T>
63b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry VyukovINLINE typename T::Type atomic_exchange(volatile T *a,
64b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov    typename T::Type v, memory_order mo) {
65b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  DCHECK(!((uptr)a % sizeof(*a)));
66b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
67b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov    __sync_synchronize();
68b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  v = __sync_lock_test_and_set(&a->val_dont_use, v);
69b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  if (mo == memory_order_seq_cst)
70b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov    __sync_synchronize();
71b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  return v;
72b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}
73b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
74b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukovtemplate<typename T>
75b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry VyukovINLINE bool atomic_compare_exchange_strong(volatile T *a,
76b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov                                           typename T::Type *cmp,
77b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov                                           typename T::Type xchg,
78b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov                                           memory_order mo) {
79b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  typedef typename T::Type Type;
80b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  Type cmpv = *cmp;
81b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
82b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  if (prev == cmpv)
83b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov    return true;
84b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  *cmp = prev;
85b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  return false;
86b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}
87b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
88b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukovtemplate<typename T>
89b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry VyukovINLINE bool atomic_compare_exchange_weak(volatile T *a,
90d264ca0436d7e881b28a43dc7e008d1889cd12b2Alexey Samsonov                                         typename T::Type *cmp,
91d264ca0436d7e881b28a43dc7e008d1889cd12b2Alexey Samsonov                                         typename T::Type xchg,
92d264ca0436d7e881b28a43dc7e008d1889cd12b2Alexey Samsonov                                         memory_order mo) {
93b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov  return atomic_compare_exchange_strong(a, cmp, xchg, mo);
94b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}
95b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
96b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov}  // namespace __sanitizer
97b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov
986fa061978b138b39d29d98a6d28c67684a23eef0Dmitry Vyukov#undef ATOMIC_ORDER
996fa061978b138b39d29d98a6d28c67684a23eef0Dmitry Vyukov
100b6eb56f5a03b4dba8de79465274a73d1ecbca7f2Dmitry Vyukov#endif  // SANITIZER_ATOMIC_CLANG_H
101