Simple SIMD Vector Operations

As you (might) know, there is Vector128 in K/N.
Vector128 is a SIMD (= Single Instruction Multiple Data) (stored in SSE 2 XMM registers on x86) value type. This type can contain 16 chars, 8 shorts, 4 ints, 4 floats, 2 doubles or 2 longs. In K/N you can currently only get elements in Vector128, create Vector128 from values, and read / write them from / to memory.
It seems like this type only exists for C interop, but I believe we should add more operations revolving around it. The most important operations we should have, are simple element-wise math operations as well as horizontal add operations (effectively summing the Vector128).
With these operations, you can manually speed up your programs.
If you are writing a math library using K/N, you could for example make mathematical 2-D double vectors a Vector128.

The problem with all of this:
Multiplatform support.
You would have to write all code that uses it in K/N.
That’s why there should be simple JVM (and other) implementations of Vector128

That would be neat. The problem is that it might be difficult to port on other platforms.

Java Vector API is still experimental (cf. JEP 460). On other platforms like JS, I do not think this is feasible at all.

Yes the problem is that everything would be a Vector128 and you need to be able to treat it as 2xDouble, 4xFloat, … which can be a problem on Kotlin/JVM and Kotlin/JS.

Instead, why not only have the Vector128 type on Kotlin/Native and then have mutable types like Vector2xD and Vector4xF, which could be defined like this:

expect class Vector2xD {
  expect var d1: Double
  expect var d2: Double

  expect fun set(n1: Double, n2: Double)

  expect operator fun plusAssign(other: Vector2xD)
}

and then the implementation on Kotlin/Native:

actual class Vector2xD {
  var vector: Vector128

  actual var d1: Double
    get() = vector.getDouble(0)
    set(v) { set(v, d2) }  // this is actually inefficient. It would be faster to get the pointer to `vector`,
                           // reinterpret it as array pointer of doubles, and set (in this case) the first element to the new value.

  actual var d2: Double
    get() = vector.getDouble(1)
    set(v) { set(d1, v) }

  actual fun set(n1: Double, n2: Double) {
    vector = vectorOf(n1, n2)
  }

  actual operator fun plusAssign(other: Vector2xD) {
    // magic
  }
}

and this on Kotlin/JVM:

actual class Vector2xD {
  actual var d1: Double
  actual var d2: Double

  actual fun set(n1: Double, n2: Double) {
    d1 = n1
    d2 = n2
  }

  actual operator fun plusAssign(other: Vector2xD) {
    this.d1 += other.d1
    this.d2 += other.d2
  }
}

I don’t think that I used expect and actual correctly, but you get the idea.

1 Like