Okay, I had some time to go through the proposal in more depth:
-
Your comment in the previous thread alludes to possible "machine-width" vectors. I don't see this in the proposal - why not? Is it coming in a follow-up proposal?
-
I find the name
SIMDVectortoo similar to the concreteVectorNtypes. Have you considered a name likeVectorProtocol(andIntegerVectorProtocol,FloatingPointVectorProtocol)? -
I really, desperately wish we could embed protocols inside of (non-generic) types. Then we could create a simple
SIMDcaseless enum to contain the huge number of protocols this proposal would introduce. There are open questions about nesting inside of generic types, but we don't need to tackle those right now. I can't say how much work that would be (@Douglas_Gregor?), but if it were possible for Swift 5.1 (which I just made up), I think it's worth considering delaying until we can do that. This has a huge surface area. -
It would be nice if
SIMDVector.init(_: Array<Element>)was generic. This would allow us to use custom collections and slices:let vec = Vector4(myCollection.prefix(4)) let vec2 = Vector4(myCollection.suffix(4)) -
The proposal includes a way to get numbers from a collection/sequence in to a vector, but it isn't clear to me how I would get my results out of the vector back in to another collection/sequence. Some kind of
SequenceorCollectionview of the vector's elements is necessary for that (as Dave mentioned):let vec = Vector4([1, 2, 3, 4]) /* do some processing */ myArray.append(contentsOf: vec.elements) // requires Sequence. return Array(vec.elements) // requires Sequence -
Have you considered a strongly-typed
IndexforSIMDVector.subscript(_: Int), instead of raw integers and specially-named getters and setters? We could make the IndexExpressibleByIntegerLiteralfor integer subscripting. This might help avoid runtime failures - since these are fixed-size types, we only need to check bounds when creating an Index, not every time we use one. I'm not sure if the proposed subscript could be@compilerEvaluable(when we have that), but bounds-checking for Index creation certainly could be:protocol SIMDVector { associatedtype Index: ExpressibleByIntegerLiteral // maybe Equatable, Hashable, Comparable, too? subscript(_: Index) -> Element } extension Vector4 { enum Index { case x, y, z, w } } extension Vector4.Index: ExpressibleByIntegerLiteral { // future: @compilerEvaluable init(integerLiteral: Int8) { switch integerLiteral { case 0: self = .x case 1: self = .y // ...etc default: fatalError("Out of bounds") // future: compiler-evaluated `#assert` } } } let vec = Vector4([9, 8, 7, 6]) vec[.y] *= -1 vec[3] = 42Large vectors could simply wrap an integer, with no special names:
extension Vector64 { struct Index: ExpressibleByIntegerLiteral { private var _value: Int8 // future: @compilerEvaluable init(integerLiteral: Int8) { guard integerLiteral >= 0, integerLiteral < 64 else { /* future: compiler-evaluated `#assert` */ } self._value = integerLiteral } } } -
The Mask's
all()andany()functions do not match the names fromCollection, and IMO are not clear enough about what they do. Collection calls these predicatesallSatisfyandcontains. I wonder if it is possible to bring these APIs closer together. I think it reads better:// okay, the word "satisfy" isn't great here. func allSatisfy(_ element: Bool) -> Bool { guard element == true else { return !_any() } return _all() } func contains(_ element: Bool) -> Bool { guard element == true else { return !_all() } return _any() } guard mask.allSatisfy(true) else { /* ... */ } if mask.contains(false) { /* ... */ } -
I think the name
SIMDIntegerVector.init(bitMaskFrom: Mask)is awkward. Can we drop the wordFrom? -
I would like to echo these points from other reviewers. The proposal needs more details.