| 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,17 +25285,30 @@ fn zirBuiltinExtern( |
| 25285 | .location, .descriptor => {}, | 25285 | .location, .descriptor => {}, |
| 25286 | }; | 25286 | }; |
| 25287 | 25287 | ||
| 25288 | switch (zcu.getTarget().os.tag) { | 25288 | const target = zcu.getTarget(); |
| 25289 | .vulkan, .opengl => switch (ptr_info.flags.address_space) { | 25289 | switch (target.os.tag) { |
| 25290 | .storage_buffer, .uniform, .push_constant => if (ptr_info.flags.size != .one) { | 25290 | .vulkan, .opengl => { |
| 25291 | return sema.failWithOwnedErrorMsg(block, msg: { | 25291 | const pointee = switch (elem_ty.zigTypeTag(zcu)) { |
| 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)}); | 25292 | .array => elem_ty.childType(zcu), |
| 25293 | errdefer msg.destroy(sema.gpa); | 25293 | .spirv => if (elem_ty.isSpirvRuntimeArray(zcu)) elem_ty.childType(zcu) else elem_ty, |
| 25294 | try sema.errNote(ty_src, msg, "wrap the element type in a struct containing a runtime-sized array", .{}); | 25294 | else => elem_ty, |
| 25295 | break :msg msg; | 25295 | }; |
| 25296 | }); | 25296 | switch (ptr_info.flags.address_space) { |
| 25297 | }, | 25297 | .uniform, |
| 25298 | else => {}, | 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 | else => {}, | 25313 | else => {}, |
| 25301 | } | 25314 | } |
| ... | @@ -25717,6 +25730,9 @@ pub fn explainWhyTypeIsNotExtern( | ... | @@ -25717,6 +25730,9 @@ pub fn explainWhyTypeIsNotExtern( |
| 25717 | .spirv => { | 25730 | .spirv => { |
| 25718 | assert(ty.isSpirvRuntimeArray(zcu)); | 25731 | assert(ty.isSpirvRuntimeArray(zcu)); |
| 25719 | try sema.errNote(src_loc, msg, "SPIR-V runtime arrays must be the last field of an extern struct", .{}); | 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 | .float => try sema.errNote(src_loc, msg, "'{f}' is not extern compatible on this target", .{ty.fmt(pt)}), | 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,6 +334,17 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 334 | break :msg msg; | 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 | } else { | 348 | } else { |
| 338 | return sema.failWithOwnedErrorMsg(&block, msg: { | 349 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 339 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed SPIR-V type '{f}' in struct", .{field_ty.fmt(pt)}); | 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,7 +3145,8 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool |
| 3145 | 3145 | ||
| 3146 | .spirv => switch (position) { | 3146 | .spirv => switch (position) { |
| 3147 | .struct_field, .union_field => true, | 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 | .pointer => { | 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,22 +3,27 @@ const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); |
| 3 | const Foo = struct { | 3 | const Foo = struct { |
| 4 | s: Sampler, | 4 | s: Sampler, |
| 5 | }; | 5 | }; |
| 6 | const Baz = struct { | 6 | const Bar = struct { |
| 7 | a: RuntimeArray, | 7 | a: RuntimeArray, |
| 8 | }; | 8 | }; |
| 9 | const Qux = extern struct { | 9 | const Baz = extern struct { |
| 10 | a: RuntimeArray, | 10 | a: RuntimeArray, |
| 11 | b: u32, | 11 | b: u32, |
| 12 | }; | 12 | }; |
| 13 | const Qux = extern struct { _: @SpirvType(.{ .runtime_array = Sampler }) }; | ||
| 13 | export fn a() void { | 14 | export fn a() void { |
| 14 | var foo: Foo = undefined; | 15 | var foo: Foo = undefined; |
| 15 | _ = &foo; | 16 | _ = &foo; |
| 16 | } | 17 | } |
| 17 | export fn c() void { | 18 | export fn c() void { |
| 19 | var bar: Bar = undefined; | ||
| 20 | _ = &bar; | ||
| 21 | } | ||
| 22 | export fn d() void { | ||
| 18 | var baz: Baz = undefined; | 23 | var baz: Baz = undefined; |
| 19 | _ = &baz; | 24 | _ = &baz; |
| 20 | } | 25 | } |
| 21 | export fn d() void { | 26 | export fn e() void { |
| 22 | var qux: Qux = undefined; | 27 | var qux: Qux = undefined; |
| 23 | _ = &qux; | 28 | _ = &qux; |
| 24 | } | 29 | } |
| ... | @@ -27,9 +32,11 @@ export fn d() void { | ... | @@ -27,9 +32,11 @@ export fn d() void { |
| 27 | // backend=selfhosted | 32 | // backend=selfhosted |
| 28 | // target=spirv32-vulkan | 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 | // :4:8: note: opaque types have unknown size | 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 | // :7:5: note: while checking this field | 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 | // :10:5: note: while checking this field | 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,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 | extern var implicit_addrspace: u32; |
| 4 | _ = x; | 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 | // error | 36 | // error |
| 8 | // backend=selfhosted | 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 | ||