@@ -54,6 +54,8 @@ public enum IntPredicate {
54
54
. ult: LLVMIntULT, . ule: LLVMIntULE, . sgt: LLVMIntSGT, . sge: LLVMIntSGE,
55
55
. slt: LLVMIntSLT, . sle: LLVMIntSLE
56
56
]
57
+
58
+ /// Retrieves the corresponding `LLVMIntPredicate`.
57
59
public var llvm : LLVMIntPredicate {
58
60
return IntPredicate . predicateMapping [ self ] !
59
61
}
@@ -103,13 +105,204 @@ public enum RealPredicate {
103
105
. true : LLVMRealPredicateTrue,
104
106
]
105
107
108
+ /// Retrieves the corresponding `LLVMRealPredicate`.
106
109
public var llvm : LLVMRealPredicate {
107
110
return RealPredicate . predicateMapping [ self ] !
108
111
}
109
112
}
110
113
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
+
111
304
extension 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
113
306
/// module if that name references an existing global variable.
114
307
///
115
308
/// - parameter name: The name of the global to reference.
@@ -942,6 +1135,91 @@ public class IRBuilder {
942
1135
return LLVMSizeOf ( val. asLLVM ( ) )
943
1136
}
944
1137
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
+
945
1223
// MARK: Aggregate Instructions
946
1224
947
1225
/// Builds an instruction to insert a value into a member field in an
0 commit comments