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...@@ -3639,11 +3639,8 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
3639 else => false,3639 else => false,
3640 },3640 },
3641 .stage2_spirv64 => switch (cc) {3641 .stage2_spirv64 => switch (cc) {
3642 .spirv_device,3642 .spirv_device, .spirv_kernel => true,
3643 .spirv_kernel,3643 .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan,
3644 .spirv_fragment,
3645 .spirv_vertex,
3646 => true,
3647 else => false,3644 else => false,
3648 },3645 },
3649 };3646 };
src/codegen/spirv.zig+13-9
...@@ -1640,13 +1640,18 @@ const NavGen = struct {...@@ -1640,13 +1640,18 @@ const NavGen = struct {
16401640
1641 comptime assert(zig_call_abi_ver == 3);1641 comptime assert(zig_call_abi_ver == 3);
1642 switch (fn_info.cc) {1642 switch (fn_info.cc) {
1643 .auto, .spirv_kernel, .spirv_fragment, .spirv_vertex => {},1643 .auto,
1644 else => @panic("TODO"),1644 .spirv_kernel,
1645 .spirv_fragment,
1646 .spirv_vertex,
1647 .spirv_device,
1648 => {},
1649 else => unreachable,
1645 }1650 }
16461651
1647 // TODO: Put this somewhere in Sema.zig1652 // Guaranteed by callConvSupportsVarArgs, there are nog SPIR-V CCs which support
1648 if (fn_info.is_var_args)1653 // varargs.
1649 return self.fail("VarArgs functions are unsupported for SPIR-V", .{});1654 assert(!fn_info.is_var_args);
16501655
1651 // Note: Logic is different from functionType().1656 // Note: Logic is different from functionType().
1652 const param_ty_ids = try self.gpa.alloc(IdRef, fn_info.param_types.len);1657 const param_ty_ids = try self.gpa.alloc(IdRef, fn_info.param_types.len);
...@@ -2969,11 +2974,10 @@ const NavGen = struct {...@@ -2969,11 +2974,10 @@ const NavGen = struct {
2969 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{2974 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
2970 .id_result_type = return_ty_id,2975 .id_result_type = return_ty_id,
2971 .id_result = result_id,2976 .id_result = result_id,
2972 .function_control = switch (fn_info.cc) {
2973 .@"inline" => .{ .Inline = true },
2974 else => .{},
2975 },
2976 .function_type = prototype_ty_id,2977 .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 = .{},
2977 });2981 });
29782982
2979 comptime assert(zig_call_abi_ver == 3);2983 comptime assert(zig_call_abi_ver == 3);
src/link/SpirV.zig+26-19
...@@ -161,28 +161,35 @@ pub fn updateExports(...@@ -161,28 +161,35 @@ pub fn updateExports(
161 },161 },
162 };162 };
163 const nav_ty = ip.getNav(nav_index).typeOf(ip);163 const nav_ty = ip.getNav(nav_index).typeOf(ip);
164 const target = zcu.getTarget();
164 if (ip.isFunctionType(nav_ty)) {165 if (ip.isFunctionType(nav_ty)) {
165 const target = zcu.getTarget();
166 const spv_decl_index = try self.object.resolveNav(zcu, nav_index);166 const spv_decl_index = try self.object.resolveNav(zcu, nav_index);
167 const execution_model = switch (Type.fromInterned(nav_ty).fnCallingConvention(zcu)) {167 const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu);
168 .spirv_vertex => spec.ExecutionModel.Vertex,168 const execution_model: spec.ExecutionModel = switch (target.os.tag) {
169 .spirv_fragment => spec.ExecutionModel.Fragment,169 .vulkan => switch (cc) {
170 .spirv_kernel => spec.ExecutionModel.Kernel,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 },
171 else => unreachable,183 else => unreachable,
172 };184 };
173 const is_vulkan = target.os.tag == .vulkan;185
174186 for (export_indices) |export_idx| {
175 if ((!is_vulkan and execution_model == .Kernel) or187 const exp = zcu.all_exports.items[export_idx];
176 (is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))188 try self.object.spv.declareEntryPoint(
177 {189 spv_decl_index,
178 for (export_indices) |export_idx| {190 exp.opts.name.toSlice(ip),
179 const exp = zcu.all_exports.items[export_idx];191 execution_model,
180 try self.object.spv.declareEntryPoint(192 );
181 spv_decl_index,
182 exp.opts.name.toSlice(ip),
183 execution_model,
184 );
185 }
186 }193 }
187 }194 }
188195
...@@ -258,7 +265,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n...@@ -258,7 +265,7 @@ pub fn flushModule(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
258 const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {265 const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {
259 error.OutOfMemory => return error.OutOfMemory,266 error.OutOfMemory => return error.OutOfMemory,
260 else => |other| {267 else => |other| {
261 log.err("error while linking: {s}\n", .{@errorName(other)});268 log.err("error while linking: {s}", .{@errorName(other)});
262 return error.FlushFailure;269 return error.FlushFailure;
263 },270 },
264 };271 };