| author | |
| committer | |
| log | 4d044ee7e0b1ca61b8f2205f318449780ae23bd2 |
| tree | 682b42b724238e7dc0231685eecaf0f408a1620e |
| parent | ffaeb4533395fafcf020d0aca2f2efd58e48a384 |
- Add resolveUnionAlignment, to resolve a union's alignment only, without triggering layout resolution.
- Update resolveUnionLayout to cache size, alignment, and padding. abiSizeAdvanced and abiAlignmentAdvanced
now use this information instead of computing it each time.4 files changed, 153 insertions(+), 95 deletions(-)
src/InternPool.zig+32-3| ... | @@ -491,7 +491,7 @@ pub const Key = union(enum) { | ... | @@ -491,7 +491,7 @@ pub const Key = union(enum) { |
| 491 | 491 | ||
| 492 | /// The returned pointer expires with any addition to the `InternPool`. | 492 | /// The returned pointer expires with any addition to the `InternPool`. |
| 493 | /// Asserts the struct is not packed. | 493 | /// Asserts the struct is not packed. |
| 494 | pub fn flagsPtr(self: @This(), ip: *InternPool) *Tag.TypeStruct.Flags { | 494 | pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeStruct.Flags { |
| 495 | assert(self.layout != .Packed); | 495 | assert(self.layout != .Packed); |
| 496 | const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?; | 496 | const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?; |
| 497 | return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]); | 497 | return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]); |
| ... | @@ -687,6 +687,18 @@ pub const Key = union(enum) { | ... | @@ -687,6 +687,18 @@ pub const Key = union(enum) { |
| 687 | return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]); | 687 | return @ptrCast(&ip.extra.items[self.extra_index + flags_field_index]); |
| 688 | } | 688 | } |
| 689 | 689 | ||
| 690 | /// The returned pointer expires with any addition to the `InternPool`. | ||
| 691 | pub fn size(self: @This(), ip: *InternPool) *u32 { | ||
| 692 | const size_field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?; | ||
| 693 | return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]); | ||
| 694 | } | ||
| 695 | |||
| 696 | /// The returned pointer expires with any addition to the `InternPool`. | ||
| 697 | pub fn padding(self: @This(), ip: *InternPool) *u32 { | ||
| 698 | const padding_field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?; | ||
| 699 | return @ptrCast(&ip.extra.items[self.extra_index + padding_field_index]); | ||
| 700 | } | ||
| 701 | |||
| 690 | pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool { | 702 | pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool { |
| 691 | return self.flagsPtr(ip).status.haveFieldTypes(); | 703 | return self.flagsPtr(ip).status.haveFieldTypes(); |
| 692 | } | 704 | } |
| ... | @@ -1744,6 +1756,10 @@ pub const UnionType = struct { | ... | @@ -1744,6 +1756,10 @@ pub const UnionType = struct { |
| 1744 | enum_tag_ty: Index, | 1756 | enum_tag_ty: Index, |
| 1745 | /// The integer tag type of the enum. | 1757 | /// The integer tag type of the enum. |
| 1746 | int_tag_ty: Index, | 1758 | int_tag_ty: Index, |
| 1759 | /// ABI size of the union, including padding | ||
| 1760 | size: u64, | ||
| 1761 | /// Trailing padding bytes | ||
| 1762 | padding: u32, | ||
| 1747 | /// List of field names in declaration order. | 1763 | /// List of field names in declaration order. |
| 1748 | field_names: NullTerminatedString.Slice, | 1764 | field_names: NullTerminatedString.Slice, |
| 1749 | /// List of field types in declaration order. | 1765 | /// List of field types in declaration order. |
| ... | @@ -1830,6 +1846,10 @@ pub const UnionType = struct { | ... | @@ -1830,6 +1846,10 @@ pub const UnionType = struct { |
| 1830 | return self.flagsPtr(ip).runtime_tag.hasTag(); | 1846 | return self.flagsPtr(ip).runtime_tag.hasTag(); |
| 1831 | } | 1847 | } |
| 1832 | 1848 | ||
| 1849 | pub fn haveFieldTypes(self: UnionType, ip: *const InternPool) bool { | ||
| 1850 | return self.flagsPtr(ip).status.haveFieldTypes(); | ||
| 1851 | } | ||
| 1852 | |||
| 1833 | pub fn haveLayout(self: UnionType, ip: *const InternPool) bool { | 1853 | pub fn haveLayout(self: UnionType, ip: *const InternPool) bool { |
| 1834 | return self.flagsPtr(ip).status.haveLayout(); | 1854 | return self.flagsPtr(ip).status.haveLayout(); |
| 1835 | } | 1855 | } |
| ... | @@ -1867,6 +1887,8 @@ pub fn loadUnionType(ip: *InternPool, key: Key.UnionType) UnionType { | ... | @@ -1867,6 +1887,8 @@ pub fn loadUnionType(ip: *InternPool, key: Key.UnionType) UnionType { |
| 1867 | .namespace = type_union.data.namespace, | 1887 | .namespace = type_union.data.namespace, |
| 1868 | .enum_tag_ty = enum_ty, | 1888 | .enum_tag_ty = enum_ty, |
| 1869 | .int_tag_ty = enum_info.tag_ty, | 1889 | .int_tag_ty = enum_info.tag_ty, |
| 1890 | .size = type_union.data.padding, | ||
| 1891 | .padding = type_union.data.padding, | ||
| 1870 | .field_names = enum_info.names, | 1892 | .field_names = enum_info.names, |
| 1871 | .names_map = enum_info.names_map, | 1893 | .names_map = enum_info.names_map, |
| 1872 | .field_types = .{ | 1894 | .field_types = .{ |
| ... | @@ -2943,6 +2965,10 @@ pub const Tag = enum(u8) { | ... | @@ -2943,6 +2965,10 @@ pub const Tag = enum(u8) { |
| 2943 | /// 1. field align: Alignment for each field; declaration order | 2965 | /// 1. field align: Alignment for each field; declaration order |
| 2944 | pub const TypeUnion = struct { | 2966 | pub const TypeUnion = struct { |
| 2945 | flags: Flags, | 2967 | flags: Flags, |
| 2968 | // Only valid after .have_layout | ||
| 2969 | size: u32, | ||
| 2970 | // Only valid after .have_layout | ||
| 2971 | padding: u32, | ||
| 2946 | decl: Module.Decl.Index, | 2972 | decl: Module.Decl.Index, |
| 2947 | namespace: Module.Namespace.Index, | 2973 | namespace: Module.Namespace.Index, |
| 2948 | /// The enum that provides the list of field names and values. | 2974 | /// The enum that provides the list of field names and values. |
| ... | @@ -2957,7 +2983,8 @@ pub const Tag = enum(u8) { | ... | @@ -2957,7 +2983,8 @@ pub const Tag = enum(u8) { |
| 2957 | status: UnionType.Status, | 2983 | status: UnionType.Status, |
| 2958 | requires_comptime: RequiresComptime, | 2984 | requires_comptime: RequiresComptime, |
| 2959 | assumed_runtime_bits: bool, | 2985 | assumed_runtime_bits: bool, |
| 2960 | _: u21 = 0, | 2986 | alignment: Alignment, |
| 2987 | _: u15 = 0, | ||
| 2961 | }; | 2988 | }; |
| 2962 | }; | 2989 | }; |
| 2963 | 2990 | ||
| ... | @@ -3021,7 +3048,7 @@ pub const Tag = enum(u8) { | ... | @@ -3021,7 +3048,7 @@ pub const Tag = enum(u8) { |
| 3021 | any_comptime_fields: bool, | 3048 | any_comptime_fields: bool, |
| 3022 | any_default_inits: bool, | 3049 | any_default_inits: bool, |
| 3023 | any_aligned_fields: bool, | 3050 | any_aligned_fields: bool, |
| 3024 | /// `undefined` until the layout_resolved | 3051 | /// `.none` until layout_resolved |
| 3025 | alignment: Alignment, | 3052 | alignment: Alignment, |
| 3026 | /// Dependency loop detection when resolving struct alignment. | 3053 | /// Dependency loop detection when resolving struct alignment. |
| 3027 | alignment_wip: bool, | 3054 | alignment_wip: bool, |
| ... | @@ -5262,6 +5289,8 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat | ... | @@ -5262,6 +5289,8 @@ pub fn getUnionType(ip: *InternPool, gpa: Allocator, ini: UnionTypeInit) Allocat |
| 5262 | 5289 | ||
| 5263 | const union_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{ | 5290 | const union_type_extra_index = ip.addExtraAssumeCapacity(Tag.TypeUnion{ |
| 5264 | .flags = ini.flags, | 5291 | .flags = ini.flags, |
| 5292 | .size = std.math.maxInt(u32), | ||
| 5293 | .padding = std.math.maxInt(u32), | ||
| 5265 | .decl = ini.decl, | 5294 | .decl = ini.decl, |
| 5266 | .namespace = ini.namespace, | 5295 | .namespace = ini.namespace, |
| 5267 | .tag_ty = ini.enum_tag_ty, | 5296 | .tag_ty = ini.enum_tag_ty, |
src/Module.zig+3-23| ... | @@ -6538,31 +6538,11 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { | ... | @@ -6538,31 +6538,11 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { |
| 6538 | .padding = 0, | 6538 | .padding = 0, |
| 6539 | }; | 6539 | }; |
| 6540 | } | 6540 | } |
| 6541 | // Put the tag before or after the payload depending on which one's | 6541 | |
| 6542 | // alignment is greater. | ||
| 6543 | const tag_size = u.enum_tag_ty.toType().abiSize(mod); | 6542 | const tag_size = u.enum_tag_ty.toType().abiSize(mod); |
| 6544 | const tag_align = u.enum_tag_ty.toType().abiAlignment(mod).max(.@"1"); | 6543 | const tag_align = u.enum_tag_ty.toType().abiAlignment(mod).max(.@"1"); |
| 6545 | var size: u64 = 0; | ||
| 6546 | var padding: u32 = undefined; | ||
| 6547 | if (tag_align.compare(.gte, payload_align)) { | ||
| 6548 | // {Tag, Payload} | ||
| 6549 | size += tag_size; | ||
| 6550 | size = payload_align.forward(size); | ||
| 6551 | size += payload_size; | ||
| 6552 | const prev_size = size; | ||
| 6553 | size = tag_align.forward(size); | ||
| 6554 | padding = @intCast(size - prev_size); | ||
| 6555 | } else { | ||
| 6556 | // {Payload, Tag} | ||
| 6557 | size += payload_size; | ||
| 6558 | size = tag_align.forward(size); | ||
| 6559 | size += tag_size; | ||
| 6560 | const prev_size = size; | ||
| 6561 | size = payload_align.forward(size); | ||
| 6562 | padding = @intCast(size - prev_size); | ||
| 6563 | } | ||
| 6564 | return .{ | 6544 | return .{ |
| 6565 | .abi_size = size, | 6545 | .abi_size = u.size, |
| 6566 | .abi_align = tag_align.max(payload_align), | 6546 | .abi_align = tag_align.max(payload_align), |
| 6567 | .most_aligned_field = most_aligned_field, | 6547 | .most_aligned_field = most_aligned_field, |
| 6568 | .most_aligned_field_size = most_aligned_field_size, | 6548 | .most_aligned_field_size = most_aligned_field_size, |
| ... | @@ -6571,7 +6551,7 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { | ... | @@ -6571,7 +6551,7 @@ pub fn getUnionLayout(mod: *Module, u: InternPool.UnionType) UnionLayout { |
| 6571 | .payload_align = payload_align, | 6551 | .payload_align = payload_align, |
| 6572 | .tag_align = tag_align, | 6552 | .tag_align = tag_align, |
| 6573 | .tag_size = tag_size, | 6553 | .tag_size = tag_size, |
| 6574 | .padding = padding, | 6554 | .padding = u.padding, |
| 6575 | }; | 6555 | }; |
| 6576 | } | 6556 | } |
| 6577 | 6557 |
src/Sema.zig+104-9| ... | @@ -3200,6 +3200,7 @@ fn zirUnionDecl( | ... | @@ -3200,6 +3200,7 @@ fn zirUnionDecl( |
| 3200 | .any_aligned_fields = small.any_aligned_fields, | 3200 | .any_aligned_fields = small.any_aligned_fields, |
| 3201 | .requires_comptime = .unknown, | 3201 | .requires_comptime = .unknown, |
| 3202 | .assumed_runtime_bits = false, | 3202 | .assumed_runtime_bits = false, |
| 3203 | .alignment = .none, | ||
| 3203 | }, | 3204 | }, |
| 3204 | .decl = new_decl_index, | 3205 | .decl = new_decl_index, |
| 3205 | .namespace = new_namespace_index, | 3206 | .namespace = new_namespace_index, |
| ... | @@ -20988,6 +20989,7 @@ fn zirReify( | ... | @@ -20988,6 +20989,7 @@ fn zirReify( |
| 20988 | .any_aligned_fields = any_aligned_fields, | 20989 | .any_aligned_fields = any_aligned_fields, |
| 20989 | .requires_comptime = .unknown, | 20990 | .requires_comptime = .unknown, |
| 20990 | .assumed_runtime_bits = false, | 20991 | .assumed_runtime_bits = false, |
| 20992 | .alignment = .none, | ||
| 20991 | }, | 20993 | }, |
| 20992 | .field_types = union_fields.items(.type), | 20994 | .field_types = union_fields.items(.type), |
| 20993 | .field_aligns = if (any_aligned_fields) union_fields.items(.alignment) else &.{}, | 20995 | .field_aligns = if (any_aligned_fields) union_fields.items(.alignment) else &.{}, |
| ... | @@ -34921,11 +34923,56 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void | ... | @@ -34921,11 +34923,56 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void |
| 34921 | return sema.failWithOwnedErrorMsg(block, msg); | 34923 | return sema.failWithOwnedErrorMsg(block, msg); |
| 34922 | } | 34924 | } |
| 34923 | 34925 | ||
| 34926 | /// Resolve a unions's alignment only without triggering resolution of its layout. | ||
| 34927 | /// Asserts that the alignment is not yet resolved. | ||
| 34928 | pub fn resolveUnionAlignment( | ||
| 34929 | sema: *Sema, | ||
| 34930 | ty: Type, | ||
| 34931 | union_type: InternPool.Key.UnionType, | ||
| 34932 | ) CompileError!Alignment { | ||
| 34933 | const mod = sema.mod; | ||
| 34934 | const ip = &mod.intern_pool; | ||
| 34935 | const target = mod.getTarget(); | ||
| 34936 | |||
| 34937 | assert(!union_type.haveLayout(ip)); | ||
| 34938 | |||
| 34939 | if (union_type.flagsPtr(ip).status == .field_types_wip) { | ||
| 34940 | // We'll guess "pointer-aligned", if the union has an | ||
| 34941 | // underaligned pointer field then some allocations | ||
| 34942 | // might require explicit alignment. | ||
| 34943 | return Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); | ||
| 34944 | } | ||
| 34945 | |||
| 34946 | try sema.resolveTypeFieldsUnion(ty, union_type); | ||
| 34947 | |||
| 34948 | const union_obj = ip.loadUnionType(union_type); | ||
| 34949 | var max_align: Alignment = .@"1"; | ||
| 34950 | for (0..union_obj.field_names.len) |field_index| { | ||
| 34951 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); | ||
| 34952 | if (!(try sema.typeHasRuntimeBits(field_ty))) continue; | ||
| 34953 | |||
| 34954 | const explicit_align = union_obj.fieldAlign(ip, @intCast(field_index)); | ||
| 34955 | const field_align = if (explicit_align != .none) | ||
| 34956 | explicit_align | ||
| 34957 | else | ||
| 34958 | try sema.typeAbiAlignment(field_ty); | ||
| 34959 | |||
| 34960 | max_align = max_align.max(field_align); | ||
| 34961 | } | ||
| 34962 | |||
| 34963 | union_type.flagsPtr(ip).alignment = max_align; | ||
| 34964 | return max_align; | ||
| 34965 | } | ||
| 34966 | |||
| 34967 | /// This logic must be kept in sync with `Module.getUnionLayout`. | ||
| 34924 | fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | 34968 | fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 34925 | const mod = sema.mod; | 34969 | const mod = sema.mod; |
| 34926 | const ip = &mod.intern_pool; | 34970 | const ip = &mod.intern_pool; |
| 34927 | try sema.resolveTypeFields(ty); | 34971 | |
| 34928 | const union_obj = mod.typeToUnion(ty).?; | 34972 | const union_type = ip.indexToKey(ty.ip_index).union_type; |
| 34973 | try sema.resolveTypeFieldsUnion(ty, union_type); | ||
| 34974 | |||
| 34975 | const union_obj = ip.loadUnionType(union_type); | ||
| 34929 | switch (union_obj.flagsPtr(ip).status) { | 34976 | switch (union_obj.flagsPtr(ip).status) { |
| 34930 | .none, .have_field_types => {}, | 34977 | .none, .have_field_types => {}, |
| 34931 | .field_types_wip, .layout_wip => { | 34978 | .field_types_wip, .layout_wip => { |
| ... | @@ -34939,25 +34986,74 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -34939,25 +34986,74 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 34939 | }, | 34986 | }, |
| 34940 | .have_layout, .fully_resolved_wip, .fully_resolved => return, | 34987 | .have_layout, .fully_resolved_wip, .fully_resolved => return, |
| 34941 | } | 34988 | } |
| 34989 | |||
| 34942 | const prev_status = union_obj.flagsPtr(ip).status; | 34990 | const prev_status = union_obj.flagsPtr(ip).status; |
| 34943 | errdefer if (union_obj.flagsPtr(ip).status == .layout_wip) { | 34991 | errdefer if (union_obj.flagsPtr(ip).status == .layout_wip) { |
| 34944 | union_obj.flagsPtr(ip).status = prev_status; | 34992 | union_obj.flagsPtr(ip).status = prev_status; |
| 34945 | }; | 34993 | }; |
| 34946 | 34994 | ||
| 34947 | union_obj.flagsPtr(ip).status = .layout_wip; | 34995 | union_obj.flagsPtr(ip).status = .layout_wip; |
| 34948 | for (0..union_obj.field_types.len) |field_index| { | 34996 | |
| 34997 | var max_size: u64 = 0; | ||
| 34998 | var max_align: Alignment = .@"1"; | ||
| 34999 | for (0..union_obj.field_names.len) |field_index| { | ||
| 34949 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); | 35000 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); |
| 34950 | sema.resolveTypeLayout(field_ty) catch |err| switch (err) { | 35001 | if (!(try sema.typeHasRuntimeBits(field_ty))) continue; |
| 35002 | |||
| 35003 | max_size = @max(max_size, sema.typeAbiSize(field_ty) catch |err| switch (err) { | ||
| 34951 | error.AnalysisFail => { | 35004 | error.AnalysisFail => { |
| 34952 | const msg = sema.err orelse return err; | 35005 | const msg = sema.err orelse return err; |
| 34953 | try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{}); | 35006 | try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{}); |
| 34954 | return err; | 35007 | return err; |
| 34955 | }, | 35008 | }, |
| 34956 | else => return err, | 35009 | else => return err, |
| 34957 | }; | 35010 | }); |
| 34958 | } | 35011 | |
| 34959 | union_obj.flagsPtr(ip).status = .have_layout; | 35012 | const explicit_align = union_obj.fieldAlign(ip, @intCast(field_index)); |
| 34960 | _ = try sema.typeRequiresComptime(ty); | 35013 | const field_align = if (explicit_align != .none) |
| 35014 | explicit_align | ||
| 35015 | else | ||
| 35016 | try sema.typeAbiAlignment(field_ty); | ||
| 35017 | |||
| 35018 | max_align = max_align.max(field_align); | ||
| 35019 | } | ||
| 35020 | |||
| 35021 | const flags = union_obj.flagsPtr(ip); | ||
| 35022 | const has_runtime_tag = flags.runtime_tag.hasTag() and try sema.typeHasRuntimeBits(union_obj.enum_tag_ty.toType()); | ||
| 35023 | const size, const alignment, const padding = if (has_runtime_tag) layout: { | ||
| 35024 | const enum_tag_type = union_obj.enum_tag_ty.toType(); | ||
| 35025 | const tag_align = try sema.typeAbiAlignment(enum_tag_type); | ||
| 35026 | const tag_size = try sema.typeAbiSize(enum_tag_type); | ||
| 35027 | |||
| 35028 | // Put the tag before or after the payload depending on which one's | ||
| 35029 | // alignment is greater. | ||
| 35030 | var size: u64 = 0; | ||
| 35031 | var padding: u32 = 0; | ||
| 35032 | if (tag_align.compare(.gte, max_align)) { | ||
| 35033 | // {Tag, Payload} | ||
| 35034 | size += tag_size; | ||
| 35035 | size = max_align.forward(size); | ||
| 35036 | size += max_size; | ||
| 35037 | const prev_size = size; | ||
| 35038 | size = tag_align.forward(size); | ||
| 35039 | padding = @intCast(size - prev_size); | ||
| 35040 | } else { | ||
| 35041 | // {Payload, Tag} | ||
| 35042 | size += max_size; | ||
| 35043 | size = tag_align.forward(size); | ||
| 35044 | size += tag_size; | ||
| 35045 | const prev_size = size; | ||
| 35046 | size = max_align.forward(size); | ||
| 35047 | padding = @intCast(size - prev_size); | ||
| 35048 | } | ||
| 35049 | |||
| 35050 | break :layout .{ size, max_align.max(tag_align), padding }; | ||
| 35051 | } else .{ max_align.forward(max_size), max_align, 0 }; | ||
| 35052 | |||
| 35053 | union_type.size(ip).* = @intCast(size); | ||
| 35054 | union_type.padding(ip).* = padding; | ||
| 35055 | flags.alignment = alignment; | ||
| 35056 | flags.status = .have_layout; | ||
| 34961 | 35057 | ||
| 34962 | if (union_obj.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { | 35058 | if (union_obj.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) { |
| 34963 | const msg = try Module.ErrorMsg.create( | 35059 | const msg = try Module.ErrorMsg.create( |
| ... | @@ -35034,7 +35130,6 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -35034,7 +35130,6 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void { |
| 35034 | 35130 | ||
| 35035 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { | 35131 | fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void { |
| 35036 | try sema.resolveUnionLayout(ty); | 35132 | try sema.resolveUnionLayout(ty); |
| 35037 | try sema.resolveTypeFields(ty); | ||
| 35038 | 35133 | ||
| 35039 | const mod = sema.mod; | 35134 | const mod = sema.mod; |
| 35040 | const ip = &mod.intern_pool; | 35135 | const ip = &mod.intern_pool; |
src/type.zig+14-60| ... | @@ -1034,66 +1034,20 @@ pub const Type = struct { | ... | @@ -1034,66 +1034,20 @@ pub const Type = struct { |
| 1034 | } | 1034 | } |
| 1035 | return .{ .scalar = big_align }; | 1035 | return .{ .scalar = big_align }; |
| 1036 | }, | 1036 | }, |
| 1037 | |||
| 1038 | .union_type => |union_type| { | 1037 | .union_type => |union_type| { |
| 1039 | if (opt_sema) |sema| { | 1038 | const flags = union_type.flagsPtr(ip).*; |
| 1040 | if (union_type.flagsPtr(ip).status == .field_types_wip) { | 1039 | if (flags.alignment != .none) return .{ .scalar = flags.alignment }; |
| 1041 | // We'll guess "pointer-aligned", if the union has an | 1040 | |
| 1042 | // underaligned pointer field then some allocations | 1041 | if (!union_type.haveLayout(ip)) switch (strat) { |
| 1043 | // might require explicit alignment. | ||
| 1044 | return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) }; | ||
| 1045 | } | ||
| 1046 | _ = try sema.resolveTypeFields(ty); | ||
| 1047 | } | ||
| 1048 | if (!union_type.haveFieldTypes(ip)) switch (strat) { | ||
| 1049 | .eager => unreachable, // union layout not resolved | 1042 | .eager => unreachable, // union layout not resolved |
| 1050 | .sema => unreachable, // handled above | 1043 | .sema => |sema| return .{ .scalar = try sema.resolveUnionAlignment(ty, union_type) }, |
| 1051 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | 1044 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ |
| 1052 | .ty = .comptime_int_type, | 1045 | .ty = .comptime_int_type, |
| 1053 | .storage = .{ .lazy_align = ty.toIntern() }, | 1046 | .storage = .{ .lazy_align = ty.toIntern() }, |
| 1054 | } })).toValue() }, | 1047 | } })).toValue() }, |
| 1055 | }; | 1048 | }; |
| 1056 | const union_obj = ip.loadUnionType(union_type); | ||
| 1057 | if (union_obj.field_names.len == 0) { | ||
| 1058 | if (union_obj.hasTag(ip)) { | ||
| 1059 | return abiAlignmentAdvanced(union_obj.enum_tag_ty.toType(), mod, strat); | ||
| 1060 | } else { | ||
| 1061 | return .{ .scalar = .@"1" }; | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | 1049 | ||
| 1065 | var max_align: Alignment = .@"1"; | 1050 | return .{ .scalar = union_type.flagsPtr(ip).alignment }; |
| 1066 | if (union_obj.hasTag(ip)) max_align = union_obj.enum_tag_ty.toType().abiAlignment(mod); | ||
| 1067 | for (0..union_obj.field_names.len) |field_index| { | ||
| 1068 | const field_ty = union_obj.field_types.get(ip)[field_index].toType(); | ||
| 1069 | const field_align = if (union_obj.field_aligns.len == 0) | ||
| 1070 | .none | ||
| 1071 | else | ||
| 1072 | union_obj.field_aligns.get(ip)[field_index]; | ||
| 1073 | if (!(field_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | ||
| 1074 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1075 | .ty = .comptime_int_type, | ||
| 1076 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1077 | } })).toValue() }, | ||
| 1078 | else => |e| return e, | ||
| 1079 | })) continue; | ||
| 1080 | |||
| 1081 | const field_align_bytes: Alignment = if (field_align != .none) | ||
| 1082 | field_align | ||
| 1083 | else switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { | ||
| 1084 | .scalar => |a| a, | ||
| 1085 | .val => switch (strat) { | ||
| 1086 | .eager => unreachable, // struct layout not resolved | ||
| 1087 | .sema => unreachable, // handled above | ||
| 1088 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | ||
| 1089 | .ty = .comptime_int_type, | ||
| 1090 | .storage = .{ .lazy_align = ty.toIntern() }, | ||
| 1091 | } })).toValue() }, | ||
| 1092 | }, | ||
| 1093 | }; | ||
| 1094 | max_align = max_align.max(field_align_bytes); | ||
| 1095 | } | ||
| 1096 | return .{ .scalar = max_align }; | ||
| 1097 | }, | 1051 | }, |
| 1098 | .opaque_type => return .{ .scalar = .@"1" }, | 1052 | .opaque_type => return .{ .scalar = .@"1" }, |
| 1099 | .enum_type => |enum_type| return .{ | 1053 | .enum_type => |enum_type| return .{ |
| ... | @@ -1451,8 +1405,8 @@ pub const Type = struct { | ... | @@ -1451,8 +1405,8 @@ pub const Type = struct { |
| 1451 | }, | 1405 | }, |
| 1452 | .eager => {}, | 1406 | .eager => {}, |
| 1453 | } | 1407 | } |
| 1454 | const union_obj = ip.loadUnionType(union_type); | 1408 | |
| 1455 | return AbiSizeAdvanced{ .scalar = mod.unionAbiSize(union_obj) }; | 1409 | return .{ .scalar = union_type.size(ip).* }; |
| 1456 | }, | 1410 | }, |
| 1457 | .opaque_type => unreachable, // no size available | 1411 | .opaque_type => unreachable, // no size available |
| 1458 | .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) }, | 1412 | .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) }, |
| ... | @@ -2680,11 +2634,11 @@ pub const Type = struct { | ... | @@ -2680,11 +2634,11 @@ pub const Type = struct { |
| 2680 | if (struct_type.flagsPtr(ip).field_types_wip) | 2634 | if (struct_type.flagsPtr(ip).field_types_wip) |
| 2681 | return false; | 2635 | return false; |
| 2682 | 2636 | ||
| 2683 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); | ||
| 2684 | |||
| 2685 | struct_type.flagsPtr(ip).requires_comptime = .wip; | 2637 | struct_type.flagsPtr(ip).requires_comptime = .wip; |
| 2686 | errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown; | 2638 | errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown; |
| 2687 | 2639 | ||
| 2640 | try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type); | ||
| 2641 | |||
| 2688 | for (0..struct_type.field_types.len) |i_usize| { | 2642 | for (0..struct_type.field_types.len) |i_usize| { |
| 2689 | const i: u32 = @intCast(i_usize); | 2643 | const i: u32 = @intCast(i_usize); |
| 2690 | if (struct_type.fieldIsComptime(ip, i)) continue; | 2644 | if (struct_type.fieldIsComptime(ip, i)) continue; |
| ... | @@ -2723,12 +2677,12 @@ pub const Type = struct { | ... | @@ -2723,12 +2677,12 @@ pub const Type = struct { |
| 2723 | if (union_type.flagsPtr(ip).status == .field_types_wip) | 2677 | if (union_type.flagsPtr(ip).status == .field_types_wip) |
| 2724 | return false; | 2678 | return false; |
| 2725 | 2679 | ||
| 2726 | try sema.resolveTypeFieldsUnion(ty, union_type); | 2680 | union_type.flagsPtr(ip).requires_comptime = .wip; |
| 2727 | const union_obj = ip.loadUnionType(union_type); | 2681 | errdefer union_type.flagsPtr(ip).requires_comptime = .unknown; |
| 2728 | 2682 | ||
| 2729 | union_obj.flagsPtr(ip).requires_comptime = .wip; | 2683 | try sema.resolveTypeFieldsUnion(ty, union_type); |
| 2730 | errdefer union_obj.flagsPtr(ip).requires_comptime = .unknown; | ||
| 2731 | 2684 | ||
| 2685 | const union_obj = ip.loadUnionType(union_type); | ||
| 2732 | for (0..union_obj.field_types.len) |field_idx| { | 2686 | for (0..union_obj.field_types.len) |field_idx| { |
| 2733 | const field_ty = union_obj.field_types.get(ip)[field_idx]; | 2687 | const field_ty = union_obj.field_types.get(ip)[field_idx]; |
| 2734 | if (try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) { | 2688 | if (try field_ty.toType().comptimeOnlyAdvanced(mod, opt_sema)) { |