Setting a global enum on WASM fails silently
Zig Version
0.14.0-dev.1694+3b465ebec
Steps to Reproduce and Observed Behavior
A global variable, of type an enum with 4 fields, sometimes updates incorrectly on WASM :
src/main.zig:
const std = @import("std");
pub fn main() !void {
buggy_fn(2);
}
var my_global_value: Direction = undefined;
export fn buggy_fn(new_value: u32) void {
std.debug.print("input to fn was: {d}\n", .{new_value});
my_global_value = Direction.num2dir(new_value);
std.debug.print("global is now: {d}\n", .{Direction.dir2num(my_global_value)});
}
const Direction = enum {
Left,
Right,
Up,
Down,
fn dir2num(d: Direction) u32 {
return switch (d) {
.Up => 0,
.Down => 1,
.Left => 2,
.Right => 3,
};
}
fn num2dir(n: u32) Direction {
return switch (n) {
0 => .Up,
1 => .Down,
2 => .Left,
3 => .Right,
else => unreachable,
};
}
};
build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.resolveTargetQuery(.{
.cpu_arch = .wasm32,
.os_tag = .wasi,
});
const optimize: std.builtin.OptimizeMode = .ReleaseSmall;
const exe = b.addExecutable(.{
.name = "main",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
const run_exe = b.addRunArtifact(exe);
const run_step = b.step("run", "Run");
run_step.dependOn(&run_exe.step);
}
zig build run -fwasmtime outputs, on my machine:
input to fn was: 2 global is now: 0
Expected Behavior
The output should be:
input to fn was: 2 global is now: 2
The issue only happens in WASM, with optimize mode set to ReleaseSmall. It also works correctly if Direction is an enum(u3), but not if it's an enum(u2) (despite having 4 values).
As a workaround, add a type to the enum:
const Direction = enum(u2) {
It fails too. Surprisingly, it works with
const Direction = enum(u3) {
I think it is fixed in LLVM 20. From IR triangulation problem lies in SimplifyCFG pass, which was probably solved in https://github.com/llvm/llvm-project/commit/6f194a6dea4b4067336431e699ea3588417d4b96
@alexrp I could not reproduce this on 0.14.0, I think llvm 20 did the job.