ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.79k stars 2.54k forks source link

Suboptimal codegen for integer variables whose bit width isn't a multiple of 8 #21121

Open milogreg opened 2 months ago

milogreg commented 2 months ago

Version: 0.14.0-dev.1117+11176d22f

There are several cases where, on release builds, trivial optimizations that are done on 2^n 8*n bit integer variables aren't done on non-2^n non-8*n bit integer variables. This includes cases where variables that are completely unused are still computed:

export fn unusedVars1_u63() void {
    var x: u63 = 0;
    // Iteration count doesn't need to be this big, but there is some threshold it needs to surpass to get the bad behavior.
    // I assume this is related to small loops being fully unrolled, while larger ones aren't.
    for (std.math.maxInt(usize)) |_| {
        x = x;
    }
}

I've gathered a few other examples here (with comparisons to well-behaving 2^n 8*n bit versions): https://godbolt.org/z/PGsM8zeGE.

Note: I don't have any experience with compiler design, so when I say 'trivial' I mean conceptually simple, not trivial to implement.

milogreg commented 2 months ago

After testing some more types for x in the unusedVars1_u63 function, it appears that any integer with a bit width of 8*n behaves well, not just integers with a bit width of 2^n. The same holds true for the other examples I listed.

xxxbxxx commented 2 months ago

I think it is the same issue as https://github.com/ziglang/zig/issues/17768

or at least: I've checked that using the workaround https://github.com/ziglang/zig/pull/18137, the compiler does produce the same code for all functions pairs from https://godbolt.org/z/PGsM8zeGE.