1 //===-- llvm/Support/AtomicOrdering.h ---Atomic Ordering---------*- 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 /// \file
10 /// Atomic ordering constants.
11 ///
12 /// These values are used by LLVM to represent atomic ordering for C++11's
13 /// memory model and more, as detailed in docs/Atomics.rst.
14 ///
15 //===----------------------------------------------------------------------===//
16
17 #ifndef LLVM_SUPPORT_ATOMICORDERING_H
18 #define LLVM_SUPPORT_ATOMICORDERING_H
19
20 #include <cstddef>
21
22 namespace llvm {
23
24 /// Atomic ordering for C11 / C++11's memory models.
25 ///
26 /// These values cannot change because they are shared with standard library
27 /// implementations as well as with other compilers.
28 enum class AtomicOrderingCABI {
29 relaxed = 0,
30 consume = 1,
31 acquire = 2,
32 release = 3,
33 acq_rel = 4,
34 seq_cst = 5,
35 };
36
37 bool operator<(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
38 bool operator>(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
39 bool operator<=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
40 bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
41
42 // Validate an integral value which isn't known to fit within the enum's range
43 // is a valid AtomicOrderingCABI.
isValidAtomicOrderingCABI(Int I)44 template <typename Int> inline bool isValidAtomicOrderingCABI(Int I) {
45 return (Int)AtomicOrderingCABI::relaxed <= I &&
46 I <= (Int)AtomicOrderingCABI::seq_cst;
47 }
48
49 /// Atomic ordering for LLVM's memory model.
50 ///
51 /// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and
52 /// Unordered, which are both below the C++ orders.
53 ///
54 /// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst
55 /// \-->consume-->acquire--/
56 enum class AtomicOrdering : unsigned {
57 NotAtomic = 0,
58 Unordered = 1,
59 Monotonic = 2, // Equivalent to C++'s relaxed.
60 // Consume = 3, // Not specified yet.
61 Acquire = 4,
62 Release = 5,
63 AcquireRelease = 6,
64 SequentiallyConsistent = 7,
65 LAST = SequentiallyConsistent
66 };
67
68 bool operator<(AtomicOrdering, AtomicOrdering) = delete;
69 bool operator>(AtomicOrdering, AtomicOrdering) = delete;
70 bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
71 bool 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.
isValidAtomicOrdering(Int I)75 template <typename Int> 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.
toIRString(AtomicOrdering ao)81 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.
isStrongerThan(AtomicOrdering AO,AtomicOrdering Other)90 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
isAtLeastOrStrongerThan(AtomicOrdering AO,AtomicOrdering Other)105 inline bool isAtLeastOrStrongerThan(AtomicOrdering AO, AtomicOrdering Other) {
106 static const bool lookup[8][8] = {
107 // NA UN RX CO AC RE AR SC
108 /* NotAtomic */ { true, false, false, false, false, false, false, false},
109 /* Unordered */ { true, true, false, false, false, false, false, false},
110 /* relaxed */ { true, true, true, false, false, false, false, false},
111 /* consume */ { true, true, true, true, false, false, false, false},
112 /* acquire */ { true, true, true, true, true, false, false, false},
113 /* release */ { true, true, true, false, false, true, false, false},
114 /* acq_rel */ { true, true, true, true, true, true, true, false},
115 /* seq_cst */ { true, true, true, true, true, true, true, true},
116 };
117 return lookup[static_cast<size_t>(AO)][static_cast<size_t>(Other)];
118 }
119
isStrongerThanUnordered(AtomicOrdering AO)120 inline bool isStrongerThanUnordered(AtomicOrdering AO) {
121 return isStrongerThan(AO, AtomicOrdering::Unordered);
122 }
123
isStrongerThanMonotonic(AtomicOrdering AO)124 inline bool isStrongerThanMonotonic(AtomicOrdering AO) {
125 return isStrongerThan(AO, AtomicOrdering::Monotonic);
126 }
127
isAcquireOrStronger(AtomicOrdering AO)128 inline bool isAcquireOrStronger(AtomicOrdering AO) {
129 return isAtLeastOrStrongerThan(AO, AtomicOrdering::Acquire);
130 }
131
isReleaseOrStronger(AtomicOrdering AO)132 inline bool isReleaseOrStronger(AtomicOrdering AO) {
133 return isAtLeastOrStrongerThan(AO, AtomicOrdering::Release);
134 }
135
136 /// Return a single atomic ordering that is at least as strong as both the \p AO
137 /// and \p Other orderings for an atomic operation.
getMergedAtomicOrdering(AtomicOrdering AO,AtomicOrdering Other)138 inline AtomicOrdering getMergedAtomicOrdering(AtomicOrdering AO,
139 AtomicOrdering Other) {
140 if ((AO == AtomicOrdering::Acquire && Other == AtomicOrdering::Release) ||
141 (AO == AtomicOrdering::Release && Other == AtomicOrdering::Acquire))
142 return AtomicOrdering::AcquireRelease;
143 return isStrongerThan(AO, Other) ? AO : Other;
144 }
145
toCABI(AtomicOrdering AO)146 inline AtomicOrderingCABI toCABI(AtomicOrdering AO) {
147 static const AtomicOrderingCABI lookup[8] = {
148 /* NotAtomic */ AtomicOrderingCABI::relaxed,
149 /* Unordered */ AtomicOrderingCABI::relaxed,
150 /* relaxed */ AtomicOrderingCABI::relaxed,
151 /* consume */ AtomicOrderingCABI::consume,
152 /* acquire */ AtomicOrderingCABI::acquire,
153 /* release */ AtomicOrderingCABI::release,
154 /* acq_rel */ AtomicOrderingCABI::acq_rel,
155 /* seq_cst */ AtomicOrderingCABI::seq_cst,
156 };
157 return lookup[static_cast<size_t>(AO)];
158 }
159
160 } // end namespace llvm
161
162 #endif // LLVM_SUPPORT_ATOMICORDERING_H
163