Commit e0f3975fc8

Jakub Konka <kubkon@jakubkonka.com>
2023-02-01 16:01:43
link: make SpirV atoms fully owned by the linker
1 parent 5de2aae
Changed files (4)
src/codegen/spirv.zig
@@ -49,7 +49,7 @@ pub const DeclGen = struct {
     spv: *SpvModule,
 
     /// The decl we are currently generating code for.
-    decl: *Decl,
+    decl_index: Decl.Index,
 
     /// The intermediate code of the declaration we are currently generating. Note: If
     /// the declaration is not a function, this value will be undefined!
@@ -59,6 +59,8 @@ pub const DeclGen = struct {
     /// Note: If the declaration is not a function, this value will be undefined!
     liveness: Liveness,
 
+    ids: *const std.AutoHashMap(Decl.Index, IdResult),
+
     /// An array of function argument result-ids. Each index corresponds with the
     /// function argument of the same index.
     args: std.ArrayListUnmanaged(IdRef) = .{},
@@ -133,14 +135,20 @@ pub const DeclGen = struct {
 
     /// Initialize the common resources of a DeclGen. Some fields are left uninitialized,
     /// only set when `gen` is called.
-    pub fn init(allocator: Allocator, module: *Module, spv: *SpvModule) DeclGen {
+    pub fn init(
+        allocator: Allocator,
+        module: *Module,
+        spv: *SpvModule,
+        ids: *const std.AutoHashMap(Decl.Index, IdResult),
+    ) DeclGen {
         return .{
             .gpa = allocator,
             .module = module,
             .spv = spv,
-            .decl = undefined,
+            .decl_index = undefined,
             .air = undefined,
             .liveness = undefined,
+            .ids = ids,
             .next_arg_index = undefined,
             .current_block_label_id = undefined,
             .error_msg = undefined,
@@ -150,9 +158,9 @@ pub const DeclGen = struct {
     /// Generate the code for `decl`. If a reportable error occurred during code generation,
     /// a message is returned by this function. Callee owns the memory. If this function
     /// returns such a reportable error, it is valid to be called again for a different decl.
-    pub fn gen(self: *DeclGen, decl: *Decl, air: Air, liveness: Liveness) !?*Module.ErrorMsg {
+    pub fn gen(self: *DeclGen, decl_index: Decl.Index, air: Air, liveness: Liveness) !?*Module.ErrorMsg {
         // Reset internal resources, we don't want to re-allocate these.
-        self.decl = decl;
+        self.decl_index = decl_index;
         self.air = air;
         self.liveness = liveness;
         self.args.items.len = 0;
@@ -194,7 +202,7 @@ pub const DeclGen = struct {
     pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
         @setCold(true);
         const src = LazySrcLoc.nodeOffset(0);
-        const src_loc = src.toSrcLoc(self.decl);
+        const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index));
         assert(self.error_msg == null);
         self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
         return error.CodegenFail;
@@ -332,7 +340,7 @@ pub const DeclGen = struct {
             };
             const decl = self.module.declPtr(fn_decl_index);
             self.module.markDeclAlive(decl);
-            return decl.fn_link.spirv.id.toRef();
+            return self.ids.get(fn_decl_index).?.toRef();
         }
 
         const target = self.getTarget();
@@ -553,8 +561,8 @@ pub const DeclGen = struct {
     }
 
     fn genDecl(self: *DeclGen) !void {
-        const decl = self.decl;
-        const result_id = decl.fn_link.spirv.id;
+        const result_id = self.ids.get(self.decl_index).?;
+        const decl = self.module.declPtr(self.decl_index);
 
         if (decl.val.castTag(.function)) |_| {
             assert(decl.ty.zigTypeTag() == .Fn);
@@ -945,7 +953,7 @@ pub const DeclGen = struct {
 
     fn airDbgStmt(self: *DeclGen, inst: Air.Inst.Index) !void {
         const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
-        const src_fname_id = try self.spv.resolveSourceFileName(self.decl);
+        const src_fname_id = try self.spv.resolveSourceFileName(self.module.declPtr(self.decl_index));
         try self.func.body.emit(self.spv.gpa, .OpLine, .{
             .file = src_fname_id,
             .line = dbg_stmt.line,
@@ -1106,7 +1114,7 @@ pub const DeclGen = struct {
                 assert(as.errors.items.len != 0);
                 assert(self.error_msg == null);
                 const loc = LazySrcLoc.nodeOffset(0);
-                const src_loc = loc.toSrcLoc(self.decl);
+                const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index));
                 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
                 const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);
 
src/link/SpirV.zig
@@ -42,13 +42,6 @@ const SpvModule = @import("../codegen/spirv/Module.zig");
 const spec = @import("../codegen/spirv/spec.zig");
 const IdResult = spec.IdResult;
 
-// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
-pub const FnData = struct {
-    // We're going to fill these in flushModule, and we're going to fill them unconditionally,
-    // so just set it to undefined.
-    id: IdResult = undefined,
-};
-
 base: link.File,
 
 /// This linker backend does not try to incrementally link output SPIR-V code.
@@ -209,16 +202,19 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
     // so that we can access them before processing them.
     // TODO: We're allocating an ID unconditionally now, are there
     // declarations which don't generate a result?
-    // TODO: fn_link is used here, but thats probably not the right field. It will work anyway though.
+    var ids = std.AutoHashMap(Module.Decl.Index, IdResult).init(self.base.allocator);
+    defer ids.deinit();
+    try ids.ensureTotalCapacity(@intCast(u32, self.decl_table.count()));
+
     for (self.decl_table.keys()) |decl_index| {
         const decl = module.declPtr(decl_index);
         if (decl.has_tv) {
-            decl.fn_link.spirv.id = spv.allocId();
+            ids.putAssumeCapacityNoClobber(decl_index, spv.allocId());
         }
     }
 
     // Now, actually generate the code for all declarations.
-    var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv);
+    var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv, &ids);
     defer decl_gen.deinit();
 
     var it = self.decl_table.iterator();
@@ -231,7 +227,7 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
         const liveness = entry.value_ptr.liveness;
 
         // Note, if `decl` is not a function, air/liveness may be undefined.
-        if (try decl_gen.gen(decl, air, liveness)) |msg| {
+        if (try decl_gen.gen(decl_index, air, liveness)) |msg| {
             try module.failed_decls.put(module.gpa, decl_index, msg);
             return; // TODO: Attempt to generate more decls?
         }
src/link.zig
@@ -279,7 +279,7 @@ pub const File = struct {
         plan9: void,
         c: void,
         wasm: Wasm.FnData,
-        spirv: SpirV.FnData,
+        spirv: void,
         nvptx: void,
     };
 
src/Module.zig
@@ -5183,20 +5183,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
     decl.zir_decl_index = @intCast(u32, decl_sub_index);
     if (decl.getFunction()) |_| {
         switch (comp.bin_file.tag) {
-            .coff => {
-                // TODO Implement for COFF
-            },
-            .elf => {
-                // TODO Look into detecting when this would be unnecessary by storing enough state
-                // in `Decl` to notice that the line number did not change.
-                comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
-            },
-            .macho => {
-                // TODO Look into detecting when this would be unnecessary by storing enough state
-                // in `Decl` to notice that the line number did not change.
-                comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
-            },
-            .plan9 => {
+            .coff, .elf, .macho, .plan9 => {
                 // TODO Look into detecting when this would be unnecessary by storing enough state
                 // in `Decl` to notice that the line number did not change.
                 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
@@ -5290,7 +5277,7 @@ pub fn clearDecl(
                 .plan9 => .{ .plan9 = {} },
                 .c => .{ .c = {} },
                 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
-                .spirv => .{ .spirv = .{} },
+                .spirv => .{ .spirv = {} },
                 .nvptx => .{ .nvptx = {} },
             };
         }
@@ -5710,7 +5697,7 @@ pub fn allocateNewDecl(
             .plan9 => .{ .plan9 = {} },
             .c => .{ .c = {} },
             .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
-            .spirv => .{ .spirv = .{} },
+            .spirv => .{ .spirv = {} },
             .nvptx => .{ .nvptx = {} },
         },
         .generation = 0,