diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index f40b63c85f..5001a0c375 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -7,6 +7,7 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const DW = std.dwarf; const log = std.log.scoped(.llvm); +const maxInt = std.math.maxInt; const Writer = std.Io.Writer; const bitcode_writer = @import("bitcode_writer.zig"); @@ -55,6 +56,8 @@ constant_items: std.MultiArrayList(Constant.Item), constant_extra: std.ArrayList(u32), constant_limbs: std.ArrayList(std.math.big.Limb), +alignment_forward_references: std.ArrayList(Alignment), + metadata_map: std.AutoArrayHashMapUnmanaged(void, void), metadata_items: std.MultiArrayList(Metadata.Item), metadata_extra: std.ArrayList(u32), @@ -85,7 +88,7 @@ pub const Options = struct { }; pub const String = enum(u32) { - none = std.math.maxInt(u31), + none = maxInt(u31), empty, _, @@ -245,7 +248,7 @@ pub const Type = enum(u32) { ptr, @"ptr addrspace(4)", - none = std.math.maxInt(u32), + none = maxInt(u32), _, pub const ptr_amdgpu_constant = @@ -941,7 +944,7 @@ pub const Attribute = union(Kind) { inalloca: Type, sret: Type, elementtype: Type, - @"align": Alignment, + @"align": Alignment.Lazy, @"noalias", nocapture, nofree, @@ -956,7 +959,7 @@ pub const Attribute = union(Kind) { immarg, noundef, nofpclass: FpClass, - alignstack: Alignment, + alignstack: Alignment.Lazy, allocalign, allocptr, readnone, @@ -964,7 +967,7 @@ pub const Attribute = union(Kind) { writeonly, // Function Attributes - //alignstack: Alignment, + //alignstack: Alignment.Lazy, allockind: AllocKind, allocsize: AllocSize, alwaysinline, @@ -1145,7 +1148,7 @@ pub const Attribute = union(Kind) { return @unionInit(Attribute, field.name, switch (field.type) { void => {}, u32 => storage.value, - Alignment, String, Type, UwTable => @enumFromInt(storage.value), + Alignment.Lazy, String, Type, UwTable => @enumFromInt(storage.value), AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(storage.value), else => @compileError("bad payload type: " ++ field.name ++ ": " ++ @typeName(field.type)), @@ -1246,7 +1249,7 @@ pub const Attribute = union(Kind) { .sret, .elementtype, => |ty| try w.print(" {s}({f})", .{ @tagName(attribute), ty.fmt(data.builder, .percent) }), - .@"align" => |alignment| try w.print("{f}", .{alignment.fmt(" ")}), + .@"align" => |alignment| try w.print("{f}", .{alignment.resolve(data.builder).fmt(" ")}), .dereferenceable, .dereferenceable_or_null, => |size| try w.print(" {s}({d})", .{ @tagName(attribute), size }), @@ -1270,7 +1273,7 @@ pub const Attribute = union(Kind) { }, .alignstack => |alignment| { try w.print(" {t}", .{attribute}); - const alignment_bytes = alignment.toByteUnits() orelse return; + const alignment_bytes = alignment.resolve(data.builder).toByteUnits() orelse return; if (data.flags.pound) { try w.print("={d}", .{alignment_bytes}); } else { @@ -1435,8 +1438,8 @@ pub const Attribute = union(Kind) { //sanitize_memtag, sanitize_address_dyninit = 102, - string = std.math.maxInt(u31), - none = std.math.maxInt(u32), + string = maxInt(u31), + none = maxInt(u32), _, pub const len = @typeInfo(Kind).@"enum".fields.len - 2; @@ -1516,12 +1519,12 @@ pub const Attribute = union(Kind) { elem_size: u16, num_elems: u16, - pub const none = std.math.maxInt(u16); + pub const none = maxInt(u16); fn toLlvm(self: AllocSize) packed struct(u64) { num_elems: u32, elem_size: u32 } { return .{ .num_elems = switch (self.num_elems) { else => self.num_elems, - none => std.math.maxInt(u32), + none => maxInt(u32), }, .elem_size = self.elem_size }; } }; @@ -1577,7 +1580,7 @@ pub const Attribute = union(Kind) { inline else => |value, tag| .{ .kind = @as(Kind, self), .value = switch (@TypeOf(value)) { void => 0, u32 => value, - Alignment, String, Type, UwTable => @intFromEnum(value), + Alignment.Lazy, String, Type, UwTable => @intFromEnum(value), AllocKind, AllocSize, FpClass, Memory, VScaleRange => @bitCast(value), else => @compileError("bad payload type: " ++ @tagName(tag) ++ @typeName(@TypeOf(value))), } }, @@ -2017,9 +2020,32 @@ pub const ExternallyInitialized = enum { }; pub const Alignment = enum(u6) { - default = std.math.maxInt(u6), + default = maxInt(u6), _, + pub const Lazy = enum(u32) { + /// Values which fit in a `u6` are already-resolved `Alignment` values. Other values are + /// indices into `Builder.alignment_forward_references`, offset by `maxInt(u6)`. + _, + + pub fn wrap(a: Alignment) Lazy { + return @enumFromInt(@intFromEnum(a)); + } + pub fn resolve(l: Lazy, b: *const Builder) Alignment { + return switch (@intFromEnum(l)) { + 0...maxInt(u6) => |raw| @enumFromInt(raw), + else => |offset_index| b.alignment_forward_references.items[offset_index - maxInt(u6)], + }; + } + + fn fromFwdRefIndex(index: usize) Lazy { + return @enumFromInt(index + maxInt(u6)); + } + fn toFwdRefIndex(l: Lazy) usize { + return @intFromEnum(l) - maxInt(u6); + } + }; + pub fn fromByteUnits(bytes: u64) Alignment { if (bytes == 0) return .default; assert(std.math.isPowerOfTwo(bytes)); @@ -2028,11 +2054,17 @@ pub const Alignment = enum(u6) { } pub fn toByteUnits(self: Alignment) ?u64 { - return if (self == .default) null else @as(u64, 1) << @intFromEnum(self); + return switch (self) { + .default => null, + else => @as(u64, 1) << @intFromEnum(self), + }; } pub fn toLlvm(self: Alignment) u6 { - return if (self == .default) 0 else (@intFromEnum(self) + 1); + return switch (self) { + .default => 0, + else => @intFromEnum(self) + 1, + }; } pub const Prefixed = struct { @@ -2180,7 +2212,7 @@ pub const CallConv = enum(u10) { }; pub const StrtabString = enum(u32) { - none = std.math.maxInt(u31), + none = maxInt(u31), empty, _, @@ -2308,7 +2340,7 @@ pub const Global = struct { }, pub const Index = enum(u32) { - none = std.math.maxInt(u32), + none = maxInt(u32), _, pub fn unwrap(self: Index, builder: *const Builder) Index { @@ -2478,7 +2510,7 @@ pub const Alias = struct { aliasee: Constant = .no_init, pub const Index = enum(u32) { - none = std.math.maxInt(u32), + none = maxInt(u32), _, pub fn ptr(self: Index, builder: *Builder) *Alias { @@ -2530,7 +2562,7 @@ pub const Variable = struct { alignment: Alignment = .default, pub const Index = enum(u32) { - none = std.math.maxInt(u32), + none = maxInt(u32), _, pub fn ptr(self: Index, builder: *Builder) *Variable { @@ -3949,7 +3981,7 @@ pub const Intrinsic = enum { .params = &.{ .{ .kind = .{ .type = Type.ptr_amdgpu_constant }, - .attrs = &.{.{ .@"align" = Builder.Alignment.fromByteUnits(4) }}, + .attrs = &.{.{ .@"align" = .wrap(.fromByteUnits(4)) }}, }, }, .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } }, @@ -4057,7 +4089,7 @@ pub const Function = struct { extra: []const u32 = &.{}, pub const Index = enum(u32) { - none = std.math.maxInt(u32), + none = maxInt(u32), _, pub fn ptr(self: Index, builder: *Builder) *Function { @@ -4411,7 +4443,7 @@ pub const Function = struct { }; pub const Index = enum(u32) { - none = std.math.maxInt(u31), + none = maxInt(u31), _, pub fn name(self: Instruction.Index, function: *const Function) String { @@ -5007,7 +5039,7 @@ pub const Function = struct { fsub = 12, fmax = 13, fmin = 14, - none = std.math.maxInt(u5), + none = maxInt(u5), }; }; @@ -6132,8 +6164,8 @@ pub const WipFunction = struct { kind: MemoryAccessKind, @"inline": bool, ) Allocator.Error!Instruction.Index { - var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })}; - var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })}; + var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })}; + var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })}; const value = try self.callIntrinsic( .normal, try self.builder.fnAttrs(&.{ @@ -6162,8 +6194,8 @@ pub const WipFunction = struct { len: Value, kind: MemoryAccessKind, ) Allocator.Error!Instruction.Index { - var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })}; - var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })}; + var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })}; + var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(src_align) })}; const value = try self.callIntrinsic( .normal, try self.builder.fnAttrs(&.{ @@ -6192,7 +6224,7 @@ pub const WipFunction = struct { kind: MemoryAccessKind, @"inline": bool, ) Allocator.Error!Instruction.Index { - var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })}; + var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = .wrap(dst_align) })}; const value = try self.callIntrinsic( .normal, try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }), @@ -7329,7 +7361,7 @@ pub const Constant = enum(u32) { //indices: [info.indices_len]Constant, pub const Kind = enum { normal, inbounds }; - pub const InRangeIndex = enum(u16) { none = std.math.maxInt(u16), _ }; + pub const InRangeIndex = enum(u16) { none = maxInt(u16), _ }; pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex }; }; @@ -7579,7 +7611,7 @@ pub const Constant = enum(u32) { string: [ (std.math.big.int.Const{ .limbs = &([1]std.math.big.Limb{ - std.math.maxInt(std.math.big.Limb), + maxInt(std.math.big.Limb), } ** expected_limbs), .positive = false, }).sizeInBaseUpperBound(10) @@ -7643,7 +7675,7 @@ pub const Constant = enum(u32) { std.math.minInt(Exponent64), else => @as(Exponent64, repr.exponent) + (std.math.floatExponentMax(f64) - std.math.floatExponentMax(f32)), - std.math.maxInt(Exponent32) => std.math.maxInt(Exponent64), + maxInt(Exponent32) => maxInt(Exponent64), }, .sign = repr.sign, }))}); @@ -7820,7 +7852,7 @@ pub const Constant = enum(u32) { }; pub const Value = enum(u32) { - none = std.math.maxInt(u31), + none = maxInt(u31), false = first_constant + @intFromEnum(Constant.false), true = first_constant + @intFromEnum(Constant.true), @"0" = first_constant + @intFromEnum(Constant.@"0"), @@ -8688,6 +8720,8 @@ pub fn init(options: Options) Allocator.Error!Builder { .constant_extra = .empty, .constant_limbs = .empty, + .alignment_forward_references = .empty, + .metadata_map = .empty, .metadata_items = .empty, .metadata_extra = .empty, @@ -8800,51 +8834,55 @@ pub fn clearAndFree(self: *Builder) void { } pub fn deinit(self: *Builder) void { - self.module_asm.deinit(self.gpa); + const gpa = self.gpa; - self.string_map.deinit(self.gpa); - self.string_indices.deinit(self.gpa); - self.string_bytes.deinit(self.gpa); + self.module_asm.deinit(gpa); - self.types.deinit(self.gpa); - self.next_unique_type_id.deinit(self.gpa); - self.type_map.deinit(self.gpa); - self.type_items.deinit(self.gpa); - self.type_extra.deinit(self.gpa); + self.string_map.deinit(gpa); + self.string_indices.deinit(gpa); + self.string_bytes.deinit(gpa); - self.attributes.deinit(self.gpa); - self.attributes_map.deinit(self.gpa); - self.attributes_indices.deinit(self.gpa); - self.attributes_extra.deinit(self.gpa); + self.types.deinit(gpa); + self.next_unique_type_id.deinit(gpa); + self.type_map.deinit(gpa); + self.type_items.deinit(gpa); + self.type_extra.deinit(gpa); - self.function_attributes_set.deinit(self.gpa); + self.attributes.deinit(gpa); + self.attributes_map.deinit(gpa); + self.attributes_indices.deinit(gpa); + self.attributes_extra.deinit(gpa); - self.globals.deinit(self.gpa); - self.next_unique_global_id.deinit(self.gpa); - self.aliases.deinit(self.gpa); - self.variables.deinit(self.gpa); - for (self.functions.items) |*function| function.deinit(self.gpa); - self.functions.deinit(self.gpa); + self.function_attributes_set.deinit(gpa); - self.strtab_string_map.deinit(self.gpa); - self.strtab_string_indices.deinit(self.gpa); - self.strtab_string_bytes.deinit(self.gpa); + self.globals.deinit(gpa); + self.next_unique_global_id.deinit(gpa); + self.aliases.deinit(gpa); + self.variables.deinit(gpa); + for (self.functions.items) |*function| function.deinit(gpa); + self.functions.deinit(gpa); - self.constant_map.deinit(self.gpa); - self.constant_items.deinit(self.gpa); - self.constant_extra.deinit(self.gpa); - self.constant_limbs.deinit(self.gpa); + self.strtab_string_map.deinit(gpa); + self.strtab_string_indices.deinit(gpa); + self.strtab_string_bytes.deinit(gpa); - self.metadata_map.deinit(self.gpa); - self.metadata_items.deinit(self.gpa); - self.metadata_extra.deinit(self.gpa); - self.metadata_limbs.deinit(self.gpa); - self.metadata_forward_references.deinit(self.gpa); - self.metadata_named.deinit(self.gpa); + self.constant_map.deinit(gpa); + self.constant_items.deinit(gpa); + self.constant_extra.deinit(gpa); + self.constant_limbs.deinit(gpa); - self.metadata_string_map.deinit(self.gpa); - self.metadata_string_indices.deinit(self.gpa); - self.metadata_string_bytes.deinit(self.gpa); + self.alignment_forward_references.deinit(gpa); + + self.metadata_map.deinit(gpa); + self.metadata_items.deinit(gpa); + self.metadata_extra.deinit(gpa); + self.metadata_limbs.deinit(gpa); + self.metadata_forward_references.deinit(gpa); + self.metadata_named.deinit(gpa); + + self.metadata_string_map.deinit(gpa); + self.metadata_string_indices.deinit(gpa); + self.metadata_string_bytes.deinit(gpa); self.* = undefined; } @@ -8962,7 +9000,7 @@ pub fn structType( pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type { try self.string_map.ensureUnusedCapacity(self.gpa, 1); if (name.slice(self)) |id| { - const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)}); + const count: usize = comptime std.fmt.count("{d}", .{maxInt(u32)}); try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len + count); } try self.string_indices.ensureUnusedCapacity(self.gpa, 1); @@ -9578,6 +9616,21 @@ pub fn asmValue( return (try self.asmConst(ty, info, assembly, constraints)).toValue(); } +/// The initial "resolved" value of the forward reference is `Alignment.default`. +pub fn alignmentForwardReference(b: *Builder) Allocator.Error!Alignment.Lazy { + const index = b.alignment_forward_references.items.len; + try b.alignment_forward_references.append(b.gpa, .default); + return .fromFwdRefIndex(index); +} + +/// Updates the "resolved" value of the alignment forward reference `fwd_ref` to `value`. +/// +/// Asserts that `fwd_ref` is a forward reference, as opposed to a resolved alignment value. +pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, value: Alignment) void { + const index = fwd_ref.toFwdRefIndex(); + b.alignment_forward_references.items[index] = value; +} + pub fn dump(b: *Builder, io: Io) void { var buffer: [4000]u8 = undefined; const stderr: Io.File = .stderr(); @@ -10515,7 +10568,7 @@ pub fn print(self: *Builder, w: *Writer) (Writer.Error || Allocator.Error)!void string: [ (std.math.big.int.Const{ .limbs = &([1]std.math.big.Limb{ - std.math.maxInt(std.math.big.Limb), + maxInt(std.math.big.Limb), } ** expected_limbs), .positive = false, }).sizeInBaseUpperBound(10) @@ -10665,7 +10718,7 @@ fn printEscapedString(slice: []const u8, quotes: QuoteBehavior, w: *Writer) Writ fn ensureUnusedGlobalCapacity(self: *Builder, name: StrtabString) Allocator.Error!void { try self.strtab_string_map.ensureUnusedCapacity(self.gpa, 1); if (name.slice(self)) |id| { - const count: usize = comptime std.fmt.count("{d}", .{std.math.maxInt(u32)}); + const count: usize = comptime std.fmt.count("{d}", .{maxInt(u32)}); try self.strtab_string_bytes.ensureUnusedCapacity(self.gpa, id.len + count); } try self.strtab_string_indices.ensureUnusedCapacity(self.gpa, 1); @@ -13518,7 +13571,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator, producer: Producer) bitco try record.ensureUnusedCapacity(self.gpa, 3); record.appendAssumeCapacity(1); record.appendAssumeCapacity(@intFromEnum(kind)); - record.appendAssumeCapacity(alignment.toByteUnits() orelse 0); + record.appendAssumeCapacity(alignment.resolve(self).toByteUnits() orelse 0); }, .dereferenceable, .dereferenceable_or_null, diff --git a/src/Sema.zig b/src/Sema.zig index 02c2efd2ee..9e3024b7ed 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7110,12 +7110,7 @@ fn analyzeCall( } for (args, 0..) |arg, arg_idx| { const arg_src = args_info.argSrc(block, arg_idx); - const arg_ty = sema.typeOf(arg); try sema.validateRuntimeValue(block, arg_src, arg); - if (arg_ty.isPtrAtRuntime(zcu) or arg_ty.isSliceAtRuntime(zcu)) { - // LLVM wants this information for an "align" attribute on the argument. - try sema.ensureLayoutResolved(arg_ty.nullablePtrElem(zcu), arg_src, .init); - } } const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: { if (!any_generic_types and !any_comptime_params) break :func .{ callee, args }; @@ -24779,16 +24774,6 @@ fn zirBuiltinExtern( } const ptr_info = ty.ptrInfo(zcu); - if (Type.fromInterned(ptr_info.child).zigTypeTag(zcu) == .@"fn") { - const func_type = ip.indexToKey(ptr_info.child).func_type; - for (func_type.param_types.get(ip)) |param_ty_ip| { - const param_ty: Type = .fromInterned(param_ty_ip); - if (param_ty.isPtrAtRuntime(zcu) or param_ty.isSliceAtRuntime(zcu)) { - // LLVM wants this information for an "align" attribute on the parameter. - try sema.ensureLayoutResolved(param_ty.nullablePtrElem(zcu), ty_src, .parameter); - } - } - } const extern_val = try pt.getExtern(.{ .name = options.name, .ty = ptr_info.child, diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index bf45502fac..9fde840232 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -1832,16 +1832,6 @@ fn analyzeNavVal( const lib_name_src = block.src(.{ .node_offset_lib_name = .zero }); try sema.handleExternLibName(&block, lib_name_src, l); } - if (nav_ty.zigTypeTag(zcu) == .@"fn") { - const func_type = ip.indexToKey(nav_ty.toIntern()).func_type; - for (func_type.param_types.get(ip)) |param_ty_ip| { - const param_ty: Type = .fromInterned(param_ty_ip); - if (param_ty.isPtrAtRuntime(zcu) or param_ty.isSliceAtRuntime(zcu)) { - // LLVM wants this information for an "align" attribute on the parameter. - try sema.ensureLayoutResolved(param_ty.nullablePtrElem(zcu), ty_src, .parameter); - } - } - } break :val .fromInterned(try pt.getExtern(.{ .name = old_nav.name, .ty = nav_ty.toIntern(), @@ -3398,10 +3388,6 @@ fn analyzeFuncBodyInner( const param_ty_src = inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) }); try sema.ensureLayoutResolved(param_ty, param_ty_src, .parameter); - if (param_ty.isPtrAtRuntime(zcu) or param_ty.isSliceAtRuntime(zcu)) { - // LLVM wants this information for an "align" attribute on the parameter. - try sema.ensureLayoutResolved(param_ty.nullablePtrElem(zcu), param_ty_src, .parameter); - } if (try param_ty.onePossibleValue(pt)) |opv| { gop.value_ptr.* = .fromValue(opv); continue; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 972a536eef..009e472d06 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -520,6 +520,21 @@ pub const Object = struct { gpa: Allocator, builder: Builder, + /// This pool contains only types (and not `@as(type, undefined)`). It has two purposes: + /// + /// * Lazily tracking ABI alignment of types, so that `@"align"` attributes can be set to a + /// type's ABI alignment before that type is fully resolved. Each type in the pool has a + /// corresponding entry in `lazy_abi_aligns`. + /// + /// * If `!Object.builder.strip`, lazily tracking debug information types, so that debug + /// information can handle indirect self-reference (and so that debug information works + /// correctly across incremental updates). Each type has a corresponding entry in + /// `debug_types`, provided that `Object.builder.strip` is `false`. + type_pool: link.ConstPool, + + /// Keyed on `link.ConstPool.Index`. + lazy_abi_aligns: std.ArrayList(Builder.Alignment.Lazy), + debug_compile_unit: Builder.Metadata.Optional, debug_enums_fwd_ref: Builder.Metadata.Optional, @@ -530,8 +545,6 @@ pub const Object = struct { debug_file_map: std.AutoHashMapUnmanaged(Zcu.File.Index, Builder.Metadata), - /// This pool *only* contains types (and does not contain `@as(type, undefined)`). - debug_type_pool: link.ConstPool, /// Keyed on `link.ConstPool.Index`. debug_types: std.ArrayList(Builder.Metadata), /// Initially `.none`, set if the type `anyerror` is lowered to a debug type. The type will not @@ -660,13 +673,14 @@ pub const Object = struct { obj.* = .{ .gpa = gpa, .builder = builder, + .type_pool = .empty, + .lazy_abi_aligns = .empty, .debug_compile_unit = debug_compile_unit, .debug_enums_fwd_ref = debug_enums_fwd_ref, .debug_globals_fwd_ref = debug_globals_fwd_ref, .debug_enums = .empty, .debug_globals = .empty, .debug_file_map = .empty, - .debug_type_pool = .empty, .debug_types = .empty, .debug_anyerror_fwd_ref = .none, .target = target, @@ -685,10 +699,11 @@ pub const Object = struct { pub fn deinit(self: *Object) void { const gpa = self.gpa; + self.type_pool.deinit(gpa); + self.lazy_abi_aligns.deinit(gpa); self.debug_enums.deinit(gpa); self.debug_globals.deinit(gpa); self.debug_file_map.deinit(gpa); - self.debug_type_pool.deinit(gpa); self.debug_types.deinit(gpa); self.nav_map.deinit(gpa); self.uav_map.deinit(gpa); @@ -836,7 +851,7 @@ pub const Object = struct { o.builder.resolveDebugForwardReference(fwd_ref, debug_anyerror_type); } - try o.flushPendingDebugTypes(pt); + try o.flushTypePool(pt); o.builder.resolveDebugForwardReference( o.debug_enums_fwd_ref.unwrap().?, @@ -1396,10 +1411,10 @@ pub const Object = struct { if (ptr_info.flags.is_const) { try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); } - const elem_align = (if (ptr_info.flags.alignment != .none) - @as(InternPool.Alignment, ptr_info.flags.alignment) - else - Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm(); + const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) { + else => |a| .wrap(a.toLlvm()), + .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)), + }; try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); const ptr_param = wip.arg(llvm_arg_i); llvm_arg_i += 1; @@ -1600,7 +1615,7 @@ pub const Object = struct { } try fg.wip.finish(); - try o.flushPendingDebugTypes(pt); + try o.flushTypePool(pt); } pub fn updateNav(self: *Object, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { @@ -1617,11 +1632,11 @@ pub const Object = struct { }, else => |e| return e, }; - try self.flushPendingDebugTypes(pt); + try self.flushTypePool(pt); } - fn flushPendingDebugTypes(o: *Object, pt: Zcu.PerThread) Allocator.Error!void { - try o.debug_type_pool.flushPending(pt, .{ .llvm = o }); + fn flushTypePool(o: *Object, pt: Zcu.PerThread) Allocator.Error!void { + try o.type_pool.flushPending(pt, .{ .llvm = o }); } pub fn updateExports( @@ -1818,51 +1833,81 @@ pub const Object = struct { } pub fn updateContainerType(o: *Object, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) Allocator.Error!void { - if (!o.builder.strip) { - try o.debug_type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success); - } + try o.type_pool.updateContainerType(pt, .{ .llvm = o }, ty, success); } /// Should only be called by the `link.ConstPool` implementation. /// - /// `val` is always a type because `o.debug_type_pool` only contains types. + /// `val` is always a type because `o.type_pool` only contains types. pub fn addConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void { const zcu = pt.zcu; const gpa = zcu.comp.gpa; assert(zcu.intern_pool.typeOf(val) == .type_type); - assert(@intFromEnum(index) == o.debug_types.items.len); - try o.debug_types.ensureUnusedCapacity(gpa, 1); - const fwd_ref = try o.builder.debugForwardReference(); - o.debug_types.appendAssumeCapacity(fwd_ref); - if (val == .anyerror_type) { - assert(o.debug_anyerror_fwd_ref.is_none); - o.debug_anyerror_fwd_ref = fwd_ref.toOptional(); + + { + assert(@intFromEnum(index) == o.lazy_abi_aligns.items.len); + try o.lazy_abi_aligns.ensureUnusedCapacity(gpa, 1); + const fwd_ref = try o.builder.alignmentForwardReference(); + o.lazy_abi_aligns.appendAssumeCapacity(fwd_ref); + } + + if (!o.builder.strip) { + assert(@intFromEnum(index) == o.debug_types.items.len); + try o.debug_types.ensureUnusedCapacity(gpa, 1); + const fwd_ref = try o.builder.debugForwardReference(); + o.debug_types.appendAssumeCapacity(fwd_ref); + if (val == .anyerror_type) { + assert(o.debug_anyerror_fwd_ref.is_none); + o.debug_anyerror_fwd_ref = fwd_ref.toOptional(); + } } } /// Should only be called by the `link.ConstPool` implementation. /// - /// `val` is always a type because `o.debug_type_pool` only contains types. + /// `val` is always a type because `o.type_pool` only contains types. pub fn updateConstIncomplete(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void { - assert(pt.zcu.intern_pool.typeOf(val) == .type_type); - const fwd_ref = o.debug_types.items[@intFromEnum(index)]; - assert(val != .anyerror_type); - const name_str = try o.builder.metadataStringFmt("{f}", .{Type.fromInterned(val).fmt(pt)}); - const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0); - o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type); + const zcu = pt.zcu; + assert(zcu.intern_pool.typeOf(val) == .type_type); + + const ty: Type = .fromInterned(val); + + { + const fwd_ref = o.lazy_abi_aligns.items[@intFromEnum(index)]; + o.builder.resolveAlignmentForwardReference(fwd_ref, .fromByteUnits(1)); + } + + if (!o.builder.strip) { + assert(val != .anyerror_type); + const fwd_ref = o.debug_types.items[@intFromEnum(index)]; + const name_str = try o.builder.metadataStringFmt("{f}", .{ty.fmt(pt)}); + const debug_incomplete_type = try o.builder.debugSignedType(name_str, 0); + o.builder.resolveDebugForwardReference(fwd_ref, debug_incomplete_type); + } } /// Should only be called by the `link.ConstPool` implementation. /// - /// `val` is always a type because `o.debug_type_pool` only contains types. + /// `val` is always a type because `o.type_pool` only contains types. pub fn updateConst(o: *Object, pt: Zcu.PerThread, index: link.ConstPool.Index, val: InternPool.Index) Allocator.Error!void { - assert(pt.zcu.intern_pool.typeOf(val) == .type_type); - const fwd_ref = o.debug_types.items[@intFromEnum(index)]; - if (val == .anyerror_type) { - // Don't lower this now; it will be populated in `emit` instead. - assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional()); - return; + const zcu = pt.zcu; + assert(zcu.intern_pool.typeOf(val) == .type_type); + + const ty: Type = .fromInterned(val); + + { + const fwd_ref = o.lazy_abi_aligns.items[@intFromEnum(index)]; + o.builder.resolveAlignmentForwardReference(fwd_ref, ty.abiAlignment(zcu).toLlvm()); + } + + if (!o.builder.strip) { + const fwd_ref = o.debug_types.items[@intFromEnum(index)]; + if (val == .anyerror_type) { + // Don't lower this now; it will be populated in `emit` instead. + assert(o.debug_anyerror_fwd_ref == fwd_ref.toOptional()); + } else { + const debug_type = try o.lowerDebugType(pt, ty, fwd_ref); + o.builder.resolveDebugForwardReference(fwd_ref, debug_type); + } } - const debug_type = try o.lowerDebugType(pt, .fromInterned(val), fwd_ref); - o.builder.resolveDebugForwardReference(fwd_ref, debug_type); } fn getDebugFile(o: *Object, pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!Builder.Metadata { @@ -1883,7 +1928,7 @@ pub const Object = struct { fn getDebugType(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Metadata { assert(!o.builder.strip); - const index = try o.debug_type_pool.get(pt, .{ .llvm = o }, ty.toIntern()); + const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern()); return o.debug_types.items[@intFromEnum(index)]; } @@ -2680,7 +2725,7 @@ pub const Object = struct { function_index.setCallConv(cc_info.llvm_cc, &o.builder); if (cc_info.align_stack) { - try attributes.addFnAttr(.{ .alignstack = .fromByteUnits(target.stackAlignment()) }, &o.builder); + try attributes.addFnAttr(.{ .alignstack = .wrap(.fromByteUnits(target.stackAlignment())) }, &o.builder); } else { _ = try attributes.removeFnAttr(.alignstack); } @@ -4166,11 +4211,11 @@ pub const Object = struct { if (ptr_info.flags.is_const) { try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); } - const elem_align = if (ptr_info.flags.alignment != .none) - ptr_info.flags.alignment - else - Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1"); - try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align.toLlvm() }, &o.builder); + const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) { + else => |a| .wrap(a.toLlvm()), + .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)), + }; + try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); } else if (ccAbiPromoteInt(fn_info.cc, zcu, param_ty)) |s| switch (s) { .signed => try attributes.addParamAttr(llvm_arg_i, .signext, &o.builder), .unsigned => try attributes.addParamAttr(llvm_arg_i, .zeroext, &o.builder), @@ -4187,7 +4232,7 @@ pub const Object = struct { ) Allocator.Error!void { try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); - try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = alignment }, &o.builder); + try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = .wrap(alignment) }, &o.builder); if (byval) try attributes.addParamAttr(llvm_arg_i, .{ .byval = param_llvm_ty }, &o.builder); } @@ -4297,6 +4342,11 @@ pub const Object = struct { try wip.finish(); return function_index; } + + fn lazyAbiAlignment(o: *Object, pt: Zcu.PerThread, ty: Type) Allocator.Error!Builder.Alignment.Lazy { + const index = try o.type_pool.get(pt, .{ .llvm = o }, ty.toIntern()); + return o.lazy_abi_aligns.items[@intFromEnum(index)]; + } }; pub const NavGen = struct { @@ -5259,10 +5309,10 @@ pub const FuncGen = struct { if (ptr_info.flags.is_const) { try attributes.addParamAttr(llvm_arg_i, .readonly, &o.builder); } - const elem_align = (if (ptr_info.flags.alignment != .none) - @as(InternPool.Alignment, ptr_info.flags.alignment) - else - Type.fromInterned(ptr_info.child).abiAlignment(zcu).max(.@"1")).toLlvm(); + const elem_align: Builder.Alignment.Lazy = switch (ptr_info.flags.alignment) { + else => |a| .wrap(a.toLlvm()), + .none => try o.lazyAbiAlignment(pt, .fromInterned(ptr_info.child)), + }; try attributes.addParamAttr(llvm_arg_i, .{ .@"align" = elem_align }, &o.builder); }, };