Skip to content

Commit f747162

Browse files
committed
Implement the Atomic type
1 parent ae983d8 commit f747162

12 files changed

+1829
-4
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Builtin
14+
15+
/// An atomic value.
16+
@available(SwiftStdlib 5.10, *)
17+
@_rawLayout(like: Value.AtomicRepresentation)
18+
@frozen
19+
public struct Atomic<Value: AtomicValue>: ~Copyable {
20+
@available(SwiftStdlib 5.10, *)
21+
@_alwaysEmitIntoClient
22+
@_transparent
23+
var address: UnsafeMutablePointer<Value.AtomicRepresentation> {
24+
UnsafeMutablePointer<Value.AtomicRepresentation>(rawAddress)
25+
}
26+
27+
@available(SwiftStdlib 5.10, *)
28+
@_alwaysEmitIntoClient
29+
@_transparent
30+
var rawAddress: Builtin.RawPointer {
31+
Builtin.unprotectedAddressOfBorrow(self)
32+
}
33+
34+
/// Initializes a value of this atomic with the given initial value.
35+
///
36+
/// - Parameter initialValue: The initial value to set this atomic.
37+
@available(SwiftStdlib 5.10, *)
38+
@inlinable
39+
public init(_ initialValue: consuming Value) {
40+
address.initialize(to: Value.encodeAtomicRepresentation(initialValue))
41+
}
42+
43+
@inlinable
44+
deinit {
45+
address.deinitialize(count: 1)
46+
}
47+
}
48+
49+
@available(SwiftStdlib 5.10, *)
50+
extension Atomic: @unchecked Sendable where Value: Sendable {}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
% from SwiftAtomics import *
14+
15+
import Builtin
16+
17+
//===----------------------------------------------------------------------===//
18+
// Bool AtomicValue conformance
19+
//===----------------------------------------------------------------------===//
20+
21+
@available(SwiftStdlib 5.10, *)
22+
extension Bool: AtomicValue {
23+
public typealias AtomicRepresentation = AtomicInt8Storage
24+
25+
@available(SwiftStdlib 5.10, *)
26+
@_alwaysEmitIntoClient
27+
@_transparent
28+
public static func encodeAtomicRepresentation(
29+
_ value: borrowing Bool
30+
) -> AtomicInt8Storage {
31+
AtomicInt8Storage(Builtin.zext_Int1_Int8(value._value))
32+
}
33+
34+
@available(SwiftStdlib 5.10, *)
35+
@_alwaysEmitIntoClient
36+
@_transparent
37+
public static func decodeAtomicRepresentation(
38+
_ representation: consuming AtomicInt8Storage
39+
) -> Bool {
40+
Bool(Builtin.trunc_Int8_Int1(representation.storage))
41+
}
42+
}
43+
44+
//===----------------------------------------------------------------------===//
45+
// Bool load then atomic operations
46+
//===----------------------------------------------------------------------===//
47+
48+
@available(SwiftStdlib 5.10, *)
49+
extension Atomic where Value == Bool {
50+
% for (name, llvmName, op, label, doc) in boolOperations:
51+
% for (_, apiOrder, _, llvmOrder, failureOrder) in updateOrderings:
52+
/// Perform an atomic ${doc} operation and return the original value, applying
53+
/// the specified memory ordering.
54+
///
55+
/// - Parameter operand: A boolean value.
56+
/// - Parameter ordering: The memory ordering to apply on this operation.
57+
/// - Returns: The original value before the operation.
58+
@available(SwiftStdlib 5.10, *)
59+
@_alwaysEmitIntoClient
60+
@_transparent
61+
public func loadThen${name}(
62+
with operand: Bool,
63+
ordering: Atomic${apiOrder}
64+
) -> Bool {
65+
let original = Builtin.atomicrmw_${llvmName}_${llvmOrder}_Int8(
66+
rawAddress,
67+
Bool.encodeAtomicRepresentation(operand).storage
68+
)
69+
70+
return Bool.decodeAtomicRepresentation(AtomicInt8Storage(original))
71+
}
72+
% end
73+
% end
74+
}
75+
76+
//===----------------------------------------------------------------------===//
77+
// Bool atomic operation then loads
78+
//===----------------------------------------------------------------------===//
79+
80+
@available(SwiftStdlib 5.10, *)
81+
extension Atomic where Value == Bool {
82+
% for (name, llvmName, op, label, doc) in boolOperations:
83+
% for (_, apiOrder, _, llvmOrder, failureOrder) in updateOrderings:
84+
/// Perform an atomic ${doc} operation and return the original value after the
85+
/// operation, applying the specified memory ordering.
86+
///
87+
/// - Parameter operand: A boolean value.
88+
/// - Parameter ordering: The memory ordering to apply on this operation.
89+
/// - Returns: The original value after the operation.
90+
@available(SwiftStdlib 5.10, *)
91+
@_alwaysEmitIntoClient
92+
@_transparent
93+
public func ${lowerFirst(name)}ThenLoad(
94+
with operand: Bool,
95+
ordering: Atomic${apiOrder}
96+
) -> Bool {
97+
let original = Builtin.atomicrmw_${llvmName}_${llvmOrder}_Int8(
98+
rawAddress,
99+
Bool.encodeAtomicRepresentation(operand).storage
100+
)
101+
102+
return Bool.decodeAtomicRepresentation(AtomicInt8Storage(original)) ${op} operand
103+
}
104+
% end
105+
% end
106+
}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Atomics open source project
4+
//
5+
// Copyright (c) 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
% from SwiftAtomics import *
14+
15+
import Builtin
16+
17+
% for (intType, intStorage, builtinInt) in intTypes:
18+
19+
//===----------------------------------------------------------------------===//
20+
// ${intType} AtomicValue conformance
21+
//===----------------------------------------------------------------------===//
22+
23+
// FIXME: Conditionalize the conformance of {U}Int64 on 32 bit platforms that do
24+
// not support double word atomics.
25+
26+
@available(SwiftStdlib 5.10, *)
27+
extension ${intType}: AtomicValue {
28+
% if intType == "Int" or intType == "UInt":
29+
#if _pointerBitWidth(_64)
30+
public typealias AtomicRepresentation = AtomicInt64Storage
31+
#elseif _pointerBitWidth(_32)
32+
public typealias AtomicRepresentation = AtomicInt32Storage
33+
#else
34+
#error("Unsupported platform")
35+
#endif
36+
% else:
37+
public typealias AtomicRepresentation = ${intStorage}
38+
% end
39+
40+
@available(SwiftStdlib 5.10, *)
41+
@_alwaysEmitIntoClient
42+
@_transparent
43+
public static func encodeAtomicRepresentation(
44+
_ value: borrowing ${intType}
45+
) -> AtomicRepresentation {
46+
AtomicRepresentation(value._value)
47+
}
48+
49+
@available(SwiftStdlib 5.10, *)
50+
@_alwaysEmitIntoClient
51+
@_transparent
52+
public static func decodeAtomicRepresentation(
53+
_ representation: consuming AtomicRepresentation
54+
) -> ${intType} {
55+
${intType}(representation.storage)
56+
}
57+
}
58+
59+
//===----------------------------------------------------------------------===//
60+
// ${intType} load then atomic operations
61+
//===----------------------------------------------------------------------===//
62+
63+
@available(SwiftStdlib 5.10, *)
64+
extension Atomic where Value == ${intType} {
65+
% for (_, apiOrder, _, llvmOrder, failureOrder) in updateOrderings:
66+
% for (name, builtinName, op, label, doc) in integerOperations:
67+
/// Perform an atomic ${doc} operation and return the original value, applying
68+
/// the specified memory ordering.
69+
///
70+
% if "Wrapping" in name:
71+
/// Note: This operation silently wraps around on overflow, like the
72+
/// `${op}` operator does on `${intType}` values.
73+
///
74+
% end
75+
/// - Parameter operand: An integer value.
76+
/// - Parameter ordering: The memory ordering to apply on this operation.
77+
/// - Returns: The original value before the operation.
78+
@available(SwiftStdlib 5.10, *)
79+
@_alwaysEmitIntoClient
80+
@_transparent
81+
public func loadThen${name}(
82+
${label} operand: ${intType}${" = 1" if "crement" in name else ""},
83+
ordering: Atomic${apiOrder}
84+
) -> ${intType} {
85+
% if intType == "Int" or intType == "UInt":
86+
#if _pointerBitWidth(_64)
87+
let result = Builtin.atomicrmw_${atomicOperationName(intType, builtinName)}_${llvmOrder}_Int64(
88+
rawAddress,
89+
operand._value
90+
)
91+
#elseif _pointerBitWidth(_32)
92+
let result = Builtin.atomicrmw_${atomicOperationName(intType, builtinName)}_${llvmOrder}_Int32(
93+
rawAddress,
94+
operand._value
95+
)
96+
#else
97+
#error("Unsupported platform")
98+
#endif
99+
% else:
100+
let result = Builtin.atomicrmw_${atomicOperationName(intType, builtinName)}_${llvmOrder}_${builtinInt}(
101+
rawAddress,
102+
operand._value
103+
)
104+
% end
105+
106+
return ${intType}(result)
107+
}
108+
% end
109+
110+
/// Perform an atomic wrapping increment operation applying the
111+
/// specified memory ordering.
112+
///
113+
/// Note: This operation silently wraps around on overflow, like the
114+
/// `&+=` operator does on `${intType}` values.
115+
///
116+
/// - Parameter operand: The value to add to the current value.
117+
/// - Parameter ordering: The memory ordering to apply on this operation.
118+
@available(SwiftStdlib 5.10, *)
119+
@_alwaysEmitIntoClient
120+
@_transparent
121+
public func wrappingIncrement(
122+
by operand: ${intType} = 1,
123+
ordering: Atomic${apiOrder}
124+
) {
125+
_ = loadThenWrappingIncrement(by: operand, ordering: ordering)
126+
}
127+
128+
/// Perform an atomic wrapping decrement operation applying the
129+
/// specified memory ordering.
130+
///
131+
/// Note: This operation silently wraps around on overflow, like the
132+
/// `&-=` operator does on `${intType}` values.
133+
///
134+
/// - Parameter operand: The value to subtract from the current value.
135+
/// - Parameter ordering: The memory ordering to apply on this operation.
136+
@available(SwiftStdlib 5.10, *)
137+
@_alwaysEmitIntoClient
138+
@_transparent
139+
public func wrappingDecrement(
140+
by operand: ${intType} = 1,
141+
ordering: Atomic${apiOrder}
142+
) {
143+
_ = loadThenWrappingDecrement(by: operand, ordering: ordering)
144+
}
145+
% end
146+
}
147+
148+
//===----------------------------------------------------------------------===//
149+
// ${intType} atomic operation then loads
150+
//===----------------------------------------------------------------------===//
151+
152+
@available(SwiftStdlib 5.10, *)
153+
extension Atomic where Value == ${intType} {
154+
% for (name, builtinName, op, label, doc) in integerOperations:
155+
% for (_, apiOrder, _, llvmOrder, _) in updateOrderings:
156+
/// Perform an atomic ${doc} operation and return the new value, applying
157+
/// the specified memory ordering.
158+
///
159+
% if "Wrapping" in name:
160+
/// Note: This operation silently wraps around on overflow, like the
161+
/// `${op}` operator does on `${intType}` values.
162+
///
163+
% end
164+
/// - Parameter operand: An integer value.
165+
/// - Parameter ordering: The memory ordering to apply on this operation.
166+
/// - Returns: The new value after the operation.
167+
@available(SwiftStdlib 5.10, *)
168+
@_alwaysEmitIntoClient
169+
@_transparent
170+
public func ${lowerFirst(name)}ThenLoad(
171+
${label} operand: Value${" = 1" if "crement" in name else ""},
172+
ordering: Atomic${apiOrder}
173+
) -> ${intType} {
174+
% if intType == "Int" or intType == "UInt":
175+
#if _pointerBitWidth(_64)
176+
let original = Builtin.atomicrmw_${atomicOperationName(intType, builtinName)}_${llvmOrder}_Int64(
177+
rawAddress,
178+
operand._value
179+
)
180+
#elseif _pointerBitWidth(_32)
181+
let original = Builtin.atomicrmw_${atomicOperationName(intType, builtinName)}_${llvmOrder}_Int32(
182+
rawAddress,
183+
operand._value
184+
)
185+
#else
186+
#error("Unsupported platform")
187+
#endif
188+
% else:
189+
let original = Builtin.atomicrmw_${atomicOperationName(intType, builtinName)}_${llvmOrder}_${builtinInt}(
190+
rawAddress,
191+
operand._value
192+
)
193+
% end
194+
195+
% if name == "Min":
196+
return Swift.min(${intType}(original), operand)
197+
% elif name == "Max":
198+
return Swift.max(${intType}(original), operand)
199+
% else:
200+
return ${intType}(original) ${op} operand
201+
% end
202+
}
203+
% end
204+
% end
205+
}
206+
207+
% end

0 commit comments

Comments
 (0)