Commit e3be1a1e88

Robin Voetter <robin@voetter.nl>
2021-05-20 20:35:52
SPIR-V: DeclGen constructor/destructor
1 parent 46184ab
Changed files (2)
src
codegen
link
src/codegen/spirv.zig
@@ -157,6 +157,45 @@ pub const DeclGen = struct {
         class: Class,
     };
 
+    /// Initialize the common resources of a DeclGen. Some fields are left uninitialized, only set when `gen` is called.
+    pub fn init(gpa: *Allocator, module: *Module, spv: *SPIRVModule) DeclGen {
+        return .{
+            .module = module,
+            .spv = spv,
+            .args = std.ArrayList(ResultId).init(gpa),
+            .next_arg_index = undefined,
+            .inst_results = InstMap.init(gpa),
+            .blocks = BlockMap.init(gpa),
+            .current_block_label_id = undefined,
+            .decl = undefined,
+            .error_msg = undefined,
+        };
+    }
+
+    /// Generate the code for `decl`. If a reportable error occured 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) !?*Module.ErrorMsg {
+        // Reset internal resources, we don't want to re-allocate these.
+        self.args.items.len = 0;
+        self.next_arg_index = 0;
+        self.inst_results.clearRetainingCapacity();
+        self.blocks.clearRetainingCapacity();
+        self.current_block_label_id = undefined;
+        self.decl = decl;
+        self.error_msg = null;
+
+        try self.genDecl();
+        return self.error_msg;
+    }
+
+    /// Free resources owned by the DeclGen.
+    pub fn deinit(self: *DeclGen) void {
+        self.args.deinit();
+        self.inst_results.deinit();
+        self.blocks.deinit();
+    }
+
     fn fail(self: *DeclGen, src: LazySrcLoc, comptime format: []const u8, args: anytype) Error {
         @setCold(true);
         const src_loc = src.toSrcLocWithDecl(self.decl);
@@ -476,7 +515,7 @@ pub const DeclGen = struct {
         return result_id;
     }
 
-    pub fn gen(self: *DeclGen) !void {
+    fn genDecl(self: *DeclGen) !void {
         const decl = self.decl;
         const result_id = decl.fn_link.spirv.id;
 
src/link/SpirV.zig
@@ -152,45 +152,17 @@ pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
 
     // Now, actually generate the code for all declarations.
     {
-        // We are just going to re-use this same DeclGen for every Decl, and we are just going to
-        // change the decl. Otherwise, we would have to keep a separate `args` and `types`, and re-construct this
-        // structure every time.
-        var decl_gen = codegen.DeclGen{
-            .module = module,
-            .spv = &spv,
-            .args = std.ArrayList(codegen.Word).init(self.base.allocator),
-            .next_arg_index = undefined,
-            .inst_results = codegen.InstMap.init(self.base.allocator),
-            .blocks = codegen.BlockMap.init(self.base.allocator),
-            .current_block_label_id = undefined,
-            .decl = undefined,
-            .error_msg = undefined,
-        };
-
-        defer decl_gen.inst_results.deinit();
-        defer decl_gen.args.deinit();
-        defer decl_gen.blocks.deinit();
+        var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv);
+        defer decl_gen.deinit();
 
         for (self.decl_table.items()) |entry| {
             const decl = entry.key;
             if (!decl.has_tv) continue;
 
-            // Reset the decl_gen, but retain allocated resources.
-            decl_gen.args.items.len = 0;
-            decl_gen.next_arg_index = 0;
-            decl_gen.inst_results.clearRetainingCapacity();
-            decl_gen.blocks.clearRetainingCapacity();
-            decl_gen.current_block_label_id = undefined;
-            decl_gen.decl = decl;
-            decl_gen.error_msg = null;
-
-            decl_gen.gen() catch |err| switch (err) {
-                error.AnalysisFail => {
-                    try module.failed_decls.put(module.gpa, decl, decl_gen.error_msg.?);
-                    return;
-                },
-                else => |e| return e,
-            };
+            if (try decl_gen.gen(decl)) |msg| {
+                try module.failed_decls.put(module.gpa, decl, msg);
+                return; // TODO: Attempt to generate more decls?
+            }
         }
     }