From 521bd2e94a3b32382b2d1de1e6185149032b49db Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 1 Feb 2022 21:55:34 +0100 Subject: x86_64: pass more behaviour tests --- test/behavior/struct.zig | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'test/behavior/struct.zig') diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 7ff67e1c90..e25f862e41 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -9,6 +9,8 @@ const maxInt = std.math.maxInt; top_level_field: i32, test "top level fields" { + if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + var instance = @This(){ .top_level_field = 1234, }; @@ -29,6 +31,8 @@ const StructFoo = struct { }; test "structs" { + if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + var foo: StructFoo = undefined; @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); foo.a += 1; @@ -45,6 +49,8 @@ fn testMutation(foo: *StructFoo) void { } test "struct byval assign" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + var foo1: StructFoo = undefined; var foo2: StructFoo = undefined; @@ -56,6 +62,8 @@ test "struct byval assign" { } test "call struct static method" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const result = StructWithNoFields.add(3, 4); try expect(result == 7); } @@ -85,6 +93,8 @@ const Val = struct { }; test "fn call of struct field" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const Foo = struct { ptr: fn () i32, }; @@ -114,12 +124,16 @@ const MemberFnTestFoo = struct { }; test "call member function directly" { + if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const instance = MemberFnTestFoo{ .x = 1234 }; const result = MemberFnTestFoo.member(instance); try expect(result == 1234); } test "store member function in variable" { + if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const instance = MemberFnTestFoo{ .x = 1234 }; const memberFn = MemberFnTestFoo.member; const result = memberFn(instance); @@ -127,6 +141,8 @@ test "store member function in variable" { } test "member functions" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const r = MemberFnRand{ .seed = 1234 }; try expect(r.getSeed() == 1234); } @@ -138,6 +154,8 @@ const MemberFnRand = struct { }; test "return struct byval from function" { + if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const bar = makeBar2(1234, 5678); try expect(bar.y == 5678); } @@ -153,6 +171,8 @@ fn makeBar2(x: i32, y: i32) Bar { } test "call method with mutable reference to struct with no fields" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const S = struct { fn doC(s: *const @This()) bool { _ = s; @@ -172,6 +192,8 @@ test "call method with mutable reference to struct with no fields" { } test "usingnamespace within struct scope" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const S = struct { usingnamespace struct { pub fn inner() i32 { @@ -183,6 +205,8 @@ test "usingnamespace within struct scope" { } test "struct field init with catch" { + if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + const S = struct { fn doTheTest() !void { var x: anyerror!isize = 1; -- cgit v1.2.3 From 15ff891f044102ba6515cb07f40805452420ea24 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 2 Feb 2022 00:20:41 +0100 Subject: stage2: pad out (non-packed) struct fields when lowering to bytes * pad out (non-packed) struct fields when lowering to bytes to be saved in the binary - prior to this change, fields would be saved at non-aligned addresses leading to wrong accesses * add a matching test case to `behavior/struct.zig` tests * fix offset to field calculation in `struct_field_ptr` on `x86_64` --- src/arch/x86_64/CodeGen.zig | 6 +++--- src/codegen.zig | 25 ++++++++++++++++++++++++- test/behavior/struct.zig | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) (limited to 'test/behavior/struct.zig') diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 09b51bf59a..80b50f228b 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -1801,13 +1801,12 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); const struct_field_ty = struct_ty.structFieldType(index); const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); - const offset_to_field = struct_size - struct_field_offset - struct_field_size; const dst_mcv: MCValue = result: { switch (mcv) { .stack_offset => { const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ - .immediate = offset_to_field, + .immediate = struct_field_offset, }); self.register_manager.freezeRegs(&.{offset_reg}); defer self.register_manager.unfreezeRegs(&.{offset_reg}); @@ -1817,12 +1816,13 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde break :result dst_mcv; }, .ptr_stack_offset => |off| { + const offset_to_field = struct_size - struct_field_offset - struct_field_size; const ptr_stack_offset = off + @intCast(i32, offset_to_field); break :result MCValue{ .ptr_stack_offset = ptr_stack_offset }; }, .register => |reg| { const offset_reg = try self.copyToTmpRegister(ptr_ty, .{ - .immediate = offset_to_field, + .immediate = struct_field_offset, }); self.register_manager.freezeRegs(&.{offset_reg}); defer self.register_manager.unfreezeRegs(&.{offset_reg}); diff --git a/src/codegen.zig b/src/codegen.zig index faafe79c13..bcd36358b1 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -373,11 +373,24 @@ pub fn generateSymbol( }, .Struct => { // TODO debug info - // TODO padding of struct members + const struct_obj = typed_value.ty.castTag(.@"struct").?.data; + if (struct_obj.layout == .Packed) { + return Result{ + .fail = try ErrorMsg.create( + bin_file.allocator, + src_loc, + "TODO implement generateSymbol for packed struct", + .{}, + ), + }; + } + + const struct_begin = code.items.len; const field_vals = typed_value.val.castTag(.@"struct").?.data; for (field_vals) |field_val, index| { const field_ty = typed_value.ty.structFieldType(index); if (!field_ty.hasRuntimeBits()) continue; + switch (try generateSymbol(bin_file, src_loc, .{ .ty = field_ty, .val = field_val, @@ -388,6 +401,16 @@ pub fn generateSymbol( }, .fail => |em| return Result{ .fail = em }, } + const unpadded_field_end = code.items.len - struct_begin; + + // Pad struct members if required + const target = bin_file.options.target; + const padded_field_end = typed_value.ty.structFieldOffset(index + 1, target); + const padding = try math.cast(usize, padded_field_end - unpadded_field_end); + + if (padding > 0) { + try code.writer().writeByteNTimes(0, padding); + } } return Result{ .appended = {} }; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index e25f862e41..c470279aad 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -18,6 +18,39 @@ test "top level fields" { try expect(@as(i32, 1235) == instance.top_level_field); } +const StructWithFields = struct { + a: u8, + b: u32, + c: u64, + d: u32, + + fn first(self: *const StructWithFields) u8 { + return self.a; + } + + fn second(self: *const StructWithFields) u32 { + return self.b; + } + + fn third(self: *const StructWithFields) u64 { + return self.c; + } + + fn fourth(self: *const StructWithFields) u32 { + return self.d; + } +}; + +test "non-packed struct has fields padded out to the required alignment" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + + const foo = StructWithFields{ .a = 5, .b = 1, .c = 10, .d = 2 }; + try expect(foo.first() == 5); + try expect(foo.second() == 1); + try expect(foo.third() == 10); + try expect(foo.fourth() == 2); +} + const StructWithNoFields = struct { fn add(a: i32, b: i32) i32 { return a + b; -- cgit v1.2.3