Commit c4fcf0e22a

Jacob Young <jacobly0@users.noreply.github.com>
2023-10-20 03:23:09
codegen: implement lowering aligned anon decls
1 parent dd402f6
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| {
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}", .{
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);
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}", .{
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 {
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,
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,
         }