Commit c9db6e43af
src/codegen/spirv.zig
@@ -37,6 +37,8 @@ pub const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
incoming_blocks: *std.ArrayListUnmanaged(IncomingBlock),
});
+pub const DeclMap = std.AutoHashMap(Module.Decl.Index, IdResult);
+
/// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that.
pub const DeclGen = struct {
/// A general-purpose allocator that can be used for any allocations for this DeclGen.
@@ -59,7 +61,8 @@ pub const DeclGen = struct {
/// Note: If the declaration is not a function, this value will be undefined!
liveness: Liveness,
- ids: *const std.AutoHashMap(Decl.Index, IdResult),
+ /// Maps Zig Decl indices to SPIR-V result indices.
+ decl_ids: *DeclMap,
/// An array of function argument result-ids. Each index corresponds with the
/// function argument of the same index.
@@ -149,7 +152,7 @@ pub const DeclGen = struct {
allocator: Allocator,
module: *Module,
spv: *SpvModule,
- ids: *const std.AutoHashMap(Decl.Index, IdResult),
+ decl_ids: *DeclMap,
) DeclGen {
return .{
.gpa = allocator,
@@ -158,7 +161,7 @@ pub const DeclGen = struct {
.decl_index = undefined,
.air = undefined,
.liveness = undefined,
- .ids = ids,
+ .decl_ids = decl_ids,
.next_arg_index = undefined,
.current_block_label_id = undefined,
.error_msg = undefined,
@@ -232,9 +235,7 @@ pub const DeclGen = struct {
.function => val.castTag(.function).?.data.owner_decl,
else => unreachable,
};
- const decl = self.module.declPtr(fn_decl_index);
- self.module.markDeclAlive(decl);
- return self.ids.get(fn_decl_index).?;
+ return try self.resolveDecl(fn_decl_index);
}
const result_id = self.spv.allocId();
@@ -245,6 +246,21 @@ pub const DeclGen = struct {
return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage.
}
+ /// Fetch or allocate a result id for decl index. This function also marks the decl as alive.
+ /// Note: Function does not actually generate the decl.
+ fn resolveDecl(self: *DeclGen, decl_index: Module.Decl.Index) !IdResult {
+ const decl = self.module.declPtr(decl_index);
+ self.module.markDeclAlive(decl);
+
+ const entry = try self.decl_ids.getOrPut(decl_index);
+ if (entry.found_existing) {
+ return entry.value_ptr.*;
+ }
+ const result_id = self.spv.allocId();
+ entry.value_ptr.* = result_id;
+ return result_id;
+ }
+
/// Start a new SPIR-V block, Emits the label of the new block, and stores which
/// block we are currently generating.
/// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to
@@ -767,8 +783,8 @@ pub const DeclGen = struct {
}
fn genDecl(self: *DeclGen) !void {
- const result_id = self.ids.get(self.decl_index).?;
const decl = self.module.declPtr(self.decl_index);
+ const result_id = try self.resolveDecl(self.decl_index);
if (decl.val.castTag(.function)) |_| {
assert(decl.ty.zigTypeTag() == .Fn);
src/link/SpirV.zig
@@ -44,34 +44,25 @@ const IdResult = spec.IdResult;
base: link.File,
-/// This linker backend does not try to incrementally link output SPIR-V code.
-/// Instead, it tracks all declarations in this table, and iterates over it
-/// in the flush function.
-decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclGenContext) = .{},
-
-const DeclGenContext = struct {
- air: Air,
- air_arena: ArenaAllocator.State,
- liveness: Liveness,
-
- fn deinit(self: *DeclGenContext, gpa: Allocator) void {
- self.air.deinit(gpa);
- self.liveness.deinit(gpa);
- self.air_arena.promote(gpa).deinit();
- self.* = undefined;
- }
-};
+spv: SpvModule,
+spv_arena: ArenaAllocator,
+decl_ids: codegen.DeclMap,
pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
- const spirv = try gpa.create(SpirV);
- spirv.* = .{
+ const self = try gpa.create(SpirV);
+ self.* = .{
.base = .{
.tag = .spirv,
.options = options,
.file = null,
.allocator = gpa,
},
+ .spv = undefined,
+ .spv_arena = ArenaAllocator.init(gpa),
+ .decl_ids = codegen.DeclMap.init(self.base.allocator),
};
+ self.spv = SpvModule.init(gpa, self.spv_arena.allocator());
+ errdefer self.deinit();
// TODO: Figure out where to put all of these
switch (options.target.cpu.arch) {
@@ -88,7 +79,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
return error.TODOAbiNotSupported;
}
- return spirv;
+ return self;
}
pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV {
@@ -107,44 +98,35 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
}
pub fn deinit(self: *SpirV) void {
- self.decl_table.deinit(self.base.allocator);
+ self.spv.deinit();
+ self.spv_arena.deinit();
+ self.decl_ids.deinit();
}
pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
if (build_options.skip_non_native) {
@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().
- 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);
+ var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_ids);
+ defer decl_gen.deinit();
- result.value_ptr.* = .{
- .air = new_air,
- .air_arena = arena.state,
- .liveness = new_liveness,
- };
+ if (try decl_gen.gen(func.owner_decl, air, liveness)) |msg| {
+ try module.failed_decls.put(module.gpa, func.owner_decl, msg);
+ }
}
pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index) !void {
if (build_options.skip_non_native) {
@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, decl_index);
+
+ var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_ids);
+ defer decl_gen.deinit();
+
+ if (try decl_gen.gen(decl_index, undefined, undefined)) |msg| {
+ try module.failed_decls.put(module.gpa, decl_index, msg);
+ }
}
pub fn updateDeclExports(
@@ -160,13 +142,8 @@ pub fn updateDeclExports(
}
pub fn freeDecl(self: *SpirV, decl_index: Module.Decl.Index) void {
- if (self.decl_table.getIndex(decl_index)) |index| {
- const module = self.base.options.module.?;
- const decl = module.declPtr(decl_index);
- if (decl.val.tag() == .function) {
- self.decl_table.values()[index].deinit(self.base.allocator);
- }
- }
+ _ = self;
+ _ = decl_index;
}
pub fn flush(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
@@ -189,56 +166,11 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
sub_prog_node.activate();
defer sub_prog_node.end();
- const module = self.base.options.module.?;
const target = comp.getTarget();
+ try writeCapabilities(&self.spv, target);
+ try writeMemoryModel(&self.spv, target);
- var arena = std.heap.ArenaAllocator.init(self.base.allocator);
- defer arena.deinit();
-
- var spv = SpvModule.init(self.base.allocator, arena.allocator());
- defer spv.deinit();
-
- // Allocate an ID for every declaration before generating code,
- // so that we can access them before processing them.
- // TODO: We're allocating an ID unconditionally now, are there
- // declarations which don't generate a result?
- var ids = std.AutoHashMap(Module.Decl.Index, IdResult).init(self.base.allocator);
- defer ids.deinit();
- try ids.ensureTotalCapacity(@intCast(u32, self.decl_table.count()));
-
- for (self.decl_table.keys()) |decl_index| {
- const decl = module.declPtr(decl_index);
- if (decl.has_tv) {
- ids.putAssumeCapacityNoClobber(decl_index, spv.allocId());
- }
- }
-
- // Now, actually generate the code for all declarations.
- var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &spv, &ids);
- defer decl_gen.deinit();
-
- var it = self.decl_table.iterator();
- while (it.next()) |entry| {
- const decl_index = entry.key_ptr.*;
- const decl = module.declPtr(decl_index);
- if (!decl.has_tv) continue;
-
- const air = entry.value_ptr.air;
- const liveness = entry.value_ptr.liveness;
-
- log.debug("generating code for {s}", .{decl.name});
-
- // Note, if `decl` is not a function, air/liveness may be undefined.
- if (try decl_gen.gen(decl_index, air, liveness)) |msg| {
- try module.failed_decls.put(module.gpa, decl_index, msg);
- return; // TODO: Attempt to generate more decls?
- }
- }
-
- try writeCapabilities(&spv, target);
- try writeMemoryModel(&spv, target);
-
- try spv.flush(self.base.file.?);
+ try self.spv.flush(self.base.file.?);
}
fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {
@@ -281,45 +213,3 @@ fn writeMemoryModel(spv: *SpvModule, target: std.Target) !void {
.memory_model = 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, air_arena: Allocator) !Air {
- const values = try gpa.alloc(Value, air.values.len);
- errdefer gpa.free(values);
-
- for (values, 0..) |*value, i| {
- value.* = try air.values[i].copy(air_arena);
- }
-
- var instructions = try air.instructions.toMultiArrayList().clone(gpa);
- errdefer instructions.deinit(gpa);
-
- const air_tags = instructions.items(.tag);
- const air_datas = instructions.items(.data);
-
- for (air_tags, 0..) |tag, i| {
- switch (tag) {
- .alloc, .ret_ptr, .const_ty => air_datas[i].ty = try air_datas[i].ty.copy(air_arena),
- else => {},
- }
- }
-
- return Air{
- .instructions = instructions.slice(),
- .extra = try gpa.dupe(u32, air.extra),
- .values = values,
- };
-}