From 462d8fd3ac643c48f61dd58a6d42ef60593cce13 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Fri, 21 Jan 2022 15:43:25 +0100 Subject: [PATCH] spirv: keep track of air & liveness so that it can be used in flush() --- src/codegen/spirv.zig | 14 ++++++--- src/link/SpirV.zig | 73 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index b4f02a14a7..f2337b604f 100644 --- a/src/codegen/spirv.zig +++ b/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 { diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 7fc54d509e..7c70260f0d 100644 --- a/src/link/SpirV.zig +++ b/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); - _ = air; - _ = liveness; - @panic("TODO SPIR-V needs to keep track of Air and Liveness so it can use them later"); + // Keep track of all decls so we can iterate over them on flush(). + 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); + + 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, + }; +}