Endless llvm emit object with release on linux

I run into an endless LLVM Emit Object when building on linux. On windows it takes 40 seconds but it is compiling correctly. I tested linux with a windows WSL2.

I suspect the use of @embedFile builtin as a long llvm emit object happens when the file is rather small (diff) to in fine being infinite (tested for 15 minutes) for this diff with a bigger file.

Couln’t find anyone complaining about this on the forum. Is there a known bug?

(Using zig 0.16.0)

Update : I removed the @embedFile and this still happens.

A lead i have is that it might be related to the emission of SIMD code for large vectors. The vectors are longer in the second diff.

I was able to detect the code that stalls the compiler:
(which corresponds to line 42)

const V = @Vector(1024, i32);
pub var vector: [8]V = undefined;
pub var arr: [8][1024]i16 = undefined;
for (0..8) |i| {
    arr[i] = std.mem.zeroes([1024]i16); // Original assignement is @memcpy from a buffer
    vector[i] = arr[i]; // <-- This is the line that breaks (L42)
}

I tried reproducing it in a fresh zig init without success yet.

I should also mention this only happens when building in release mode which corresponds to when LLVM is used

Wow, those are some really big vectors you’ve got there. The largest SIMD registers I’ve heard of are 128 bytes long. Usually people stick to small vectors, or arrays of small vectors, and loop over them - it gives you more control, and it’s what the compiler would do anyway.

Still an interesting problem. I didn’t know that you could just assign an array of i16 into a vector of 132 like that, but yeah it works. That does mean lots of integer-widening and bit-shifting operations under the hood, which is likely contributing to the problem.


I was able to replicate the issue on my computer with this code:

type or paste code hereconst std = @import("std");

const lanes = 4096;

const V = @Vector(lanes, i32);
pub var vector: V = undefined;
pub var arr: [lanes]i16 = undefined;

export fn frobnicate(a: i32) i32 {
    vector = @splat(a);

        arr = std.mem.zeroes([lanes]i16); // Original assignment is @memcpy from a buffer
        vector = arr; // <-- This is the line that breaks (L42)

    const popv = @popCount(vector);
    

    return @reduce(.Add, popv);
}

pub fn main(init: std.process.Init) !void {
    _ = init;
    std.debug.print("HELLO: {}", .{frobnicate(-1)});

}

So here’s the wacky part:

lanes compile time (s)
1024 8.1
2048 8.6
3072 10.1
4095 12.0
4096 4008

Not only does that +balloon the compile time, it also uses 100% of a single CPU core the entire time (4095 and below, it only did that for a second or so.

EDIT: On a second attempt, it stalled (22 minutes without completing). No change to the code.


I also tried looking at it with compiler explorer: Compiler Explorer

It has something similar going on: the output for lanes = 512 is 8x larger than the output for lanes = 256 or lanes = 508.


My guess is that either zig or LLVM is changing it’s strategy at certain powers of two and it’s causing a later compiler pass to crap itself.