aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/spirv/Module.zig
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2023-09-18 22:39:44 +0200
committerAndrew Kelley <andrew@ziglang.org>2023-09-23 12:36:56 -0700
commitb845c9d5326bc83691edcb483ac44793b88afe75 (patch)
treea965db64c6d8a6c657d46ab9983cdf88fb0c853f /src/codegen/spirv/Module.zig
parent5d844faf7c5c30555664b4161e5f9a903daaf562 (diff)
downloadzig-b845c9d5326bc83691edcb483ac44793b88afe75.tar.gz
zig-b845c9d5326bc83691edcb483ac44793b88afe75.zip
spirv: generate module initializer
Diffstat (limited to 'src/codegen/spirv/Module.zig')
-rw-r--r--src/codegen/spirv/Module.zig116
1 files changed, 95 insertions, 21 deletions
diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig
index cafc2f0662..b6ed381360 100644
--- a/src/codegen/spirv/Module.zig
+++ b/src/codegen/spirv/Module.zig
@@ -94,6 +94,8 @@ pub const Global = struct {
begin_inst: u32,
/// The past-end offset into `self.flobals.section`.
end_inst: u32,
+ /// The result-id of the function that initializes this value.
+ initializer_id: IdRef,
};
/// This models a kernel entry point.
@@ -174,9 +176,6 @@ globals: struct {
section: Section = .{},
} = .{},
-/// The function IDs of global variable initializers
-initializers: std.ArrayListUnmanaged(IdRef) = .{},
-
pub fn init(gpa: Allocator, arena: Allocator) Module {
return .{
.gpa = gpa,
@@ -205,8 +204,6 @@ pub fn deinit(self: *Module) void {
self.globals.globals.deinit(self.gpa);
self.globals.section.deinit(self.gpa);
- self.initializers.deinit(self.gpa);
-
self.* = undefined;
}
@@ -289,6 +286,10 @@ fn addEntryPointDeps(
const decl = self.declPtr(decl_index);
const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep];
+ if (seen.isSet(@intFromEnum(decl_index))) {
+ return;
+ }
+
seen.set(@intFromEnum(decl_index));
if (self.globalPtr(decl_index)) |global| {
@@ -296,9 +297,7 @@ fn addEntryPointDeps(
}
for (deps) |dep| {
- if (!seen.isSet(@intFromEnum(dep))) {
- try self.addEntryPointDeps(dep, seen, interface);
- }
+ try self.addEntryPointDeps(dep, seen, interface);
}
}
@@ -330,20 +329,76 @@ fn entryPoints(self: *Module) !Section {
return entry_points;
}
+/// Generate a function that calls all initialization functions,
+/// in unspecified order (an order should not be required here).
+/// It generated as follows:
+/// %init = OpFunction %void None
+/// foreach %initializer:
+/// OpFunctionCall %initializer
+/// OpReturn
+/// OpFunctionEnd
+fn initializer(self: *Module, entry_points: *Section) !Section {
+ var section = Section{};
+ errdefer section.deinit(self.gpa);
+
+ // const void_ty_ref = try self.resolveType(Type.void, .direct);
+ const void_ty_ref = try self.resolve(.void_type);
+ const void_ty_id = self.resultId(void_ty_ref);
+ const init_proto_ty_ref = try self.resolve(.{ .function_type = .{
+ .return_type = void_ty_ref,
+ .parameters = &.{},
+ } });
+
+ const init_id = self.allocId();
+ try section.emit(self.gpa, .OpFunction, .{
+ .id_result_type = void_ty_id,
+ .id_result = init_id,
+ .function_control = .{},
+ .function_type = self.resultId(init_proto_ty_ref),
+ });
+ try section.emit(self.gpa, .OpLabel, .{
+ .id_result = self.allocId(),
+ });
+
+ var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len);
+ defer seen.deinit(self.gpa);
+
+ var interface = std.ArrayList(IdRef).init(self.gpa);
+ defer interface.deinit();
+
+ for (self.globals.globals.keys(), self.globals.globals.values()) |decl_index, global| {
+ try self.addEntryPointDeps(decl_index, &seen, &interface);
+ try section.emit(self.gpa, .OpFunctionCall, .{
+ .id_result_type = void_ty_id,
+ .id_result = self.allocId(),
+ .function = global.initializer_id,
+ });
+ }
+
+ try section.emit(self.gpa, .OpReturn, {});
+ try section.emit(self.gpa, .OpFunctionEnd, {});
+
+ try entry_points.emit(self.gpa, .OpEntryPoint, .{
+ // TODO: Rusticl does not support this because its poorly defined.
+ // Do we need to generate a workaround here?
+ .execution_model = .Kernel,
+ .entry_point = init_id,
+ .name = "zig global initializer",
+ .interface = interface.items,
+ });
+
+ try self.sections.execution_modes.emit(self.gpa, .OpExecutionMode, .{
+ .entry_point = init_id,
+ .mode = .Initializer,
+ });
+
+ return section;
+}
+
/// Emit this module as a spir-v binary.
pub fn flush(self: *Module, file: std.fs.File) !void {
// See SPIR-V Spec section 2.3, "Physical Layout of a SPIR-V Module and Instruction"
- const header = [_]Word{
- spec.magic_number,
- // TODO: From cpu features
- // Emit SPIR-V 1.4 for now. This is the highest version that Intel's CPU OpenCL supports.
- (1 << 16) | (4 << 8),
- 0, // TODO: Register Zig compiler magic number.
- self.idBound(),
- 0, // Schema (currently reserved for future use)
- };
-
// TODO: Perform topological sort on the globals.
var globals = try self.orderGlobals();
defer globals.deinit(self.gpa);
@@ -354,6 +409,19 @@ pub fn flush(self: *Module, file: std.fs.File) !void {
var types_constants = try self.cache.materialize(self);
defer types_constants.deinit(self.gpa);
+ var init_func = try self.initializer(&entry_points);
+ defer init_func.deinit(self.gpa);
+
+ const header = [_]Word{
+ spec.magic_number,
+ // TODO: From cpu features
+ // Emit SPIR-V 1.4 for now. This is the highest version that Intel's CPU OpenCL supports.
+ (1 << 16) | (4 << 8),
+ 0, // TODO: Register Zig compiler magic number.
+ self.idBound(),
+ 0, // Schema (currently reserved for future use)
+ };
+
// Note: needs to be kept in order according to section 2.3!
const buffers = &[_][]const Word{
&header,
@@ -368,6 +436,7 @@ pub fn flush(self: *Module, file: std.fs.File) !void {
self.sections.types_globals_constants.toWords(),
globals.toWords(),
self.sections.functions.toWords(),
+ init_func.toWords(),
};
var iovc_buffers: [buffers.len]std.os.iovec_const = undefined;
@@ -529,6 +598,7 @@ pub fn allocDecl(self: *Module, kind: DeclKind) !Decl.Index {
.result_id = undefined,
.begin_inst = undefined,
.end_inst = undefined,
+ .initializer_id = undefined,
}),
}
@@ -558,10 +628,14 @@ pub fn beginGlobal(self: *Module) u32 {
return @as(u32, @intCast(self.globals.section.instructions.items.len));
}
-pub fn endGlobal(self: *Module, global_index: Decl.Index, begin_inst: u32) void {
+pub fn endGlobal(self: *Module, global_index: Decl.Index, begin_inst: u32, result_id: IdRef, initializer_id: IdRef) void {
const global = self.globalPtr(global_index).?;
- global.begin_inst = begin_inst;
- global.end_inst = @as(u32, @intCast(self.globals.section.instructions.items.len));
+ global.* = .{
+ .result_id = result_id,
+ .begin_inst = begin_inst,
+ .end_inst = @intCast(self.globals.section.instructions.items.len),
+ .initializer_id = initializer_id,
+ };
}
pub fn declareEntryPoint(self: *Module, decl_index: Decl.Index, name: []const u8) !void {