| author | |
| committer | |
| log | 21575a44837861c0c9a7b2b42904afb0933995ea |
| tree | c65c98a1864841211311f2f6824be0f990f02f00 |
| parent | e955d137e7d23eacd6aeb0eeb406d9fd9cfa9526 |
8 files changed, 143 insertions(+), 74 deletions(-)
src/Sema.zig+27-11| ... | ... | @@ -25285,17 +25285,30 @@ fn zirBuiltinExtern( |
| 25285 | 25285 | .location, .descriptor => {}, |
| 25286 | 25286 | }; |
| 25287 | 25287 | |
| 25288 | switch (zcu.getTarget().os.tag) { | |
| 25289 | .vulkan, .opengl => switch (ptr_info.flags.address_space) { | |
| 25290 | .storage_buffer, .uniform, .push_constant => if (ptr_info.flags.size != .one) { | |
| 25291 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 25292 | const msg = try sema.errMsg(ty_src, "extern in '{s}' address space must be a single-item pointer to a struct", .{@tagName(ptr_info.flags.address_space)}); | |
| 25293 | errdefer msg.destroy(sema.gpa); | |
| 25294 | try sema.errNote(ty_src, msg, "wrap the element type in a struct containing a runtime-sized array", .{}); | |
| 25295 | break :msg msg; | |
| 25296 | }); | |
| 25297 | }, | |
| 25298 | else => {}, | |
| 25288 | const target = zcu.getTarget(); | |
| 25289 | switch (target.os.tag) { | |
| 25290 | .vulkan, .opengl => { | |
| 25291 | const pointee = switch (elem_ty.zigTypeTag(zcu)) { | |
| 25292 | .array => elem_ty.childType(zcu), | |
| 25293 | .spirv => if (elem_ty.isSpirvRuntimeArray(zcu)) elem_ty.childType(zcu) else elem_ty, | |
| 25294 | else => elem_ty, | |
| 25295 | }; | |
| 25296 | switch (ptr_info.flags.address_space) { | |
| 25297 | .uniform, | |
| 25298 | .storage_buffer, | |
| 25299 | => if (ptr_info.flags.size != .one or pointee.zigTypeTag(zcu) != .@"struct") { | |
| 25300 | return sema.fail(block, ty_src, "extern in '{t}' address space must be a single-item pointer to a struct", .{ptr_info.flags.address_space}); | |
| 25301 | }, | |
| 25302 | .push_constant => if (ptr_info.flags.size != .one or elem_ty.zigTypeTag(zcu) != .@"struct") { | |
| 25303 | return sema.fail(block, ty_src, "extern in 'push_constant' address space must be a single-item pointer to a struct", .{}); | |
| 25304 | }, | |
| 25305 | .constant => if (target.os.tag == .vulkan and (pointee.zigTypeTag(zcu) != .spirv or pointee.isSpirvRuntimeArray(zcu))) { | |
| 25306 | return sema.fail(block, ty_src, "extern in 'constant' address space must point to an opaque SPIR-V type, or to an array of one", .{}); | |
| 25307 | }, | |
| 25308 | else => if (elem_ty.isSpirvRuntimeArray(zcu)) { | |
| 25309 | return sema.fail(block, ty_src, "SPIR-V runtime array is not allowed in the '{t}' address space", .{ptr_info.flags.address_space}); | |
| 25310 | }, | |
| 25311 | } | |
| 25299 | 25312 | }, |
| 25300 | 25313 | else => {}, |
| 25301 | 25314 | } |
| ... | ... | @@ -25717,6 +25730,9 @@ pub fn explainWhyTypeIsNotExtern( |
| 25717 | 25730 | .spirv => { |
| 25718 | 25731 | assert(ty.isSpirvRuntimeArray(zcu)); |
| 25719 | 25732 | try sema.errNote(src_loc, msg, "SPIR-V runtime arrays must be the last field of an extern struct", .{}); |
| 25733 | if (position == .other) { | |
| 25734 | try sema.errNote(src_loc, msg, "consider enabling the 'runtime_descriptor_array' feature to use the runtime array as the extern pointee", .{}); | |
| 25735 | } | |
| 25720 | 25736 | }, |
| 25721 | 25737 | |
| 25722 | 25738 | .float => try sema.errNote(src_loc, msg, "'{f}' is not extern compatible on this target", .{ty.fmt(pt)}), |
src/Sema/type_resolution.zig+11| ... | ... | @@ -334,6 +334,17 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 334 | 334 | break :msg msg; |
| 335 | 335 | }); |
| 336 | 336 | } |
| 337 | ||
| 338 | const elem_ty: Type = field_ty.childType(zcu); | |
| 339 | if (elem_ty.zigTypeTag(zcu) == .spirv) { | |
| 340 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 341 | const msg = try sema.errMsg(field_ty_src, "cannot embed SPIR-V type '{f}' in struct", .{elem_ty.fmt(pt)}); | |
| 342 | errdefer msg.destroy(gpa); | |
| 343 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | |
| 344 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 345 | break :msg msg; | |
| 346 | }); | |
| 347 | } | |
| 337 | 348 | } else { |
| 338 | 349 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 339 | 350 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed SPIR-V type '{f}' in struct", .{field_ty.fmt(pt)}); |
src/Type.zig+2-1| ... | ... | @@ -3145,7 +3145,8 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool |
| 3145 | 3145 | |
| 3146 | 3146 | .spirv => switch (position) { |
| 3147 | 3147 | .struct_field, .union_field => true, |
| 3148 | .ret_ty, .param_ty, .element, .other => !ty.isSpirvRuntimeArray(zcu), | |
| 3148 | .ret_ty, .param_ty, .element => !ty.isSpirvRuntimeArray(zcu), | |
| 3149 | .other => !ty.isSpirvRuntimeArray(zcu) or zcu.getTarget().cpu.has(.spirv, .runtime_descriptor_array), | |
| 3149 | 3150 | }, |
| 3150 | 3151 | |
| 3151 | 3152 | .pointer => { |
test/cases/compile_errors/directly_embedding_spirv_type_in_struct_and_union.zig+13-6| ... | ... | @@ -3,22 +3,27 @@ const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); |
| 3 | 3 | const Foo = struct { |
| 4 | 4 | s: Sampler, |
| 5 | 5 | }; |
| 6 | const Baz = struct { | |
| 6 | const Bar = struct { | |
| 7 | 7 | a: RuntimeArray, |
| 8 | 8 | }; |
| 9 | const Qux = extern struct { | |
| 9 | const Baz = extern struct { | |
| 10 | 10 | a: RuntimeArray, |
| 11 | 11 | b: u32, |
| 12 | 12 | }; |
| 13 | const Qux = extern struct { _: @SpirvType(.{ .runtime_array = Sampler }) }; | |
| 13 | 14 | export fn a() void { |
| 14 | 15 | var foo: Foo = undefined; |
| 15 | 16 | _ = &foo; |
| 16 | 17 | } |
| 17 | 18 | export fn c() void { |
| 19 | var bar: Bar = undefined; | |
| 20 | _ = &bar; | |
| 21 | } | |
| 22 | export fn d() void { | |
| 18 | 23 | var baz: Baz = undefined; |
| 19 | 24 | _ = &baz; |
| 20 | 25 | } |
| 21 | export fn d() void { | |
| 26 | export fn e() void { | |
| 22 | 27 | var qux: Qux = undefined; |
| 23 | 28 | _ = &qux; |
| 24 | 29 | } |
| ... | ... | @@ -27,9 +32,11 @@ export fn d() void { |
| 27 | 32 | // backend=selfhosted |
| 28 | 33 | // target=spirv32-vulkan |
| 29 | 34 | // |
| 30 | // :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct | |
| 35 | // :4:8: error: cannot directly embed SPIR-V type '@SpirvType(.sampler)' in struct | |
| 31 | 36 | // :4:8: note: opaque types have unknown size |
| 32 | // :6:13: error: non-extern struct cannot contain fields of type 'tmp.RuntimeArray__SpirvType_11' | |
| 37 | // :6:13: error: non-extern struct cannot contain fields of type '@SpirvType(.runtime_array, u32)' | |
| 33 | 38 | // :7:5: note: while checking this field |
| 34 | // :9:20: error: struct field of type 'tmp.RuntimeArray__SpirvType_11' must be the last field | |
| 39 | // :9:20: error: struct field of type '@SpirvType(.runtime_array, u32)' must be the last field | |
| 35 | 40 | // :10:5: note: while checking this field |
| 41 | // :13:32: error: cannot embed SPIR-V type '@SpirvType(.sampler)' in struct | |
| 42 | // :13:32: note: opaque types have unknown size |
test/cases/compile_errors/extern_spirv_storage_buffer_must_be_single_pointer.zig deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | const a = @extern([*]addrspace(.storage_buffer) u32, .{ | |
| 2 | .name = "a", | |
| 3 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, | |
| 4 | }); | |
| 5 | const b = @extern([]addrspace(.uniform) u32, .{ | |
| 6 | .name = "b", | |
| 7 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } }, | |
| 8 | }); | |
| 9 | const c = @extern([*c]addrspace(.push_constant) u32, .{ .name = "c" }); | |
| 10 | comptime { | |
| 11 | _ = a; | |
| 12 | _ = b; | |
| 13 | _ = c; | |
| 14 | } | |
| 15 | ||
| 16 | // error | |
| 17 | // backend=selfhosted | |
| 18 | // target=spirv32-vulkan | |
| 19 | // | |
| 20 | // :1:19: error: extern in 'storage_buffer' address space must be a single-item pointer to a struct | |
| 21 | // :1:19: note: wrap the element type in a struct containing a runtime-sized array | |
| 22 | // :5:19: error: extern in 'uniform' address space must be a single-item pointer to a struct | |
| 23 | // :5:19: note: wrap the element type in a struct containing a runtime-sized array | |
| 24 | // :9:19: error: extern in 'push_constant' address space must be a single-item pointer to a struct | |
| 25 | // :9:19: note: wrap the element type in a struct containing a runtime-sized array |
test/cases/compile_errors/spirv_extern_runtime_descriptor_array.zig created+49| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | const Buffer = extern struct { value: u32 }; | |
| 2 | const Sampler = @SpirvType(.sampler); | |
| 3 | const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); | |
| 4 | const SamplerRuntimeArray = @SpirvType(.{ .runtime_array = Sampler }); | |
| 5 | const BufferRuntimeArray = @SpirvType(.{ .runtime_array = Buffer }); | |
| 6 | ||
| 7 | const a = @extern(*addrspace(.input) const RuntimeArray, .{ .name = "a" }); | |
| 8 | const b = @extern(*addrspace(.uniform) const RuntimeArray, .{ .name = "b" }); | |
| 9 | const c = @extern(*addrspace(.storage_buffer) const RuntimeArray, .{ .name = "c" }); | |
| 10 | const d = @extern(*addrspace(.constant) const RuntimeArray, .{ .name = "d" }); | |
| 11 | const e = @extern(*addrspace(.constant) const SamplerRuntimeArray, .{ | |
| 12 | .name = "samplers", | |
| 13 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, | |
| 14 | }); | |
| 15 | const f = @extern(*addrspace(.storage_buffer) [4]Buffer, .{ | |
| 16 | .name = "sized_buffers", | |
| 17 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } }, | |
| 18 | }); | |
| 19 | const g = @extern(*addrspace(.storage_buffer) BufferRuntimeArray, .{ | |
| 20 | .name = "buffers", | |
| 21 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 2 } }, | |
| 22 | }); | |
| 23 | ||
| 24 | comptime { | |
| 25 | _ = a; | |
| 26 | } | |
| 27 | comptime { | |
| 28 | _ = b; | |
| 29 | } | |
| 30 | comptime { | |
| 31 | _ = c; | |
| 32 | } | |
| 33 | ||
| 34 | export fn main() callconv(.{ .spirv_fragment = .{} }) void { | |
| 35 | _ = &d[0]; | |
| 36 | _ = &e[0]; | |
| 37 | f[0].value = 1; | |
| 38 | g[0].value = 2; | |
| 39 | } | |
| 40 | ||
| 41 | // error | |
| 42 | // backend=selfhosted | |
| 43 | // target=spirv32-vulkan | |
| 44 | // cpu_features=baseline+runtime_descriptor_array | |
| 45 | // | |
| 46 | // :7:19: error: SPIR-V runtime array is not allowed in the 'input' address space | |
| 47 | // :8:19: error: extern in 'uniform' address space must be a single-item pointer to a struct | |
| 48 | // :9:19: error: extern in 'storage_buffer' address space must be a single-item pointer to a struct | |
| 49 | // :10:19: error: extern in 'constant' address space must point to an opaque SPIR-V type, or to an array of one |
test/cases/compile_errors/spirv_extern_var_addrspace.zig+41-5| ... | ... | @@ -1,11 +1,47 @@ |
| 1 | extern var x: u32; | |
| 1 | const Block = extern struct { x: u32 }; | |
| 2 | const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); | |
| 2 | 3 | |
| 3 | export fn main() callconv(.kernel) void { | |
| 4 | _ = x; | |
| 4 | extern var implicit_addrspace: u32; | |
| 5 | ||
| 6 | const many = @extern([*]addrspace(.storage_buffer) u32, .{ | |
| 7 | .name = "many", | |
| 8 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, | |
| 9 | }); | |
| 10 | const push_array = @extern(*addrspace(.push_constant) const [4]Block, .{ .name = "push_array" }); | |
| 11 | const plain_constant = @extern(*addrspace(.constant) const Block, .{ | |
| 12 | .name = "plain_constant", | |
| 13 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } }, | |
| 14 | }); | |
| 15 | const runtime_array = @extern(*addrspace(.storage_buffer) RuntimeArray, .{ | |
| 16 | .name = "runtime_array", | |
| 17 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 2 } }, | |
| 18 | }); | |
| 19 | ||
| 20 | comptime { | |
| 21 | _ = implicit_addrspace; | |
| 22 | } | |
| 23 | comptime { | |
| 24 | _ = many; | |
| 25 | } | |
| 26 | comptime { | |
| 27 | _ = push_array; | |
| 28 | } | |
| 29 | comptime { | |
| 30 | _ = plain_constant; | |
| 31 | } | |
| 32 | comptime { | |
| 33 | _ = runtime_array; | |
| 5 | 34 | } |
| 6 | 35 | |
| 7 | 36 | // error |
| 8 | 37 | // backend=selfhosted |
| 9 | // target=spirv64-vulkan | |
| 38 | // target=spirv32-vulkan | |
| 10 | 39 | // |
| 11 | // :1:15: error: SPIR-V extern variables require an explicit address space | |
| 40 | // :4:32: error: SPIR-V extern variables require an explicit address space | |
| 41 | // :6:22: error: extern in 'storage_buffer' address space must be a single-item pointer to a struct | |
| 42 | // :10:28: error: extern in 'push_constant' address space must be a single-item pointer to a struct | |
| 43 | // :11:32: error: extern in 'constant' address space must point to an opaque SPIR-V type, or to an array of one | |
| 44 | // :15:31: error: extern symbol cannot have type '*addrspace(.storage_buffer) @SpirvType(.runtime_array, u32)' | |
| 45 | // :15:31: note: pointer element type '@SpirvType(.runtime_array, u32)' is not extern compatible | |
| 46 | // :15:31: note: SPIR-V runtime arrays must be the last field of an extern struct | |
| 47 | // :15:31: note: consider enabling the 'runtime_descriptor_array' feature to use the runtime array as the extern pointee |
test/cases/compile_errors/spirv_runtime_array_as_value_type.zig deleted-26| ... | ... | @@ -1,26 +0,0 @@ |
| 1 | const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); | |
| 2 | ||
| 3 | const a = @extern(*addrspace(.storage_buffer) RuntimeArray, .{ | |
| 4 | .name = "a", | |
| 5 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, | |
| 6 | }); | |
| 7 | const b = @extern(*addrspace(.uniform) const RuntimeArray, .{ | |
| 8 | .name = "b", | |
| 9 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } }, | |
| 10 | }); | |
| 11 | ||
| 12 | comptime { | |
| 13 | _ = a; | |
| 14 | _ = b; | |
| 15 | } | |
| 16 | ||
| 17 | // error | |
| 18 | // backend=selfhosted | |
| 19 | // target=spirv32-vulkan | |
| 20 | // | |
| 21 | // :3:19: error: extern symbol cannot have type '*addrspace(.storage_buffer) @SpirvType(.runtime_array, u32)' | |
| 22 | // :3:19: note: pointer element type '@SpirvType(.runtime_array, u32)' is not extern compatible | |
| 23 | // :3:19: note: SPIR-V runtime arrays must be the last field of an extern struct | |
| 24 | // :7:19: error: extern symbol cannot have type '*addrspace(.uniform) const @SpirvType(.runtime_array, u32)' | |
| 25 | // :7:19: note: pointer element type '@SpirvType(.runtime_array, u32)' is not extern compatible | |
| 26 | // :7:19: note: SPIR-V runtime arrays must be the last field of an extern struct |