Skip to content

Commit c0c07f0

Browse files
committed
amend codegen: fix access to byte-aligned nested packed struct elems.
implement wasm & x86_64 cases and split the test case into a simple one that passes all backend and an other that hits various limitations
1 parent d161e27 commit c0c07f0

File tree

3 files changed

+79
-22
lines changed

3 files changed

+79
-22
lines changed

src/arch/wasm/CodeGen.zig

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3675,18 +3675,20 @@ fn airStructFieldPtr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
36753675
const extra = func.air.extraData(Air.StructField, ty_pl.payload);
36763676

36773677
const struct_ptr = try func.resolveInst(extra.data.struct_operand);
3678-
const struct_ty = func.typeOf(extra.data.struct_operand).childType(mod);
3679-
const result = try func.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ty, extra.data.field_index);
3678+
const struct_ptr_ty = func.typeOf(extra.data.struct_operand);
3679+
const struct_ty = struct_ptr_ty.childType(mod);
3680+
const result = try func.structFieldPtr(inst, extra.data.struct_operand, struct_ptr, struct_ptr_ty, struct_ty, extra.data.field_index);
36803681
func.finishAir(inst, result, &.{extra.data.struct_operand});
36813682
}
36823683

36833684
fn airStructFieldPtrIndex(func: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {
36843685
const mod = func.bin_file.base.options.module.?;
36853686
const ty_op = func.air.instructions.items(.data)[inst].ty_op;
36863687
const struct_ptr = try func.resolveInst(ty_op.operand);
3687-
const struct_ty = func.typeOf(ty_op.operand).childType(mod);
3688+
const struct_ptr_ty = func.typeOf(ty_op.operand);
3689+
const struct_ty = struct_ptr_ty.childType(mod);
36883690

3689-
const result = try func.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ty, index);
3691+
const result = try func.structFieldPtr(inst, ty_op.operand, struct_ptr, struct_ptr_ty, struct_ty, index);
36903692
func.finishAir(inst, result, &.{ty_op.operand});
36913693
}
36923694

@@ -3695,18 +3697,21 @@ fn structFieldPtr(
36953697
inst: Air.Inst.Index,
36963698
ref: Air.Inst.Ref,
36973699
struct_ptr: WValue,
3700+
struct_ptr_ty: Type,
36983701
struct_ty: Type,
36993702
index: u32,
37003703
) InnerError!WValue {
37013704
const mod = func.bin_file.base.options.module.?;
37023705
const result_ty = func.typeOfIndex(inst);
3706+
const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
3707+
37033708
const offset = switch (struct_ty.containerLayout(mod)) {
37043709
.Packed => switch (struct_ty.zigTypeTag(mod)) {
37053710
.Struct => offset: {
37063711
if (result_ty.ptrInfo(mod).packed_offset.host_size != 0) {
37073712
break :offset @as(u32, 0);
37083713
}
3709-
break :offset struct_ty.packedStructFieldByteOffset(index, mod);
3714+
break :offset struct_ty.packedStructFieldByteOffset(index, mod) + @divExact(struct_ptr_ty_info.packed_offset.bit_offset, 8);
37103715
},
37113716
.Union => 0,
37123717
else => unreachable,

src/arch/x86_64/CodeGen.zig

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5556,12 +5556,14 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
55565556
const mod = self.bin_file.options.module.?;
55575557
const ptr_field_ty = self.typeOfIndex(inst);
55585558
const ptr_container_ty = self.typeOf(operand);
5559+
const ptr_container_ty_info = ptr_container_ty.ptrInfo(mod);
55595560
const container_ty = ptr_container_ty.childType(mod);
5561+
55605562
const field_offset: i32 = @intCast(switch (container_ty.containerLayout(mod)) {
55615563
.Auto, .Extern => container_ty.structFieldOffset(index, mod),
55625564
.Packed => if (container_ty.zigTypeTag(mod) == .Struct and
55635565
ptr_field_ty.ptrInfo(mod).packed_offset.host_size == 0)
5564-
container_ty.packedStructFieldByteOffset(index, mod)
5566+
container_ty.packedStructFieldByteOffset(index, mod) + @divExact(ptr_container_ty_info.packed_offset.bit_offset, 8)
55655567
else
55665568
0,
55675569
});

test/behavior/packed-struct.zig

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -529,12 +529,41 @@ test "nested packed struct field access test" {
529529
}
530530

531531
test "nested packed struct at non-zero offset" {
532+
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
533+
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
534+
535+
const Pair = packed struct(u24) {
536+
a: u16 = 0,
537+
b: u8 = 0,
538+
};
539+
const A = packed struct {
540+
p1: Pair,
541+
p2: Pair,
542+
};
543+
544+
var k: u8 = 123;
545+
var v: A = .{
546+
.p1 = .{ .a = k + 1, .b = k },
547+
.p2 = .{ .a = k + 1, .b = k },
548+
};
549+
550+
try expect(v.p1.a == k + 1 and v.p1.b == k);
551+
try expect(v.p2.a == k + 1 and v.p2.b == k);
552+
553+
v.p2.a -= v.p1.a;
554+
v.p2.b -= v.p1.b;
555+
try expect(v.p2.a == 0 and v.p2.b == 0);
556+
try expect(v.p1.a == k + 1 and v.p1.b == k);
557+
}
558+
559+
test "nested packed struct at non-zero offset 2" {
532560
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
533561
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
534562
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
535563
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
536564
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
537565
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
566+
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
538567

539568
const S = struct {
540569
const Pair = packed struct(u40) {
@@ -544,27 +573,48 @@ test "nested packed struct at non-zero offset" {
544573
const A = packed struct {
545574
p1: Pair,
546575
p2: Pair,
576+
c: C,
577+
};
578+
const C = packed struct {
579+
p1: Pair,
580+
pad1: u5,
581+
p2: Pair,
582+
pad2: u3,
583+
last: i16,
547584
};
548585

549586
fn doTheTest() !void {
550-
var v: u8 = 123;
551-
var a: A = .{
552-
.p1 = .{ .a = v + 1, .b = v },
553-
.p2 = .{ .a = v + 1, .b = v },
587+
var k: u8 = 123;
588+
var v: A = .{
589+
.p1 = .{ .a = k + 1, .b = k },
590+
.p2 = .{ .a = k + 1, .b = k },
591+
.c = .{
592+
.pad1 = 11,
593+
.pad2 = 2,
594+
.p1 = .{ .a = k + 1, .b = k },
595+
.p2 = .{ .a = k + 1, .b = k },
596+
.last = -12345,
597+
},
554598
};
555599

556-
try expect(a.p1.a == v + 1);
557-
try expect(a.p2.a == v + 1);
558-
try expect(a.p1.b == v);
559-
try expect(a.p2.b == v);
560-
try expect(a.p1.a == a.p2.a and a.p1.b == a.p2.b);
561-
562-
a.p2.a -= a.p1.a;
563-
a.p2.b -= a.p1.b;
564-
try expect(a.p2.a == 0);
565-
try expect(a.p2.b == 0);
566-
try expect(a.p1.a == v + 1);
567-
try expect(a.p1.b == v);
600+
try expect(v.p1.a == k + 1 and v.p1.b == k);
601+
try expect(v.p2.a == k + 1 and v.p2.b == k);
602+
try expect(v.c.p2.a == k + 1 and v.c.p2.b == k);
603+
try expect(v.c.p2.a == k + 1 and v.c.p2.b == k);
604+
try expect(v.c.last == -12345);
605+
try expect(v.c.pad1 == 11 and v.c.pad2 == 2);
606+
607+
v.p2.a -= v.p1.a;
608+
v.p2.b -= v.p1.b;
609+
v.c.p2.a -= v.c.p1.a;
610+
v.c.p2.b -= v.c.p1.b;
611+
v.c.last -|= 32000;
612+
try expect(v.p2.a == 0 and v.p2.b == 0);
613+
try expect(v.p1.a == k + 1 and v.p1.b == k);
614+
try expect(v.c.p2.a == 0 and v.c.p2.b == 0);
615+
try expect(v.c.p1.a == k + 1 and v.c.p1.b == k);
616+
try expect(v.c.last == -32768);
617+
try expect(v.c.pad1 == 11 and v.c.pad2 == 2);
568618
}
569619
};
570620

0 commit comments

Comments
 (0)