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 | I != 3; |
79 | } |
80 | |
81 | /// String used by LLVM IR to represent atomic ordering. |
82 | inline const char *toIRString(AtomicOrdering ao) { |
83 | static const char *names[8] = {"not_atomic" , "unordered" , "monotonic" , |
84 | "consume" , "acquire" , "release" , |
85 | "acq_rel" , "seq_cst" }; |
86 | return names[static_cast<size_t>(ao)]; |
87 | } |
88 | |
89 | /// Returns true if ao is stronger than other as defined by the AtomicOrdering |
90 | /// lattice, which is based on C++'s definition. |
91 | inline bool isStrongerThan(AtomicOrdering AO, AtomicOrdering Other) { |
92 | static const bool lookup[8][8] = { |
93 | // NA UN RX CO AC RE AR SC |
94 | /* NotAtomic */ {false, false, false, false, false, false, false, false}, |
95 | /* Unordered */ { true, false, false, false, false, false, false, false}, |
96 | /* relaxed */ { true, true, false, false, false, false, false, false}, |
97 | /* consume */ { true, true, true, false, false, false, false, false}, |
98 | /* acquire */ { true, true, true, true, false, false, false, false}, |
99 | /* release */ { true, true, true, false, false, false, false, false}, |
100 | /* acq_rel */ { true, true, true, true, true, true, false, false}, |
101 | /* seq_cst */ { true, true, true, true, true, true, true, false}, |
102 | }; |
103 | return lookup[static_cast<size_t>(AO)][static_cast<size_t>(Other)]; |
104 | } |
105 | |
106 | inline bool isAtLeastOrStrongerThan(AtomicOrdering AO, 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 | |
121 | inline bool isStrongerThanUnordered(AtomicOrdering AO) { |
122 | return isStrongerThan(AO, Other: AtomicOrdering::Unordered); |
123 | } |
124 | |
125 | inline bool isStrongerThanMonotonic(AtomicOrdering AO) { |
126 | return isStrongerThan(AO, Other: AtomicOrdering::Monotonic); |
127 | } |
128 | |
129 | inline bool isAcquireOrStronger(AtomicOrdering AO) { |
130 | return isAtLeastOrStrongerThan(AO, Other: AtomicOrdering::Acquire); |
131 | } |
132 | |
133 | inline bool isReleaseOrStronger(AtomicOrdering AO) { |
134 | return isAtLeastOrStrongerThan(AO, Other: AtomicOrdering::Release); |
135 | } |
136 | |
137 | /// Return a single atomic ordering that is at least as strong as both the \p AO |
138 | /// and \p Other orderings for an atomic operation. |
139 | inline AtomicOrdering getMergedAtomicOrdering(AtomicOrdering AO, |
140 | AtomicOrdering Other) { |
141 | if ((AO == AtomicOrdering::Acquire && Other == AtomicOrdering::Release) || |
142 | (AO == AtomicOrdering::Release && Other == AtomicOrdering::Acquire)) |
143 | return AtomicOrdering::AcquireRelease; |
144 | return isStrongerThan(AO, Other) ? AO : Other; |
145 | } |
146 | |
147 | inline AtomicOrderingCABI toCABI(AtomicOrdering AO) { |
148 | static const AtomicOrderingCABI lookup[8] = { |
149 | /* NotAtomic */ AtomicOrderingCABI::relaxed, |
150 | /* Unordered */ AtomicOrderingCABI::relaxed, |
151 | /* relaxed */ AtomicOrderingCABI::relaxed, |
152 | /* consume */ AtomicOrderingCABI::consume, |
153 | /* acquire */ AtomicOrderingCABI::acquire, |
154 | /* release */ AtomicOrderingCABI::release, |
155 | /* acq_rel */ AtomicOrderingCABI::acq_rel, |
156 | /* seq_cst */ AtomicOrderingCABI::seq_cst, |
157 | }; |
158 | return lookup[static_cast<size_t>(AO)]; |
159 | } |
160 | |
161 | } // end namespace llvm |
162 | |
163 | #endif // LLVM_SUPPORT_ATOMICORDERING_H |
164 | |