authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-01-21 15:43:25+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2022-01-28 14:38:57+01:00
log462d8fd3ac643c48f61dd58a6d42ef60593cce13
treef759203616c9d732b874bddcfa866a6f1eca75a0
parent94dd7639363bd48ba50655ddf1e94d488a0bc75c

spirv: keep track of air & liveness so that it can be used in flush()


2 files changed, 75 insertions(+), 10 deletions(-)

src/codegen/spirv.zig+9-5
......@@ -190,12 +190,12 @@ pub const DeclGen = struct {
190190 /// The decl we are currently generating code for.
191191 decl: *Decl,
192192
193 /// If `gen` returned `Error.AnalysisFail`, this contains an explanatory message.
193 /// If `gen` returned `Error.CodegenFail`, this contains an explanatory message.
194194 /// Memory is owned by `module.gpa`.
195195 error_msg: ?*Module.ErrorMsg,
196196
197197 /// Possible errors the `gen` function may return.
198 const Error = error{ AnalysisFail, OutOfMemory };
198 const Error = error{ CodegenFail, OutOfMemory };
199199
200200 /// This structure is used to return information about a type typically used for
201201 /// arithmetic operations. These types may either be integers, floats, or a vector
......@@ -276,8 +276,12 @@ pub const DeclGen = struct {
276276 self.decl = decl;
277277 self.error_msg = null;
278278
279 try self.genDecl();
280 return self.error_msg;
279 self.genDecl() catch |err| switch (err) {
280 error.CodegenFail => return self.error_msg,
281 else => |others| return others,
282 };
283
284 return null;
281285 }
282286
283287 /// Free resources owned by the DeclGen.
......@@ -297,7 +301,7 @@ pub const DeclGen = struct {
297301 const src: LazySrcLoc = .{ .node_offset = 0 };
298302 const src_loc = src.toSrcLoc(self.decl);
299303 self.error_msg = try Module.ErrorMsg.create(self.spv.module.gpa, src_loc, format, args);
300 return error.AnalysisFail;
304 return error.CodegenFail;
301305 }
302306
303307 fn resolve(self: *DeclGen, inst: Air.Inst.Ref) !ResultId {
src/link/SpirV.zig+66-5
......@@ -24,6 +24,7 @@ const SpirV = @This();
2424
2525const std = @import("std");
2626const Allocator = std.mem.Allocator;
27const ArenaAllocator = std.heap.ArenaAllocator;
2728const assert = std.debug.assert;
2829const log = std.log.scoped(.link);
2930
......@@ -38,6 +39,7 @@ const build_options = @import("build_options");
3839const spec = @import("../codegen/spirv/spec.zig");
3940const Air = @import("../Air.zig");
4041const Liveness = @import("../Liveness.zig");
42const Value = @import("../value.zig").Value;
4143
4244// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
4345pub const FnData = struct {
......@@ -55,7 +57,15 @@ decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, DeclGenContext) = .{},
5557
5658const DeclGenContext = struct {
5759 air: Air,
60 air_value_arena: ArenaAllocator.State,
5861 liveness: Liveness,
62
63 fn deinit(self: *DeclGenContext, gpa: Allocator) void {
64 self.air.deinit(gpa);
65 self.liveness.deinit(gpa);
66 self.air_value_arena.promote(gpa).deinit();
67 self.* = undefined;
68 }
5969};
6070
6171pub 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
113123 @panic("Attempted to compile for architecture that was disabled by build configuration");
114124 }
115125 _ = module;
126
116127 // Keep track of all decls so we can iterate over them on flush().
117 _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
128 const result = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
129 if (result.found_existing) {
130 result.value_ptr.deinit(self.base.allocator);
131 }
132
133 var arena = ArenaAllocator.init(self.base.allocator);
134 errdefer arena.deinit();
135
136 var new_air = try cloneAir(air, self.base.allocator, arena.allocator());
137 errdefer new_air.deinit(self.base.allocator);
118138
119 _ = air;
120 _ = liveness;
121 @panic("TODO SPIR-V needs to keep track of Air and Liveness so it can use them later");
139 var new_liveness = try cloneLiveness(liveness, self.base.allocator);
140 errdefer new_liveness.deinit(self.base.allocator);
141
142 result.value_ptr.* = .{
143 .air = new_air,
144 .air_value_arena = arena.state,
145 .liveness = new_liveness,
146 };
122147}
123148
124149pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {
......@@ -143,7 +168,11 @@ pub fn updateDeclExports(
143168}
144169
145170pub fn freeDecl(self: *SpirV, decl: *Module.Decl) void {
146 assert(self.decl_table.swapRemove(decl));
171 const index = self.decl_table.getIndex(decl).?;
172 if (decl.val.tag() == .function) {
173 self.decl_table.values()[index].deinit(self.base.allocator);
174 }
175 self.decl_table.swapRemoveAt(index);
147176}
148177
149178pub fn flush(self: *SpirV, comp: *Compilation) !void {
......@@ -273,3 +302,35 @@ fn writeMemoryModel(binary: *std.ArrayList(Word), target: std.Target) !void {
273302 @enumToInt(addressing_model), @enumToInt(memory_model),
274303 });
275304}
305
306fn cloneLiveness(l: Liveness, gpa: Allocator) !Liveness {
307 const tomb_bits = try gpa.dupe(usize, l.tomb_bits);
308 errdefer gpa.free(tomb_bits);
309
310 const extra = try gpa.dupe(u32, l.extra);
311 errdefer gpa.free(extra);
312
313 return Liveness{
314 .tomb_bits = tomb_bits,
315 .extra = extra,
316 .special = try l.special.clone(gpa),
317 };
318}
319
320fn cloneAir(air: Air, gpa: Allocator, value_arena: Allocator) !Air {
321 const values = try gpa.alloc(Value, air.values.len);
322 errdefer gpa.free(values);
323
324 for (values) |*value, i| {
325 value.* = try air.values[i].copy(value_arena);
326 }
327
328 var instructions = try air.instructions.toMultiArrayList().clone(gpa);
329 errdefer instructions.deinit(gpa);
330
331 return Air{
332 .instructions = instructions.slice(),
333 .extra = try gpa.dupe(u32, air.extra),
334 .values = values,
335 };
336}