zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit f4c4daec863cf7394e141aefc5ad52e9c34f5979 (tree)
parent c9ca79fb487f934b001b4d947e8c8808b4062cb2
Author: Ali Cheraghi <alichraghi@proton.me>
Date:   Sun, 14 Jun 2026 21:22:51 +0330

spirv: emit debug info for invocation globals

Diffstat:
Msrc/codegen/spirv/CodeGen.zig | 1+
Msrc/link/SpirV/lower_invocation_globals.zig | 40++++++++++++++++++++++++++++++++++------
Msrc/link/SpirV/prune_unused.zig | 19++++++-------------
3 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig @@ -556,6 +556,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { try cg.module.sections.functions.append(gpa, cg.body); try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)}); + try cg.module.debugName(result_id, nav.fqn.toSlice(ip)); try cg.module.sections.globals.emit(gpa, .OpExtInst, .{ .id_result_type = ptr_ty_id, diff --git a/src/link/SpirV/lower_invocation_globals.zig b/src/link/SpirV/lower_invocation_globals.zig @@ -366,6 +366,8 @@ const ModuleBuilder = struct { /// The first ID of the new entry points. Entry points are allocated from /// here according to their index in `info.entry_points`. entry_point_new_id_base: u32, + /// OpName operands saved for invocation globals to re-emit. + global_names: std.array_hash_map.Auto(ResultId, []const Word) = .empty, /// A set of all function types in the new program. SPIR-V mandates that these are unique, /// and until a general type deduplication pass is programmed, we just handle it here via this. function_types: std.array_hash_map.Custom(FunctionType, ResultId, FunctionType.Context, true) = .empty, @@ -403,14 +405,41 @@ const ModuleBuilder = struct { binary.functions_start = self.new_functions_section orelse binary.instructions.len; } + fn emitGlobalNames(self: *ModuleBuilder, info: ModuleInfo) !void { + for (info.functions.keys(), info.functions.values()) |func, fn_info| { + if (info.dead_initializers.contains(func)) continue; + const new_info = self.function_new_info.get(func) orelse continue; + for (fn_info.invocation_globals.keys(), 0..) |global, i| { + if (!info.live_invocation_globals.contains(global)) continue; + const name_words = self.global_names.get(global) orelse continue; + const id = new_info.invocationGlobalId(i); + try self.section.emitRaw(self.arena, .OpName, 1 + name_words.len); + self.section.writeOperand(ResultId, id); + self.section.writeWords(name_words); + } + } + } + /// Process everything from `binary` up to the first function and emit it into the builder. fn processPreamble(self: *ModuleBuilder, binary: BinaryModule, info: ModuleInfo) !void { + var emitted_global_names = false; var it = binary.iterateInstructions(); while (it.next()) |inst| { + if (!emitted_global_names) switch (inst.opcode.class()) { + .annotation, .type_declaration, .constant_creation => { + try self.emitGlobalNames(info); + emitted_global_names = true; + }, + else => {}, + }; + switch (inst.opcode) { .OpName => { const id: ResultId = @enumFromInt(inst.operands[0]); - if (info.invocation_globals.contains(id)) continue; + if (info.invocation_globals.contains(id)) { + try self.global_names.put(self.arena, id, inst.operands[1..]); + continue; + } if (info.dead_initializers.contains(id)) continue; }, .OpExtInstImport => { @@ -446,11 +475,6 @@ const ModuleBuilder = struct { continue; }, .OpTypeFunction => { - // Re-emitted in `emitFunctionTypes()`. We can do this because - // OpTypeFunction's may not currently be used anywhere that is not - // directly with an OpFunction. For now we ignore Intels function - // pointers extension, that is not a problem with a generalized - // pass anyway. continue; }, .OpFunction => break, @@ -459,6 +483,10 @@ const ModuleBuilder = struct { try self.section.emitRawInstruction(self.arena, inst.opcode, inst.operands); } + + if (!emitted_global_names) { + try self.emitGlobalNames(info); + } } /// Derive new information required for further emitting this module, diff --git a/src/link/SpirV/prune_unused.zig b/src/link/SpirV/prune_unused.zig @@ -100,20 +100,13 @@ pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule) !void { }; if (!alive.isSet(index)) continue; } else { - // annotation-style: emit only if all id operands are alive - id_offset_buf.items.len = 0; - parser.parseInstructionResultIds(binary.*, inst, &id_offset_buf) catch continue; - var all_alive = true; - for (id_offset_buf.items) |off| { - const id: ResultId = @enumFromInt(inst.operands[off]); - if (id_to_index.get(id)) |idx| { - if (!alive.isSet(idx)) { - all_alive = false; - break; - } - } + // annotation-style: emit only if the target id is alive + if (inst.operands.len > 0) { + const target: ResultId = @enumFromInt(inst.operands[0]); + if (id_to_index.get(target)) |idx| { + if (!alive.isSet(idx)) continue; + } else continue; } - if (!all_alive) continue; } }