SIMD, Vectors and Inline Assembly

31.1 @Vector

const V4 = @Vector(4, f32);
const a: V4 = .{ 1, 2, 3, 4 };
const b: V4 = @splat(2.0);
const c = a * b + a;                         // element-wise operations
const total = @reduce(.Add, c);              // horizontal reduction
const mask = a > b;                          // @Vector(4, bool)
const picked = @select(f32, mask, a, b);
const shuffled = @shuffle(f32, a, undefined, [4]i32{ 3, 2, 1, 0 });
const arr: [4]f32 = c;                       // vector ↔ array coercion
std.debug.print("{d} {any} {any}\n", .{ total, picked, arr });
_ = shuffled;

fn sumSimd(data: []const f32) f32 {
    const L = std.simd.suggestVectorLength(f32) orelse 4;
    var acc: @Vector(L, f32) = @splat(0);
    var i: usize = 0;
    while (i + L <= data.len) : (i += L) {
        const chunk: @Vector(L, f32) = data[i..][0..L].*;
        acc += chunk;
    }
    var s = @reduce(.Add, acc);
    while (i < data.len) : (i += 1) s += data[i];
    return s;
}

31.2 Inline Assembly

Clobber syntax changed in 0.15 (struct of booleans instead of strings). Global assembly goes in comptime { asm (...); }.

fn rdtsc() u64 {
    var lo: u32 = undefined;
    var hi: u32 = undefined;
    asm volatile ("rdtsc"
        : [lo] "={eax}" (lo),
          [hi] "={edx}" (hi),
    );
    return (@as(u64, hi) << 32) | lo;
}

fn syscall1(number: usize, arg1: usize) usize {
    return asm volatile ("syscall"
        : [ret] "={rax}" (-> usize),
        : [number] "{rax}" (number),
          [arg1] "{rdi}" (arg1),
        : .{ .rcx = true, .r11 = true, .memory = true });   // 0.15 clobber syntax
}