From 6de456c179d81b9118ecd26eb9d7c90213bac313 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sun, 20 Oct 2024 16:53:53 +0200 Subject: [PATCH] spirv: fix up calling conventions for vulkan * Fragment and Vertex CCs are only valid for SPIR-V when running under Vulkan. * Emit GLCompute instead of Kernel for SPIR-V kernels. --- src/Zcu.zig | 7 ++----- src/codegen/spirv.zig | 22 +++++++++++++--------- src/link/SpirV.zig | 43 +++++++++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/Zcu.zig b/src/Zcu.zig index d86fee6365..aa8610b7fd 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -3639,11 +3639,8 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu else => false, }, .stage2_spirv64 => switch (cc) { - .spirv_device, - .spirv_kernel, - .spirv_fragment, - .spirv_vertex, - => true, + .spirv_device, .spirv_kernel => true, + .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan, else => false, }, }; diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 279b7d5056..da527c9ac8 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -1640,13 +1640,18 @@ const NavGen = struct { comptime assert(zig_call_abi_ver == 3); switch (fn_info.cc) { - .auto, .spirv_kernel, .spirv_fragment, .spirv_vertex => {}, - else => @panic("TODO"), + .auto, + .spirv_kernel, + .spirv_fragment, + .spirv_vertex, + .spirv_device, + => {}, + else => unreachable, } - // TODO: Put this somewhere in Sema.zig - if (fn_info.is_var_args) - return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); + // Guaranteed by callConvSupportsVarArgs, there are nog SPIR-V CCs which support + // varargs. + assert(!fn_info.is_var_args); // Note: Logic is different from functionType(). const param_ty_ids = try self.gpa.alloc(IdRef, fn_info.param_types.len); @@ -2969,11 +2974,10 @@ const NavGen = struct { try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ .id_result_type = return_ty_id, .id_result = result_id, - .function_control = switch (fn_info.cc) { - .@"inline" => .{ .Inline = true }, - else => .{}, - }, .function_type = prototype_ty_id, + // Note: the backend will never be asked to generate an inline function + // (this is handled in sema), so we don't need to set function_control here. + .function_control = .{}, }); comptime assert(zig_call_abi_ver == 3); diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index c6b0752aee..59ca27d48e 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -161,28 +161,35 @@ pub fn updateExports( }, }; const nav_ty = ip.getNav(nav_index).typeOf(ip); + const target = zcu.getTarget(); if (ip.isFunctionType(nav_ty)) { - const target = zcu.getTarget(); const spv_decl_index = try self.object.resolveNav(zcu, nav_index); - const execution_model = switch (Type.fromInterned(nav_ty).fnCallingConvention(zcu)) { - .spirv_vertex => spec.ExecutionModel.Vertex, - .spirv_fragment => spec.ExecutionModel.Fragment, - .spirv_kernel => spec.ExecutionModel.Kernel, + const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu); + const execution_model: spec.ExecutionModel = switch (target.os.tag) { + .vulkan => switch (cc) { + .spirv_vertex => .Vertex, + .spirv_fragment => .Fragment, + .spirv_kernel => .GLCompute, + // TODO: We should integrate with the Linkage capability and export this function + .spirv_device => return, + else => unreachable, + }, + .opencl => switch (cc) { + .spirv_kernel => .Kernel, + // TODO: We should integrate with the Linkage capability and export this function + .spirv_device => return, + else => unreachable, + }, else => unreachable, }; - const is_vulkan = target.os.tag == .vulkan; - if ((!is_vulkan and execution_model == .Kernel) or - (is_vulkan and (execution_model == .Fragment or execution_model == .Vertex))) - { - for (export_indices) |export_idx| { - const exp = zcu.all_exports.items[export_idx]; - try self.object.spv.declareEntryPoint( - spv_decl_index, - exp.opts.name.toSlice(ip), - execution_model, - ); - } + for (export_indices) |export_idx| { + const exp = zcu.all_exports.items[export_idx]; + try self.object.spv.declareEntryPoint( + spv_decl_index, + exp.opts.name.toSlice(ip), + execution_model, + ); } } @@ -258,7 +265,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => |other| { - log.err("error while linking: {s}\n", .{@errorName(other)}); + log.err("error while linking: {s}", .{@errorName(other)}); return error.FlushFailure; }, };