authorgravatar for xavierb@gmail.comXavier Bouchoux <xavierb@gmail.com> 2023-10-03 05:34:19+00:00
committergravatar for xavierb@gmail.comXavier Bouchoux <xavierb@gmail.com> 2023-10-03 05:34:19+00:00
log405705cb76914072b9a91ac29f7cf0bf67b255f4
tree2f2928e3a6c42626cf1464a2f52dba546ea6e50d
parent62d178e91af57c19d0ac000fe6930039a23e53a3

codegen: fix byte-aligned field offsets in unaligned nested packed structs


4 files changed, 38 insertions(+), 8 deletions(-)

src/arch/wasm/CodeGen.zig+2-1
...@@ -3828,7 +3828,8 @@ fn structFieldPtr(...@@ -3828,7 +3828,8 @@ fn structFieldPtr(
3828 if (result_ty.ptrInfo(mod).packed_offset.host_size != 0) {3828 if (result_ty.ptrInfo(mod).packed_offset.host_size != 0) {
3829 break :offset @as(u32, 0);3829 break :offset @as(u32, 0);
3830 }3830 }
3831 break :offset struct_ty.packedStructFieldByteOffset(index, mod) + @divExact(struct_ptr_ty_info.packed_offset.bit_offset, 8);3831 const struct_type = mod.typeToStruct(struct_ty).?;
3832 break :offset @divExact(mod.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
3832 },3833 },
3833 .Union => 0,3834 .Union => 0,
3834 else => unreachable,3835 else => unreachable,
src/codegen/llvm.zig+2-1
...@@ -10140,6 +10140,7 @@ pub const FuncGen = struct {...@@ -10140,6 +10140,7 @@ pub const FuncGen = struct {
10140 const result_ty = self.typeOfIndex(inst);10140 const result_ty = self.typeOfIndex(inst);
10141 const result_ty_info = result_ty.ptrInfo(mod);10141 const result_ty_info = result_ty.ptrInfo(mod);
10142 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);10142 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
10143 const struct_type = mod.typeToStruct(struct_ty).?;
1014310144
10144 if (result_ty_info.packed_offset.host_size != 0) {10145 if (result_ty_info.packed_offset.host_size != 0) {
10145 // From LLVM's perspective, a pointer to a packed struct and a pointer10146 // From LLVM's perspective, a pointer to a packed struct and a pointer
...@@ -10151,7 +10152,7 @@ pub const FuncGen = struct {...@@ -10151,7 +10152,7 @@ pub const FuncGen = struct {
1015110152
10152 // We have a pointer to a packed struct field that happens to be byte-aligned.10153 // We have a pointer to a packed struct field that happens to be byte-aligned.
10153 // Offset our operand pointer by the correct number of bytes.10154 // Offset our operand pointer by the correct number of bytes.
10154 const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod) + @divExact(struct_ptr_ty_info.packed_offset.bit_offset, 8);10155 const byte_offset = @divExact(mod.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
10155 if (byte_offset == 0) return struct_ptr;10156 if (byte_offset == 0) return struct_ptr;
10156 const usize_ty = try o.lowerType(Type.usize);10157 const usize_ty = try o.lowerType(Type.usize);
10157 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);10158 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
src/type.zig-6
...@@ -3028,12 +3028,6 @@ pub const Type = struct {...@@ -3028,12 +3028,6 @@ pub const Type = struct {
3028 };3028 };
3029 }3029 }
30303030
3031 pub fn packedStructFieldByteOffset(ty: Type, field_index: u32, mod: *Module) u32 {
3032 const ip = &mod.intern_pool;
3033 const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
3034 return @divExact(mod.structPackedFieldBitOffset(struct_type, field_index), 8);
3035 }
3036
3037 pub const FieldOffset = struct {3031 pub const FieldOffset = struct {
3038 field: usize,3032 field: usize,
3039 offset: u64,3033 offset: u64,
test/behavior/packed-struct.zig+34
...@@ -622,6 +622,8 @@ test "@intFromPtr on a packed struct field unaligned and nested" {...@@ -622,6 +622,8 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
622}622}
623623
624test "packed struct fields modification" {624test "packed struct fields modification" {
625 // Originally reported at https://github.com/ziglang/zig/issues/16615
626
625 const Small = packed struct {627 const Small = packed struct {
626 val: u8 = 0,628 val: u8 = 0,
627 lo: u4 = 0,629 lo: u4 = 0,
...@@ -989,6 +991,7 @@ test "bitcast back and forth" {...@@ -989,6 +991,7 @@ test "bitcast back and forth" {
989}991}
990992
991test "field access of packed struct smaller than its abi size inside struct initialized with rls" {993test "field access of packed struct smaller than its abi size inside struct initialized with rls" {
994 // Originally reported at https://github.com/ziglang/zig/issues/14200
992 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .arm) return error.SkipZigTest;995 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .arm) return error.SkipZigTest;
993 const S = struct {996 const S = struct {
994 ps: packed struct { x: i2, y: i2 },997 ps: packed struct { x: i2, y: i2 },
...@@ -1003,3 +1006,34 @@ test "field access of packed struct smaller than its abi size inside struct init...@@ -1003,3 +1006,34 @@ test "field access of packed struct smaller than its abi size inside struct init
1003 try expect(@as(i2, 0) == s.ps.x);1006 try expect(@as(i2, 0) == s.ps.x);
1004 try expect(@as(i2, 1) == s.ps.y);1007 try expect(@as(i2, 1) == s.ps.y);
1005}1008}
1009
1010test "modify nested packed struct aligned field" {
1011 // Originally reported at https://github.com/ziglang/zig/issues/14632
1012 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1013 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1014 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1015 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1016 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1017
1018 const Options = packed struct {
1019 foo: bool = false,
1020 bar: bool = false,
1021 pretty_print: packed struct {
1022 enabled: bool = false,
1023 num_spaces: u4 = 4,
1024 space_char: enum { space, tab } = .space,
1025 indent: u8 = 0,
1026 } = .{},
1027 baz: bool = false,
1028 };
1029
1030 var opts = Options{};
1031 opts.pretty_print.indent += 1;
1032 try std.testing.expectEqual(@as(u17, 0b00000000100100000), @bitCast(opts));
1033 try std.testing.expect(!opts.foo);
1034 try std.testing.expect(!opts.bar);
1035 try std.testing.expect(!opts.pretty_print.enabled);
1036 try std.testing.expectEqual(@as(u4, 4), opts.pretty_print.num_spaces);
1037 try std.testing.expectEqual(@as(u8, 1), opts.pretty_print.indent);
1038 try std.testing.expect(!opts.baz);
1039}