@@ -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,196 @@ 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 : Int {
125
+ /// A load or store which is not atomic
126
+ case notAtomic = 0
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 = 1
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 = 2
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 = 3
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 = 4
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 = 5
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 = 6
186
+
187
+ 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
+ /// Retrieves the corresponding `LLVMAtomicOrdering`.
198
+ public var llvm : LLVMAtomicOrdering {
199
+ return AtomicOrdering . orderingMapping [ self ] !
200
+ }
201
+ }
202
+
203
+ /// `AtomicRMWOperation` enumerates the kinds of supported atomic
204
+ /// read-write-modify operations.
205
+ public enum AtomicRMWOperation {
206
+ /// Set the new value and return the one old
207
+ ///
208
+ /// ```
209
+ /// *ptr = val
210
+ /// ```
211
+ case xchg
212
+ /// Add a value and return the old one
213
+ ///
214
+ /// ```
215
+ /// *ptr = *ptr + val
216
+ /// ```
217
+ case add
218
+ /// Subtract a value and return the old one
219
+ ///
220
+ /// ```
221
+ /// *ptr = *ptr - val
222
+ /// ```
223
+ case sub
224
+ /// And a value and return the old one
225
+ ///
226
+ /// ```
227
+ /// *ptr = *ptr & val
228
+ /// ```
229
+ case and
230
+ /// Not-And a value and return the old one
231
+ ///
232
+ /// ```
233
+ /// *ptr = ~(*ptr & val)
234
+ /// ```
235
+ case nand
236
+ /// OR a value and return the old one
237
+ ///
238
+ /// ```
239
+ /// *ptr = *ptr | val
240
+ /// ```
241
+ case or
242
+ /// Xor a value and return the old one
243
+ ///
244
+ /// ```
245
+ /// *ptr = *ptr ^ val
246
+ /// ```
247
+ case xor
248
+ /// Sets the value if it's greater than the original using a signed comparison
249
+ /// and return the old one.
250
+ ///
251
+ /// ```
252
+ /// // Using a signed comparison
253
+ /// *ptr = *ptr > val ? *ptr : val
254
+ /// ```
255
+ case max
256
+ /// Sets the value if it's Smaller 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 min
264
+ /// Sets the value if it's greater than the original using an unsigned
265
+ /// comparison and return the old one.
266
+ ///
267
+ /// ```
268
+ /// // Using an unsigned comparison
269
+ /// *ptr = *ptr > val ? *ptr : val
270
+ /// ```
271
+ case umax
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 umin
280
+
281
+ static let atomicRMWMapping : [ AtomicRMWOperation : LLVMAtomicRMWBinOp ] = [
282
+ . xchg: LLVMAtomicRMWBinOpXchg, . add: LLVMAtomicRMWBinOpAdd,
283
+ . sub: LLVMAtomicRMWBinOpSub, . and: LLVMAtomicRMWBinOpAnd,
284
+ . nand: LLVMAtomicRMWBinOpNand, . or: LLVMAtomicRMWBinOpOr,
285
+ . xor: LLVMAtomicRMWBinOpXor, . max: LLVMAtomicRMWBinOpMax,
286
+ . min: LLVMAtomicRMWBinOpMin, . umax: LLVMAtomicRMWBinOpUMax,
287
+ . umin: LLVMAtomicRMWBinOpUMin,
288
+ ]
289
+
290
+ /// Retrieves the corresponding `LLVMAtomicRMWBinOp`.
291
+ public var llvm : LLVMAtomicRMWBinOp {
292
+ return AtomicRMWOperation . atomicRMWMapping [ self ] !
293
+ }
294
+ }
295
+
111
296
extension Module {
112
- /// Searches for and retrieves a global variable with the given name in this
297
+ /// Searches for and retrieves a global variable with the given name in this
113
298
/// module if that name references an existing global variable.
114
299
///
115
300
/// - parameter name: The name of the global to reference.
@@ -942,6 +1127,91 @@ public class IRBuilder {
942
1127
return LLVMSizeOf ( val. asLLVM ( ) )
943
1128
}
944
1129
1130
+ // MARK: Atomic Instructions
1131
+
1132
+ /// Builds a fence instruction that introduces "happens-before" edges between
1133
+ /// operations.
1134
+ ///
1135
+ /// - parameter ordering: Defines the kind of "synchronizes-with" edge this
1136
+ /// fence adds.
1137
+ /// - parameter singleThreaded: Specifies that the fence only synchronizes
1138
+ /// with other atomics in the same thread. (This is useful for interacting
1139
+ /// with signal handlers.) Otherwise this fence is atomic with respect to
1140
+ /// all other code in the system.
1141
+ ///
1142
+ /// - returns: A value representing `void`.
1143
+ public func buildFence( ordering: AtomicOrdering , singleThreaded: Bool = false , name: String = " " ) -> IRValue {
1144
+ return LLVMBuildFence ( llvm, ordering. llvm, singleThreaded. llvm, name)
1145
+ }
1146
+
1147
+ /// Builds an atomic compare-and-exchange instruction to atomically modify
1148
+ /// memory. It loads a value in memory and compares it to a given value. If
1149
+ /// they are equal, it tries to store a new value into the memory.
1150
+ ///
1151
+ /// - parameter ptr: The address of data to update atomically.
1152
+ /// - parameter old: The value to base the comparison on.
1153
+ /// - parameter new: The new value to write if comparison with the old value
1154
+ /// returns true.
1155
+ /// - parameter successOrdering: Specifies how this cmpxchg synchronizes with
1156
+ /// other atomic operations when it succeeds.
1157
+ /// - parameter failureOrdering: Specifies how this cmpxchg synchronizes with
1158
+ /// other atomic operations when it fails.
1159
+ /// - parameter singleThreaded: Specifies that this cmpxchg only synchronizes
1160
+ /// with other atomics in the same thread. (This is useful for interacting
1161
+ /// with signal handlers.) Otherwise this cmpxchg is atomic with respect to
1162
+ /// all other code in the system.
1163
+ ///
1164
+ /// - returns: A value representing the original value at the given location
1165
+ /// is together with a flag indicating success (true) or failure (false).
1166
+ public func buildAtomicCmpXchg(
1167
+ ptr: IRValue , of old: IRValue , to new: IRValue ,
1168
+ successOrdering: AtomicOrdering , failureOrdering: AtomicOrdering ,
1169
+ singleThreaded: Bool = false
1170
+ ) -> IRValue {
1171
+
1172
+ if failureOrdering. rawValue < AtomicOrdering . monotonic. rawValue {
1173
+ fatalError ( " Failure ordering must be at least 'Monotonic' " )
1174
+ }
1175
+
1176
+ if successOrdering. rawValue < AtomicOrdering . monotonic. rawValue {
1177
+ fatalError ( " Success ordering must be at least 'Monotonic' " )
1178
+ }
1179
+
1180
+ if failureOrdering == . release || failureOrdering == . acquireRelease {
1181
+ fatalError ( " Failure ordering may not be 'Release' or 'Acquire Release' " )
1182
+ }
1183
+
1184
+ if failureOrdering. rawValue > successOrdering. rawValue {
1185
+ fatalError ( " Failure ordering must be no stronger than that on success ordering " )
1186
+ }
1187
+
1188
+ return LLVMBuildAtomicCmpXchg (
1189
+ llvm, ptr. asLLVM ( ) , old. asLLVM ( ) , new. asLLVM ( ) ,
1190
+ successOrdering. llvm, failureOrdering. llvm, singleThreaded. llvm
1191
+ )
1192
+ }
1193
+
1194
+ /// Builds an atomic read-modify-write instruction to atomically modify memory.
1195
+ ///
1196
+ /// - parameter atomicOp: The atomic operation to perform.
1197
+ /// - parameter ptr: The address of a value to modify.
1198
+ /// - parameter value: The second argument to the given operation.
1199
+ /// - parameter ordering: Defines the kind of "synchronizes-with" edge this
1200
+ /// atomic operation adds.
1201
+ /// - parameter singleThreaded: Specifies that this atomicRMW instruction only
1202
+ /// synchronizes with other atomics in the same thread. (This is useful for
1203
+ /// interacting with signal handlers.) Otherwise this atomicRMW is atomic
1204
+ /// with respect to all other code in the system.
1205
+ ///
1206
+ /// - returns: A value representing the old value of the given pointer before
1207
+ /// the atomic operation was executed.
1208
+ public func buildAtomicRMW(
1209
+ atomicOp: AtomicRMWOperation , ptr: IRValue , value: IRValue ,
1210
+ ordering: AtomicOrdering , singleThreaded: Bool = false
1211
+ ) -> IRValue {
1212
+ return LLVMBuildAtomicRMW ( llvm, atomicOp. llvm, ptr. asLLVM ( ) , value. asLLVM ( ) , ordering. llvm, singleThreaded. llvm)
1213
+ }
1214
+
945
1215
// MARK: Vector Instructions
946
1216
947
1217
/// Builds an instruction to insert a value into a member field in an
0 commit comments