authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-14 21:22:51+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-18 13:38:58+02:00
logf4c4daec863cf7394e141aefc5ad52e9c34f5979
tree181f0451634aade4e0720d35b6678e26fc868ad9
parentc9ca79fb487f934b001b4d947e8c8808b4062cb2

spirv: emit debug info for invocation globals


3 files changed, 41 insertions(+), 19 deletions(-)

src/codegen/spirv/CodeGen.zig+1
......@@ -556,6 +556,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
556556 try cg.module.sections.functions.append(gpa, cg.body);
557557
558558 try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
559 try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
559560
560561 try cg.module.sections.globals.emit(gpa, .OpExtInst, .{
561562 .id_result_type = ptr_ty_id,
src/link/SpirV/lower_invocation_globals.zig+34-6
......@@ -366,6 +366,8 @@ const ModuleBuilder = struct {
366366 /// The first ID of the new entry points. Entry points are allocated from
367367 /// here according to their index in `info.entry_points`.
368368 entry_point_new_id_base: u32,
369 /// OpName operands saved for invocation globals to re-emit.
370 global_names: std.array_hash_map.Auto(ResultId, []const Word) = .empty,
369371 /// A set of all function types in the new program. SPIR-V mandates that these are unique,
370372 /// and until a general type deduplication pass is programmed, we just handle it here via this.
371373 function_types: std.array_hash_map.Custom(FunctionType, ResultId, FunctionType.Context, true) = .empty,
......@@ -403,14 +405,41 @@ const ModuleBuilder = struct {
403405 binary.functions_start = self.new_functions_section orelse binary.instructions.len;
404406 }
405407
408 fn emitGlobalNames(self: *ModuleBuilder, info: ModuleInfo) !void {
409 for (info.functions.keys(), info.functions.values()) |func, fn_info| {
410 if (info.dead_initializers.contains(func)) continue;
411 const new_info = self.function_new_info.get(func) orelse continue;
412 for (fn_info.invocation_globals.keys(), 0..) |global, i| {
413 if (!info.live_invocation_globals.contains(global)) continue;
414 const name_words = self.global_names.get(global) orelse continue;
415 const id = new_info.invocationGlobalId(i);
416 try self.section.emitRaw(self.arena, .OpName, 1 + name_words.len);
417 self.section.writeOperand(ResultId, id);
418 self.section.writeWords(name_words);
419 }
420 }
421 }
422
406423 /// Process everything from `binary` up to the first function and emit it into the builder.
407424 fn processPreamble(self: *ModuleBuilder, binary: BinaryModule, info: ModuleInfo) !void {
425 var emitted_global_names = false;
408426 var it = binary.iterateInstructions();
409427 while (it.next()) |inst| {
428 if (!emitted_global_names) switch (inst.opcode.class()) {
429 .annotation, .type_declaration, .constant_creation => {
430 try self.emitGlobalNames(info);
431 emitted_global_names = true;
432 },
433 else => {},
434 };
435
410436 switch (inst.opcode) {
411437 .OpName => {
412438 const id: ResultId = @enumFromInt(inst.operands[0]);
413 if (info.invocation_globals.contains(id)) continue;
439 if (info.invocation_globals.contains(id)) {
440 try self.global_names.put(self.arena, id, inst.operands[1..]);
441 continue;
442 }
414443 if (info.dead_initializers.contains(id)) continue;
415444 },
416445 .OpExtInstImport => {
......@@ -446,11 +475,6 @@ const ModuleBuilder = struct {
446475 continue;
447476 },
448477 .OpTypeFunction => {
449 // Re-emitted in `emitFunctionTypes()`. We can do this because
450 // OpTypeFunction's may not currently be used anywhere that is not
451 // directly with an OpFunction. For now we ignore Intels function
452 // pointers extension, that is not a problem with a generalized
453 // pass anyway.
454478 continue;
455479 },
456480 .OpFunction => break,
......@@ -459,6 +483,10 @@ const ModuleBuilder = struct {
459483
460484 try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands);
461485 }
486
487 if (!emitted_global_names) {
488 try self.emitGlobalNames(info);
489 }
462490 }
463491
464492 /// Derive new information required for further emitting this module,
src/link/SpirV/prune_unused.zig+6-13
......@@ -100,20 +100,13 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void {
100100 };
101101 if (!alive.isSet(index)) continue;
102102 } else {
103 // annotation-style: emit only if all id operands are alive
104 id_offset_buf.items.len = 0;
105 parser.parseInstructionResultIds(binary.*, inst, &id_offset_buf) catch continue;
106 var all_alive = true;
107 for (id_offset_buf.items) |off| {
108 const id: ResultId = @enumFromInt(inst.operands[off]);
109 if (id_to_index.get(id)) |idx| {
110 if (!alive.isSet(idx)) {
111 all_alive = false;
112 break;
113 }
114 }
103 // annotation-style: emit only if the target id is alive
104 if (inst.operands.len > 0) {
105 const target: ResultId = @enumFromInt(inst.operands[0]);
106 if (id_to_index.get(target)) |idx| {
107 if (!alive.isSet(idx)) continue;
108 } else continue;
115109 }
116 if (!all_alive) continue;
117110 }
118111 }
119112