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. |
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. |
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. |
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. |
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 | |
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 | |
120 | inline bool isStrongerThanUnordered(AtomicOrdering AO) { |
121 | return isStrongerThan(AO, AtomicOrdering::Unordered); |
122 | } |
123 | |
124 | inline bool isStrongerThanMonotonic(AtomicOrdering AO) { |
125 | return isStrongerThan(AO, AtomicOrdering::Monotonic); |
126 | } |
127 | |
128 | inline bool isAcquireOrStronger(AtomicOrdering AO) { |
129 | return isAtLeastOrStrongerThan(AO, AtomicOrdering::Acquire); |
130 | } |
131 | |
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. |
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 | |
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 | |