authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-21 09:51:04+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-25 15:47:10+02:00
logdccc724179d984ac5785b6a20bd187bb9c8f749d
tree78575696dabb14415565a12d0cf88fb23158086b
parent6754fc8af277e65827ae531ca4d114df0576398c

spirv: require `mesh_shading_ext` for `spirv_task` and `spirv_mesh`

Also adds a `cpu_features` key to the test manifest.

12 files changed, 38 insertions(+), 29 deletions(-)

src/Sema.zig+13-2
...@@ -8694,15 +8694,26 @@ fn checkReturnTypeAndCallConv(...@@ -8694,15 +8694,26 @@ fn checkReturnTypeAndCallConv(
8694 return sema.fail(block, callconv_src, "'pixel_centered_integer' is not supported on this target", .{});8694 return sema.fail(block, callconv_src, "'pixel_centered_integer' is not supported on this target", .{});
8695 }8695 }
8696 },8696 },
8697 .spirv_kernel, .spirv_task => |kernel| {8697 .spirv_kernel => |kernel| {
8698 if (kernel.x == 0 or kernel.y == 0 or kernel.z == 0) {8698 if (kernel.x == 0 or kernel.y == 0 or kernel.z == 0) {
8699 return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{});8699 return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{});
8700 }8700 }
8701 },8701 },
8702 .spirv_task => |task| {
8703 if (task.x == 0 or task.y == 0 or task.z == 0) {
8704 return sema.fail(block, callconv_src, "kernel workgroup dimensions must be at least 1", .{});
8705 }
8706 if (!target.cpu.has(.spirv, .mesh_shading_ext)) {
8707 return sema.fail(block, callconv_src, "calling convention '{t}' requires the 'mesh_shading_ext' feature", .{@"callconv"});
8708 }
8709 },
8702 .spirv_mesh => |mesh| {8710 .spirv_mesh => |mesh| {
8703 if (mesh.max_vertices == 0 or mesh.max_primitives == 0) {8711 if (mesh.max_vertices == 0 or mesh.max_primitives == 0) {
8704 return sema.fail(block, callconv_src, "mesh shader 'max_vertices' and 'max_primitives' must be at least 1", .{});8712 return sema.fail(block, callconv_src, "mesh shader 'max_vertices' and 'max_primitives' must be at least 1", .{});
8705 }8713 }
8714 if (!target.cpu.has(.spirv, .mesh_shading_ext)) {
8715 return sema.fail(block, callconv_src, "calling convention '{t}' requires the 'mesh_shading_ext' feature", .{@"callconv"});
8716 }
8706 },8717 },
8707 else => {},8718 else => {},
8708 }8719 }
...@@ -8844,7 +8855,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type)...@@ -8844,7 +8855,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type)
8844 try sema.errNote(runtime_src, msg, "runtime control flow here", .{});8855 try sema.errNote(runtime_src, msg, "runtime control flow here", .{});
88458856
8846 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm);8857 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm);
8847 try sema.errNote(src, msg, "pointers with address space '{s}' cannot be returned from a branch on target {s}-{s} by compiler backend {s}", .{8858 try sema.errNote(src, msg, "pointers with address space '{s}' cannot be returned from a branch on target '{s}-{s}' by compiler backend '{s}'", .{
8848 @tagName(as),8859 @tagName(as),
8849 @tagName(target.cpu.arch.family()),8860 @tagName(target.cpu.arch.family()),
8850 @tagName(target.os.tag),8861 @tagName(target.os.tag),
test/behavior/array.zig+2
...@@ -1150,6 +1150,8 @@ test "resist alias of explicit copy of array passed as arg" {...@@ -1150,6 +1150,8 @@ test "resist alias of explicit copy of array passed as arg" {
1150}1150}
11511151
1152test "access element through reference" {1152test "access element through reference" {
1153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1154
1153 const S = struct {1155 const S = struct {
1154 fn doTheTest(x: u8) !void {1156 fn doTheTest(x: u8) !void {
1155 {1157 {
test/cases/callconv_spirv.zig+3-2
...@@ -7,5 +7,6 @@ export fn mesh() callconv(.{ .spirv_mesh = .{ .stage_output = .output_lines, .ma...@@ -7,5 +7,6 @@ export fn mesh() callconv(.{ .spirv_mesh = .{ .stage_output = .output_lines, .ma
7// compile7// compile
8// output_mode=Obj8// output_mode=Obj
9// backend=selfhosted9// backend=selfhosted
10// target=spirv64-vulkan10// target=spirv32-vulkan
11// emit_bin=false11// cpu_features=vulkan_v1_2+mesh_shading_ext
12// emit_bin=true
test/cases/compile_errors/SpirvType_vulkan_target.zig+1-1
...@@ -48,7 +48,7 @@ comptime {...@@ -48,7 +48,7 @@ comptime {
4848
49// error49// error
50// backend=selfhosted50// backend=selfhosted
51// target=spirv64-vulkan51// target=spirv32-vulkan
52//52//
53// :2:21: error: access qualifier '.read_only' is only valid under the 'opencl' os53// :2:21: error: access qualifier '.read_only' is only valid under the 'opencl' os
54// :14:21: error: invalid 'sampled' field value 'bool'54// :14:21: error: invalid 'sampled' field value 'bool'
test/cases/compile_errors/callconv_spirv_invalid_options.zig+1-1
...@@ -21,7 +21,7 @@ export fn entry4() void {...@@ -21,7 +21,7 @@ export fn entry4() void {
2121
22// error22// error
23// backend=selfhosted23// backend=selfhosted
24// target=spirv64-vulkan24// target=spirv32-vulkan
25//25//
26// :1:28: error: kernel workgroup dimensions must be at least 126// :1:28: error: kernel workgroup dimensions must be at least 1
27// :2:28: error: kernel workgroup dimensions must be at least 127// :2:28: error: kernel workgroup dimensions must be at least 1
test/cases/compile_errors/callconv_spirv_mesh_task_require_vulkan.zig deleted-17
...@@ -1,17 +0,0 @@
1const F1 = fn () callconv(.{ .spirv_task = .{ .x = 1, .y = 1, .z = 1 } }) void;
2const F2 = fn () callconv(.{ .spirv_mesh = .{} }) void;
3export fn entry1() void {
4 const a: F1 = undefined;
5 _ = a;
6}
7export fn entry2() void {
8 const a: F2 = undefined;
9 _ = a;
10}
11
12// error
13// backend=selfhosted
14// target=spirv64-opengl
15//
16// :1:28: error: calling convention 'spirv_task' not supported by compiler backend 'stage2_spirv'
17// :2:28: error: calling convention 'spirv_mesh' not supported by compiler backend 'stage2_spirv'
test/cases/compile_errors/callconv_spirv_on_unsupported_platform.zig+1
...@@ -22,6 +22,7 @@ export fn entry4() void {...@@ -22,6 +22,7 @@ export fn entry4() void {
22// error22// error
23// backend=selfhosted23// backend=selfhosted
24// target=spirv64-opencl24// target=spirv64-opencl
25// cpu_features=opencl_v2+mesh_shading_ext
25//26//
26// :1:28: error: calling convention 'spirv_fragment' not supported by compiler backend 'stage2_spirv'27// :1:28: error: calling convention 'spirv_fragment' not supported by compiler backend 'stage2_spirv'
27// :2:28: error: calling convention 'spirv_vertex' not supported by compiler backend 'stage2_spirv'28// :2:28: error: calling convention 'spirv_vertex' not supported by compiler backend 'stage2_spirv'
test/cases/compile_errors/directly_embedding_spirv_type_in_struct_and_union.zig+1-1
...@@ -25,7 +25,7 @@ export fn d() void {...@@ -25,7 +25,7 @@ export fn d() void {
2525
26// error26// error
27// backend=selfhosted27// backend=selfhosted
28// target=spirv64-vulkan28// target=spirv32-vulkan
29//29//
30// :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct30// :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct
31// :4:8: note: opaque types have unknown size31// :4:8: note: opaque types have unknown size
test/cases/compile_errors/extern_spirv_decoration_validation.zig+1-1
...@@ -8,6 +8,6 @@ comptime {...@@ -8,6 +8,6 @@ comptime {
88
9// error9// error
10// backend=selfhosted10// backend=selfhosted
11// target=spirv64-vulkan11// target=spirv32-vulkan
12//12//
13// :1:45: error: 'flat' decoration requires 'input' address space13// :1:45: error: 'flat' decoration requires 'input' address space
test/cases/compile_errors/spirv_merge_logical_pointers.zig+2-2
...@@ -11,8 +11,8 @@ export fn a() void {...@@ -11,8 +11,8 @@ export fn a() void {
11}11}
1212
13// error13// error
14// target=spirv64-vulkan14// target=spirv32-vulkan
15//15//
16// :9:13: error: value with non-mergable pointer type '*i32' depends on runtime control flow16// :9:13: error: value with non-mergable pointer type '*i32' depends on runtime control flow
17// :9:17: note: runtime control flow here17// :9:17: note: runtime control flow here
18// :9:13: note: pointers with address space 'generic' cannot be returned from a branch on target spirv-vulkan by compiler backend stage2_spirv18// :9:13: note: pointers with address space 'generic' cannot be returned from a branch on target 'spirv-vulkan' by compiler backend 'stage2_spirv'
test/cases/spirv_mergable_pointers.zig+1-1
...@@ -13,5 +13,5 @@ export fn a() void {...@@ -13,5 +13,5 @@ export fn a() void {
13// compile13// compile
14// output_mode=Obj14// output_mode=Obj
15// backend=selfhosted15// backend=selfhosted
16// target=spirv64-vulkan16// target=spirv32-vulkan
17// emit_bin=true17// emit_bin=true
test/src/Cases.zig+12-1
...@@ -357,7 +357,15 @@ fn addFromDirInner(...@@ -357,7 +357,15 @@ fn addFromDirInner(
357 var manifest = try TestManifest.parse(ctx.arena, src);357 var manifest = try TestManifest.parse(ctx.arena, src);
358358
359 const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend);359 const backends = try manifest.getConfigForKeyAlloc(ctx.arena, "backend", Backend);
360 const targets = try manifest.getConfigForKeyAlloc(ctx.arena, "target", std.Target.Query);360 const target_strs = try manifest.getConfigForKeyAlloc(ctx.arena, "target", []const u8);
361 const cpu_features_str = manifest.config_map.get("cpu_features") orelse "";
362 const targets = try ctx.arena.alloc(std.Target.Query, target_strs.len);
363 for (targets, target_strs) |*query, target_str| {
364 query.* = try std.Target.Query.parse(.{
365 .arch_os_abi = target_str,
366 .cpu_features = if (cpu_features_str.len == 0) null else cpu_features_str,
367 });
368 }
361 const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);369 const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);
362 const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);370 const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);
363 const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);371 const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);
...@@ -707,6 +715,8 @@ const TestManifestConfigDefaults = struct {...@@ -707,6 +715,8 @@ const TestManifestConfigDefaults = struct {
707 return "null";715 return "null";
708 } else if (std.mem.eql(u8, key, "imports")) {716 } else if (std.mem.eql(u8, key, "imports")) {
709 return "";717 return "";
718 } else if (std.mem.eql(u8, key, "cpu_features")) {
719 return "";
710 } else unreachable;720 } else unreachable;
711 }721 }
712};722};
...@@ -739,6 +749,7 @@ const TestManifest = struct {...@@ -739,6 +749,7 @@ const TestManifest = struct {
739 .{ "is_test", {} },749 .{ "is_test", {} },
740 .{ "output_mode", {} },750 .{ "output_mode", {} },
741 .{ "target", {} },751 .{ "target", {} },
752 .{ "cpu_features", {} },
742 .{ "c_frontend", {} },753 .{ "c_frontend", {} },
743 .{ "link_libc", {} },754 .{ "link_libc", {} },
744 .{ "backend", {} },755 .{ "backend", {} },