Tinkered with SIMD operations in Swift
Working on PRs [string] SIMD-izes internal func in StringCreate.swift and on SIMD
variant of PR [stdlib] Add to Unsafe[Mutable]RawBufferPointer implementation of _custom[Last]IndexOfEquatableElement explained in post I have found that Swift’s implementation of SIMD
misses operations for checking if SIMD
vector includes particular scalar. At the same time, simd
implementation in Objective-C has simd_any
and simd_all
. These is poor documented in Apple documentation. These operations allow check not only presence of some scalar but allow use conditions like
if (simd_any(x < 0)) {
// executed if any lane of x
// contains a negative value.
}
if (simd_all(x == 0)) {
// executed if every lane of x
// contains zero.
}
Implementing these operations in Swift would become reasonable Swift proposal extending proposal SIMD Vectors which introduced SIMD
.
Proposal makes possible above mentioned operations only on two steps:
if (SIMD4<Int>(1,2,-3,4) .< 0) != SIMDMask<SIMD4<Int>>(repeating: false) {
// executed if any lane of vector
// contains a negative value.
print("There's a lane with negative value.")
} else {
print("All lanes have non-negative values.")
}
if (SIMD4<Int>(-1,-2,-3,-4) .< 0) == SIMDMask<SIMD4<Int>>(repeating: true) {
// executed if every lane of vector
// contains a negative value.
print("All lanes have negative values.")
} else {
print("There's a lane with non-negative value.")
}
May be it does make sense defining operations like ∀<
for all and ∃<
for any. Math symbol ∀ means ‘all’, and ∃ - ‘there exists’. These operations could be defined like:
infix operator ∀<: ComparisonPrecedence // all
infix operator ∃<: ComparisonPrecedence // any
extension SIMD where Scalar: Comparable {
/// Returns a boolean if all lane contains value less then provided scalar.
public static func ∀<(vector: Self, scalar: Scalar) -> Bool {
for index in vector.indices where !(vector[index] < scalar) {
return false
}
return true
/// Alternative implementation in terms of vector operations
return (vector .< scalar) == SIMDMask(repeating: true)
}
/// Returns a boolean if any lane contains value less then provided scalar.
public static func ∃<(vector: Self, scalar: Scalar) -> Bool {
for index in vector.indices where vector[index] < scalar {
return true
}
return false
/// Alternative implementation in terms of vector operations
return (vector .< scalar) != SIMDMask(repeating: false)
}
}
With such operations comparisons from snippets above become one step and much more readable:
if SIMD4<Int>(1,2,-3,4) ∃< 0 {
// executed if any lane of vector
// contains a negative value.
print("There's a lane with negative value.")
} else {
print("All lanes have non-negative values.")
}
if SIMD4<Int>(-1,-2,-3,-4) ∀< 0 {
// executed if every lane of vector
// contains a negative value.
print("All lanes have negative values.")
} else {
print("There's a lane with non-negative value.")
}
Fuuuuuuuuuck. SIMDVector.swift
defines global functions any
and all
on SIMDMask
argument which make possible what is needed. Why SIMD neither SIMD proposal nor any post/article I have read mentions these important functions!?
if all(SIMD4<Int>(-1,-2,-3,-4) .< 0) {
// executed if any lane of vector
// contains a negative value.
print("There's a lane with negative value.")
}
if any(SIMD4<Int>(1,2,-3,4) .< 0) {
// executed if any lane of vector
// contains a negative value.
print("There's a lane with negative value.")
}