Implement the Atomic type

This commit is contained in:
Alejandro Alonso
2023-09-28 20:54:32 -07:00
parent ae983d8f84
commit f747162084
12 changed files with 1829 additions and 4 deletions

View File

@@ -0,0 +1,328 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Atomics open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
% from SwiftAtomics import *
import Builtin
% for (type, size, alignment, builtin) in atomicTypes:
//===----------------------------------------------------------------------===//
// ${size} bit Atomic Storage
//===----------------------------------------------------------------------===//
@available(SwiftStdlib 5.10, *)
@_alignment(${alignment})
@frozen
public struct ${type} {
@usableFromInline
var storage: ${builtin}
@available(SwiftStdlib 5.10, *)
@inlinable
init(_ builtin: ${builtin}) {
self.storage = builtin
}
}
// ${size} bit atomic loads
@available(SwiftStdlib 5.10, *)
extension Atomic where Value.AtomicRepresentation == ${type} {
% for (swift, api, doc, llvm) in loadOrderings:
/// Atomically loads and returns the current value, applying the specified
/// memory ordering.
///
/// - Parameter ordering: The memory ordering to apply on this operation.
/// - Returns: The current value.
@available(SwiftStdlib 5.10, *)
@_alwaysEmitIntoClient
@_transparent
public func load(ordering: Atomic${api}) -> Value {
Value.decodeAtomicRepresentation(
${type}(Builtin.atomicload_${llvm}_Int${size}(rawAddress))
)
}
% end
}
// ${size} bit atomic stores
@available(SwiftStdlib 5.10, *)
extension Atomic where Value.AtomicRepresentation == ${type} {
% for (swift, api, doc, llvm) in storeOrderings:
/// Atomically sets the current value to `desired`, applying the specified
/// memory ordering.
///
/// - Parameter desired: The desired new value.
/// - Parameter ordering: The memory ordering to apply on this operation.
@available(SwiftStdlib 5.10, *)
@_alwaysEmitIntoClient
@_transparent
public func store(
_ desired: consuming Value,
ordering: Atomic${api}
) {
Builtin.atomicstore_${llvm}_Int${size}(
rawAddress,
Value.encodeAtomicRepresentation(desired).storage
)
}
% end
}
// ${size} bit atomic exchanges
@available(SwiftStdlib 5.10, *)
extension Atomic where Value.AtomicRepresentation == ${type} {
% for (swift, api, _, llvm, _) in updateOrderings:
/// Atomically sets the current value to `desired` and returns the original
/// value, applying the specified memory ordering.
///
/// - Parameter desired: The desired new value.
/// - Parameter ordering: The memory ordering to apply on this operation.
/// - Returns: The original value.
@available(SwiftStdlib 5.10, *)
@_alwaysEmitIntoClient
@_transparent
public func exchange(
_ desired: consuming Value,
ordering: Atomic${api}
) -> Value {
let desired = Value.encodeAtomicRepresentation(desired).storage
let result = Builtin.atomicrmw_xchg_${llvm}_Int${size}(rawAddress, desired)
let atomicStorage = ${type}(result)
return Value.decodeAtomicRepresentation(atomicStorage)
}
% end
}
// ${size} bit atomic compare and exchanges
@available(SwiftStdlib 5.10, *)
extension Atomic where Value.AtomicRepresentation == ${type} {
% for (_, api, _, llvm, failure) in updateOrderings:
/// Perform an atomic compare and exchange operation on the current value,
/// applying the specified memory ordering.
///
/// This operation performs the following algorithm as a single atomic
/// transaction:
///
/// ```
/// atomic(self) { currentValue in
/// let original = currentValue
/// guard original == expected else { return (false, original) }
/// currentValue = desired
/// return (true, original)
/// }
/// ```
///
/// This method implements a "strong" compare and exchange operation
/// that does not permit spurious failures.
///
/// - Parameter expected: The expected current value.
/// - Parameter desired: The desired new value.
/// - Parameter ordering: The memory ordering to apply on this operation.
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
/// the exchange was successful, and `original` is the original value.
@available(SwiftStdlib 5.10, *)
@_alwaysEmitIntoClient
@_transparent
public func compareExchange(
expected: consuming Value,
desired: consuming Value,
ordering: Atomic${api}
) -> (exchanged: Bool, original: Value) {
compareExchange(
expected: expected,
desired: desired,
successOrdering: ordering,
failureOrdering: .${llvmToCaseName(failure)}
)
}
% end
}
@available(SwiftStdlib 5.10, *)
extension Atomic where Value.AtomicRepresentation == ${type} {
% for (_, successApi, _, successLLVM, successFailure) in updateOrderings:
% for (_, failureApi, _, failureLLVM) in loadOrderings:
/// Perform an atomic compare and exchange operation on the current value,
/// applying the specified success/failure memory orderings.
///
/// This operation performs the following algorithm as a single atomic
/// transaction:
///
/// ```
/// atomic(self) { currentValue in
/// let original = currentValue
/// guard original == expected else { return (false, original) }
/// currentValue = desired
/// return (true, original)
/// }
/// ```
///
/// The `successOrdering` argument specifies the memory ordering to use when
/// the operation manages to update the current value, while `failureOrdering`
/// will be used when the operation leaves the value intact.
///
/// This method implements a "strong" compare and exchange operation
/// that does not permit spurious failures.
///
/// - Parameter expected: The expected current value.
/// - Parameter desired: The desired new value.
/// - Parameter successOrdering: The memory ordering to apply if this
/// operation performs the exchange.
/// - Parameter failureOrdering: The memory ordering to apply on this
/// operation does not perform the exchange.
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
/// the exchange was successful, and `original` is the original value.
@available(SwiftStdlib 5.10, *)
@_alwaysEmitIntoClient
@_transparent
public func compareExchange(
expected: consuming Value,
desired: consuming Value,
successOrdering: Atomic${successApi},
failureOrdering: Atomic${failureApi}
) -> (exchanged: Bool, original: Value) {
let expected = Value.encodeAtomicRepresentation(expected).storage
let desired = Value.encodeAtomicRepresentation(desired).storage
let (ov, won) = Builtin.cmpxchg_${actualOrders(successLLVM, failureLLVM)}_Int${size}(
rawAddress,
expected,
desired
)
return (
exchanged: Bool(won),
original: Value.decodeAtomicRepresentation(${type}(ov))
)
}
% end
% end
}
// ${size} bit atomic weak compare and exchanges
@available(SwiftStdlib 5.10, *)
extension Atomic where Value.AtomicRepresentation == ${type} {
% for (_, api, _, llvm, failure) in updateOrderings:
/// Perform an atomic weak compare and exchange operation on the current
/// value, applying the memory ordering. This compare-exchange variant is
/// allowed to spuriously fail; it is designed to be called in a loop until
/// it indicates a successful exchange has happened.
///
/// This operation performs the following algorithm as a single atomic
/// transaction:
///
/// ```
/// atomic(self) { currentValue in
/// let original = currentValue
/// guard original == expected else { return (false, original) }
/// currentValue = desired
/// return (true, original)
/// }
/// ```
///
/// (In this weak form, transient conditions may cause the `original ==
/// expected` check to sometimes return false when the two values are in fact
/// the same.)
///
/// - Parameter expected: The expected current value.
/// - Parameter desired: The desired new value.
/// - Parameter ordering: The memory ordering to apply on this operation.
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
/// the exchange was successful, and `original` is the original value.
@available(SwiftStdlib 5.10, *)
@_alwaysEmitIntoClient
@_transparent
public func weakCompareExchange(
expected: consuming Value,
desired: consuming Value,
ordering: Atomic${api}
) -> (exchanged: Bool, original: Value) {
weakCompareExchange(
expected: expected,
desired: desired,
successOrdering: ordering,
failureOrdering: .${llvmToCaseName(failure)}
)
}
% end
}
@available(SwiftStdlib 5.10, *)
extension Atomic where Value.AtomicRepresentation == ${type} {
% for (_, successApi, _, successLLVM, successFailure) in updateOrderings:
% for (_, failureApi, _, failureLLVM) in loadOrderings:
/// Perform an atomic weak compare and exchange operation on the current
/// value, applying the specified success/failure memory orderings. This
/// compare-exchange variant is allowed to spuriously fail; it is designed to
/// be called in a loop until it indicates a successful exchange has happened.
///
/// This operation performs the following algorithm as a single atomic
/// transaction:
///
/// ```
/// atomic(self) { currentValue in
/// let original = currentValue
/// guard original == expected else { return (false, original) }
/// currentValue = desired
/// return (true, original)
/// }
/// ```
///
/// (In this weak form, transient conditions may cause the `original ==
/// expected` check to sometimes return false when the two values are in fact
/// the same.)
///
/// The `ordering` argument specifies the memory ordering to use when the
/// operation manages to update the current value, while `failureOrdering`
/// will be used when the operation leaves the value intact.
///
/// - Parameter expected: The expected current value.
/// - Parameter desired: The desired new value.
/// - Parameter successOrdering: The memory ordering to apply if this
/// operation performs the exchange.
/// - Parameter failureOrdering: The memory ordering to apply on this
/// operation does not perform the exchange.
/// - Returns: A tuple `(exchanged, original)`, where `exchanged` is true if
/// the exchange was successful, and `original` is the original value.
@available(SwiftStdlib 5.10, *)
@_alwaysEmitIntoClient
@_transparent
public func weakCompareExchange(
expected: consuming Value,
desired: consuming Value,
successOrdering: Atomic${successApi},
failureOrdering: Atomic${failureApi}
) -> (exchanged: Bool, original: Value) {
let expected = Value.encodeAtomicRepresentation(expected).storage
let desired = Value.encodeAtomicRepresentation(desired).storage
let (ov, won) = Builtin.cmpxchg_${actualOrders(successLLVM, failureLLVM)}_weak_Int${size}(
rawAddress,
expected,
desired
)
return (
exchanged: Bool(won),
original: Value.decodeAtomicRepresentation(${type}(ov))
)
}
% end
% end
}
% end