Your assembly outplut looks like it is compiled in debug mode.
You are right that your two functions compile to the same machine code. This gets even more obvious when compiling with ReleaseSafe:
example.multiplyAsScalar:
push rbp
mov rbp, rsp
vmulsd xmm0, xmm0, xmm1
pop rbp
ret
multiplyAsScalar = example.multiplyAsScalar
multiplyAsVec = example.multiplyAsScalar
This is because SIMD vectors in zig are not really special. They do not force the compiler to use SIMD registers. They just keep data in a shape for which the optimizer probably is able to use simd instructions if it sees fit.
Under the right cicumstances scalar zig code can also generate simd instructions. The following will most likely result in vectorized machine code if f is just some scalar math.
fn apply2(f: fn (f64, f64) f64, x: @Vector(8, f64), y: @Vector(8, f64)) @Vector(8, f64) {
var res: [8]f64 = undefined;
const x_arr: [8]f64 = x;
const y_arr: [8]f64 = y;
for (&res, x_arr, y_arr) |*r, xe, ye| r.* = f(xe, ye);
return res;
}
Here is a version of apply that works for functions that take arbitrarily many args:
Note that this produces exactly the same assembly if I replace all uses of @Vector(n, T) with [n]T.