blob: 76cb5795b454afbc1f12fe2393c4dd860450298a [file] [log] [blame]
//===--- SIMDVectorTypes.swift.gyb ----------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2018 - 2019 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 SwiftIntTypes import all_integer_types
word_bits = int(CMAKE_SIZEOF_VOID_P) * 8
storagescalarCounts = [2,4,8,16,32,64]
vectorscalarCounts = storagescalarCounts + [3]
spelledNumbers = {
2: 'two', 4: 'four', 8: 'eight', 16: '16', 32: '32', 64: '64',
3: 'three'
}
ordinalPositions = ['first', 'second', 'third', 'fourth']
}%
%for n in vectorscalarCounts:
% storageN = 4 if n == 3 else n
/// A vector of ${spelledNumbers[n]} scalar values.
@_fixed_layout
public struct SIMD${n}<Scalar> : SIMD where Scalar: SIMDScalar {
public var _storage: Scalar.SIMD${storageN}Storage
public typealias MaskStorage = SIMD${n}<Scalar.SIMDMaskScalar>
/// The number of scalars in the vector.
@_transparent
public var scalarCount: Int {
return ${n}
}
/// Creates a vector with zero in all lanes.
@_transparent
public init() {
_storage = Scalar.SIMD${storageN}Storage()
}
/// Accesses the scalar at the specified position.
public subscript(index: Int) -> Scalar {
@_transparent get {
_precondition(indices.contains(index))
return _storage[index]
}
@_transparent set {
_precondition(indices.contains(index))
_storage[index] = newValue
}
}
/// Creates a new vector from the given elements.
@_transparent
public init(${', '.join(['_ v' + str(i) + ': Scalar' for i in range(n)])}) {
self.init()
% for i in range(n):
self[${i}] = v${i}
% end
}
% if n <= 4:
/// Creates a new vector from the given elements.
///
/// - Parameters:
% for i in range(n):
/// - ${'xyzw'[i]}: The ${ordinalPositions[i]} element of the vector.
% end
@_transparent
public init(${', '.join([c + ': Scalar' for c in 'xyzw'[:n]])}) {
self.init(${', '.join('xyzw'[:n])})
}
% for i in range(n):
/// The ${ordinalPositions[i]} element of the vector.
@_transparent
public var ${'xyzw'[i]}: Scalar {
@_transparent get { return self[${i}]}
@_transparent set { self[${i}] = newValue }
}
% end
% end
% if n >= 4:
/// Creates a new vector from two half-length vectors.
@_transparent
public init(lowHalf: SIMD${n/2}<Scalar>, highHalf: SIMD${n/2}<Scalar>) {
self.init()
self.lowHalf = lowHalf
self.highHalf = highHalf
}
% for (half,indx) in [('low','i'), ('high',str(n/2)+'+i'), ('even','2*i'), ('odd','2*i+1')]:
/// A half-length vector made up of the ${half} elements of the vector.
public var ${half}Half: SIMD${n/2}<Scalar> {
@inlinable get {
var result = SIMD${n/2}<Scalar>()
for i in result.indices { result[i] = self[${indx}] }
return result
}
@inlinable set {
for i in newValue.indices { self[${indx}] = newValue[i] }
}
}
% end
% end
}
extension SIMD${n} where Scalar : FixedWidthInteger {
/// Creates a new vector from the given vector, truncating the bit patterns
/// of the given vector's elements if necessary.
///
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(truncatingIfNeeded other: SIMD${n}<Other>)
where Other : FixedWidthInteger {
self.init()
for i in indices { self[i] = Scalar(truncatingIfNeeded: other[i]) }
}
/// Creates a new vector from the given vector, clamping the values of the
/// given vector's elements if necessary.
///
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(clamping other: SIMD${n}<Other>)
where Other : FixedWidthInteger {
self.init()
for i in indices { self[i] = Scalar(clamping: other[i]) }
}
/// Creates a new vector from the given vector, rounding the given vector's
/// of elements using the specified rounding rule.
///
/// - Parameters:
/// - other: The vector to convert.
/// - rule: The round rule to use when converting elements of `other.` The
/// default is `.towardZero`.
@inlinable
public init<Other>(
_ other: SIMD${n}<Other>,
rounding rule: FloatingPointRoundingRule = .towardZero
)
where Other : BinaryFloatingPoint {
self.init()
// TODO: this should clamp
for i in indices { self[i] = Scalar(other[i].rounded(rule)) }
}
}
extension SIMD${n} : CustomDebugStringConvertible {
public var debugDescription: String {
return "SIMD${n}<\(Scalar.self)>(${', '.join(map(lambda c:
'\\(self['+ str(c) + '])',
xrange(n)))})"
}
}
extension SIMD${n} where Scalar : BinaryFloatingPoint {
/// Creates a new vector from the given vector of integers.
///
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(_ other: SIMD${n}<Other>)
where Other : FixedWidthInteger {
self.init()
for i in indices { self[i] = Scalar(other[i]) }
}
/// Creates a new vector from the given vector of floating-point values.
///
/// - Parameter other: The vector to convert.
@inlinable
public init<Other>(_ other: SIMD${n}<Other>)
where Other : BinaryFloatingPoint {
self.init()
for i in indices { self[i] = Scalar(other[i]) }
}
}
%end
%for self_type in all_integer_types(word_bits):
% Self = self_type.stdlib_name
% BuiltinName = self_type.builtin_name
% Mask = Self if self_type.is_signed else self_type.get_opposite_signedness().stdlib_name
extension ${Self} : SIMDScalar {
public typealias SIMDMaskScalar = ${Mask}
% for n in storagescalarCounts:
% bytes = n * self_type.bits / 8
/// Storage for a vector of ${spelledNumbers[n]} integers.
@_fixed_layout
@_alignment(${bytes if bytes <= 16 else 16})
public struct SIMD${n}Storage : SIMDStorage {
public var _value: Builtin.Vec${n}x${BuiltinName}
@_transparent
public var scalarCount: Int {
return ${n}
}
@_transparent
public init() {
_value = Builtin.zeroInitializer()
}
public subscript(index: Int) -> ${Self} {
@_transparent
get {
return ${Self}(Builtin.extractelement_Vec${n}x${BuiltinName}_Int32(
_value, Int32(truncatingIfNeeded: index)._value
))
}
@_transparent
set {
_value = Builtin.insertelement_Vec${n}x${BuiltinName}_${BuiltinName}_Int32(
_value, newValue._value, Int32(truncatingIfNeeded: index)._value
)
}
}
}
% end
}
%end
%for (Self, bits) in [('Float',32), ('Double',64)]:
extension ${Self} : SIMDScalar {
public typealias SIMDMaskScalar = Int${bits}
% for n in storagescalarCounts:
% bytes = n * bits / 8
/// Storage for a vector of ${spelledNumbers[n]} floating-point values.
@_fixed_layout
@_alignment(${bytes if bytes <= 16 else 16})
public struct SIMD${n}Storage : SIMDStorage {
public var _value: Builtin.Vec${n}xFPIEEE${bits}
@_transparent
public var scalarCount: Int {
return ${n}
}
@_transparent
public init() {
_value = Builtin.zeroInitializer()
}
public subscript(index: Int) -> ${Self} {
@_transparent
get {
return ${Self}(Builtin.extractelement_Vec${n}xFPIEEE${bits}_Int32(
_value, Int32(truncatingIfNeeded: index)._value
))
}
@_transparent
set {
_value = Builtin.insertelement_Vec${n}xFPIEEE${bits}_FPIEEE${bits}_Int32(
_value, newValue._value, Int32(truncatingIfNeeded: index)._value
)
}
}
}
% end
}
%end