Calling AVX2 code from zig

Hey

I have an c file which i would like call from zig. In that file are 2 implementations of matrix vector multiplication, one with avx2 and another with the standart approach. The naive function is easily callable from c, but the “mat_vec_AVX2” causes an error:

“error: ld.lld: undefined symbol: mat_vec_AVX2”

I cant quite get behind why this is occuring and how to fix it.

On another unrelated note, i realized that the compiled c files get cached. Is there some compiler flag to recompile those files ? Because my current method is to delete the cache dir which cant be the intended way.

void naive_algo(int cols, int rows, float *matrix, float *vec_add, float *vec_mul, float *res){

void mat_vec_AVX2(int cols, int rows, float *matrix, float *vec_add, float *vec_mul, float *res){

Thanks a lot for the help and keep up the great work

Double check that you don’t have a C macro that omits the definition of that second function unless a given DEFINE is present, that’s something that happens very often.

You can look at All Your Codebase · GitHub for a few examples on how to integrate C files with macros with the Zig build system.

1 Like

I have not worked with c macros at all. :frowning:

To get better help you might want to push your project on a publicly accessible repo. You probably have a header file that defines that function conditionally, which makes sense, since AVX is not always available, and that’s what’s tripping you.

There’s a few details that need to be done right for C integration to work and if you don’t know if those were taken care of, the only way you can efficiently communicate your situation is by showing the full code.

1 Like

Sure, the project is already public: chess_bot/src/simd at main · qub3s/chess_bot · GitHub

It looks like you are @cImporting the C file with the AVX code. The C to Zig translation feature is mainly intended for header declarations, not full implementations. You should probably change your build.zig to compile the C file separately and link it with your executable.

If this is your only vector function, you can probably write it directly in Zig. For example (not yet tested):

pub fn matVecAVX2(
    cols: usize,
    rows: usize,
    matrix: []const f32,
    vec_add: []const f32,
    vec_mul: []const f32,
    res: []f32,
) void {
    if (cols % 8 != 0 or rows % 8 != 0) {
        std.debug.print("break\n", .{});
        return;
    }

    for (0..cols) |i| {
        var sum: f32 = 0.0;

        var j: usize = 0;
        while (j < rows) : (j += 8) {
            // Load 8 elements as vectors
            const v_vec: @Vector(8, f32) = @Vector(8, f32){
                vec_mul[j], vec_mul[j + 1], vec_mul[j + 2], vec_mul[j + 3],
                vec_mul[j + 4], vec_mul[j + 5], vec_mul[j + 6], vec_mul[j + 7],
            };
            const v_mat: @Vector(8, f32) = @Vector(8, f32){
                matrix[rows * i + j], matrix[rows * i + j + 1], matrix[rows * i + j + 2], matrix[rows * i + j + 3],
                matrix[rows * i + j + 4], matrix[rows * i + j + 5], matrix[rows * i + j + 6], matrix[rows * i + j + 7],
            };

            // Perform element-wise multiplication and accumulation
            const product: @Vector(8, f32) = v_mat * v_vec;
            sum += @reduce(.Add, product);
        }

        res[i] = sum + vec_add[i];
    }
}

Heureka

Thank you all a lot for the advice and the help, i ended up using the advice from @permutationlock and that worked. For anyone who has a similar problem and is fighting the build system like me :pensive: (no hate on the system just hard to understand with the existing documentation), this is the way i have done it:


    const simd = b.addStaticLibrary(.{
        .name = "simd",
        .target = target,
        .optimize = optimize,
    });

    simd.addCSourceFiles(.{ .files = &.{"c_src/simd/vm_mul.c"} });
    simd.addIncludePath(b.path("simd"));
    simd.linkLibC();
    simd.installHeader(b.path("c_src/simd/vm_mul.h"), "c_src/simd/vm_mul.h");

    b.installArtifact(simd);


    exe.linkLibrary(simd);