@@ -54,6 +54,8 @@ public enum IntPredicate {
5454 . ult: LLVMIntULT, . ule: LLVMIntULE, . sgt: LLVMIntSGT, . sge: LLVMIntSGE,
5555 . slt: LLVMIntSLT, . sle: LLVMIntSLE
5656 ]
57+
58+ /// Retrieves the corresponding `LLVMIntPredicate`.
5759 public var llvm : LLVMIntPredicate {
5860 return IntPredicate . predicateMapping [ self ] !
5961 }
@@ -103,13 +105,204 @@ public enum RealPredicate {
103105 . true : LLVMRealPredicateTrue,
104106 ]
105107
108+ /// Retrieves the corresponding `LLVMRealPredicate`.
106109 public var llvm : LLVMRealPredicate {
107110 return RealPredicate . predicateMapping [ self ] !
108111 }
109112}
110113
114+ /// `AtomicOrdering` enumerates available memory ordering semantics.
115+ ///
116+ /// Atomic instructions (`cmpxchg`, `atomicrmw`, `fence`, `atomic load`, and
117+ /// `atomic store`) take ordering parameters that determine which other atomic
118+ /// instructions on the same address they synchronize with. These semantics are
119+ /// borrowed from Java and C++0x, but are somewhat more colloquial. If these
120+ /// descriptions aren’t precise enough, check those specs (see spec references
121+ /// in the atomics guide). fence instructions treat these orderings somewhat
122+ /// differently since they don’t take an address. See that instruction’s
123+ /// documentation for details.
124+ public enum AtomicOrdering : Comparable {
125+ /// A load or store which is not atomic
126+ case notAtomic
127+ /// Lowest level of atomicity, guarantees somewhat sane results, lock free.
128+ ///
129+ /// The set of values that can be read is governed by the happens-before
130+ /// partial order. A value cannot be read unless some operation wrote it. This
131+ /// is intended to provide a guarantee strong enough to model Java’s
132+ /// non-volatile shared variables. This ordering cannot be specified for
133+ /// read-modify-write operations; it is not strong enough to make them atomic
134+ /// in any interesting way.
135+ case unordered
136+ /// Guarantees that if you take all the operations affecting a specific
137+ /// address, a consistent ordering exists.
138+ ///
139+ /// In addition to the guarantees of unordered, there is a single total order
140+ /// for modifications by monotonic operations on each address. All
141+ /// modification orders must be compatible with the happens-before order.
142+ /// There is no guarantee that the modification orders can be combined to a
143+ /// global total order for the whole program (and this often will not be
144+ /// possible). The read in an atomic read-modify-write operation (cmpxchg and
145+ /// atomicrmw) reads the value in the modification order immediately before
146+ /// the value it writes. If one atomic read happens before another atomic read
147+ /// of the same address, the later read must see the same value or a later
148+ /// value in the address’s modification order. This disallows reordering of
149+ /// monotonic (or stronger) operations on the same address. If an address is
150+ /// written monotonic-ally by one thread, and other threads monotonic-ally
151+ /// read that address repeatedly, the other threads must eventually see the
152+ /// write. This corresponds to the C++0x/C1x memory_order_relaxed.
153+ case monotonic
154+ /// Acquire provides a barrier of the sort necessary to acquire a lock to
155+ /// access other memory with normal loads and stores.
156+ ///
157+ /// In addition to the guarantees of monotonic, a synchronizes-with edge may
158+ /// be formed with a release operation. This is intended to model C++’s
159+ /// `memory_order_acquire`.
160+ case acquire
161+ /// Release is similar to Acquire, but with a barrier of the sort necessary to
162+ /// release a lock.
163+ ///
164+ /// In addition to the guarantees of monotonic, if this operation writes a
165+ /// value which is subsequently read by an acquire operation, it
166+ /// synchronizes-with that operation. (This isn’t a complete description; see
167+ /// the C++0x definition of a release sequence.) This corresponds to the
168+ /// C++0x/C1x memory_order_release.
169+ case release
170+ /// provides both an Acquire and a Release barrier (for fences and operations
171+ /// which both read and write memory).
172+ ///
173+ /// This corresponds to the C++0x/C1x memory_order_acq_rel.
174+ case acquireRelease
175+ /// Provides Acquire semantics for loads and Release semantics for stores.
176+ ///
177+ /// In addition to the guarantees of acq_rel (acquire for an operation that
178+ /// only reads, release for an operation that only writes), there is a global
179+ /// total order on all sequentially-consistent operations on all addresses,
180+ /// which is consistent with the happens-before partial order and with the
181+ /// modification orders of all the affected addresses. Each
182+ /// sequentially-consistent read sees the last preceding write to the same
183+ /// address in this global order. This corresponds to the C++0x/C1x
184+ /// `memory_order_seq_cst` and Java volatile.
185+ case sequentiallyConsistent
186+
187+ private static let orderingMapping : [ AtomicOrdering : LLVMAtomicOrdering ] = [
188+ . notAtomic: LLVMAtomicOrderingNotAtomic,
189+ . unordered: LLVMAtomicOrderingUnordered,
190+ . monotonic: LLVMAtomicOrderingMonotonic,
191+ . acquire: LLVMAtomicOrderingAcquire,
192+ . release: LLVMAtomicOrderingRelease,
193+ . acquireRelease: LLVMAtomicOrderingAcquireRelease,
194+ . sequentiallyConsistent: LLVMAtomicOrderingSequentiallyConsistent,
195+ ]
196+
197+ public static func == ( lhs: AtomicOrdering , rhs: AtomicOrdering ) -> Bool {
198+ return lhs. llvm == rhs. llvm
199+ }
200+
201+ public static func < ( lhs: AtomicOrdering , rhs: AtomicOrdering ) -> Bool {
202+ return lhs. llvm. rawValue < rhs. llvm. rawValue
203+ }
204+
205+ /// Retrieves the corresponding `LLVMAtomicOrdering`.
206+ public var llvm : LLVMAtomicOrdering {
207+ return AtomicOrdering . orderingMapping [ self ] !
208+ }
209+ }
210+
211+ /// `AtomicReadModifyWriteOperation` enumerates the kinds of supported atomic
212+ /// read-write-modify operations.
213+ public enum AtomicReadModifyWriteOperation {
214+ /// Set the new value and return the one old
215+ ///
216+ /// ```
217+ /// *ptr = val
218+ /// ```
219+ case xchg
220+ /// Add a value and return the old one
221+ ///
222+ /// ```
223+ /// *ptr = *ptr + val
224+ /// ```
225+ case add
226+ /// Subtract a value and return the old one
227+ ///
228+ /// ```
229+ /// *ptr = *ptr - val
230+ /// ```
231+ case sub
232+ /// And a value and return the old one
233+ ///
234+ /// ```
235+ /// *ptr = *ptr & val
236+ /// ```
237+ case and
238+ /// Not-And a value and return the old one
239+ ///
240+ /// ```
241+ /// *ptr = ~(*ptr & val)
242+ /// ```
243+ case nand
244+ /// OR a value and return the old one
245+ ///
246+ /// ```
247+ /// *ptr = *ptr | val
248+ /// ```
249+ case or
250+ /// Xor a value and return the old one
251+ ///
252+ /// ```
253+ /// *ptr = *ptr ^ val
254+ /// ```
255+ case xor
256+ /// Sets the value if it's greater than the original using a signed comparison
257+ /// and return the old one.
258+ ///
259+ /// ```
260+ /// // Using a signed comparison
261+ /// *ptr = *ptr > val ? *ptr : val
262+ /// ```
263+ case max
264+ /// Sets the value if it's Smaller than the original using a signed comparison
265+ /// and return the old one.
266+ ///
267+ /// ```
268+ /// // Using a signed comparison
269+ /// *ptr = *ptr < val ? *ptr : val
270+ /// ```
271+ case min
272+ /// Sets the value if it's greater than the original using an unsigned
273+ /// comparison and return the old one.
274+ ///
275+ /// ```
276+ /// // Using an unsigned comparison
277+ /// *ptr = *ptr > val ? *ptr : val
278+ /// ```
279+ case umax
280+ /// Sets the value if it's greater than the original using an unsigned
281+ /// comparison and return the old one.
282+ ///
283+ /// ```
284+ /// // Using an unsigned comparison
285+ /// *ptr = *ptr < val ? *ptr : val
286+ /// ```
287+ case umin
288+
289+ static let atomicRMWMapping : [ AtomicReadModifyWriteOperation : LLVMAtomicRMWBinOp ] = [
290+ . xchg: LLVMAtomicRMWBinOpXchg, . add: LLVMAtomicRMWBinOpAdd,
291+ . sub: LLVMAtomicRMWBinOpSub, . and: LLVMAtomicRMWBinOpAnd,
292+ . nand: LLVMAtomicRMWBinOpNand, . or: LLVMAtomicRMWBinOpOr,
293+ . xor: LLVMAtomicRMWBinOpXor, . max: LLVMAtomicRMWBinOpMax,
294+ . min: LLVMAtomicRMWBinOpMin, . umax: LLVMAtomicRMWBinOpUMax,
295+ . umin: LLVMAtomicRMWBinOpUMin,
296+ ]
297+
298+ /// Retrieves the corresponding `LLVMAtomicRMWBinOp`.
299+ public var llvm : LLVMAtomicRMWBinOp {
300+ return AtomicReadModifyWriteOperation . atomicRMWMapping [ self ] !
301+ }
302+ }
303+
111304extension Module {
112- /// Searches for and retrieves a global variable with the given name in this
305+ /// Searches for and retrieves a global variable with the given name in this
113306 /// module if that name references an existing global variable.
114307 ///
115308 /// - parameter name: The name of the global to reference.
@@ -942,6 +1135,91 @@ public class IRBuilder {
9421135 return LLVMSizeOf ( val. asLLVM ( ) )
9431136 }
9441137
1138+ // MARK: Atomic Instructions
1139+
1140+ /// Builds a fence instruction that introduces "happens-before" edges between
1141+ /// operations.
1142+ ///
1143+ /// - parameter ordering: Defines the kind of "synchronizes-with" edge this
1144+ /// fence adds.
1145+ /// - parameter singleThreaded: Specifies that the fence only synchronizes
1146+ /// with other atomics in the same thread. (This is useful for interacting
1147+ /// with signal handlers.) Otherwise this fence is atomic with respect to
1148+ /// all other code in the system.
1149+ ///
1150+ /// - returns: A value representing `void`.
1151+ public func buildFence( ordering: AtomicOrdering , singleThreaded: Bool = false , name: String = " " ) -> IRValue {
1152+ return LLVMBuildFence ( llvm, ordering. llvm, singleThreaded. llvm, name)
1153+ }
1154+
1155+ /// Builds an atomic compare-and-exchange instruction to atomically modify
1156+ /// memory. It loads a value in memory and compares it to a given value. If
1157+ /// they are equal, it tries to store a new value into the memory.
1158+ ///
1159+ /// - parameter ptr: The address of data to update atomically.
1160+ /// - parameter old: The value to base the comparison on.
1161+ /// - parameter new: The new value to write if comparison with the old value
1162+ /// returns true.
1163+ /// - parameter successOrdering: Specifies how this cmpxchg synchronizes with
1164+ /// other atomic operations when it succeeds.
1165+ /// - parameter failureOrdering: Specifies how this cmpxchg synchronizes with
1166+ /// other atomic operations when it fails.
1167+ /// - parameter singleThreaded: Specifies that this cmpxchg only synchronizes
1168+ /// with other atomics in the same thread. (This is useful for interacting
1169+ /// with signal handlers.) Otherwise this cmpxchg is atomic with respect to
1170+ /// all other code in the system.
1171+ ///
1172+ /// - returns: A value representing the original value at the given location
1173+ /// is together with a flag indicating success (true) or failure (false).
1174+ public func buildAtomicCmpXchg(
1175+ ptr: IRValue , of old: IRValue , to new: IRValue ,
1176+ successOrdering: AtomicOrdering , failureOrdering: AtomicOrdering ,
1177+ singleThreaded: Bool = false
1178+ ) -> IRValue {
1179+
1180+ if failureOrdering < . monotonic {
1181+ fatalError ( " Failure ordering must be at least 'Monotonic' " )
1182+ }
1183+
1184+ if successOrdering < . monotonic {
1185+ fatalError ( " Success ordering must be at least 'Monotonic' " )
1186+ }
1187+
1188+ if failureOrdering == . release || failureOrdering == . acquireRelease {
1189+ fatalError ( " Failure ordering may not be 'Release' or 'Acquire Release' " )
1190+ }
1191+
1192+ if failureOrdering > successOrdering {
1193+ fatalError ( " Failure ordering must be no stronger than success ordering " )
1194+ }
1195+
1196+ return LLVMBuildAtomicCmpXchg (
1197+ llvm, ptr. asLLVM ( ) , old. asLLVM ( ) , new. asLLVM ( ) ,
1198+ successOrdering. llvm, failureOrdering. llvm, singleThreaded. llvm
1199+ )
1200+ }
1201+
1202+ /// Builds an atomic read-modify-write instruction to atomically modify memory.
1203+ ///
1204+ /// - parameter atomicOp: The atomic operation to perform.
1205+ /// - parameter ptr: The address of a value to modify.
1206+ /// - parameter value: The second argument to the given operation.
1207+ /// - parameter ordering: Defines the kind of "synchronizes-with" edge this
1208+ /// atomic operation adds.
1209+ /// - parameter singleThreaded: Specifies that this atomicRMW instruction only
1210+ /// synchronizes with other atomics in the same thread. (This is useful for
1211+ /// interacting with signal handlers.) Otherwise this atomicRMW is atomic
1212+ /// with respect to all other code in the system.
1213+ ///
1214+ /// - returns: A value representing the old value of the given pointer before
1215+ /// the atomic operation was executed.
1216+ public func buildAtomicRMW(
1217+ atomicOp: AtomicReadModifyWriteOperation , ptr: IRValue , value: IRValue ,
1218+ ordering: AtomicOrdering , singleThreaded: Bool = false
1219+ ) -> IRValue {
1220+ return LLVMBuildAtomicRMW ( llvm, atomicOp. llvm, ptr. asLLVM ( ) , value. asLLVM ( ) , ordering. llvm, singleThreaded. llvm)
1221+ }
1222+
9451223 // MARK: Aggregate Instructions
9461224
9471225 /// Builds an instruction to insert a value into a member field in an
0 commit comments