10b57cec5SDimitry Andric //===-- llvm/Support/AtomicOrdering.h ---Atomic Ordering---------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// Atomic ordering constants.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric /// These values are used by LLVM to represent atomic ordering for C++11's
130b57cec5SDimitry Andric /// memory model and more, as detailed in docs/Atomics.rst.
140b57cec5SDimitry Andric ///
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_ATOMICORDERING_H
180b57cec5SDimitry Andric #define LLVM_SUPPORT_ATOMICORDERING_H
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include <cstddef>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric namespace llvm {
230b57cec5SDimitry Andric 
24e8d8bef9SDimitry Andric /// Atomic ordering for C11 / C++11's memory models.
250b57cec5SDimitry Andric ///
260b57cec5SDimitry Andric /// These values cannot change because they are shared with standard library
270b57cec5SDimitry Andric /// implementations as well as with other compilers.
280b57cec5SDimitry Andric enum class AtomicOrderingCABI {
290b57cec5SDimitry Andric   relaxed = 0,
300b57cec5SDimitry Andric   consume = 1,
310b57cec5SDimitry Andric   acquire = 2,
320b57cec5SDimitry Andric   release = 3,
330b57cec5SDimitry Andric   acq_rel = 4,
340b57cec5SDimitry Andric   seq_cst = 5,
350b57cec5SDimitry Andric };
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric bool operator<(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
380b57cec5SDimitry Andric bool operator>(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
390b57cec5SDimitry Andric bool operator<=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
400b57cec5SDimitry Andric bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric // Validate an integral value which isn't known to fit within the enum's range
430b57cec5SDimitry Andric // is a valid AtomicOrderingCABI.
isValidAtomicOrderingCABI(Int I)440b57cec5SDimitry Andric template <typename Int> inline bool isValidAtomicOrderingCABI(Int I) {
450b57cec5SDimitry Andric   return (Int)AtomicOrderingCABI::relaxed <= I &&
460b57cec5SDimitry Andric          I <= (Int)AtomicOrderingCABI::seq_cst;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric /// Atomic ordering for LLVM's memory model.
500b57cec5SDimitry Andric ///
510b57cec5SDimitry Andric /// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and
520b57cec5SDimitry Andric /// Unordered, which are both below the C++ orders.
530b57cec5SDimitry Andric ///
540b57cec5SDimitry Andric /// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst
550b57cec5SDimitry Andric ///                                   \-->consume-->acquire--/
565ffd83dbSDimitry Andric enum class AtomicOrdering : unsigned {
570b57cec5SDimitry Andric   NotAtomic = 0,
580b57cec5SDimitry Andric   Unordered = 1,
590b57cec5SDimitry Andric   Monotonic = 2, // Equivalent to C++'s relaxed.
600b57cec5SDimitry Andric   // Consume = 3,  // Not specified yet.
610b57cec5SDimitry Andric   Acquire = 4,
620b57cec5SDimitry Andric   Release = 5,
630b57cec5SDimitry Andric   AcquireRelease = 6,
645ffd83dbSDimitry Andric   SequentiallyConsistent = 7,
655ffd83dbSDimitry Andric   LAST = SequentiallyConsistent
660b57cec5SDimitry Andric };
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric bool operator<(AtomicOrdering, AtomicOrdering) = delete;
690b57cec5SDimitry Andric bool operator>(AtomicOrdering, AtomicOrdering) = delete;
700b57cec5SDimitry Andric bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
710b57cec5SDimitry Andric bool operator>=(AtomicOrdering, AtomicOrdering) = delete;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric // Validate an integral value which isn't known to fit within the enum's range
740b57cec5SDimitry Andric // is a valid AtomicOrdering.
isValidAtomicOrdering(Int I)750b57cec5SDimitry Andric template <typename Int> inline bool isValidAtomicOrdering(Int I) {
760b57cec5SDimitry Andric   return static_cast<Int>(AtomicOrdering::NotAtomic) <= I &&
7706c3fb27SDimitry Andric          I <= static_cast<Int>(AtomicOrdering::SequentiallyConsistent) &&
7806c3fb27SDimitry Andric          I != 3;
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric /// String used by LLVM IR to represent atomic ordering.
toIRString(AtomicOrdering ao)820b57cec5SDimitry Andric inline const char *toIRString(AtomicOrdering ao) {
830b57cec5SDimitry Andric   static const char *names[8] = {"not_atomic", "unordered", "monotonic",
840b57cec5SDimitry Andric                                  "consume",    "acquire",   "release",
850b57cec5SDimitry Andric                                  "acq_rel",    "seq_cst"};
860b57cec5SDimitry Andric   return names[static_cast<size_t>(ao)];
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric /// Returns true if ao is stronger than other as defined by the AtomicOrdering
900b57cec5SDimitry Andric /// lattice, which is based on C++'s definition.
isStrongerThan(AtomicOrdering AO,AtomicOrdering Other)91e8d8bef9SDimitry Andric inline bool isStrongerThan(AtomicOrdering AO, AtomicOrdering Other) {
920b57cec5SDimitry Andric   static const bool lookup[8][8] = {
930b57cec5SDimitry Andric       //               NA     UN     RX     CO     AC     RE     AR     SC
940b57cec5SDimitry Andric       /* NotAtomic */ {false, false, false, false, false, false, false, false},
950b57cec5SDimitry Andric       /* Unordered */ { true, false, false, false, false, false, false, false},
960b57cec5SDimitry Andric       /* relaxed   */ { true,  true, false, false, false, false, false, false},
970b57cec5SDimitry Andric       /* consume   */ { true,  true,  true, false, false, false, false, false},
980b57cec5SDimitry Andric       /* acquire   */ { true,  true,  true,  true, false, false, false, false},
990b57cec5SDimitry Andric       /* release   */ { true,  true,  true, false, false, false, false, false},
1000b57cec5SDimitry Andric       /* acq_rel   */ { true,  true,  true,  true,  true,  true, false, false},
1010b57cec5SDimitry Andric       /* seq_cst   */ { true,  true,  true,  true,  true,  true,  true, false},
1020b57cec5SDimitry Andric   };
103e8d8bef9SDimitry Andric   return lookup[static_cast<size_t>(AO)][static_cast<size_t>(Other)];
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
isAtLeastOrStrongerThan(AtomicOrdering AO,AtomicOrdering Other)106e8d8bef9SDimitry Andric inline bool isAtLeastOrStrongerThan(AtomicOrdering AO, AtomicOrdering Other) {
1070b57cec5SDimitry Andric   static const bool lookup[8][8] = {
1080b57cec5SDimitry Andric       //               NA     UN     RX     CO     AC     RE     AR     SC
1090b57cec5SDimitry Andric       /* NotAtomic */ { true, false, false, false, false, false, false, false},
1100b57cec5SDimitry Andric       /* Unordered */ { true,  true, false, false, false, false, false, false},
1110b57cec5SDimitry Andric       /* relaxed   */ { true,  true,  true, false, false, false, false, false},
1120b57cec5SDimitry Andric       /* consume   */ { true,  true,  true,  true, false, false, false, false},
1130b57cec5SDimitry Andric       /* acquire   */ { true,  true,  true,  true,  true, false, false, false},
1140b57cec5SDimitry Andric       /* release   */ { true,  true,  true, false, false,  true, false, false},
1150b57cec5SDimitry Andric       /* acq_rel   */ { true,  true,  true,  true,  true,  true,  true, false},
1160b57cec5SDimitry Andric       /* seq_cst   */ { true,  true,  true,  true,  true,  true,  true,  true},
1170b57cec5SDimitry Andric   };
118e8d8bef9SDimitry Andric   return lookup[static_cast<size_t>(AO)][static_cast<size_t>(Other)];
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
isStrongerThanUnordered(AtomicOrdering AO)121e8d8bef9SDimitry Andric inline bool isStrongerThanUnordered(AtomicOrdering AO) {
122e8d8bef9SDimitry Andric   return isStrongerThan(AO, AtomicOrdering::Unordered);
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
isStrongerThanMonotonic(AtomicOrdering AO)125e8d8bef9SDimitry Andric inline bool isStrongerThanMonotonic(AtomicOrdering AO) {
126e8d8bef9SDimitry Andric   return isStrongerThan(AO, AtomicOrdering::Monotonic);
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
isAcquireOrStronger(AtomicOrdering AO)129e8d8bef9SDimitry Andric inline bool isAcquireOrStronger(AtomicOrdering AO) {
130e8d8bef9SDimitry Andric   return isAtLeastOrStrongerThan(AO, AtomicOrdering::Acquire);
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric 
isReleaseOrStronger(AtomicOrdering AO)133e8d8bef9SDimitry Andric inline bool isReleaseOrStronger(AtomicOrdering AO) {
134e8d8bef9SDimitry Andric   return isAtLeastOrStrongerThan(AO, AtomicOrdering::Release);
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
137349cc55cSDimitry Andric /// Return a single atomic ordering that is at least as strong as both the \p AO
138349cc55cSDimitry Andric /// and \p Other orderings for an atomic operation.
getMergedAtomicOrdering(AtomicOrdering AO,AtomicOrdering Other)139349cc55cSDimitry Andric inline AtomicOrdering getMergedAtomicOrdering(AtomicOrdering AO,
140349cc55cSDimitry Andric                                               AtomicOrdering Other) {
141349cc55cSDimitry Andric   if ((AO == AtomicOrdering::Acquire && Other == AtomicOrdering::Release) ||
142349cc55cSDimitry Andric       (AO == AtomicOrdering::Release && Other == AtomicOrdering::Acquire))
143349cc55cSDimitry Andric     return AtomicOrdering::AcquireRelease;
144349cc55cSDimitry Andric   return isStrongerThan(AO, Other) ? AO : Other;
145349cc55cSDimitry Andric }
146349cc55cSDimitry Andric 
toCABI(AtomicOrdering AO)147e8d8bef9SDimitry Andric inline AtomicOrderingCABI toCABI(AtomicOrdering AO) {
1480b57cec5SDimitry Andric   static const AtomicOrderingCABI lookup[8] = {
1490b57cec5SDimitry Andric       /* NotAtomic */ AtomicOrderingCABI::relaxed,
1500b57cec5SDimitry Andric       /* Unordered */ AtomicOrderingCABI::relaxed,
1510b57cec5SDimitry Andric       /* relaxed   */ AtomicOrderingCABI::relaxed,
1520b57cec5SDimitry Andric       /* consume   */ AtomicOrderingCABI::consume,
1530b57cec5SDimitry Andric       /* acquire   */ AtomicOrderingCABI::acquire,
1540b57cec5SDimitry Andric       /* release   */ AtomicOrderingCABI::release,
1550b57cec5SDimitry Andric       /* acq_rel   */ AtomicOrderingCABI::acq_rel,
1560b57cec5SDimitry Andric       /* seq_cst   */ AtomicOrderingCABI::seq_cst,
1570b57cec5SDimitry Andric   };
158e8d8bef9SDimitry Andric   return lookup[static_cast<size_t>(AO)];
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric } // end namespace llvm
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric #endif // LLVM_SUPPORT_ATOMICORDERING_H
164