1//===-- llvm/Support/AtomicOrdering.h ---Atomic Ordering---------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief Atomic ordering constants.
12///
13/// These values are used by LLVM to represent atomic ordering for C++11's
14/// memory model and more, as detailed in docs/Atomics.rst.
15///
16//===----------------------------------------------------------------------===//
17
18#ifndef LLVM_SUPPORT_ATOMICORDERING_H
19#define LLVM_SUPPORT_ATOMICORDERING_H
20
21#include <cstddef>
22
23namespace llvm {
24
25/// Atomic ordering for C11 / C++11's memody models.
26///
27/// These values cannot change because they are shared with standard library
28/// implementations as well as with other compilers.
29enum class AtomicOrderingCABI {
30  relaxed = 0,
31  consume = 1,
32  acquire = 2,
33  release = 3,
34  acq_rel = 4,
35  seq_cst = 5,
36};
37
38bool operator<(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
39bool operator>(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
40bool operator<=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
41bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
42
43// Validate an integral value which isn't known to fit within the enum's range
44// is a valid AtomicOrderingCABI.
45template <typename Int> static inline bool isValidAtomicOrderingCABI(Int I) {
46  return (Int)AtomicOrderingCABI::relaxed <= I &&
47         I <= (Int)AtomicOrderingCABI::seq_cst;
48}
49
50/// Atomic ordering for LLVM's memory model.
51///
52/// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and
53/// Unordered, which are both below the C++ orders.
54///
55/// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst
56///                                   \-->consume-->acquire--/
57enum class AtomicOrdering {
58  NotAtomic = 0,
59  Unordered = 1,
60  Monotonic = 2, // Equivalent to C++'s relaxed.
61  // Consume = 3,  // Not specified yet.
62  Acquire = 4,
63  Release = 5,
64  AcquireRelease = 6,
65  SequentiallyConsistent = 7
66};
67
68bool operator<(AtomicOrdering, AtomicOrdering) = delete;
69bool operator>(AtomicOrdering, AtomicOrdering) = delete;
70bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
71bool operator>=(AtomicOrdering, AtomicOrdering) = delete;
72
73// Validate an integral value which isn't known to fit within the enum's range
74// is a valid AtomicOrdering.
75template <typename Int> static inline bool isValidAtomicOrdering(Int I) {
76  return static_cast<Int>(AtomicOrdering::NotAtomic) <= I &&
77         I <= static_cast<Int>(AtomicOrdering::SequentiallyConsistent);
78}
79
80/// String used by LLVM IR to represent atomic ordering.
81static inline const char *toIRString(AtomicOrdering ao) {
82  static const char *names[8] = {"not_atomic", "unordered", "monotonic",
83                                 "consume",    "acquire",   "release",
84                                 "acq_rel",    "seq_cst"};
85  return names[static_cast<size_t>(ao)];
86}
87
88/// Returns true if ao is stronger than other as defined by the AtomicOrdering
89/// lattice, which is based on C++'s definition.
90static inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) {
91  static const bool lookup[8][8] = {
92      //               NA     UN     RX     CO     AC     RE     AR     SC
93      /* NotAtomic */ {false, false, false, false, false, false, false, false},
94      /* Unordered */ { true, false, false, false, false, false, false, false},
95      /* relaxed   */ { true,  true, false, false, false, false, false, false},
96      /* consume   */ { true,  true,  true, false, false, false, false, false},
97      /* acquire   */ { true,  true,  true,  true, false, false, false, false},
98      /* release   */ { true,  true,  true, false, false, false, false, false},
99      /* acq_rel   */ { true,  true,  true,  true,  true,  true, false, false},
100      /* seq_cst   */ { true,  true,  true,  true,  true,  true,  true, false},
101  };
102  return lookup[static_cast<size_t>(ao)][static_cast<size_t>(other)];
103}
104
105static inline bool isAtLeastOrStrongerThan(AtomicOrdering ao,
106                                           AtomicOrdering other) {
107  static const bool lookup[8][8] = {
108      //               NA     UN     RX     CO     AC     RE     AR     SC
109      /* NotAtomic */ { true, false, false, false, false, false, false, false},
110      /* Unordered */ { true,  true, false, false, false, false, false, false},
111      /* relaxed   */ { true,  true,  true, false, false, false, false, false},
112      /* consume   */ { true,  true,  true,  true, false, false, false, false},
113      /* acquire   */ { true,  true,  true,  true,  true, false, false, false},
114      /* release   */ { true,  true,  true, false, false,  true, false, false},
115      /* acq_rel   */ { true,  true,  true,  true,  true,  true,  true, false},
116      /* seq_cst   */ { true,  true,  true,  true,  true,  true,  true,  true},
117  };
118  return lookup[static_cast<size_t>(ao)][static_cast<size_t>(other)];
119}
120
121static inline bool isStrongerThanUnordered(AtomicOrdering ao) {
122  return isStrongerThan(ao, AtomicOrdering::Unordered);
123}
124
125static inline bool isStrongerThanMonotonic(AtomicOrdering ao) {
126  return isStrongerThan(ao, AtomicOrdering::Monotonic);
127}
128
129static inline bool isAcquireOrStronger(AtomicOrdering ao) {
130  return isAtLeastOrStrongerThan(ao, AtomicOrdering::Acquire);
131}
132
133static inline bool isReleaseOrStronger(AtomicOrdering ao) {
134  return isAtLeastOrStrongerThan(ao, AtomicOrdering::Release);
135}
136
137static inline AtomicOrderingCABI toCABI(AtomicOrdering ao) {
138  static const AtomicOrderingCABI lookup[8] = {
139      /* NotAtomic */ AtomicOrderingCABI::relaxed,
140      /* Unordered */ AtomicOrderingCABI::relaxed,
141      /* relaxed   */ AtomicOrderingCABI::relaxed,
142      /* consume   */ AtomicOrderingCABI::consume,
143      /* acquire   */ AtomicOrderingCABI::acquire,
144      /* release   */ AtomicOrderingCABI::release,
145      /* acq_rel   */ AtomicOrderingCABI::acq_rel,
146      /* seq_cst   */ AtomicOrderingCABI::seq_cst,
147  };
148  return lookup[static_cast<size_t>(ao)];
149}
150
151} // end namespace llvm
152
153#endif // LLVM_SUPPORT_ATOMICORDERING_H
154