From 7bab406c790566781406a7968be22961ed7c305d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Oct 2023 15:10:35 -0700 Subject: InternPool: store alignment of anon decls Commit 5393e56500d499753dbc39704c0161b47d1e4d5c has a flaw pointed out by @mlugg: the `ty` field of pointer values changes when comptime values are pointer-casted. This commit introduces a new encoding which additionally stores the "original pointer type" which is used to store the alignment of the anonymous decl, and potentially other information in the future such as section and pointer address space. However, this new encoding is only used when the original pointer type differs from the casted pointer type in a meaningful way. I was able to make the LLVM backend and the C backend lower anonymous decls with the appropriate alignment, however I will need some help figuring out how to do this for the backends that lower anonymous decls via src/codegen.zig and the wasm backend. --- src/codegen.zig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/codegen.zig') 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, -- cgit v1.2.3 From c4fcf0e22a0a0bab19ac9d1335b10decbfb2f137 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 19 Oct 2023 21:23:09 -0400 Subject: codegen: implement lowering aligned anon decls --- src/arch/wasm/CodeGen.zig | 7 ++----- src/codegen.zig | 7 ++----- src/link.zig | 10 +++++----- src/link/Coff.zig | 28 ++++++++++++++++++---------- src/link/Elf.zig | 21 +++++++++++++-------- src/link/MachO.zig | 22 +++++++++++++--------- src/link/Wasm.zig | 35 ++++++++++++++++++++--------------- 7 files changed, 73 insertions(+), 57 deletions(-) (limited to 'src/codegen.zig') diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 639af3d8c4..83ab118ac5 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3153,11 +3153,8 @@ fn lowerAnonDeclRef( return WValue{ .imm32 = 0xaaaaaaaa }; } - 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)); + const decl_align = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment; + const res = try func.bin_file.lowerAnonDecl(decl_val, decl_align, func.decl.srcLoc(mod)); switch (res) { .ok => {}, .fail => |em| { diff --git a/src/codegen.zig b/src/codegen.zig index d7a5666986..fe948d18bd 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -731,16 +731,13 @@ fn lowerAnonDeclRef( return Result.ok; } - const res = try bin_file.lowerAnonDecl(decl_val, src_loc); + const decl_align = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment; + const res = try bin_file.lowerAnonDecl(decl_val, decl_align, src_loc); switch (res) { .ok => {}, .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/link.zig b/src/link.zig index 9c79de290d..6e5c809f62 100644 --- a/src/link.zig +++ b/src/link.zig @@ -940,15 +940,15 @@ pub const File = struct { pub const LowerResult = @import("codegen.zig").Result; - pub fn lowerAnonDecl(base: *File, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !LowerResult { + pub fn lowerAnonDecl(base: *File, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !LowerResult { if (build_options.only_c) unreachable; switch (base.tag) { - .coff => return @fieldParentPtr(Coff, "base", base).lowerAnonDecl(decl_val, src_loc), - .elf => return @fieldParentPtr(Elf, "base", base).lowerAnonDecl(decl_val, src_loc), - .macho => return @fieldParentPtr(MachO, "base", base).lowerAnonDecl(decl_val, src_loc), + .coff => return @fieldParentPtr(Coff, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), + .elf => return @fieldParentPtr(Elf, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), + .macho => return @fieldParentPtr(MachO, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerAnonDecl(decl_val, src_loc), .c => unreachable, - .wasm => return @fieldParentPtr(Wasm, "base", base).lowerAnonDecl(decl_val, src_loc), + .wasm => return @fieldParentPtr(Wasm, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc), .spirv => unreachable, .nvptx => unreachable, } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 94b3c63741..35f0b84411 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1091,7 +1091,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In const index = unnamed_consts.items.len; const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(sym_name); - const atom_index = switch (try self.lowerConst(sym_name, tv, self.rdata_section_index.?, decl.srcLoc(mod))) { + const atom_index = switch (try self.lowerConst(sym_name, tv, tv.ty.abiAlignment(mod), self.rdata_section_index.?, decl.srcLoc(mod))) { .ok => |atom_index| atom_index, .fail => |em| { decl.analysis = .codegen_failure; @@ -1109,13 +1109,12 @@ const LowerConstResult = union(enum) { fail: *Module.ErrorMsg, }; -fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult { +fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult { const gpa = self.base.allocator; var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); - const mod = self.base.options.module.?; const atom_index = try self.createAtom(); const sym = self.getAtom(atom_index).getSymbolPtr(self); try self.setSymbolName(sym, name); @@ -1129,10 +1128,13 @@ fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, sect_id: u16, src_l .fail => |em| return .{ .fail = em }, }; - const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0)); const atom = self.getAtomPtr(atom_index); atom.size = @as(u32, @intCast(code.len)); - atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); + atom.getSymbolPtr(self).value = try self.allocateAtom( + atom_index, + atom.size, + @intCast(required_alignment.toByteUnitsOptional().?), + ); errdefer self.freeAtom(atom_index); log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(self).value }); @@ -1736,7 +1738,7 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link return 0; } -pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result { +pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result { // This is basically the same as lowerUnnamedConst. // example: // const ty = mod.intern_pool.typeOf(decl_val).toType(); @@ -1747,15 +1749,21 @@ pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, src_loc: Module.Sr // to put it in some location. // ... const gpa = self.base.allocator; + const mod = self.base.options.module.?; + const ty = mod.intern_pool.typeOf(decl_val).toType(); const gop = try self.anon_decls.getOrPut(gpa, decl_val); - if (!gop.found_existing) { - const mod = self.base.options.module.?; - const ty = mod.intern_pool.typeOf(decl_val).toType(); + const required_alignment = switch (decl_align) { + .none => ty.abiAlignment(mod), + else => decl_align, + }; + if (!gop.found_existing or + !required_alignment.check(self.getAtom(gop.value_ptr.*).getSymbol(self).value)) + { const val = decl_val.toValue(); const tv = TypedValue{ .ty = ty, .val = val }; const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); defer gpa.free(name); - const res = self.lowerConst(name, tv, self.rdata_section_index.?, src_loc) catch |err| switch (err) { + const res = self.lowerConst(name, tv, required_alignment, self.rdata_section_index.?, src_loc) catch |err| switch (err) { else => { // TODO improve error message const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{ diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 2d16cd03e9..738d648ebe 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -473,7 +473,7 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link. return vaddr; } -pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result { +pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result { // This is basically the same as lowerUnnamedConst. // example: // const ty = mod.intern_pool.typeOf(decl_val).toType(); @@ -484,15 +484,21 @@ pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, src_loc: Module.Src // to put it in some location. // ... const gpa = self.base.allocator; + const mod = self.base.options.module.?; + const ty = mod.intern_pool.typeOf(decl_val).toType(); const gop = try self.anon_decls.getOrPut(gpa, decl_val); - if (!gop.found_existing) { - const mod = self.base.options.module.?; - const ty = mod.intern_pool.typeOf(decl_val).toType(); + const required_alignment = switch (decl_align) { + .none => ty.abiAlignment(mod), + else => decl_align, + }; + if (!gop.found_existing or + required_alignment.order(self.symbol(gop.value_ptr.*).atom(self).?.alignment).compare(.gt)) + { const val = decl_val.toValue(); const tv = TypedValue{ .ty = ty, .val = val }; const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); defer gpa.free(name); - const res = self.lowerConst(name, tv, self.zig_rodata_section_index.?, src_loc) catch |err| switch (err) { + const res = self.lowerConst(name, tv, required_alignment, self.zig_rodata_section_index.?, src_loc) catch |err| switch (err) { else => { // TODO improve error message const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{ @@ -3479,7 +3485,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module const index = unnamed_consts.items.len; const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(name); - const sym_index = switch (try self.lowerConst(name, typed_value, self.zig_rodata_section_index.?, decl.srcLoc(mod))) { + const sym_index = switch (try self.lowerConst(name, typed_value, typed_value.ty.abiAlignment(mod), self.zig_rodata_section_index.?, decl.srcLoc(mod))) { .ok => |sym_index| sym_index, .fail => |em| { decl.analysis = .codegen_failure; @@ -3502,6 +3508,7 @@ fn lowerConst( self: *Elf, name: []const u8, tv: TypedValue, + required_alignment: InternPool.Alignment, output_section_index: u16, src_loc: Module.SrcLoc, ) !LowerConstResult { @@ -3510,7 +3517,6 @@ fn lowerConst( var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); - const mod = self.base.options.module.?; const zig_module = self.file(self.zig_module_index.?).?.zig_module; const sym_index = try zig_module.addAtom(self); @@ -3524,7 +3530,6 @@ fn lowerConst( .fail => |em| return .{ .fail = em }, }; - const required_alignment = tv.ty.abiAlignment(mod); const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?; const local_sym = self.symbol(sym_index); const name_str_index = try self.strtab.insert(gpa, name); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index cc537cdd72..eb82de7374 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2196,7 +2196,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu const index = unnamed_consts.items.len; const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(name); - const atom_index = switch (try self.lowerConst(name, typed_value, self.data_const_section_index.?, decl.srcLoc(mod))) { + const atom_index = switch (try self.lowerConst(name, typed_value, typed_value.ty.abiAlignment(mod), self.data_const_section_index.?, decl.srcLoc(mod))) { .ok => |atom_index| atom_index, .fail => |em| { decl.analysis = .codegen_failure; @@ -2219,6 +2219,7 @@ fn lowerConst( self: *MachO, name: []const u8, tv: TypedValue, + required_alignment: InternPool.Alignment, sect_id: u8, src_loc: Module.SrcLoc, ) !LowerConstResult { @@ -2227,8 +2228,6 @@ fn lowerConst( var code_buffer = std.ArrayList(u8).init(gpa); defer code_buffer.deinit(); - const mod = self.base.options.module.?; - log.debug("allocating symbol indexes for {s}", .{name}); const sym_index = try self.allocateSymbol(); @@ -2243,7 +2242,6 @@ fn lowerConst( .fail => |em| return .{ .fail = em }, }; - const required_alignment = tv.ty.abiAlignment(mod); const atom = self.getAtomPtr(atom_index); atom.size = code.len; // TODO: work out logic for disambiguating functions from function pointers @@ -2868,7 +2866,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil return 0; } -pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result { +pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !codegen.Result { // This is basically the same as lowerUnnamedConst. // example: // const ty = mod.intern_pool.typeOf(decl_val).toType(); @@ -2879,15 +2877,21 @@ pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, src_loc: Module.S // to put it in some location. // ... const gpa = self.base.allocator; + const mod = self.base.options.module.?; + const ty = mod.intern_pool.typeOf(decl_val).toType(); const gop = try self.anon_decls.getOrPut(gpa, decl_val); - if (!gop.found_existing) { - const mod = self.base.options.module.?; - const ty = mod.intern_pool.typeOf(decl_val).toType(); + const required_alignment = switch (decl_align) { + .none => ty.abiAlignment(mod), + else => decl_align, + }; + if (!gop.found_existing or + !required_alignment.check(self.getAtom(gop.value_ptr.*).getSymbol(self).n_value)) + { const val = decl_val.toValue(); const tv = TypedValue{ .ty = ty, .val = val }; const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); defer gpa.free(name); - const res = self.lowerConst(name, tv, self.data_const_section_index.?, src_loc) catch |err| switch (err) { + const res = self.lowerConst(name, tv, required_alignment, self.data_const_section_index.?, src_loc) catch |err| switch (err) { else => { // TODO improve error message const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{ diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index fc827b23eb..f138cdc3e2 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1702,25 +1702,30 @@ pub fn getDeclVAddr( return target_symbol_index; } -pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result { +pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, decl_align: Alignment, src_loc: Module.SrcLoc) !codegen.Result { const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val); - if (gop.found_existing) { - return .ok; - } + if (!gop.found_existing) { + const mod = wasm.base.options.module.?; + const ty = mod.intern_pool.typeOf(decl_val).toType(); + const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() }; + const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)}); + defer wasm.base.allocator.free(name); - const mod = wasm.base.options.module.?; - const ty = mod.intern_pool.typeOf(decl_val).toType(); - const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() }; - const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)}); - defer wasm.base.allocator.free(name); + switch (try wasm.lowerConst(name, tv, src_loc)) { + .ok => |atom_index| gop.value_ptr.* = atom_index, + .fail => |em| return .{ .fail = em }, + } + } - switch (try wasm.lowerConst(name, tv, src_loc)) { - .ok => |atom_index| { - gop.value_ptr.* = atom_index; - return .ok; + const atom = wasm.getAtomPtr(gop.value_ptr.*); + atom.alignment = switch (atom.alignment) { + .none => decl_align, + else => switch (decl_align) { + .none => atom.alignment, + else => atom.alignment.maxStrict(decl_align), }, - .fail => |em| return .{ .fail = em }, - } + }; + return .ok; } pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { -- cgit v1.2.3