diff options
| author | Robin Voetter <robin@voetter.nl> | 2023-09-18 22:39:44 +0200 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-09-23 12:36:56 -0700 |
| commit | b845c9d5326bc83691edcb483ac44793b88afe75 (patch) | |
| tree | a965db64c6d8a6c657d46ab9983cdf88fb0c853f /src/codegen/spirv/Module.zig | |
| parent | 5d844faf7c5c30555664b4161e5f9a903daaf562 (diff) | |
| download | zig-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.zig | 116 |
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 { |
