Commit 462d8fd3ac
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,
+ };
+}