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