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

This commit is contained in:
Robin Voetter 2022-01-21 15:43:25 +01:00
parent 94dd763936
commit 462d8fd3ac
2 changed files with 76 additions and 11 deletions

View File

@ -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 {

View File

@ -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,
};
}