Commit 462d8fd3ac

Robin Voetter <robin@voetter.nl>
2022-01-21 15:43:25
spirv: keep track of air & liveness so that it can be used in flush()
1 parent 94dd763
Changed files (2)
src
codegen
link
src/codegen/spirv.zig
@@ -190,12 +190,12 @@ pub const DeclGen = struct {
     /// The decl we are currently generating code for.
     decl: *Decl,
 
-    /// If `gen` returned `Error.AnalysisFail`, this contains an explanatory message.
+    /// If `gen` returned `Error.CodegenFail`, this contains an explanatory message.
     /// Memory is owned by `module.gpa`.
     error_msg: ?*Module.ErrorMsg,
 
     /// Possible errors the `gen` function may return.
-    const Error = error{ AnalysisFail, OutOfMemory };
+    const Error = error{ CodegenFail, OutOfMemory };
 
     /// This structure is used to return information about a type typically used for
     /// arithmetic operations. These types may either be integers, floats, or a vector
@@ -276,8 +276,12 @@ pub const DeclGen = struct {
         self.decl = decl;
         self.error_msg = null;
 
-        try self.genDecl();
-        return self.error_msg;
+        self.genDecl() catch |err| switch (err) {
+            error.CodegenFail => return self.error_msg,
+            else => |others| return others,
+        };
+
+        return null;
     }
 
     /// Free resources owned by the DeclGen.
@@ -297,7 +301,7 @@ pub const DeclGen = struct {
         const src: LazySrcLoc = .{ .node_offset = 0 };
         const src_loc = src.toSrcLoc(self.decl);
         self.error_msg = try Module.ErrorMsg.create(self.spv.module.gpa, src_loc, format, args);
-        return error.AnalysisFail;
+        return error.CodegenFail;
     }
 
     fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !ResultId {
src/link/SpirV.zig
@@ -24,6 +24,7 @@ const SpirV = @This();
 
 const std = @import("std");
 const Allocator = std.mem.Allocator;
+const ArenaAllocator = std.heap.ArenaAllocator;
 const assert = std.debug.assert;
 const log = std.log.scoped(.link);
 
@@ -38,6 +39,7 @@ const build_options = @import("build_options");
 const spec = @import("../codegen/spirv/spec.zig");
 const Air = @import("../Air.zig");
 const Liveness = @import("../Liveness.zig");
+const Value = @import("../value.zig").Value;
 
 // TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
 pub const FnData = struct {
@@ -55,7 +57,15 @@ decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, DeclGenContext) = .{},
 
 const DeclGenContext = struct {
     air: Air,
+    air_value_arena: ArenaAllocator.State,
     liveness: Liveness,
+
+    fn deinit(self: *DeclGenContext, gpa: Allocator) void {
+        self.air.deinit(gpa);
+        self.liveness.deinit(gpa);
+        self.air_value_arena.promote(gpa).deinit();
+        self.* = undefined;
+    }
 };
 
 pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
@@ -113,12 +123,27 @@ pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liv
         @panic("Attempted to compile for architecture that was disabled by build configuration");
     }
     _ = module;
+
     // Keep track of all decls so we can iterate over them on flush().
-    _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
+    const result = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
+    if (result.found_existing) {
+        result.value_ptr.deinit(self.base.allocator);
+    }
+
+    var arena = ArenaAllocator.init(self.base.allocator);
+    errdefer arena.deinit();
+
+    var new_air = try cloneAir(air, self.base.allocator, arena.allocator());
+    errdefer new_air.deinit(self.base.allocator);
 
-    _ = air;
-    _ = liveness;
-    @panic("TODO SPIR-V needs to keep track of Air and Liveness so it can use them later");
+    var new_liveness = try cloneLiveness(liveness, self.base.allocator);
+    errdefer new_liveness.deinit(self.base.allocator);
+
+    result.value_ptr.* = .{
+        .air = new_air,
+        .air_value_arena = arena.state,
+        .liveness = new_liveness,
+    };
 }
 
 pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {
@@ -143,7 +168,11 @@ pub fn updateDeclExports(
 }
 
 pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void {
-    assert(self.decl_table.swapRemove(decl));
+    const index = self.decl_table.getIndex(decl).?;
+    if (decl.val.tag() == .function) {
+        self.decl_table.values()[index].deinit(self.base.allocator);
+    }
+    self.decl_table.swapRemoveAt(index);
 }
 
 pub fn flush(self: *SpirV, comp: *Compilation) !void {
@@ -273,3 +302,35 @@ fn writeMemoryModel(binary: *std.ArrayList(Word), target: std.Target) !void {
         @enumToInt(addressing_model), @enumToInt(memory_model),
     });
 }
+
+fn cloneLiveness(l: Liveness, gpa: Allocator) !Liveness {
+    const tomb_bits = try gpa.dupe(usize, l.tomb_bits);
+    errdefer gpa.free(tomb_bits);
+
+    const extra = try gpa.dupe(u32, l.extra);
+    errdefer gpa.free(extra);
+
+    return Liveness{
+        .tomb_bits = tomb_bits,
+        .extra = extra,
+        .special = try l.special.clone(gpa),
+    };
+}
+
+fn cloneAir(air: Air, gpa: Allocator, value_arena: Allocator) !Air {
+    const values = try gpa.alloc(Value, air.values.len);
+    errdefer gpa.free(values);
+
+    for (values) |*value, i| {
+        value.* = try air.values[i].copy(value_arena);
+    }
+
+    var instructions = try air.instructions.toMultiArrayList().clone(gpa);
+    errdefer instructions.deinit(gpa);
+
+    return Air{
+        .instructions = instructions.slice(),
+        .extra = try gpa.dupe(u32, air.extra),
+        .values = values,
+    };
+}