diff --git a/src/Compilation.zig b/src/Compilation.zig index 800c8288d0..70d0e5ff82 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3545,6 +3545,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = .{}, .anon_decl_deps = .{}, + .aligned_anon_decls = .{}, }; defer { dg.ctypes.deinit(gpa); diff --git a/src/InternPool.zig b/src/InternPool.zig index 8cf121896d..707e2d95b9 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1074,7 +1074,7 @@ pub const Key = union(enum) { decl: Module.Decl.Index, mut_decl: MutDecl, - anon_decl: Index, + anon_decl: AnonDecl, comptime_field: Index, int: Index, eu_payload: Index, @@ -1090,6 +1090,14 @@ pub const Key = union(enum) { base: Index, index: u64, }; + pub const AnonDecl = extern struct { + val: Index, + /// Contains the canonical pointer type of the anonymous + /// declaration. This may equal `ty` of the `Ptr` or it may be + /// different. Importantly, when lowering the anonymous decl, + /// the original pointer type alignment must be used. + orig_ty: Index, + }; }; }; @@ -1231,7 +1239,8 @@ pub const Key = union(enum) { common ++ asBytes(&x.decl) ++ asBytes(&x.runtime_index), ), - .anon_decl, + .anon_decl => |x| Hash.hash(seed2, common ++ asBytes(&x)), + .int, .eu_payload, .opt_payload, @@ -1500,7 +1509,8 @@ pub const Key = union(enum) { return switch (a_info.addr) { .decl => |a_decl| a_decl == b_info.addr.decl, .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), - .anon_decl => |a_decl| a_decl == b_info.addr.anon_decl, + .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and + ad.orig_ty == b_info.addr.anon_decl.orig_ty, .int => |a_int| a_int == b_info.addr.int, .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload, .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload, @@ -2133,6 +2143,7 @@ pub const Index = enum(u32) { ptr_decl: struct { data: *PtrDecl }, ptr_mut_decl: struct { data: *PtrMutDecl }, ptr_anon_decl: struct { data: *PtrAnonDecl }, + ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned }, ptr_comptime_field: struct { data: *PtrComptimeField }, ptr_int: struct { data: *PtrBase }, ptr_eu_payload: struct { data: *PtrBase }, @@ -2583,8 +2594,16 @@ pub const Tag = enum(u8) { /// data is extra index of `PtrMutDecl`, which contains the type and address. ptr_mut_decl, /// A pointer to an anonymous decl. - /// data is extra index of `PtrAnonDecl`, which contains the type and decl value. + /// data is extra index of `PtrAnonDecl`, which contains the pointer type and decl value. + /// The alignment of the anonymous decl is communicated via the pointer type. ptr_anon_decl, + /// A pointer to an anonymous decl. + /// data is extra index of `PtrAnonDeclAligned`, which contains the pointer + /// type and decl value. + /// The original pointer type is also provided, which will be different than `ty`. + /// This encoding is only used when a pointer to an anonymous decl is + /// coerced to a different pointer type with a different alignment. + ptr_anon_decl_aligned, /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value. ptr_comptime_field, /// A pointer with an integer value. @@ -2781,6 +2800,7 @@ pub const Tag = enum(u8) { .ptr_decl => PtrDecl, .ptr_mut_decl => PtrMutDecl, .ptr_anon_decl => PtrAnonDecl, + .ptr_anon_decl_aligned => PtrAnonDeclAligned, .ptr_comptime_field => PtrComptimeField, .ptr_int => PtrBase, .ptr_eu_payload => PtrBase, @@ -3383,6 +3403,13 @@ pub const PtrAnonDecl = struct { val: Index, }; +pub const PtrAnonDeclAligned = struct { + ty: Index, + val: Index, + /// Must be nonequal to `ty`. Only the alignment from this value is important. + orig_ty: Index, +}; + pub const PtrMutDecl = struct { ty: Index, decl: Module.Decl.Index, @@ -3736,7 +3763,20 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { const info = ip.extraData(PtrAnonDecl, data); return .{ .ptr = .{ .ty = info.ty, - .addr = .{ .anon_decl = info.val }, + .addr = .{ .anon_decl = .{ + .val = info.val, + .orig_ty = info.ty, + } }, + } }; + }, + .ptr_anon_decl_aligned => { + const info = ip.extraData(PtrAnonDeclAligned, data); + return .{ .ptr = .{ + .ty = info.ty, + .addr = .{ .anon_decl = .{ + .val = info.val, + .orig_ty = info.orig_ty, + } }, } }; }, .ptr_comptime_field => { @@ -3817,7 +3857,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { } }; }, .ptr_anon_decl => .{ - .anon_decl = ip.extraData(PtrAnonDecl, ptr_item.data).val, + .anon_decl = .{ + .val = ip.extraData(PtrAnonDecl, ptr_item.data).val, + .orig_ty = info.ty, + }, + }, + .ptr_anon_decl_aligned => b: { + const sub_info = ip.extraData(PtrAnonDeclAligned, ptr_item.data); + break :b .{ .anon_decl = .{ + .val = sub_info.val, + .orig_ty = sub_info.orig_ty, + } }; }, .ptr_comptime_field => .{ .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val, @@ -4571,13 +4621,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { .runtime_index = mut_decl.runtime_index, }), }), - .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(.{ - .tag = .ptr_anon_decl, - .data = try ip.addExtra(gpa, PtrAnonDecl{ - .ty = ptr.ty, - .val = anon_decl, - }), - }), + .anon_decl => |anon_decl| ip.items.appendAssumeCapacity( + if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) .{ + .tag = .ptr_anon_decl, + .data = try ip.addExtra(gpa, PtrAnonDecl{ + .ty = ptr.ty, + .val = anon_decl.val, + }), + } else .{ + .tag = .ptr_anon_decl_aligned, + .data = try ip.addExtra(gpa, PtrAnonDeclAligned{ + .ty = ptr.ty, + .val = anon_decl.val, + .orig_ty = anon_decl.orig_ty, + }), + }, + ), .comptime_field => |field_val| { assert(field_val != .none); ip.items.appendAssumeCapacity(.{ @@ -7184,6 +7243,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { .ptr_decl => @sizeOf(PtrDecl), .ptr_mut_decl => @sizeOf(PtrMutDecl), .ptr_anon_decl => @sizeOf(PtrAnonDecl), + .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned), .ptr_comptime_field => @sizeOf(PtrComptimeField), .ptr_int => @sizeOf(PtrBase), .ptr_eu_payload => @sizeOf(PtrBase), @@ -7314,6 +7374,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { .ptr_decl, .ptr_mut_decl, .ptr_anon_decl, + .ptr_anon_decl_aligned, .ptr_comptime_field, .ptr_int, .ptr_eu_payload, @@ -7695,6 +7756,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { inline .ptr_decl, .ptr_mut_decl, .ptr_anon_decl, + .ptr_anon_decl_aligned, .ptr_comptime_field, .ptr_int, .ptr_eu_payload, @@ -7855,7 +7917,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag { switch (ip.items.items(.tag)[base]) { .ptr_decl => return .decl, .ptr_mut_decl => return .mut_decl, - .ptr_anon_decl => return .anon_decl, + .ptr_anon_decl, .ptr_anon_decl_aligned => return .anon_decl, .ptr_comptime_field => return .comptime_field, .ptr_int => return .int, inline .ptr_eu_payload, @@ -8032,6 +8094,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois .ptr_decl, .ptr_mut_decl, .ptr_anon_decl, + .ptr_anon_decl_aligned, .ptr_comptime_field, .ptr_int, .ptr_eu_payload, @@ -8281,3 +8344,12 @@ pub fn addFieldName( ip.extra.items[names_start + field_index] = @intFromEnum(name); return null; } + +/// Used only by `get` for pointer values, and mainly intended to use `Tag.ptr_anon_decl` +/// encoding instead of `Tag.ptr_anon_decl_aligned` when possible. +fn ptrsHaveSameAlignment(ip: *InternPool, a_ty: Index, a_info: Key.PtrType, b_ty: Index) bool { + if (a_ty == b_ty) return true; + const b_info = ip.indexToKey(b_ty).ptr_type; + return a_info.flags.alignment == b_info.flags.alignment and + (a_info.child == b_info.child or a_info.flags.alignment != .none); +} diff --git a/src/Sema.zig b/src/Sema.zig index 3e8eeeb886..54e744e6e7 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3659,7 +3659,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro if (try sema.resolveComptimeKnownAllocValue(block, alloc, null)) |val| { const new_mut_ptr = Air.internedToRef((try mod.intern(.{ .ptr = .{ .ty = alloc_ty.toIntern(), - .addr = .{ .anon_decl = val }, + .addr = .{ .anon_decl = .{ + .val = val, + .orig_ty = alloc_ty.toIntern(), + } }, } }))); return sema.makePtrConst(block, new_mut_ptr); } @@ -5540,7 +5543,10 @@ fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref { }); return Air.internedToRef((try mod.intern(.{ .ptr = .{ .ty = ptr_ty.toIntern(), - .addr = .{ .anon_decl = val }, + .addr = .{ .anon_decl = .{ + .val = val, + .orig_ty = ptr_ty.toIntern(), + } }, } }))); } @@ -30546,7 +30552,8 @@ fn beginComptimePtrLoad( .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, }; }, - .anon_decl => |decl_val| blk: { + .anon_decl => |anon_decl| blk: { + const decl_val = anon_decl.val; if (decl_val.toValue().getVariable(mod) != null) return error.RuntimeLoad; const decl_ty = ip.typeOf(decl_val).toType(); const decl_tv: TypedValue = .{ .ty = decl_ty, .val = decl_val.toValue() }; @@ -36650,6 +36657,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .simple_value, .ptr_decl, .ptr_anon_decl, + .ptr_anon_decl_aligned, .ptr_mut_decl, .ptr_comptime_field, .ptr_int, diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 3d77d6b8a0..345535a06e 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -321,7 +321,8 @@ pub fn print( .val = decl.val, }, writer, level - 1, mod); }, - .anon_decl => |decl_val| { + .anon_decl => |anon_decl| { + const decl_val = anon_decl.val; if (level == 0) return writer.print("(anon decl '{d}')", .{ @intFromEnum(decl_val), }); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 3eac273164..639af3d8c4 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3139,16 +3139,25 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); } -fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) InnerError!WValue { +fn lowerAnonDeclRef( + func: *CodeGen, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, + offset: u32, +) InnerError!WValue { const mod = func.bin_file.base.options.module.?; - const ty = mod.intern_pool.typeOf(anon_decl).toType(); + const decl_val = anon_decl.val; + const ty = mod.intern_pool.typeOf(decl_val).toType(); const is_fn_body = ty.zigTypeTag(mod) == .Fn; if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(mod)) { return WValue{ .imm32 = 0xaaaaaaaa }; } - const res = try func.bin_file.lowerAnonDecl(anon_decl, func.decl.srcLoc(mod)); + const alignment = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment; + if (alignment != .none) { + @panic("TODO how to make this anon decl be aligned?"); + } + const res = try func.bin_file.lowerAnonDecl(decl_val, func.decl.srcLoc(mod)); switch (res) { .ok => {}, .fail => |em| { @@ -3156,7 +3165,7 @@ fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) In return error.CodegenFail; }, } - const target_atom_index = func.bin_file.anon_decls.get(anon_decl).?; + const target_atom_index = func.bin_file.anon_decls.get(decl_val).?; const target_sym_index = func.bin_file.getAtom(target_atom_index).getSymbolIndex().?; if (is_fn_body) { return WValue{ .function_index = target_sym_index }; diff --git a/src/codegen.zig b/src/codegen.zig index 24269f38ba..d7a5666986 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -713,7 +713,7 @@ const RelocInfo = struct { fn lowerAnonDeclRef( bin_file: *link.File, src_loc: Module.SrcLoc, - decl_val: InternPool.Index, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, code: *std.ArrayList(u8), debug_output: DebugInfoOutput, reloc_info: RelocInfo, @@ -723,6 +723,7 @@ fn lowerAnonDeclRef( const mod = bin_file.options.module.?; const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8); + const decl_val = anon_decl.val; const decl_ty = mod.intern_pool.typeOf(decl_val).toType(); const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn; if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) { @@ -736,6 +737,10 @@ fn lowerAnonDeclRef( .fail => |em| return .{ .fail = em }, } + const alignment = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment; + if (alignment != .none) { + @panic("TODO how to make this anon decl be aligned?"); + } const vaddr = try bin_file.getAnonDeclVAddr(decl_val, .{ .parent_atom_index = reloc_info.parent_atom_index, .offset = code.items.len, diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 94598985c0..897d0ea047 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -531,6 +531,7 @@ pub const DeclGen = struct { /// Keeps track of anonymous decls that need to be rendered before this /// (named) Decl in the output C code. anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock), + aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment), fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { @setCold(true); @@ -548,11 +549,12 @@ pub const DeclGen = struct { writer: anytype, ty: Type, ptr_val: Value, - decl_val: InternPool.Index, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, location: ValueRenderLocation, ) error{ OutOfMemory, AnalysisFail }!void { const mod = dg.module; const ip = &mod.intern_pool; + const decl_val = anon_decl.val; const decl_ty = ip.typeOf(decl_val).toType(); // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. @@ -592,8 +594,23 @@ pub const DeclGen = struct { // Indicate that the anon decl should be rendered to the output so that // our reference above is not undefined. + const ptr_type = ip.indexToKey(anon_decl.orig_ty).ptr_type; const gop = try dg.anon_decl_deps.getOrPut(dg.gpa, decl_val); if (!gop.found_existing) gop.value_ptr.* = .{}; + + // Only insert an alignment entry if the alignment is greater than ABI + // alignment. If there is already an entry, keep the greater alignment. + const explicit_alignment = ptr_type.flags.alignment; + if (explicit_alignment != .none) { + const abi_alignment = ptr_type.child.toType().abiAlignment(mod); + if (explicit_alignment.compareStrict(.gt, abi_alignment)) { + const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, decl_val); + aligned_gop.value_ptr.* = if (aligned_gop.found_existing) + aligned_gop.value_ptr.maxStrict(explicit_alignment) + else + explicit_alignment; + } + } } fn renderDeclValue( @@ -651,7 +668,7 @@ pub const DeclGen = struct { switch (ptr.addr) { .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location), .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location), - .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location), + .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), anon_decl, location), .int => |int| { try writer.writeByte('('); try dg.renderCType(writer, ptr_cty); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 9bb012deb1..ed4f1bdf6c 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3051,9 +3051,17 @@ pub const Object = struct { llvm_addr_space: Builder.AddrSpace, alignment: InternPool.Alignment, ) Error!Builder.Variable.Index { + assert(alignment != .none); // TODO: Add address space to the anon_decl_map const gop = try o.anon_decl_map.getOrPut(o.gpa, decl_val); - if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable; + if (gop.found_existing) { + // Keep the greater of the two alignments. + const variable_index = gop.value_ptr.ptr(&o.builder).kind.variable; + const old_alignment = InternPool.Alignment.fromLlvm(variable_index.getAlignment(&o.builder)); + const max_alignment = old_alignment.maxStrict(alignment); + variable_index.setAlignment(max_alignment.toLlvm(), &o.builder); + return variable_index; + } errdefer assert(o.anon_decl_map.remove(decl_val)); const mod = o.module; @@ -3069,8 +3077,7 @@ pub const Object = struct { try variable_index.setInitializer(try o.lowerValue(decl_val), &o.builder); variable_index.setLinkage(.internal, &o.builder); variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); - if (alignment != .none) - variable_index.setAlignment(alignment.toLlvm(), &o.builder); + variable_index.setAlignment(alignment.toLlvm(), &o.builder); return variable_index; } @@ -4253,13 +4260,6 @@ pub const Object = struct { return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint); } - fn lowerParentPtrAnonDecl(o: *Object, decl_val: InternPool.Index) Error!Builder.Constant { - const mod = o.module; - const decl_ty = mod.intern_pool.typeOf(decl_val).toType(); - const ptr_ty = try mod.singleMutPtrType(decl_ty); - return o.lowerAnonDeclRef(ptr_ty, decl_val); - } - fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { const mod = o.module; const decl = mod.declPtr(decl_index); @@ -4275,7 +4275,7 @@ pub const Object = struct { return switch (ptr.addr) { .decl => |decl| try o.lowerParentPtrDecl(decl), .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl), - .anon_decl => |anon_decl| try o.lowerParentPtrAnonDecl(anon_decl), + .anon_decl => |ad| try o.lowerAnonDeclRef(ad.orig_ty.toType(), ad), .int => |int| try o.lowerIntAsPtr(int), .eu_payload => |eu_ptr| { const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue()); @@ -4394,10 +4394,11 @@ pub const Object = struct { fn lowerAnonDeclRef( o: *Object, ptr_ty: Type, - decl_val: InternPool.Index, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, ) Error!Builder.Constant { const mod = o.module; const ip = &mod.intern_pool; + const decl_val = anon_decl.val; const decl_ty = ip.typeOf(decl_val).toType(); const target = mod.getTarget(); @@ -4416,9 +4417,9 @@ pub const Object = struct { if (is_fn_body) @panic("TODO"); - const addr_space = target_util.defaultAddressSpace(target, .global_constant); - const llvm_addr_space = toLlvmAddressSpace(addr_space, target); - const alignment = ptr_ty.ptrAlignment(mod); + const orig_ty = anon_decl.orig_ty.toType(); + const llvm_addr_space = toLlvmAddressSpace(orig_ty.ptrAddressSpace(mod), target); + const alignment = orig_ty.ptrAlignment(mod); const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global; const llvm_val = try o.builder.convConst( diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index 5a9703af3d..4f971db1de 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -2477,6 +2477,12 @@ pub const Variable = struct { self.ptr(builder).alignment = alignment; } + pub fn getAlignment(self: Index, builder: *Builder) Alignment { + if (builder.useLibLlvm()) + return Alignment.fromByteUnits(self.toLlvm(builder).getAlignment()); + return self.ptr(builder).alignment; + } + pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value { return self.ptrConst(builder).global.toLlvm(builder); } diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index bb68e28bf2..d7144b36ce 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -273,6 +273,9 @@ pub const Value = opaque { pub const setAlignment = LLVMSetAlignment; extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void; + pub const getAlignment = LLVMGetAlignment; + extern fn LLVMGetAlignment(V: *Value) c_uint; + pub const setFunctionCallConv = LLVMSetFunctionCallConv; extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void; diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index ded73d6afd..e7e6ebdef3 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -959,12 +959,17 @@ const DeclGen = struct { } } - fn constantAnonDeclRef(self: *DeclGen, ty: Type, decl_val: InternPool.Index) !IdRef { + fn constantAnonDeclRef( + self: *DeclGen, + ty: Type, + anon_decl: InternPool.Key.Ptr.Addr.AnonDecl, + ) !IdRef { // TODO: Merge this function with constantDeclRef. const mod = self.module; const ip = &mod.intern_pool; const ty_ref = try self.resolveType(ty, .direct); + const decl_val = anon_decl.val; const decl_ty = ip.typeOf(decl_val).toType(); if (decl_val.toValue().getFunction(mod)) |func| { diff --git a/src/link/C.zig b/src/link/C.zig index 7a8cc47f71..1d5672cf11 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -7,6 +7,7 @@ const fs = std.fs; const C = @This(); const Module = @import("../Module.zig"); const InternPool = @import("../InternPool.zig"); +const Alignment = InternPool.Alignment; const Compilation = @import("../Compilation.zig"); const codegen = @import("../codegen/c.zig"); const link = @import("../link.zig"); @@ -30,6 +31,10 @@ string_bytes: std.ArrayListUnmanaged(u8) = .{}, /// Tracks all the anonymous decls that are used by all the decls so they can /// be rendered during flush(). anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{}, +/// Sparse set of anon decls that are overaligned. Underaligned anon decls are +/// lowered the same as ABI-aligned anon decls. The keys here are a subset of +/// the keys of `anon_decls`. +aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .{}, /// Optimization, `updateDecl` reuses this buffer rather than creating a new /// one with every call. @@ -125,6 +130,7 @@ pub fn deinit(self: *C) void { db.deinit(gpa); } self.anon_decls.deinit(gpa); + self.aligned_anon_decls.deinit(gpa); self.string_bytes.deinit(gpa); self.fwd_decl_buf.deinit(gpa); @@ -179,6 +185,7 @@ pub fn updateFunc( .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, .anon_decl_deps = self.anon_decls, + .aligned_anon_decls = self.aligned_anon_decls, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code @@ -189,6 +196,7 @@ pub fn updateFunc( function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() }; defer { self.anon_decls = function.object.dg.anon_decl_deps; + self.aligned_anon_decls = function.object.dg.aligned_anon_decls; fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged(); code.* = function.object.code.moveToUnmanaged(); function.deinit(); @@ -232,6 +240,7 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void { .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = .{}, .anon_decl_deps = self.anon_decls, + .aligned_anon_decls = self.aligned_anon_decls, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code @@ -240,6 +249,7 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void { defer { self.anon_decls = object.dg.anon_decl_deps; + self.aligned_anon_decls = object.dg.aligned_anon_decls; object.dg.ctypes.deinit(object.dg.gpa); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); code.* = object.code.moveToUnmanaged(); @@ -250,7 +260,8 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void { .val = anon_decl.toValue(), }; const c_value: codegen.CValue = .{ .constant = anon_decl }; - codegen.genDeclValue(&object, tv, false, c_value, .none, .none) catch |err| switch (err) { + const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none; + codegen.genDeclValue(&object, tv, false, c_value, alignment, .none) catch |err| switch (err) { error.AnalysisFail => { @panic("TODO: C backend AnalysisFail on anonymous decl"); //try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?); @@ -296,6 +307,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, .anon_decl_deps = self.anon_decls, + .aligned_anon_decls = self.aligned_anon_decls, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code @@ -303,6 +315,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { self.anon_decls = object.dg.anon_decl_deps; + self.aligned_anon_decls = object.dg.aligned_anon_decls; object.dg.ctypes.deinit(object.dg.gpa); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); code.* = object.code.moveToUnmanaged(); @@ -602,6 +615,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void { .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, .anon_decl_deps = self.anon_decls, + .aligned_anon_decls = self.aligned_anon_decls, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code @@ -609,6 +623,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void { object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { self.anon_decls = object.dg.anon_decl_deps; + self.aligned_anon_decls = object.dg.aligned_anon_decls; object.dg.ctypes.deinit(gpa); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); code.* = object.code.moveToUnmanaged(); @@ -642,6 +657,7 @@ fn flushLazyFn( .fwd_decl = fwd_decl.toManaged(gpa), .ctypes = ctypes.*, .anon_decl_deps = .{}, + .aligned_anon_decls = .{}, }, .code = code.toManaged(gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code @@ -651,6 +667,7 @@ fn flushLazyFn( // If this assert trips just handle the anon_decl_deps the same as // `updateFunc()` does. assert(object.dg.anon_decl_deps.count() == 0); + assert(object.dg.aligned_anon_decls.count() == 0); object.dg.ctypes.deinit(gpa); fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); code.* = object.code.moveToUnmanaged(); diff --git a/src/value.zig b/src/value.zig index 2c4a88da17..c7560cb419 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1571,7 +1571,7 @@ pub const Value = struct { .none => switch (ip.indexToKey(switch (ptr.addr) { .decl => |decl| mod.declPtr(decl).ty.toIntern(), .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(), - .anon_decl => |anon_decl| ip.typeOf(anon_decl), + .anon_decl => |anon_decl| ip.typeOf(anon_decl.val), .comptime_field => |comptime_field| ip.typeOf(comptime_field), else => unreachable, })) { @@ -1604,7 +1604,7 @@ pub const Value = struct { })).toValue(), .ptr => |ptr| switch (ptr.addr) { .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index), - .anon_decl => |anon_decl| anon_decl.toValue().maybeElemValue(mod, index), + .anon_decl => |anon_decl| anon_decl.val.toValue().maybeElemValue(mod, index), .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) .toValue().maybeElemValue(mod, index), .int, .eu_payload => null,