mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
codegen: fix byte-aligned field offsets in unaligned nested packed structs
This commit is contained in:
parent
62d178e91a
commit
405705cb76
@ -3828,7 +3828,8 @@ fn structFieldPtr(
|
||||
if (result_ty.ptrInfo(mod).packed_offset.host_size != 0) {
|
||||
break :offset @as(u32, 0);
|
||||
}
|
||||
break :offset struct_ty.packedStructFieldByteOffset(index, mod) + @divExact(struct_ptr_ty_info.packed_offset.bit_offset, 8);
|
||||
const struct_type = mod.typeToStruct(struct_ty).?;
|
||||
break :offset @divExact(mod.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
|
||||
},
|
||||
.Union => 0,
|
||||
else => unreachable,
|
||||
|
||||
@ -10140,6 +10140,7 @@ pub const FuncGen = struct {
|
||||
const result_ty = self.typeOfIndex(inst);
|
||||
const result_ty_info = result_ty.ptrInfo(mod);
|
||||
const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
|
||||
const struct_type = mod.typeToStruct(struct_ty).?;
|
||||
|
||||
if (result_ty_info.packed_offset.host_size != 0) {
|
||||
// From LLVM's perspective, a pointer to a packed struct and a pointer
|
||||
@ -10151,7 +10152,7 @@ pub const FuncGen = struct {
|
||||
|
||||
// We have a pointer to a packed struct field that happens to be byte-aligned.
|
||||
// Offset our operand pointer by the correct number of bytes.
|
||||
const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, mod) + @divExact(struct_ptr_ty_info.packed_offset.bit_offset, 8);
|
||||
const byte_offset = @divExact(mod.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
|
||||
if (byte_offset == 0) return struct_ptr;
|
||||
const usize_ty = try o.lowerType(Type.usize);
|
||||
const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
|
||||
|
||||
@ -3028,12 +3028,6 @@ pub const Type = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn packedStructFieldByteOffset(ty: Type, field_index: u32, mod: *Module) u32 {
|
||||
const ip = &mod.intern_pool;
|
||||
const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
|
||||
return @divExact(mod.structPackedFieldBitOffset(struct_type, field_index), 8);
|
||||
}
|
||||
|
||||
pub const FieldOffset = struct {
|
||||
field: usize,
|
||||
offset: u64,
|
||||
|
||||
@ -622,6 +622,8 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
|
||||
}
|
||||
|
||||
test "packed struct fields modification" {
|
||||
// Originally reported at https://github.com/ziglang/zig/issues/16615
|
||||
|
||||
const Small = packed struct {
|
||||
val: u8 = 0,
|
||||
lo: u4 = 0,
|
||||
@ -989,6 +991,7 @@ test "bitcast back and forth" {
|
||||
}
|
||||
|
||||
test "field access of packed struct smaller than its abi size inside struct initialized with rls" {
|
||||
// Originally reported at https://github.com/ziglang/zig/issues/14200
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .arm) return error.SkipZigTest;
|
||||
const S = struct {
|
||||
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
|
||||
try expect(@as(i2, 0) == s.ps.x);
|
||||
try expect(@as(i2, 1) == s.ps.y);
|
||||
}
|
||||
|
||||
test "modify nested packed struct aligned field" {
|
||||
// Originally reported at https://github.com/ziglang/zig/issues/14632
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
const Options = packed struct {
|
||||
foo: bool = false,
|
||||
bar: bool = false,
|
||||
pretty_print: packed struct {
|
||||
enabled: bool = false,
|
||||
num_spaces: u4 = 4,
|
||||
space_char: enum { space, tab } = .space,
|
||||
indent: u8 = 0,
|
||||
} = .{},
|
||||
baz: bool = false,
|
||||
};
|
||||
|
||||
var opts = Options{};
|
||||
opts.pretty_print.indent += 1;
|
||||
try std.testing.expectEqual(@as(u17, 0b00000000100100000), @bitCast(opts));
|
||||
try std.testing.expect(!opts.foo);
|
||||
try std.testing.expect(!opts.bar);
|
||||
try std.testing.expect(!opts.pretty_print.enabled);
|
||||
try std.testing.expectEqual(@as(u4, 4), opts.pretty_print.num_spaces);
|
||||
try std.testing.expectEqual(@as(u8, 1), opts.pretty_print.indent);
|
||||
try std.testing.expect(!opts.baz);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user