diff --git a/src/link.zig b/src/link.zig index 2a6e3b8031b3..59c0a7a4c975 100644 --- a/src/link.zig +++ b/src/link.zig @@ -568,9 +568,9 @@ pub const File = struct { const gpa = comp.gpa; switch (base.tag) { .lld => assert(base.file == null), - .coff, .elf, .macho, .plan9, .wasm, .goff, .xcoff => { + .coff, .elf, .macho, .plan9, .wasm, .goff, .xcoff, .spirv => { if (base.file != null) return; - dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker }); + dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker, .goff_linker, .xcoff_linker, .spirv_linker }); const emit = base.emit; if (base.child_pid) |pid| { if (builtin.os.tag == .windows) { @@ -608,7 +608,7 @@ pub const File = struct { .mode = determineMode(output_mode, link_mode), }); }, - .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), + .c => dev.check(.c_linker), } } diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 7b908d56edf6..6ba5b94395bf 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -180,6 +180,28 @@ pub fn flush( tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.File.FlushError!void { + const tracy = trace(@src()); + defer tracy.end(); + + const comp = self.base.comp; + const diags = &comp.link_diags; + + const sub_prog_node = prog_node.start("SPIR-V Flush", 0); + defer sub_prog_node.end(); + + return flushInner(self, arena, tid, sub_prog_node) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.LinkFailure => return error.LinkFailure, + else => |e| return diags.fail("SPIR-V flush failed: {s}", .{@errorName(e)}), + }; +} + +fn flushInner( + self: *SpirV, + arena: Allocator, + tid: Zcu.PerThread.Id, + prog_node: std.Progress.Node, +) !void { // The goal is to never use this because it's only needed if we need to // write to InternPool, but flush is too late to be writing to the // InternPool. @@ -189,12 +211,6 @@ pub fn flush( @panic("Attempted to compile for architecture that was disabled by build configuration"); } - const tracy = trace(@src()); - defer tracy.end(); - - const sub_prog_node = prog_node.start("Flush Module", 0); - defer sub_prog_node.end(); - const comp = self.base.comp; const spv = &self.object.spv; const diags = &comp.link_diags; @@ -235,13 +251,14 @@ pub fn flush( const module = try spv.finalize(arena); errdefer arena.free(module); - const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) { + const linked_module = self.linkModule(arena, module, prog_node) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}), }; - self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module)) catch |err| - return diags.fail("failed to write: {s}", .{@errorName(err)}); + try self.base.makeWritable(); + try self.pwriteAll(std.mem.sliceAsBytes(linked_module), 0); + try self.setEndPos(linked_module.len * @sizeOf(Word)); } fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress.Node) ![]Word { @@ -261,3 +278,19 @@ fn linkModule(self: *SpirV, a: Allocator, module: []Word, progress: std.Progress return binary.finalize(a); } + +pub fn pwriteAll(spirv_file: *SpirV, bytes: []const u8, offset: u64) error{LinkFailure}!void { + const comp = spirv_file.base.comp; + const diags = &comp.link_diags; + spirv_file.base.file.?.pwriteAll(bytes, offset) catch |err| { + return diags.fail("failed to write: {s}", .{@errorName(err)}); + }; +} + +pub fn setEndPos(spirv_file: *SpirV, length: u64) error{LinkFailure}!void { + const comp = spirv_file.base.comp; + const diags = &comp.link_diags; + spirv_file.base.file.?.setEndPos(length) catch |err| { + return diags.fail("failed to set file end pos: {s}", .{@errorName(err)}); + }; +}