Commit e3be1a1e88
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?
+ }
}
}