| 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 |  |