authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-10-20 16:53:53+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-10-27 15:19:55+01:00
log6de456c179d81b9118ecd26eb9d7c90213bac313
tree1dda74e9dad818e8d00d03438b3bf636470011c6
parent9b42bc1ce5a1d688aa2167a068a3b75d69888c12
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

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.

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

src/Zcu.zig+2-5
......@@ -3639,11 +3639,8 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
36393639 else => false,
36403640 },
36413641 .stage2_spirv64 => switch (cc) {
3642 .spirv_device,
3643 .spirv_kernel,
3644 .spirv_fragment,
3645 .spirv_vertex,
3646 => true,
3642 .spirv_device, .spirv_kernel => true,
3643 .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan,
36473644 else => false,
36483645 },
36493646 };
src/codegen/spirv.zig+13-9
......@@ -1640,13 +1640,18 @@ const NavGen = struct {
16401640
16411641 comptime assert(zig_call_abi_ver == 3);
16421642 switch (fn_info.cc) {
1643 .auto, .spirv_kernel, .spirv_fragment, .spirv_vertex => {},
1644 else => @panic("TODO"),
1643 .auto,
1644 .spirv_kernel,
1645 .spirv_fragment,
1646 .spirv_vertex,
1647 .spirv_device,
1648 => {},
1649 else => unreachable,
16451650 }
16461651
1647 // TODO: Put this somewhere in Sema.zig
1648 if (fn_info.is_var_args)
1649 return self.fail("VarArgs functions are unsupported for SPIR-V", .{});
1652 // Guaranteed by callConvSupportsVarArgs, there are nog SPIR-V CCs which support
1653 // varargs.
1654 assert(!fn_info.is_var_args);
16501655
16511656 // Note: Logic is different from functionType().
16521657 const param_ty_ids = try self.gpa.alloc(IdRef, fn_info.param_types.len);
......@@ -2969,11 +2974,10 @@ const NavGen = struct {
29692974 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
29702975 .id_result_type = return_ty_id,
29712976 .id_result = result_id,
2972 .function_control = switch (fn_info.cc) {
2973 .@"inline" => .{ .Inline = true },
2974 else => .{},
2975 },
29762977 .function_type = prototype_ty_id,
2978 // Note: the backend will never be asked to generate an inline function
2979 // (this is handled in sema), so we don't need to set function_control here.
2980 .function_control = .{},
29772981 });
29782982
29792983 comptime assert(zig_call_abi_ver == 3);
src/link/SpirV.zig+26-19
......@@ -161,28 +161,35 @@ pub fn updateExports(
161161 },
162162 };
163163 const nav_ty = ip.getNav(nav_index).typeOf(ip);
164 const target = zcu.getTarget();
164165 if (ip.isFunctionType(nav_ty)) {
165 const target = zcu.getTarget();
166166 const spv_decl_index = try self.object.resolveNav(zcu, nav_index);
167 const execution_model = switch (Type.fromInterned(nav_ty).fnCallingConvention(zcu)) {
168 .spirv_vertex => spec.ExecutionModel.Vertex,
169 .spirv_fragment => spec.ExecutionModel.Fragment,
170 .spirv_kernel => spec.ExecutionModel.Kernel,
167 const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu);
168 const execution_model: spec.ExecutionModel = switch (target.os.tag) {
169 .vulkan => switch (cc) {
170 .spirv_vertex => .Vertex,
171 .spirv_fragment => .Fragment,
172 .spirv_kernel => .GLCompute,
173 // TODO: We should integrate with the Linkage capability and export this function
174 .spirv_device => return,
175 else => unreachable,
176 },
177 .opencl => switch (cc) {
178 .spirv_kernel => .Kernel,
179 // TODO: We should integrate with the Linkage capability and export this function
180 .spirv_device => return,
181 else => unreachable,
182 },
171183 else => unreachable,
172184 };
173 const is_vulkan = target.os.tag == .vulkan;
174
175 if ((!is_vulkan and execution_model == .Kernel) or
176 (is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))
177 {
178 for (export_indices) |export_idx| {
179 const exp = zcu.all_exports.items[export_idx];
180 try self.object.spv.declareEntryPoint(
181 spv_decl_index,
182 exp.opts.name.toSlice(ip),
183 execution_model,
184 );
185 }
185
186 for (export_indices) |export_idx| {
187 const exp = zcu.all_exports.items[export_idx];
188 try self.object.spv.declareEntryPoint(
189 spv_decl_index,
190 exp.opts.name.toSlice(ip),
191 execution_model,
192 );
186193 }
187194 }
188195
......@@ -258,7 +265,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
258265 const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {
259266 error.OutOfMemory => return error.OutOfMemory,
260267 else => |other| {
261 log.err("error while linking: {s}\n", .{@errorName(other)});
268 log.err("error while linking: {s}", .{@errorName(other)});
262269 return error.FlushFailure;
263270 },
264271 };