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.
This commit is contained in:
Robin Voetter 2024-10-20 16:53:53 +02:00
parent 9b42bc1ce5
commit 6de456c179
No known key found for this signature in database
3 changed files with 40 additions and 32 deletions

View File

@ -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,
},
};

View File

@ -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);

View File

@ -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;
},
};