authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-04-08 01:37:00+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-04-09 01:51:54+02:00
log3f2025f59e4488bff9e046cabbbff047fa1db508
treeed6f62e5f92e3d593870284c1dedbdb0fb6082f0
parent405f7298acaa4818a26fdc93991c48705c19de15
signaturelock-open Commit is signed but in an unrecognized format.

spirv: emit interface variables for entry points

Also actually implement generating the OpEntryPoint instructions.

3 files changed, 101 insertions(+), 18 deletions(-)

src/codegen/spirv.zig+15-9
...@@ -1343,7 +1343,7 @@ pub const DeclGen = struct {...@@ -1343,7 +1343,7 @@ pub const DeclGen = struct {
1343 /// OpFunctionEnd1343 /// OpFunctionEnd
1344 /// TODO is to also write out the error as a function call parameter, and to somehow fetch1344 /// TODO is to also write out the error as a function call parameter, and to somehow fetch
1345 /// the name of an error in the text executor.1345 /// the name of an error in the text executor.
1346 fn generateTestEntryPoint(self: *DeclGen, name: []const u8, func: IdResult) !void {1346 fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void {
1347 const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct);1347 const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct);
1348 const ptr_anyerror_ty_ref = try self.spv.ptrType(anyerror_ty_ref, .CrossWorkgroup, null);1348 const ptr_anyerror_ty_ref = try self.spv.ptrType(anyerror_ty_ref, .CrossWorkgroup, null);
1349 const void_ty_ref = try self.resolveType(Type.void, .direct);1349 const void_ty_ref = try self.resolveType(Type.void, .direct);
...@@ -1357,7 +1357,11 @@ pub const DeclGen = struct {...@@ -1357,7 +1357,11 @@ pub const DeclGen = struct {
1357 break :blk try self.spv.resolveType(SpvType.initPayload(&proto_payload.base));1357 break :blk try self.spv.resolveType(SpvType.initPayload(&proto_payload.base));
1358 };1358 };
13591359
1360 const kernel_id = self.spv.allocId();1360 const test_id = self.spv.declPtr(spv_test_decl_index).result_id;
1361
1362 const spv_decl_index = try self.spv.allocDecl(.func);
1363 const kernel_id = self.spv.declPtr(spv_decl_index).result_id;
1364
1361 const error_id = self.spv.allocId();1365 const error_id = self.spv.allocId();
1362 const p_error_id = self.spv.allocId();1366 const p_error_id = self.spv.allocId();
13631367
...@@ -1378,7 +1382,7 @@ pub const DeclGen = struct {...@@ -1378,7 +1382,7 @@ pub const DeclGen = struct {
1378 try section.emit(self.spv.gpa, .OpFunctionCall, .{1382 try section.emit(self.spv.gpa, .OpFunctionCall, .{
1379 .id_result_type = self.typeId(anyerror_ty_ref),1383 .id_result_type = self.typeId(anyerror_ty_ref),
1380 .id_result = error_id,1384 .id_result = error_id,
1381 .function = func,1385 .function = test_id,
1382 });1386 });
1383 try section.emit(self.spv.gpa, .OpStore, .{1387 try section.emit(self.spv.gpa, .OpStore, .{
1384 .pointer = p_error_id,1388 .pointer = p_error_id,
...@@ -1387,11 +1391,13 @@ pub const DeclGen = struct {...@@ -1387,11 +1391,13 @@ pub const DeclGen = struct {
1387 try section.emit(self.spv.gpa, .OpReturn, {});1391 try section.emit(self.spv.gpa, .OpReturn, {});
1388 try section.emit(self.spv.gpa, .OpFunctionEnd, {});1392 try section.emit(self.spv.gpa, .OpFunctionEnd, {});
13891393
1390 try self.spv.sections.entry_points.emit(self.spv.gpa, .OpEntryPoint, .{1394 try self.spv.declareDeclDeps(spv_decl_index, &.{spv_test_decl_index});
1391 .execution_model = .Kernel,1395
1392 .entry_point = kernel_id,1396 // Just generate a quick other name because the intel runtime crashes when the entry-
1393 .name = name,1397 // point name is the same as a different OpName.
1394 });1398 const test_name = try std.fmt.allocPrint(self.gpa, "test {s}", .{name});
1399 defer self.gpa.free(test_name);
1400 try self.spv.declareEntryPoint(spv_decl_index, test_name);
1395 }1401 }
13961402
1397 fn genDecl(self: *DeclGen) !void {1403 fn genDecl(self: *DeclGen) !void {
...@@ -1451,7 +1457,7 @@ pub const DeclGen = struct {...@@ -1451,7 +1457,7 @@ pub const DeclGen = struct {
1451 });1457 });
14521458
1453 if (self.module.test_functions.contains(self.decl_index)) {1459 if (self.module.test_functions.contains(self.decl_index)) {
1454 try self.generateTestEntryPoint(fqn, decl_id);1460 try self.generateTestEntryPoint(fqn, spv_decl_index);
1455 }1461 }
1456 } else {1462 } else {
1457 const init_val = if (decl.val.castTag(.variable)) |payload|1463 const init_val = if (decl.val.castTag(.variable)) |payload|
src/codegen/spirv/Assembler.zig+3-1
...@@ -435,10 +435,12 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {...@@ -435,10 +435,12 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
435 .Annotation => &self.spv.sections.annotations,435 .Annotation => &self.spv.sections.annotations,
436 .TypeDeclaration => unreachable, // Handled elsewhere.436 .TypeDeclaration => unreachable, // Handled elsewhere.
437 else => switch (self.inst.opcode) {437 else => switch (self.inst.opcode) {
438 .OpEntryPoint => &self.spv.sections.entry_points,438 // TODO: This should emit a proper entry point.
439 .OpEntryPoint => unreachable, // &self.spv.sections.entry_points,
439 .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes,440 .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes,
440 .OpVariable => switch (@intToEnum(spec.StorageClass, operands[2].value)) {441 .OpVariable => switch (@intToEnum(spec.StorageClass, operands[2].value)) {
441 .Function => &self.func.prologue,442 .Function => &self.func.prologue,
443 // TODO: Emit a decl dependency
442 else => &self.spv.sections.types_globals_constants,444 else => &self.spv.sections.types_globals_constants,
443 },445 },
444 // Default case - to be worked out further.446 // Default case - to be worked out further.
src/codegen/spirv/Module.zig+83-8
...@@ -93,6 +93,14 @@ pub const Global = struct {...@@ -93,6 +93,14 @@ pub const Global = struct {
93 end_inst: u32,93 end_inst: u32,
94};94};
9595
96/// This models a kernel entry point.
97pub const EntryPoint = struct {
98 /// The declaration that should be exported.
99 decl_index: Decl.Index,
100 /// The name of the kernel to be exported.
101 name: []const u8,
102};
103
96/// A general-purpose allocator which may be used to allocate resources for this module104/// A general-purpose allocator which may be used to allocate resources for this module
97gpa: Allocator,105gpa: Allocator,
98106
...@@ -107,8 +115,7 @@ sections: struct {...@@ -107,8 +115,7 @@ sections: struct {
107 extensions: Section = .{},115 extensions: Section = .{},
108 // OpExtInstImport instructions - skip for now.116 // OpExtInstImport instructions - skip for now.
109 // memory model defined by target, not required here.117 // memory model defined by target, not required here.
110 /// OpEntryPoint instructions.118 /// OpEntryPoint instructions - Handled by `self.entry_points`.
111 entry_points: Section = .{},
112 /// OpExecutionMode and OpExecutionModeId instructions.119 /// OpExecutionMode and OpExecutionModeId instructions.
113 execution_modes: Section = .{},120 execution_modes: Section = .{},
114 /// OpString, OpSourcExtension, OpSource, OpSourceContinued.121 /// OpString, OpSourcExtension, OpSource, OpSourceContinued.
...@@ -143,8 +150,13 @@ type_cache: TypeCache = .{},...@@ -143,8 +150,13 @@ type_cache: TypeCache = .{},
143/// Set of Decls, referred to by Decl.Index.150/// Set of Decls, referred to by Decl.Index.
144decls: std.ArrayListUnmanaged(Decl) = .{},151decls: std.ArrayListUnmanaged(Decl) = .{},
145152
153/// List of dependencies, per decl. This list holds all the dependencies, sliced by the
154/// begin_dep and end_dep in `self.decls`.
146decl_deps: std.ArrayListUnmanaged(Decl.Index) = .{},155decl_deps: std.ArrayListUnmanaged(Decl.Index) = .{},
147156
157/// The list of entry points that should be exported from this module.
158entry_points: std.ArrayListUnmanaged(EntryPoint) = .{},
159
148/// The fields in this structure help to maintain the required order for global variables.160/// The fields in this structure help to maintain the required order for global variables.
149globals: struct {161globals: struct {
150 /// Set of globals, referred to by Decl.Index.162 /// Set of globals, referred to by Decl.Index.
...@@ -166,7 +178,6 @@ pub fn init(gpa: Allocator, arena: Allocator) Module {...@@ -166,7 +178,6 @@ pub fn init(gpa: Allocator, arena: Allocator) Module {
166pub fn deinit(self: *Module) void {178pub fn deinit(self: *Module) void {
167 self.sections.capabilities.deinit(self.gpa);179 self.sections.capabilities.deinit(self.gpa);
168 self.sections.extensions.deinit(self.gpa);180 self.sections.extensions.deinit(self.gpa);
169 self.sections.entry_points.deinit(self.gpa);
170 self.sections.execution_modes.deinit(self.gpa);181 self.sections.execution_modes.deinit(self.gpa);
171 self.sections.debug_strings.deinit(self.gpa);182 self.sections.debug_strings.deinit(self.gpa);
172 self.sections.debug_names.deinit(self.gpa);183 self.sections.debug_names.deinit(self.gpa);
...@@ -180,6 +191,8 @@ pub fn deinit(self: *Module) void {...@@ -180,6 +191,8 @@ pub fn deinit(self: *Module) void {
180 self.decls.deinit(self.gpa);191 self.decls.deinit(self.gpa);
181 self.decl_deps.deinit(self.gpa);192 self.decl_deps.deinit(self.gpa);
182193
194 self.entry_points.deinit(self.gpa);
195
183 self.globals.globals.deinit(self.gpa);196 self.globals.globals.deinit(self.gpa);
184 self.globals.section.deinit(self.gpa);197 self.globals.section.deinit(self.gpa);
185198
...@@ -202,16 +215,16 @@ pub fn idBound(self: Module) Word {...@@ -202,16 +215,16 @@ pub fn idBound(self: Module) Word {
202215
203fn orderGlobalsInto(216fn orderGlobalsInto(
204 self: *Module,217 self: *Module,
205 index: Decl.Index,218 decl_index: Decl.Index,
206 section: *Section,219 section: *Section,
207 seen: *std.DynamicBitSetUnmanaged,220 seen: *std.DynamicBitSetUnmanaged,
208) !void {221) !void {
209 const decl = self.declPtr(index);222 const decl = self.declPtr(decl_index);
210 const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep];223 const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep];
211 const global = self.globalPtr(index).?;224 const global = self.globalPtr(decl_index).?;
212 const insts = self.globals.section.instructions.items[global.begin_inst..global.end_inst];225 const insts = self.globals.section.instructions.items[global.begin_inst..global.end_inst];
213226
214 seen.set(@enumToInt(index));227 seen.set(@enumToInt(decl_index));
215228
216 for (deps) |dep| {229 for (deps) |dep| {
217 if (!seen.isSet(@enumToInt(dep))) {230 if (!seen.isSet(@enumToInt(dep))) {
...@@ -229,6 +242,8 @@ fn orderGlobals(self: *Module) !Section {...@@ -229,6 +242,8 @@ fn orderGlobals(self: *Module) !Section {
229 defer seen.deinit(self.gpa);242 defer seen.deinit(self.gpa);
230243
231 var ordered_globals = Section{};244 var ordered_globals = Section{};
245 errdefer ordered_globals.deinit(self.gpa);
246
232 for (globals) |decl_index| {247 for (globals) |decl_index| {
233 if (!seen.isSet(@enumToInt(decl_index))) {248 if (!seen.isSet(@enumToInt(decl_index))) {
234 try self.orderGlobalsInto(decl_index, &ordered_globals, &seen);249 try self.orderGlobalsInto(decl_index, &ordered_globals, &seen);
...@@ -238,6 +253,56 @@ fn orderGlobals(self: *Module) !Section {...@@ -238,6 +253,56 @@ fn orderGlobals(self: *Module) !Section {
238 return ordered_globals;253 return ordered_globals;
239}254}
240255
256fn addEntryPointDeps(
257 self: *Module,
258 decl_index: Decl.Index,
259 seen: *std.DynamicBitSetUnmanaged,
260 interface: *std.ArrayList(IdRef),
261) !void {
262 const decl = self.declPtr(decl_index);
263 const deps = self.decl_deps.items[decl.begin_dep..decl.end_dep];
264
265 seen.set(@enumToInt(decl_index));
266
267 if (self.globalPtr(decl_index)) |global| {
268 try interface.append(global.result_id);
269 }
270
271 for (deps) |dep| {
272 if (!seen.isSet(@enumToInt(dep))) {
273 try self.addEntryPointDeps(dep, seen, interface);
274 }
275 }
276}
277
278fn entryPoints(self: *Module) !Section {
279 var entry_points = Section{};
280 errdefer entry_points.deinit(self.gpa);
281
282 var interface = std.ArrayList(IdRef).init(self.gpa);
283 defer interface.deinit();
284
285 var seen = try std.DynamicBitSetUnmanaged.initEmpty(self.gpa, self.decls.items.len);
286 defer seen.deinit(self.gpa);
287
288 for (self.entry_points.items) |entry_point| {
289 interface.items.len = 0;
290 seen.setRangeValue(.{ .start = 0, .end = self.decls.items.len }, false);
291
292 try self.addEntryPointDeps(entry_point.decl_index, &seen, &interface);
293
294 const entry_point_id = self.declPtr(entry_point.decl_index).result_id;
295 try entry_points.emit(self.gpa, .OpEntryPoint, .{
296 .execution_model = .Kernel,
297 .entry_point = entry_point_id,
298 .name = entry_point.name,
299 .interface = interface.items,
300 });
301 }
302
303 return entry_points;
304}
305
241/// Emit this module as a spir-v binary.306/// Emit this module as a spir-v binary.
242pub fn flush(self: *Module, file: std.fs.File) !void {307pub fn flush(self: *Module, file: std.fs.File) !void {
243 // See SPIR-V Spec section 2.3, "Physical Layout of a SPIR-V Module and Instruction"308 // See SPIR-V Spec section 2.3, "Physical Layout of a SPIR-V Module and Instruction"
...@@ -256,12 +321,15 @@ pub fn flush(self: *Module, file: std.fs.File) !void {...@@ -256,12 +321,15 @@ pub fn flush(self: *Module, file: std.fs.File) !void {
256 var globals = try self.orderGlobals();321 var globals = try self.orderGlobals();
257 defer globals.deinit(self.gpa);322 defer globals.deinit(self.gpa);
258323
324 var entry_points = try self.entryPoints();
325 defer entry_points.deinit(self.gpa);
326
259 // Note: needs to be kept in order according to section 2.3!327 // Note: needs to be kept in order according to section 2.3!
260 const buffers = &[_][]const Word{328 const buffers = &[_][]const Word{
261 &header,329 &header,
262 self.sections.capabilities.toWords(),330 self.sections.capabilities.toWords(),
263 self.sections.extensions.toWords(),331 self.sections.extensions.toWords(),
264 self.sections.entry_points.toWords(),332 entry_points.toWords(),
265 self.sections.execution_modes.toWords(),333 self.sections.execution_modes.toWords(),
266 self.sections.debug_strings.toWords(),334 self.sections.debug_strings.toWords(),
267 self.sections.debug_names.toWords(),335 self.sections.debug_names.toWords(),
...@@ -795,3 +863,10 @@ pub fn endGlobal(self: *Module, global_index: Decl.Index, begin_inst: u32) void...@@ -795,3 +863,10 @@ pub fn endGlobal(self: *Module, global_index: Decl.Index, begin_inst: u32) void
795 global.begin_inst = begin_inst;863 global.begin_inst = begin_inst;
796 global.end_inst = @intCast(u32, self.globals.section.instructions.items.len);864 global.end_inst = @intCast(u32, self.globals.section.instructions.items.len);
797}865}
866
867pub fn declareEntryPoint(self: *Module, decl_index: Decl.Index, name: []const u8) !void {
868 try self.entry_points.append(self.gpa, .{
869 .decl_index = decl_index,
870 .name = try self.arena.dupe(u8, name),
871 });
872}