Apple Engine

Apple, iPhone, iOS, その周辺のことについて

Swift 5.1 で追加された SIMD の機能

忘れていたのでまとめてみる。
Swift でビルトイン実装されている SMID の機能と Swift Standard Library で SMID を引数として持つ関数が追加された。

 

追加されたものは以下のもの

 

SIMD
  • one
  • clamp(lowerBound:upperBound:)
  • max()
  • min()
  • sum()
  • wrappedSum()
  • hashValue
  • scalarCount
  • subscript(_:)
  • イニシャライズ時に ArrayLiteralElement のサポート

 

SIMD3、SIMD4 のみ
  • init(_ xy: SIMD2, _ z: Scalar)
  • init(_ xyz: SIMD3, _ w: Scalar)

 

Swift Standard Library
  • any(_:)
  • all(_:)
  • pointwiseMax(::)
  • pointwiseMin(::)

 

内容説明

以下、特に記載がなければ、SIMD2 〜 64 と全ての型 (Scalar) を対応。
SIMD の説明はしないので前回を参照。

 

one

以前にあった zero はレーンを 0 で埋めるものだがこちらは 1 で埋めていく。

let s = SIMD4<Float>.one

// SIMD4<Float>(1.0, 1.0, 1.0, 1.0)

 

clamp(lowerBound:upperBound:)

指定された2レーンの中から上限値と下限値内に収まるように各値を変更する。

let s1 = SIMD4<Float>(1.1, 2.2, 3.3, 4.4)

let s2 = s1.clamped(
    lowerBound: SIMD4<Float>(2,2,2,2),
    upperBound: SIMD4<Float>(4,4,4,4)
)
// SIMD4<Float>(2.0, 2.2, 3.3, 4.0)

 

max()
min()

レーンの中から最大値や最小値を調べその値を返す。

let s = SIMD4<Float>(1.1, 2.2, 3.3, 4.4)

s.max() // 4.4
s.min() // 1.1

 

sum()
wrappedSum()

sum() は FloatingPoint を返し、wrappedSum() は FixedWidthInteger を返す。
そのため、型 (Scalar) が浮動小数点数の場合は sum()、
整数の場合は wrappedSum() が使用可能。

let s1 = SIMD4<Float>(0.0, 1.1, 2.2, 3.3)
let s2 = SIMD16<Int>(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)

s1.sum() // 6.6
s2.wrappedSum() // 120

 

hashValue

ハッシュ値を返す。

let s1 = SIMD4<Int>(0,1,2,4)
s1.hashValue // -8324632633033442855 など

 

scalarCount

Scalar が幾つの SIMD か調べることができる。

let s1 = SIMD4<Int>(0,1,2,3)
let s2 = SIMD16<Int>(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)

s1.scalarCount // 4
s2.scalarCount // 16

 

subscript(_:)

FixedWidthInteger の SIMD を添え字として使用し対象の SIMD の値を取り出し、
新しい値の入ったレーンを取得できる。

let s1 = SIMD2<Int>(3,2)
let s2 = SIMD4<Float>(0.1, 0.2, 0.3, 0.4)

let s3 = s2[s1] // SIMD2<Float>(0.4, 0.3)

 

イニシャライズ時に ArrayLiteralElement のサポート

配列の記述を使用し、SIMD イニシャライズすることが可能になった。
SIMD2 〜 64、全ての型 (Scalar) を対応。

let a2:[Float] = [1,2]
let a3:[Float] = [1,2,3]
let a4:[Float] = [1,2,3,4]
let a8:[Float] = [1,2,3,4,5,6,7,8]

let s2 = SIMD2<Float>(a2)
let s3 = SIMD3<Float>(a3)
let s4 = SIMD4<Float>(a4)
let s8 = SIMD8<Float>(a8)

 

init(_ xy: SIMD2, _ z: Scalar)
init(_ xyz: SIMD3, _ w: Scalar)

SIMD3、SIMD4 のみ、SIMD2、SIMD3 と最後の値を足すことでイニシャライズできる関数が追加された。

let s2 = SIMD2<Float>.zero // SIMD2<Float>(0.0, 0.0)
let s3 = SIMD3<Float>(s2, 3) // SIMD3<Float>(0.0, 0.0, 3.0)
let s4 = SIMD4<Float>(s3, 4) // SIMD4<Float>(0.0, 0.0, 3.0, 4.0)

 

any(_:)
all(_:)

SIMDMask の Bool を使い状態を判別する関数。
any はレーンのいずれかが true であれば true、
all はレーンの全てが true であれば true を返す

let s8 = SIMD8<Float>(1,2,3,4,5,6,7,8)

any(s8 .< 3) // true
all(s8 .< 7) // false
all(s8 .< 9) // true

 

pointwiseMin(_:_:)
pointwiseMax(_:_:)

2つのレーンを調べその中の最大値や最小値を設定したレーンを返す。

let s1 = SIMD3(0,1,2)
let s2 = SIMD3(2,1,0)
pointwiseMin(s1, s2) // SIMD3<Int>(0, 1, 0)
pointwiseMax(s1, s2) // SIMD3<Int>(2, 1, 2)

 

廃止になったもの

  • init(Self.Scalar)
  • static func - (Self) -> Self

 

以上、更新の内容。
実は前回のやつ全て書いてないので全部紹介しきれていないけど