The title is a bit confusing because I cannot figure out a better way to phrase this, I hope the post itself makes my issue a bit clearer.
I am writing something that operates over a buffer of bytecode. To facilitate iteration over this nicely, I’ve written something like the following:
const OpCode = enum {
add,
sub,
mul,
div,
// [snip]
};
// These union fields store pointers to avoid potentially expensive copies for some instructions
const Instruction = union(OpCode) {
add: *align(1) const Add,
mul: *align(1) const Mul,
div: *align(1) const Div,
sub: *align(1) const Sub,
// [snip]
pub const Add = packed struct {
a1: u8, // This code is generated, ignore the bad names
a2: u8,
a3: u8,
};
pub const Mul = packed struct {
a1: u8,
a2: u8,
a3: u8,
};
pub const Div = packed struct {
a1: u8,
a2: u8,
a3: u8,
};
pub const Sub = packed struct {
a1: u8,
a2: u8,
a3: u8,
};
// [snip]
};
const BytecodeIterator = struct {
bc: []const u8,
ip: u32 = 0,
pub fn next(self: *@This()) ?Instruction {
if (self.ip >= self.bc.len) return null;
const op: OpCode = @enumFromInt(self.bc[self.ip]);
self.ip += 1;
defer self.ip += size[@intFromEnum(op)]; // size is an array of instruction sizes
return switch (op) {
inline else => |o| @unionInit(Instruction, @tagName(o), @ptrCast(self.bc.ptr + self.ip)),
};
}
};
The issue here is hopefully apparent, the generated code for BytecodeIterator.next includes every single branch from the inline else, which is not optimized away.
Is there some way for me to prevent that from happening? My union fields are all the same thing, a pointer.
I have considered using an untagged union instead, however a big benefit to using a tagged union is being able to switch over Instruction and directly get the union’s value. I really do not want to lose that, it makes code a lot nicer and lessens the chance of an error sneaking in.
I have also considered manually constructing the union, however I am not certain what the memory layout of unions, or even packed unions, looks like and cannot find any examples/documentation about it at the moment.