blob: 540796ad65fe4cc856cf9444389e60f5809cca3e [file] [log] [blame]
infix operator .== : ComparisonPrecedence
infix operator .!= : ComparisonPrecedence
infix operator .< : ComparisonPrecedence
infix operator .<= : ComparisonPrecedence
infix operator .> : ComparisonPrecedence
infix operator .>= : ComparisonPrecedence
// Not used in the stdlib, but declared here so the declarations are always
// visible.
infix operator .& : LogicalConjunctionPrecedence
infix operator .^ : LogicalDisjunctionPrecedence
infix operator .| : LogicalDisjunctionPrecedence
infix operator .&= : AssignmentPrecedence
infix operator .^= : AssignmentPrecedence
infix operator .|= : AssignmentPrecedence
prefix operator .!
/// A SIMD vector type that may not have any computational operations.
///
/// This protocol only defines a storage layout and provides elementwise
/// accesses. Computational operations are defined on SIMDVector, which
/// refines this protocol, or on the concrete types that conform.
public protocol SIMDStorage {
/// The type of scalars in the vector space.
associatedtype Scalar : Hashable
/// The number of scalars/elements in the vector.
var scalarCount: Int { get }
/// A vector with zero in all lanes.
init()
/// Element access to the vector.
subscript(index: Int) -> Scalar { get set }
}
public protocol SIMDScalar {
associatedtype SIMDMaskScalar : SIMDScalar & FixedWidthInteger & SignedInteger
associatedtype SIMD2Storage : SIMDStorage where SIMD2Storage.Scalar == Self
associatedtype SIMD4Storage : SIMDStorage where SIMD4Storage.Scalar == Self
associatedtype SIMD8Storage : SIMDStorage where SIMD8Storage.Scalar == Self
associatedtype SIMD16Storage : SIMDStorage where SIMD16Storage.Scalar == Self
associatedtype SIMD32Storage : SIMDStorage where SIMD32Storage.Scalar == Self
associatedtype SIMD64Storage : SIMDStorage where SIMD64Storage.Scalar == Self
}
public protocol SIMD : SIMDStorage,
Hashable,
CustomStringConvertible,
ExpressibleByArrayLiteral {
/// The mask type resulting from pointwise comparisons of this vector type.
associatedtype MaskStorage : SIMD
where MaskStorage.Scalar : FixedWidthInteger & SignedInteger
}
public extension SIMD {
/// The valid indices for subscripting the vector.
@_transparent
var indices: Range<Int> { return 0 ..< scalarCount }
/// A vector with value in all lanes.
@_transparent
init(repeating value: Scalar) {
self.init()
for i in indices { self[i] = value }
}
/// Conformance to Equatable
@_transparent
static func ==(lhs: Self, rhs: Self) -> Bool {
var result = true
for i in lhs.indices { result = result && lhs[i] == rhs[i] }
return result
}
/// Conformance to Hashable
@inlinable
func hash(into hasher: inout Hasher) {
for i in indices { hasher.combine(self[i]) }
}
/// Conformance to CustomStringConvertible
var description: String {
get {
return "\(Self.self)(" + indices.map({"\(self[$0])"}).joined(separator: ", ") + ")"
}
}
/// Pointwise equality
@_transparent
static func .==(lhs: Self, rhs: Self) -> SIMDMask<MaskStorage> {
var result = SIMDMask<MaskStorage>()
for i in result.indices { result[i] = lhs[i] == rhs[i] }
return result
}
@_transparent
static func .!=(lhs: Self, rhs: Self) -> SIMDMask<MaskStorage> {
var result = SIMDMask<MaskStorage>()
for i in result.indices { result[i] = lhs[i] != rhs[i] }
return result
}
/// Replaces elements of this vector with `other` in the lanes where
/// `mask` is `true`.
@_transparent
mutating func replace(with other: Self, where mask: SIMDMask<MaskStorage>) {
for i in indices { self[i] = mask[i] ? other[i] : self[i] }
}
@inlinable
init(arrayLiteral scalars: Scalar...) {
self.init(scalars)
}
@inlinable
init<S: Sequence>(_ scalars: S) where S.Element == Scalar {
self.init()
var index = 0
for scalar in scalars {
if index == scalarCount {
_preconditionFailure("Too many elements in sequence.")
}
self[index] = scalar
index += 1
}
if index < scalarCount {
_preconditionFailure("Not enough elements in sequence.")
}
}
}
// Implementations of comparison operations. These should eventually all
// be replaced with @_semantics to lower directly to vector IR nodes.
public extension SIMD where Scalar : Comparable {
/// Pointwise less than
@_transparent
static func .<(lhs: Self, rhs: Self) -> SIMDMask<MaskStorage> {
var result = SIMDMask<MaskStorage>()
for i in result.indices { result[i] = lhs[i] < rhs[i] }
return result
}
/// Pointwise less than or equal to
@_transparent
static func .<=(lhs: Self, rhs: Self) -> SIMDMask<MaskStorage> {
var result = SIMDMask<MaskStorage>()
for i in result.indices { result[i] = lhs[i] <= rhs[i] }
return result
}
}
// These operations should never need @_semantics; they should be trivial
// wrappers around the core operations defined above.
public extension SIMD {
@_transparent static func .==(lhs: Scalar, rhs: Self) -> SIMDMask<MaskStorage> { return Self(repeating: lhs) .== rhs }
@_transparent static func .!=(lhs: Scalar, rhs: Self) -> SIMDMask<MaskStorage> { return Self(repeating: lhs) .!= rhs }
@_transparent static func .==(lhs: Self, rhs: Scalar) -> SIMDMask<MaskStorage> { return lhs .== Self(repeating: rhs) }
@_transparent static func .!=(lhs: Self, rhs: Scalar) -> SIMDMask<MaskStorage> { return lhs .!= Self(repeating: rhs) }
@_transparent
mutating func replace(with other: Scalar, where mask: SIMDMask<MaskStorage>) {
replace(with: Self(repeating: other), where: mask)
}
@_transparent
func replacing(with other: Self, where mask: SIMDMask<MaskStorage>) -> Self {
var result = self
result.replace(with: other, where: mask)
return result
}
@_transparent
func replacing(with other: Scalar, where mask: SIMDMask<MaskStorage>) -> Self {
return replacing(with: Self(repeating: other), where: mask)
}
}
public extension SIMD where Scalar : Comparable {
@_transparent static func .>=(lhs: Self, rhs: Self) -> SIMDMask<MaskStorage> { return rhs .<= lhs }
@_transparent static func .>(lhs: Self, rhs: Self) -> SIMDMask<MaskStorage> { return rhs .< lhs }
@_transparent static func .<(lhs: Scalar, rhs: Self) -> SIMDMask<MaskStorage> { return Self(repeating: lhs) .< rhs }
@_transparent static func .<=(lhs: Scalar, rhs: Self) -> SIMDMask<MaskStorage> { return Self(repeating: lhs) .<= rhs }
@_transparent static func .>=(lhs: Scalar, rhs: Self) -> SIMDMask<MaskStorage> { return Self(repeating: lhs) .>= rhs }
@_transparent static func .>(lhs: Scalar, rhs: Self) -> SIMDMask<MaskStorage> { return Self(repeating: lhs) .> rhs }
@_transparent static func .<(lhs: Self, rhs: Scalar) -> SIMDMask<MaskStorage> { return lhs .< Self(repeating: rhs) }
@_transparent static func .<=(lhs: Self, rhs: Scalar) -> SIMDMask<MaskStorage> { return lhs .<= Self(repeating: rhs) }
@_transparent static func .>=(lhs: Self, rhs: Scalar) -> SIMDMask<MaskStorage> { return lhs .>= Self(repeating: rhs) }
@_transparent static func .>(lhs: Self, rhs: Scalar) -> SIMDMask<MaskStorage> { return lhs .> Self(repeating: rhs) }
}
public extension SIMD where Scalar : FixedWidthInteger {
@_transparent static var zero: Self { return Self() }
@inlinable
static func random<T: RandomNumberGenerator>(
in range: Range<Scalar>,
using generator: inout T
) -> Self {
var result = Self()
for i in result.indices {
result[i] = Scalar.random(in: range, using: &generator)
}
return result
}
@inlinable
static func random(in range: Range<Scalar>) -> Self {
var g = SystemRandomNumberGenerator()
return Self.random(in: range, using: &g)
}
@inlinable
static func random<T: RandomNumberGenerator>(
in range: ClosedRange<Scalar>,
using generator: inout T
) -> Self {
var result = Self()
for i in result.indices {
result[i] = Scalar.random(in: range, using: &generator)
}
return result
}
@inlinable
static func random(in range: ClosedRange<Scalar>) -> Self {
var g = SystemRandomNumberGenerator()
return Self.random(in: range, using: &g)
}
}
public extension SIMD where Scalar : FloatingPoint {
@_transparent static var zero: Self { return Self() }
}
public extension SIMD
where Scalar : BinaryFloatingPoint, Scalar.RawSignificand : FixedWidthInteger {
@inlinable
static func random<T: RandomNumberGenerator>(
in range: Range<Scalar>,
using generator: inout T
) -> Self {
var result = Self()
for i in result.indices {
result[i] = Scalar.random(in: range, using: &generator)
}
return result
}
@inlinable
static func random(in range: Range<Scalar>) -> Self {
var g = SystemRandomNumberGenerator()
return Self.random(in: range, using: &g)
}
@inlinable
static func random<T: RandomNumberGenerator>(
in range: ClosedRange<Scalar>,
using generator: inout T
) -> Self {
var result = Self()
for i in result.indices {
result[i] = Scalar.random(in: range, using: &generator)
}
return result
}
@inlinable
static func random(in range: ClosedRange<Scalar>) -> Self {
var g = SystemRandomNumberGenerator()
return Self.random(in: range, using: &g)
}
}
@_fixed_layout
public struct SIMDMask<Storage> : SIMD
where Storage : SIMD,
Storage.Scalar : FixedWidthInteger & SignedInteger {
public var _storage : Storage
public typealias MaskStorage = Storage
public typealias Scalar = Bool
@_transparent
public var scalarCount: Int {
return _storage.scalarCount
}
@_transparent
public init() {
_storage = Storage()
}
@_transparent
public init(_ _storage: Storage) {
self._storage = _storage
}
public subscript(index: Int) -> Bool {
@_transparent
get {
_precondition(indices.contains(index))
return _storage[index] < 0
}
@_transparent
set {
_precondition(indices.contains(index))
_storage[index] = newValue ? -1 : 0
}
}
}
public extension SIMDMask {
@inlinable
static func random<T: RandomNumberGenerator>(using generator: inout T) -> SIMDMask {
var result = SIMDMask()
for i in result.indices { result[i] = Bool.random(using: &generator) }
return result
}
@inlinable
static func random() -> SIMDMask {
var g = SystemRandomNumberGenerator()
return SIMDMask.random(using: &g)
}
}