authorgravatar for ryan.mehri1@gmail.comRyan Mehri <ryan.mehri1@gmail.com> 2026-08-04 11:43:46-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-07 15:29:04+02:00
logb9852d23089a524dafaa2487f207457b2a183af1
tree6f39d844db264505e301b12eb6fabc405fee702f
parent17e07ffc6381a1650b6bac5948b9f22d24411982

Legalize: fix packed struct with OPV and multiple other fields

In legalization for packed struct init with an OPV field, we first try to see if any field accounts for the entire bit size of the struct and otherwise fall back to a sequence of bitcasts and shifts on each field (added in fc1c83a363d). However, OPV fields are not accounted for in the fallback case, which means that codegen eventually panics when seeing the bit size of 0. This change makes it so that we ignore all OPV fields in `packedAggregateInitBlockPayload` since they have no runtime bits.

2 files changed, 24 insertions(+), 1 deletions(-)

src/Air/Legalize.zig+8-1
......@@ -2906,12 +2906,18 @@ fn packedAggregateInitBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Erro
29062906 const orig_ty_pl = l.air_instructions.items(.data)[@backingInt(orig_inst)].ty_pl;
29072907 const agg_ty = orig_ty_pl.ty.toType();
29082908 const agg_field_count = agg_ty.structFieldCount(zcu);
2909 var opv_field_count: u32 = 0;
2910 for (0..agg_field_count) |field_idx| {
2911 const field_ty = agg_ty.fieldType(field_idx, zcu);
2912 const field_bits: u16 = @intCast(field_ty.bitSize(zcu));
2913 if (field_bits == 0) opv_field_count += 1;
2914 }
29092915
29102916 var bfa_buf: [4 * 32 + 2]Air.Inst.Index = undefined;
29112917 var bfa_state: std.heap.BufferFirstAllocator = .init(@ptrCast(&bfa_buf), gpa);
29122918 const bfa = bfa_state.allocator();
29132919
2914 const inst_buf = try bfa.alloc(Air.Inst.Index, 4 * agg_field_count + 2);
2920 const inst_buf = try bfa.alloc(Air.Inst.Index, 4 * (agg_field_count - opv_field_count) + 2);
29152921 defer bfa.free(inst_buf);
29162922
29172923 var main_block: Block = .init(inst_buf);
......@@ -2927,6 +2933,7 @@ fn packedAggregateInitBlockPayload(l: *Legalize, orig_inst: Air.Inst.Index) Erro
29272933 field_idx -= 1;
29282934 const field_ty = agg_ty.fieldType(field_idx, zcu);
29292935 const field_bits: u16 = @intCast(field_ty.bitSize(zcu));
2936 if (field_bits == 0) continue;
29302937 assert(field_bits < num_bits);
29312938 const field_uint_ty = try pt.intType(.unsigned, field_bits);
29322939 const field_bit_size_ref: Air.Inst.Ref = .fromValue(try pt.intValue(shift_ty, field_bits));
test/behavior/bitcast.zig+16
......@@ -432,6 +432,22 @@ test "@bitCast of packed struct with void field to integer" {
432432 try comptime S.doTheTest(123);
433433}
434434
435test "@bitCast of packed struct with void field and multiple integers" {
436 const S = packed struct {
437 x: u8,
438 v: void,
439 y: u8,
440
441 fn doTheTest(x: u8, y: u8) !void {
442 const foo = @as(@This(), .{ .x = x, .v = {}, .y = y });
443 const as_int: u16 = @bitCast(foo);
444 try expect(as_int == @as(u16, y) << 8 | x);
445 }
446 };
447 try S.doTheTest(123, 45);
448 try comptime S.doTheTest(123, 45);
449}
450
435451test "@bitCast vector to array with different element size" {
436452 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
437453