diff options
| author | Xavier Bouchoux <xavierb@gmail.com> | 2023-07-29 20:08:08 +0200 |
|---|---|---|
| committer | Xavier Bouchoux <xavierb@gmail.com> | 2023-10-03 06:39:20 +0200 |
| commit | 62d178e91af57c19d0ac000fe6930039a23e53a3 (patch) | |
| tree | f849674dd8aa13839319e05585b8513a0192b7ba /src/codegen | |
| parent | 412d863ba5801c1376af7ab8f04a71b839a820a6 (diff) | |
| download | zig-62d178e91af57c19d0ac000fe6930039a23e53a3.tar.gz zig-62d178e91af57c19d0ac000fe6930039a23e53a3.zip | |
codegen: fix field offsets in packed structs
* add nested packed struct/union behavior tests
* use ptr_info.packed_offset rather than trying to duplicate the logic from Sema.structFieldPtrByIndex()
* use the container_ptr_info.packed_offset to account for non-aligned nested structs.
* dedup type.packedStructFieldBitOffset() and module.structPackedFieldBitOffset()
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 20 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 42 |
2 files changed, 29 insertions, 33 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 97f897b344..b627d952e5 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -5269,22 +5269,26 @@ fn fieldLocation( const ip = &mod.intern_pool; const container_ty = container_ptr_ty.childType(mod); return switch (container_ty.zigTypeTag(mod)) { - .Struct => switch (container_ty.containerLayout(mod)) { - .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index_usize| { + .Struct => blk: { + if (mod.typeToPackedStruct(container_ty)) |struct_type| { + if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0) + break :blk .{ .byte_offset = @divExact(mod.structPackedFieldBitOffset(struct_type, field_index) + container_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8) } + else + break :blk .begin; + } + + for (field_index..container_ty.structFieldCount(mod)) |next_field_index_usize| { const next_field_index: u32 = @intCast(next_field_index_usize); if (container_ty.structFieldIsComptime(next_field_index, mod)) continue; const field_ty = container_ty.structFieldType(next_field_index, mod); if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; - break .{ .field = if (container_ty.isSimpleTuple(mod)) + break :blk .{ .field = if (container_ty.isSimpleTuple(mod)) .{ .field = next_field_index } else .{ .identifier = ip.stringToSlice(container_ty.legacyStructFieldName(next_field_index, mod)) } }; - } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin, - .Packed => if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0) - .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) + @divExact(container_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8) } - else - .begin, + } + break :blk if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin; }, .Union => { const union_obj = mod.typeToUnion(container_ty).?; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8cd9f6604f..753e02a857 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -4,7 +4,6 @@ const assert = std.debug.assert; const Allocator = std.mem.Allocator; const log = std.log.scoped(.codegen); const math = std.math; -const native_endian = builtin.cpu.arch.endian(); const DW = std.dwarf; const Builder = @import("llvm/Builder.zig"); @@ -3770,7 +3769,7 @@ pub const Object = struct { .opt_payload, .elem, .field, - => try o.lowerParentPtr(val, ty.ptrInfo(mod).packed_offset.bit_offset % 8 == 0), + => try o.lowerParentPtr(val), .comptime_field => unreachable, }; switch (ptr.len) { @@ -4230,15 +4229,16 @@ pub const Object = struct { return o.lowerDeclRefValue(ptr_ty, decl_index); } - fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant { + fn lowerParentPtr(o: *Object, ptr_val: Value) Allocator.Error!Builder.Constant { const mod = o.module; const ip = &mod.intern_pool; - return switch (ip.indexToKey(ptr_val.toIntern()).ptr.addr) { + const ptr = ip.indexToKey(ptr_val.toIntern()).ptr; + return switch (ptr.addr) { .decl => |decl| o.lowerParentPtrDecl(decl), .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), .int => |int| try o.lowerIntAsPtr(int), .eu_payload => |eu_ptr| { - const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true); + const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue()); const eu_ty = ip.typeOf(eu_ptr).toType().childType(mod); const payload_ty = eu_ty.errorUnionPayload(mod); @@ -4256,7 +4256,7 @@ pub const Object = struct { }); }, .opt_payload => |opt_ptr| { - const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true); + const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue()); const opt_ty = ip.typeOf(opt_ptr).toType().childType(mod); const payload_ty = opt_ty.optionalChild(mod); @@ -4274,7 +4274,7 @@ pub const Object = struct { }, .comptime_field => unreachable, .elem => |elem_ptr| { - const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true); + const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue()); const elem_ty = ip.typeOf(elem_ptr.base).toType().elemType2(mod); return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, null, &.{ @@ -4282,9 +4282,9 @@ pub const Object = struct { }); }, .field => |field_ptr| { - const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned); - const parent_ty = ip.typeOf(field_ptr.base).toType().childType(mod); - + const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue()); + const parent_ptr_ty = ip.typeOf(field_ptr.base).toType(); + const parent_ty = parent_ptr_ty.childType(mod); const field_index: u32 = @intCast(field_ptr.index); switch (parent_ty.zigTypeTag(mod)) { .Union => { @@ -4309,22 +4309,14 @@ pub const Object = struct { }, .Struct => { if (mod.typeToPackedStruct(parent_ty)) |struct_type| { - if (!byte_aligned) return parent_ptr; + const ptr_info = ptr.ty.toType().ptrInfo(mod); + if (ptr_info.packed_offset.host_size != 0) return parent_ptr; + + const parent_ptr_info = parent_ptr_ty.ptrInfo(mod); + const bit_offset = mod.structPackedFieldBitOffset(struct_type, field_index) + parent_ptr_info.packed_offset.bit_offset; const llvm_usize = try o.lowerType(Type.usize); - const base_addr = - try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize); - // count bits of fields before this one - // TODO https://github.com/ziglang/zig/issues/17178 - const prev_bits = b: { - var b: usize = 0; - for (0..field_index) |i| { - const field_ty = struct_type.field_types.get(ip)[i].toType(); - if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; - b += @intCast(field_ty.bitSize(mod)); - } - break :b b; - }; - const byte_offset = try o.builder.intConst(llvm_usize, prev_bits / 8); + const base_addr = try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize); + const byte_offset = try o.builder.intConst(llvm_usize, @divExact(bit_offset, 8)); const field_addr = try o.builder.binConst(.add, base_addr, byte_offset); return o.builder.castConst(.inttoptr, field_addr, .ptr); } |
