authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-07-08 18:42:58+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-07-10 11:39:55+03:30
log11d8a359d6447d29d8fda37ee99e0e22e67d352d
tree8a60dcae11d6c64735eb70f69ae7012378e6c613
parent48821ea886e29c5568cd2036cd46ca435550aaa3

spirv: move some compile errors into frontend


8 files changed, 123 insertions(+), 37 deletions(-)

src/Sema.zig+38-5
......@@ -6916,6 +6916,9 @@ fn analyzeCall(
69166916 const is_inline_call = block.isComptime() or inline_requested;
69176917
69186918 if (!is_inline_call) {
6919 if (func_val == null and !func_is_extern and !block.is_typeof and zcu.getTarget().cpu.arch.isSpirV()) {
6920 return sema.fail(block, func_src, "SPIR-V does not support calling function pointers", .{});
6921 }
69196922 if (sema.func_is_naked) return sema.failWithOwnedErrorMsg(block, msg: {
69206923 const msg = try sema.errMsg(call_src, "runtime {s} not allowed in naked function", .{@tagName(operation)});
69216924 errdefer msg.destroy(gpa);
......@@ -15184,6 +15187,23 @@ fn zirAsm(
1518415187 }
1518515188
1518615189 const constraint = sema.code.nullTerminatedString(input.data.constraint);
15190 if (zcu.getTarget().cpu.arch.isSpirV() and std.mem.eql(u8, constraint, "c")) {
15191 const val = sema.resolveValue(arg.*) orelse {
15192 return sema.fail(block, input_src, "assembly input with 'c' constraint must be compile-time known", .{});
15193 };
15194 if (val.isUndef(zcu)) {
15195 return sema.fail(block, input_src, "assembly input with 'c' constraint cannot be undefined", .{});
15196 }
15197 const bad_type: bool = switch (uncasted_arg_ty.zigTypeTag(zcu)) {
15198 .bool, .int, .float, .comptime_int, .comptime_float, .enum_literal => false,
15199 .vector => switch (uncasted_arg_ty.childType(zcu).zigTypeTag(zcu)) {
15200 .bool, .int, .float => false,
15201 else => true,
15202 },
15203 else => true,
15204 };
15205 if (bad_type) return sema.fail(block, input_src, "unsupported type '{f}' for 'c' constraint", .{uncasted_arg_ty.fmt(pt)});
15206 }
1518715207 needed_capacity += (constraint.len + name.len + (2 + 3)) / 4;
1518815208 inputs[arg_i] = .{ .c = constraint, .n = name };
1518915209 }
......@@ -34415,11 +34435,24 @@ pub fn resolveNavPtrModifiers(
3441534435 },
3441634436 };
3441734437 const target = zcu.getTarget();
34418 const addrspace_body = zir_decl.addrspace_body orelse break :as switch (addrspace_ctx) {
34419 .function => target_util.defaultAddressSpace(target, .function),
34420 .variable => target_util.defaultAddressSpace(target, .global_mutable),
34421 .constant => target_util.defaultAddressSpace(target, .global_constant),
34422 else => unreachable,
34438 const addrspace_body = zir_decl.addrspace_body orelse {
34439 if (zir_decl.linkage == .@"extern" and
34440 target.cpu.arch.isSpirV() and
34441 nav_ty.zigTypeTag(zcu) != .@"fn")
34442 {
34443 return sema.fail(
34444 block,
34445 block.src(.{ .node_offset_var_decl_ty = .zero }),
34446 "SPIR-V extern variables require an explicit address space",
34447 .{},
34448 );
34449 }
34450 break :as switch (addrspace_ctx) {
34451 .function => target_util.defaultAddressSpace(target, .function),
34452 .variable => target_util.defaultAddressSpace(target, .global_mutable),
34453 .constant => target_util.defaultAddressSpace(target, .global_constant),
34454 else => unreachable,
34455 };
3442334456 };
3442434457 const addrspace_ref = try sema.resolveInlineBody(block, addrspace_body, decl_inst);
3442534458 break :as try sema.analyzeAsAddressSpace(block, addrspace_src, addrspace_ref, addrspace_ctx);
src/codegen/spirv/CodeGen.zig+9-29
......@@ -2222,14 +2222,10 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
22222222 64 => target.cpu.has(.spirv, .float64),
22232223 else => false,
22242224 };
2225
2226 if (!supported) {
2227 return cg.fail(
2228 "floating point width of {} bits is not supported for the current SPIR-V feature set",
2229 .{bits},
2230 );
2231 }
2232
2225 if (!supported) return cg.fail(
2226 "'{f}' is not supported on the current SPIR-V feature set",
2227 .{ty.fmt(cg.pt)},
2228 );
22332229 return try cg.floatType(bits);
22342230 },
22352231 .array => {
......@@ -4591,10 +4587,6 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode
45914587 const zcu = cg.zcu;
45924588 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
45934589
4594 if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) {
4595 return cg.fail("vector shift with scalar rhs", .{});
4596 }
4597
45984590 const base = try cg.temporary(bin_op.lhs);
45994591 const shift = try cg.temporary(bin_op.rhs);
46004592
......@@ -5425,10 +5417,6 @@ fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
54255417 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
54265418 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
54275419
5428 if (cg.typeOf(extra.lhs).isVector(zcu) and !cg.typeOf(extra.rhs).isVector(zcu)) {
5429 return cg.fail("vector shift with scalar rhs", .{});
5430 }
5431
54325420 const base = try cg.temporary(extra.lhs);
54335421 const shift = try cg.temporary(extra.rhs);
54345422
......@@ -8685,16 +8673,9 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
86858673 const input_ty = cg.typeOf(in.operand);
86868674
86878675 if (std.mem.eql(u8, in.constraint, "c")) {
8688 // constant
8689 const val: Value = .fromInterned(in.operand.toInterned() orelse {
8690 return cg.fail("assembly inputs with 'c' constraint have to be compile-time known", .{});
8691 });
8692
8676 const val: Value = .fromInterned(in.operand.toInterned().?);
86938677 const ip = &zcu.intern_pool;
86948678 const target = cg.pt.zcu.getTarget();
8695 if (ip.indexToKey(val.toIntern()) == .undef) {
8696 return cg.fail("assembly input with 'c' constraint cannot be undefined", .{});
8697 }
86988679 switch (input_ty.zigTypeTag(zcu)) {
86998680 .int => {
87008681 const bits: u64 = switch (input_ty.intInfo(zcu).signedness) {
......@@ -8708,7 +8689,7 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
87088689 16 => @as(u16, @bitCast(val.toFloat(f16, zcu))),
87098690 32 => @as(u32, @bitCast(val.toFloat(f32, zcu))),
87108691 64 => @bitCast(val.toFloat(f64, zcu)),
8711 else => return cg.fail("unsupported float width for 'c' constraint", .{}),
8692 else => unreachable, // Sema rejects unsupported float widths.
87128693 };
87138694 try ass.value_map.put(gpa, in.name, .{ .constant = bits });
87148695 },
......@@ -8719,7 +8700,7 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
87198700 .bool => 0,
87208701 .int => @intCast(child_ty.intInfo(zcu).bits),
87218702 .float => child_ty.floatBits(target),
8722 else => return cg.fail("'c' constraint vector element must be bool, int, or float", .{}),
8703 else => unreachable, // Sema rejects unsupported vector element types.
87238704 };
87248705 const vec_len: usize = @intCast(input_ty.vectorLen(zcu));
87258706 const values = try gpa.alloc(u64, vec_len);
......@@ -8753,7 +8734,7 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
87538734 .enum_literal => |str| try ass.value_map.put(gpa, in.name, .{ .string = str.toSlice(ip) }),
87548735 else => unreachable,
87558736 },
8756 else => return cg.fail("unsupported type for 'c' constraint", .{}),
8737 else => unreachable, // Sema rejects unsupported types.
87578738 }
87588739 } else if (std.mem.eql(u8, in.constraint, "t")) {
87598740 // type
......@@ -8840,8 +8821,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
88408821 const callee_ty = cg.typeOf(air_call.callee);
88418822 const zig_fn_ty = switch (callee_ty.zigTypeTag(zcu)) {
88428823 .@"fn" => callee_ty,
8843 .pointer => return cg.fail("cannot call function pointers", .{}),
8844 else => unreachable,
8824 else => unreachable, // rejected by Sema for SPIR-V
88458825 };
88468826 const fn_info = zcu.typeToFunc(zig_fn_ty).?;
88478827 const return_type = fn_info.return_type;
test/cases/compile_errors/loading_spirv_runtime_array_value.zig+2-2
......@@ -6,11 +6,11 @@ const buf = @extern(*addrspace(.storage_buffer) Buffer, .{
66 .name = "buf",
77 .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } },
88});
9export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
9export fn main() callconv(.kernel) void {
1010 const a = buf.data;
1111 _ = a;
1212}
13export fn main2() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
13export fn main2() callconv(.kernel) void {
1414 const p: *addrspace(.storage_buffer) const RuntimeArray = &buf.data;
1515 _ = p.*;
1616}
test/cases/compile_errors/spirv_c_constraint_errors.zig created+33
......@@ -0,0 +1,33 @@
1export fn not_comptime() callconv(.kernel) void {
2 var runtime: u32 = 42;
3 _ = &runtime;
4 _ = asm ("%ret = OpSpecConstant %ty $default"
5 : [ret] "" (-> u32),
6 : [ty] "t" (u32),
7 [default] "c" (runtime),
8 );
9}
10
11export fn undef_input() callconv(.kernel) void {
12 const x: u32 = undefined;
13 _ = asm ("%ret = OpDummy $x"
14 : [ret] "" (-> u32),
15 : [x] "c" (x),
16 );
17}
18
19export fn unsupported_type() callconv(.kernel) void {
20 const s = "hi";
21 _ = asm ("%ret = OpDummy $x"
22 : [ret] "" (-> u32),
23 : [x] "c" (s),
24 );
25}
26
27// error
28// backend=selfhosted
29// target=spirv32-vulkan
30//
31// :7:26: error: assembly input with 'c' constraint must be compile-time known
32// :15:20: error: assembly input with 'c' constraint cannot be undefined
33// :23:20: error: unsupported type '*const [2:0]u8' for 'c' constraint
test/cases/compile_errors/spirv_cannot_call_function_pointer.zig created+13
......@@ -0,0 +1,13 @@
1fn foo() void {}
2
3export fn main() callconv(.kernel) void {
4 var fp = &foo;
5 fp = &foo;
6 fp();
7}
8
9// error
10// backend=selfhosted
11// target=spirv32-vulkan
12//
13// :6:5: error: SPIR-V does not support calling function pointers
test/cases/compile_errors/spirv_extern_var_addrspace.zig created+11
......@@ -0,0 +1,11 @@
1extern var x: u32;
2
3export fn main() callconv(.kernel) void {
4 _ = x;
5}
6
7// error
8// backend=selfhosted
9// target=spirv64-vulkan
10//
11// :1:15: error: SPIR-V extern variables require an explicit address space
test/cases/compile_errors/spirv_pointer_cast_requires_offset_zero.zig+1-1
......@@ -6,7 +6,7 @@ const a = @extern(*addrspace(.uniform) const A, .{
66 .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } },
77});
88
9export fn main() callconv(.{ .spirv_kernel = .{ .x = 1, .y = 1, .z = 1 } }) void {
9export fn main() callconv(.kernel) void {
1010 const b: *addrspace(.uniform) const B = @ptrCast(a);
1111 _ = &b;
1212}
test/cases/compile_errors/spirv_unsupported_float_width.zig created+16
......@@ -0,0 +1,16 @@
1export fn use_f80() callconv(.kernel) void {
2 var x: f80 = 1.5;
3 _ = &x;
4}
5
6export fn use_f16() callconv(.kernel) void {
7 var x: f16 = 1.5;
8 _ = &x;
9}
10
11// error
12// backend=selfhosted
13// target=spirv32-vulkan
14//
15// :2:5: error: 'f80' is not supported on the current SPIR-V feature set
16// :7:5: error: 'f16' is not supported on the current SPIR-V feature set