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