| author | |
| committer | |
| log | d7d131c0503ae8a02677faa01d7d518a5441cb6f |
| tree | 2ecd47f8e08c6e63c932843868ef1448c9b98474 |
| parent | 7a9f8dc9393ff4084da6c77d874d08e26897b3cb |
Closes #35240
Fixes #35238
Fixes #35259
Supported types are:
- `OpTypeSampler`
- `OpTypeImage`
- `OpTypeSampledImage`
- `OpTypeRuntimeArray` with indexing and `.len` field
The SPIR-V backend is bit-rotted so behavior tests no longer pass (compiler crashes).
However I've verified the new added tests are passing.56 files changed, 1208 insertions(+), 60 deletions(-)
doc/langref.html.in+44| ... | @@ -5792,6 +5792,50 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val | ... | @@ -5792,6 +5792,50 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val |
| 5792 | <p>Returns an {#link|enum#} type with the properties specified by the arguments.</p> | 5792 | <p>Returns an {#link|enum#} type with the properties specified by the arguments.</p> |
| 5793 | {#header_close#} | 5793 | {#header_close#} |
| 5794 | 5794 | ||
| 5795 | {#header_open|@SpirvType#} | ||
| 5796 | <pre>{#syntax#}@SpirvType(comptime options: std.lang.Type.Spirv) type{#endsyntax#}</pre> | ||
| 5797 | <p> | ||
| 5798 | Returns a SPIR-V type with the properties specified by the arguments. | ||
| 5799 | </p> | ||
| 5800 | <div class="table-wrapper"> | ||
| 5801 | <table> | ||
| 5802 | <thead> | ||
| 5803 | <tr> | ||
| 5804 | <th scope="col">Tag</th> | ||
| 5805 | <th scope="col">SPIR-V Equivalent</th> | ||
| 5806 | <th scope="col">Description</th> | ||
| 5807 | </tr> | ||
| 5808 | </thead> | ||
| 5809 | <tbody> | ||
| 5810 | <tr> | ||
| 5811 | <th scope="row"><code>.sampler</code></th> | ||
| 5812 | <td><code>OpTypeSampler</code></td> | ||
| 5813 | <td>An opaque sampler</td> | ||
| 5814 | </tr> | ||
| 5815 | <tr> | ||
| 5816 | <th scope="row"><code>.image</code></th> | ||
| 5817 | <td><code>OpTypeImage</code></td> | ||
| 5818 | <td>An opaque image</td> | ||
| 5819 | </tr> | ||
| 5820 | <tr> | ||
| 5821 | <th scope="row"><code>.sampled_image</code></th> | ||
| 5822 | <td><code>OpTypeSampledImage</code></td> | ||
| 5823 | <td>An opaque image combined with a sampler</td> | ||
| 5824 | </tr> | ||
| 5825 | <tr> | ||
| 5826 | <th scope="row"><code>.runtime_array</code></th> | ||
| 5827 | <td><code>OpTypeRuntimeArray</code></td> | ||
| 5828 | <td> | ||
| 5829 | An array whose length is determined at runtime. | ||
| 5830 | The resulting type supports indexing and exposes a {#syntax#}.len{#endsyntax#} field. | ||
| 5831 | It may only appear as the last field of an {#link|extern struct#}. | ||
| 5832 | </td> | ||
| 5833 | </tr> | ||
| 5834 | </tbody> | ||
| 5835 | </table> | ||
| 5836 | </div> | ||
| 5837 | {#header_close#} | ||
| 5838 | |||
| 5795 | {#header_open|@typeInfo#} | 5839 | {#header_open|@typeInfo#} |
| 5796 | <pre>{#syntax#}@typeInfo(comptime T: type) std.lang.Type{#endsyntax#}</pre> | 5840 | <pre>{#syntax#}@typeInfo(comptime T: type) std.lang.Type{#endsyntax#}</pre> |
| 5797 | <p> | 5841 | <p> |
lib/std/Target.zig+2-1| ... | @@ -2341,7 +2341,8 @@ pub fn supportsAddressSpace( | ... | @@ -2341,7 +2341,8 @@ pub fn supportsAddressSpace( |
| 2341 | .lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2), | 2341 | .lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2), |
| 2342 | 2342 | ||
| 2343 | .global, .local, .shared => is_gpu, | 2343 | .global, .local, .shared => is_gpu, |
| 2344 | .constant => is_gpu and (context == null or context == .constant), | 2344 | .constant => (is_gpu and (context == null or context == .constant)) or |
| 2345 | (is_spirv and (context == null or context == .constant or context == .pointer)), | ||
| 2345 | .param => is_nvptx, | 2346 | .param => is_nvptx, |
| 2346 | .input, .output, .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => is_spirv, | 2347 | .input, .output, .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => is_spirv, |
| 2347 | }; | 2348 | }; |
lib/std/hash/auto_hash.zig+1| ... | @@ -76,6 +76,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { | ... | @@ -76,6 +76,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { |
| 76 | switch (@typeInfo(Key)) { | 76 | switch (@typeInfo(Key)) { |
| 77 | .noreturn, | 77 | .noreturn, |
| 78 | .@"opaque", | 78 | .@"opaque", |
| 79 | .spirv, | ||
| 79 | .undefined, | 80 | .undefined, |
| 80 | .null, | 81 | .null, |
| 81 | .comptime_float, | 82 | .comptime_float, |
lib/std/lang.zig+54| ... | @@ -578,6 +578,7 @@ pub const Type = union(enum) { | ... | @@ -578,6 +578,7 @@ pub const Type = union(enum) { |
| 578 | @"anyframe": AnyFrame, | 578 | @"anyframe": AnyFrame, |
| 579 | vector: Vector, | 579 | vector: Vector, |
| 580 | enum_literal, | 580 | enum_literal, |
| 581 | spirv: Spirv, | ||
| 581 | 582 | ||
| 582 | /// This data structure is used by the Zig language code generation and | 583 | /// This data structure is used by the Zig language code generation and |
| 583 | /// therefore must be kept in sync with the compiler implementation. | 584 | /// therefore must be kept in sync with the compiler implementation. |
| ... | @@ -781,6 +782,59 @@ pub const Type = union(enum) { | ... | @@ -781,6 +782,59 @@ pub const Type = union(enum) { |
| 781 | }; | 782 | }; |
| 782 | }; | 783 | }; |
| 783 | 784 | ||
| 785 | /// This data structure is used by the Zig language code generation and | ||
| 786 | /// therefore must be kept in sync with the compiler implementation. | ||
| 787 | pub const Spirv = union(enum(u2)) { | ||
| 788 | sampler, | ||
| 789 | image: Image, | ||
| 790 | sampled_image: type, | ||
| 791 | runtime_array: type, | ||
| 792 | |||
| 793 | pub const Image = struct { | ||
| 794 | usage: Usage, | ||
| 795 | format: Format, | ||
| 796 | dim: Dimensionality, | ||
| 797 | depth: Depth, | ||
| 798 | access: Access, | ||
| 799 | arrayed: bool, | ||
| 800 | multisampled: bool, | ||
| 801 | |||
| 802 | pub const Usage = union(enum(u2)) { | ||
| 803 | unknown: type, | ||
| 804 | sampled: type, | ||
| 805 | storage, | ||
| 806 | }; | ||
| 807 | |||
| 808 | pub const Format = enum(u4) { | ||
| 809 | unknown, | ||
| 810 | rgba32f, | ||
| 811 | rgba32i, | ||
| 812 | rgba32u, | ||
| 813 | rgba16f, | ||
| 814 | rgba16i, | ||
| 815 | rgba16u, | ||
| 816 | rgba8unorm, | ||
| 817 | rgba8snorm, | ||
| 818 | rgba8i, | ||
| 819 | rgba8u, | ||
| 820 | r32f, | ||
| 821 | r32i, | ||
| 822 | r32u, | ||
| 823 | }; | ||
| 824 | |||
| 825 | pub const Dimensionality = enum(u2) { | ||
| 826 | @"1d", | ||
| 827 | @"2d", | ||
| 828 | @"3d", | ||
| 829 | cube, | ||
| 830 | }; | ||
| 831 | |||
| 832 | pub const Depth = enum(u2) { unknown, depth, not_depth }; | ||
| 833 | |||
| 834 | pub const Access = enum(u2) { unknown, read_only, write_only, read_write }; | ||
| 835 | }; | ||
| 836 | }; | ||
| 837 | |||
| 784 | /// This data structure is used by the Zig language code generation and | 838 | /// This data structure is used by the Zig language code generation and |
| 785 | /// therefore must be kept in sync with the compiler implementation. | 839 | /// therefore must be kept in sync with the compiler implementation. |
| 786 | pub const Opaque = struct { | 840 | pub const Opaque = struct { |
lib/std/mem.zig+1| ... | @@ -352,6 +352,7 @@ pub fn zeroes(comptime T: type) T { | ... | @@ -352,6 +352,7 @@ pub fn zeroes(comptime T: type) T { |
| 352 | .noreturn, | 352 | .noreturn, |
| 353 | .undefined, | 353 | .undefined, |
| 354 | .@"opaque", | 354 | .@"opaque", |
| 355 | .spirv, | ||
| 355 | .frame, | 356 | .frame, |
| 356 | .@"anyframe", | 357 | .@"anyframe", |
| 357 | => { | 358 | => { |
lib/std/start.zig+3-1| ... | @@ -19,7 +19,9 @@ comptime { | ... | @@ -19,7 +19,9 @@ comptime { |
| 19 | // decls there get run. | 19 | // decls there get run. |
| 20 | _ = root; | 20 | _ = root; |
| 21 | 21 | ||
| 22 | if (builtin.output_mode == .Lib and builtin.link_mode == .dynamic) { | 22 | if (builtin.zig_backend == .stage2_spirv) { |
| 23 | // Do nothing | ||
| 24 | } else if (builtin.output_mode == .Lib and builtin.link_mode == .dynamic) { | ||
| 23 | const dll_main_crt_startup = if (builtin.abi.isGnu()) "DllMainCRTStartup" else "_DllMainCRTStartup"; | 25 | const dll_main_crt_startup = if (builtin.abi.isGnu()) "DllMainCRTStartup" else "_DllMainCRTStartup"; |
| 24 | if (native_os == .windows and !builtin.link_libc and !@hasDecl(root, dll_main_crt_startup)) { | 26 | if (native_os == .windows and !builtin.link_libc and !@hasDecl(root, dll_main_crt_startup)) { |
| 25 | @export(&DllMainCRTStartup, .{ .name = dll_main_crt_startup }); | 27 | @export(&DllMainCRTStartup, .{ .name = dll_main_crt_startup }); |
lib/std/testing.zig+2| ... | @@ -79,6 +79,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { | ... | @@ -79,6 +79,7 @@ fn expectEqualInner(comptime T: type, expected: T, actual: T) !void { |
| 79 | switch (@typeInfo(@TypeOf(actual))) { | 79 | switch (@typeInfo(@TypeOf(actual))) { |
| 80 | .noreturn, | 80 | .noreturn, |
| 81 | .@"opaque", | 81 | .@"opaque", |
| 82 | .spirv, | ||
| 82 | .frame, | 83 | .frame, |
| 83 | .@"anyframe", | 84 | .@"anyframe", |
| 84 | => @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"), | 85 | => @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"), |
| ... | @@ -737,6 +738,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe | ... | @@ -737,6 +738,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe |
| 737 | switch (@typeInfo(@TypeOf(actual))) { | 738 | switch (@typeInfo(@TypeOf(actual))) { |
| 738 | .noreturn, | 739 | .noreturn, |
| 739 | .@"opaque", | 740 | .@"opaque", |
| 741 | .spirv, | ||
| 740 | .frame, | 742 | .frame, |
| 741 | .@"anyframe", | 743 | .@"anyframe", |
| 742 | => @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"), | 744 | => @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"), |
lib/std/zig/AstGen.zig+10| ... | @@ -9327,6 +9327,16 @@ fn builtinCall( | ... | @@ -9327,6 +9327,16 @@ fn builtinCall( |
| 9327 | }); | 9327 | }); |
| 9328 | return rvalue(gz, ri, result, node); | 9328 | return rvalue(gz, ri, result, node); |
| 9329 | }, | 9329 | }, |
| 9330 | .SpirvType => { | ||
| 9331 | const spirv_type_options_ty = try gz.addStdLangValue(node, .spirv_type_options); | ||
| 9332 | const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = spirv_type_options_ty } }, params[0], .type); | ||
| 9333 | const result = try gz.addExtendedPayload(.reify_spirv_type, Zir.Inst.ReifySpirvType{ | ||
| 9334 | .src_line = gz.astgen.source_line, | ||
| 9335 | .node = node, | ||
| 9336 | .operand = operand, | ||
| 9337 | }); | ||
| 9338 | return rvalue(gz, ri, result, node); | ||
| 9339 | }, | ||
| 9330 | 9340 | ||
| 9331 | .panic => { | 9341 | .panic => { |
| 9332 | try emitDbgNode(gz, node); | 9342 | try emitDbgNode(gz, node); |
lib/std/zig/AstRlAnnotate.zig+4| ... | @@ -1079,6 +1079,10 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. | ... | @@ -1079,6 +1079,10 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast. |
| 1079 | _ = try astrl.expr(args[3], block, ResultInfo.type_only); | 1079 | _ = try astrl.expr(args[3], block, ResultInfo.type_only); |
| 1080 | return false; | 1080 | return false; |
| 1081 | }, | 1081 | }, |
| 1082 | .SpirvType => { | ||
| 1083 | _ = try astrl.expr(args[0], block, ResultInfo.type_only); | ||
| 1084 | return false; | ||
| 1085 | }, | ||
| 1082 | .Vector => { | 1086 | .Vector => { |
| 1083 | _ = try astrl.expr(args[0], block, ResultInfo.type_only); | 1087 | _ = try astrl.expr(args[0], block, ResultInfo.type_only); |
| 1084 | _ = try astrl.expr(args[1], block, ResultInfo.type_only); | 1088 | _ = try astrl.expr(args[1], block, ResultInfo.type_only); |
lib/std/zig/BuiltinFn.zig+8| ... | @@ -114,6 +114,7 @@ pub const Tag = enum { | ... | @@ -114,6 +114,7 @@ pub const Tag = enum { |
| 114 | Struct, | 114 | Struct, |
| 115 | Union, | 115 | Union, |
| 116 | Enum, | 116 | Enum, |
| 117 | SpirvType, | ||
| 117 | type_info, | 118 | type_info, |
| 118 | type_name, | 119 | type_name, |
| 119 | TypeOf, | 120 | TypeOf, |
| ... | @@ -971,6 +972,13 @@ pub const list = list: { | ... | @@ -971,6 +972,13 @@ pub const list = list: { |
| 971 | .param_count = 4, | 972 | .param_count = 4, |
| 972 | }, | 973 | }, |
| 973 | }, | 974 | }, |
| 975 | .{ | ||
| 976 | "@SpirvType", | ||
| 977 | .{ | ||
| 978 | .tag = .SpirvType, | ||
| 979 | .param_count = 1, | ||
| 980 | }, | ||
| 981 | }, | ||
| 974 | .{ | 982 | .{ |
| 975 | "@typeInfo", | 983 | "@typeInfo", |
| 976 | .{ | 984 | .{ |
lib/std/zig/Zir.zig+14| ... | @@ -2055,6 +2055,9 @@ pub const Inst = struct { | ... | @@ -2055,6 +2055,9 @@ pub const Inst = struct { |
| 2055 | /// `operand` is payload index to `ReifyEnum`. | 2055 | /// `operand` is payload index to `ReifyEnum`. |
| 2056 | /// `small` contains `NameStrategy`. | 2056 | /// `small` contains `NameStrategy`. |
| 2057 | reify_enum, | 2057 | reify_enum, |
| 2058 | /// Implements builtin `@SpirvType`. | ||
| 2059 | /// `operand` is payload index to `ReifyFn`. | ||
| 2060 | reify_spirv_type, | ||
| 2058 | /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins. | 2061 | /// Implements the `@cmpxchgStrong` and `@cmpxchgWeak` builtins. |
| 2059 | /// `small` 0=>weak 1=>strong | 2062 | /// `small` 0=>weak 1=>strong |
| 2060 | /// `operand` is payload index to `Cmpxchg`. | 2063 | /// `operand` is payload index to `Cmpxchg`. |
| ... | @@ -3269,6 +3272,14 @@ pub const Inst = struct { | ... | @@ -3269,6 +3272,14 @@ pub const Inst = struct { |
| 3269 | field_values: Ref, | 3272 | field_values: Ref, |
| 3270 | }; | 3273 | }; |
| 3271 | 3274 | ||
| 3275 | pub const ReifySpirvType = struct { | ||
| 3276 | src_line: u32, | ||
| 3277 | /// This node is absolute, because `reify` instructions are tracked across updates, and | ||
| 3278 | /// this simplifies the logic for getting source locations for types. | ||
| 3279 | node: Ast.Node.Index, | ||
| 3280 | operand: Ref, | ||
| 3281 | }; | ||
| 3282 | |||
| 3272 | /// Trailing: | 3283 | /// Trailing: |
| 3273 | /// 0. multi_cases_len: u32, // If has_multi_cases is set. | 3284 | /// 0. multi_cases_len: u32, // If has_multi_cases is set. |
| 3274 | /// 1. payload_capture_placeholder: Inst.Index, // If payload_capture_inst_is_placeholder is set. | 3285 | /// 1. payload_capture_placeholder: Inst.Index, // If payload_capture_inst_is_placeholder is set. |
| ... | @@ -3584,6 +3595,7 @@ pub const Inst = struct { | ... | @@ -3584,6 +3595,7 @@ pub const Inst = struct { |
| 3584 | fn_attributes, | 3595 | fn_attributes, |
| 3585 | container_layout, | 3596 | container_layout, |
| 3586 | enum_mode, | 3597 | enum_mode, |
| 3598 | spirv_type_options, | ||
| 3587 | // Values | 3599 | // Values |
| 3588 | calling_convention_c, | 3600 | calling_convention_c, |
| 3589 | calling_convention_inline, | 3601 | calling_convention_inline, |
| ... | @@ -4389,6 +4401,7 @@ fn findTrackableInner( | ... | @@ -4389,6 +4401,7 @@ fn findTrackableInner( |
| 4389 | .reify_enum, | 4401 | .reify_enum, |
| 4390 | .reify_struct, | 4402 | .reify_struct, |
| 4391 | .reify_union, | 4403 | .reify_union, |
| 4404 | .reify_spirv_type, | ||
| 4392 | => return contents.other.append(gpa, inst), | 4405 | => return contents.other.append(gpa, inst), |
| 4393 | 4406 | ||
| 4394 | // Type declarations need tracking. | 4407 | // Type declarations need tracking. |
| ... | @@ -5181,6 +5194,7 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void { | ... | @@ -5181,6 +5194,7 @@ pub fn assertTrackable(zir: Zir, inst_idx: Zir.Inst.Index) void { |
| 5181 | .reify_enum, | 5194 | .reify_enum, |
| 5182 | .reify_struct, | 5195 | .reify_struct, |
| 5183 | .reify_union, | 5196 | .reify_union, |
| 5197 | .reify_spirv_type, | ||
| 5184 | => {}, // tracked in order, as the owner instructions of explicit container types | 5198 | => {}, // tracked in order, as the owner instructions of explicit container types |
| 5185 | else => unreachable, // assertion failure; not trackable | 5199 | else => unreachable, // assertion failure; not trackable |
| 5186 | }, | 5200 | }, |
lib/std/zon/Serializer.zig+1| ... | @@ -854,6 +854,7 @@ fn canSerializeTypeInner( | ... | @@ -854,6 +854,7 @@ fn canSerializeTypeInner( |
| 854 | .frame, | 854 | .frame, |
| 855 | .@"anyframe", | 855 | .@"anyframe", |
| 856 | .@"opaque", | 856 | .@"opaque", |
| 857 | .spirv, | ||
| 857 | => false, | 858 | => false, |
| 858 | 859 | ||
| 859 | .@"enum" => |@"enum"| @"enum".mode == .exhaustive, | 860 | .@"enum" => |@"enum"| @"enum".mode == .exhaustive, |
lib/std/zon/parse.zig+1| ... | @@ -1213,6 +1213,7 @@ fn canParseTypeInner( | ... | @@ -1213,6 +1213,7 @@ fn canParseTypeInner( |
| 1213 | .frame, | 1213 | .frame, |
| 1214 | .@"anyframe", | 1214 | .@"anyframe", |
| 1215 | .@"opaque", | 1215 | .@"opaque", |
| 1216 | .spirv, | ||
| 1216 | .comptime_int, | 1217 | .comptime_int, |
| 1217 | .comptime_float, | 1218 | .comptime_float, |
| 1218 | .enum_literal, | 1219 | .enum_literal, |
src/Air.zig+7| ... | @@ -918,6 +918,11 @@ pub const Inst = struct { | ... | @@ -918,6 +918,11 @@ pub const Inst = struct { |
| 918 | /// Uses the `ty` field. | 918 | /// Uses the `ty` field. |
| 919 | c_va_start, | 919 | c_va_start, |
| 920 | 920 | ||
| 921 | /// Implements `.len` field for `@SpirvType(.{ .runtime_array = T })`. | ||
| 922 | /// Result type is always `u32`. | ||
| 923 | /// Uses the `ty_pl` field, payload is `StructField`. | ||
| 924 | spirv_runtime_array_len, | ||
| 925 | |||
| 921 | /// Implements @workItemId builtin. | 926 | /// Implements @workItemId builtin. |
| 922 | /// Result type is always `u32` | 927 | /// Result type is always `u32` |
| 923 | /// Uses the `pl_op` field, payload is the dimension to get the work item id for. | 928 | /// Uses the `pl_op` field, payload is the dimension to get the work item id for. |
| ... | @@ -1793,6 +1798,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) | ... | @@ -1793,6 +1798,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool) |
| 1793 | .work_item_id, | 1798 | .work_item_id, |
| 1794 | .work_group_size, | 1799 | .work_group_size, |
| 1795 | .work_group_id, | 1800 | .work_group_id, |
| 1801 | .spirv_runtime_array_len, | ||
| 1796 | => return .u32, | 1802 | => return .u32, |
| 1797 | 1803 | ||
| 1798 | .legalize_compiler_rt_call => return datas[@intFromEnum(inst)].legalize_compiler_rt_call.func.returnType(), | 1804 | .legalize_compiler_rt_call => return datas[@intFromEnum(inst)].legalize_compiler_rt_call.func.returnType(), |
| ... | @@ -2056,6 +2062,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { | ... | @@ -2056,6 +2062,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool { |
| 2056 | .work_group_size, | 2062 | .work_group_size, |
| 2057 | .work_group_id, | 2063 | .work_group_id, |
| 2058 | .legalize_vec_elem_val, | 2064 | .legalize_vec_elem_val, |
| 2065 | .spirv_runtime_array_len, | ||
| 2059 | => false, | 2066 | => false, |
| 2060 | 2067 | ||
| 2061 | .is_non_null_ptr, .is_null_ptr, .is_non_err_ptr, .is_err_ptr => air.typeOf(data.un_op, ip).isVolatilePtrIp(ip), | 2068 | .is_non_null_ptr, .is_null_ptr, .is_non_err_ptr, .is_err_ptr => air.typeOf(data.un_op, ip).isVolatilePtrIp(ip), |
src/Air/Legalize.zig+1| ... | @@ -908,6 +908,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { | ... | @@ -908,6 +908,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void { |
| 908 | .legalize_vec_elem_val, | 908 | .legalize_vec_elem_val, |
| 909 | .legalize_vec_store_elem, | 909 | .legalize_vec_store_elem, |
| 910 | .legalize_compiler_rt_call, | 910 | .legalize_compiler_rt_call, |
| 911 | .spirv_runtime_array_len, | ||
| 911 | => {}, | 912 | => {}, |
| 912 | } | 913 | } |
| 913 | } | 914 | } |
src/Air/Liveness.zig+1-1| ... | @@ -673,7 +673,7 @@ fn analyzeInst( | ... | @@ -673,7 +673,7 @@ fn analyzeInst( |
| 673 | const extra = a.air.extraData(Air.UnionInit, inst_datas[@intFromEnum(inst)].ty_pl.payload).data; | 673 | const extra = a.air.extraData(Air.UnionInit, inst_datas[@intFromEnum(inst)].ty_pl.payload).data; |
| 674 | return analyzeOperands(a, pass, data, inst, .{ extra.init, .none, .none }); | 674 | return analyzeOperands(a, pass, data, inst, .{ extra.init, .none, .none }); |
| 675 | }, | 675 | }, |
| 676 | .struct_field_ptr, .struct_field_val => { | 676 | .struct_field_ptr, .struct_field_val, .spirv_runtime_array_len => { |
| 677 | const extra = a.air.extraData(Air.StructField, inst_datas[@intFromEnum(inst)].ty_pl.payload).data; | 677 | const extra = a.air.extraData(Air.StructField, inst_datas[@intFromEnum(inst)].ty_pl.payload).data; |
| 678 | return analyzeOperands(a, pass, data, inst, .{ extra.struct_operand, .none, .none }); | 678 | return analyzeOperands(a, pass, data, inst, .{ extra.struct_operand, .none, .none }); |
| 679 | }, | 679 | }, |
src/Air/Liveness/Verify.zig+1-1| ... | @@ -191,7 +191,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { | ... | @@ -191,7 +191,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void { |
| 191 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; | 191 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 192 | try self.verifyInstOperands(inst, .{ extra.init, .none, .none }); | 192 | try self.verifyInstOperands(inst, .{ extra.init, .none, .none }); |
| 193 | }, | 193 | }, |
| 194 | .struct_field_ptr, .struct_field_val => { | 194 | .struct_field_ptr, .struct_field_val, .spirv_runtime_array_len => { |
| 195 | const ty_pl = data[@intFromEnum(inst)].ty_pl; | 195 | const ty_pl = data[@intFromEnum(inst)].ty_pl; |
| 196 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; | 196 | const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| 197 | try self.verifyInstOperands(inst, .{ extra.struct_operand, .none, .none }); | 197 | try self.verifyInstOperands(inst, .{ extra.struct_operand, .none, .none }); |
src/Air/print.zig+1| ... | @@ -306,6 +306,7 @@ const Writer = struct { | ... | @@ -306,6 +306,7 @@ const Writer = struct { |
| 306 | 306 | ||
| 307 | .struct_field_ptr => try w.writeStructField(s, inst), | 307 | .struct_field_ptr => try w.writeStructField(s, inst), |
| 308 | .struct_field_val => try w.writeStructField(s, inst), | 308 | .struct_field_val => try w.writeStructField(s, inst), |
| 309 | .spirv_runtime_array_len => try w.writeStructField(s, inst), | ||
| 309 | .inferred_alloc => @panic("TODO"), | 310 | .inferred_alloc => @panic("TODO"), |
| 310 | .inferred_alloc_comptime => @panic("TODO"), | 311 | .inferred_alloc_comptime => @panic("TODO"), |
| 311 | .assembly => try w.writeAssembly(s, inst), | 312 | .assembly => try w.writeAssembly(s, inst), |
src/InternPool.zig+112-1| ... | @@ -1983,6 +1983,7 @@ pub const Key = union(enum) { | ... | @@ -1983,6 +1983,7 @@ pub const Key = union(enum) { |
| 1983 | union_type: ContainerType, | 1983 | union_type: ContainerType, |
| 1984 | opaque_type: ContainerType, | 1984 | opaque_type: ContainerType, |
| 1985 | enum_type: ContainerType, | 1985 | enum_type: ContainerType, |
| 1986 | spirv_type: SpirvType, | ||
| 1986 | func_type: FuncType, | 1987 | func_type: FuncType, |
| 1987 | error_set_type: ErrorSetType, | 1988 | error_set_type: ErrorSetType, |
| 1988 | /// The payload is the function body, either a `func_decl` or `func_instance`. | 1989 | /// The payload is the function body, either a `func_decl` or `func_instance`. |
| ... | @@ -2146,6 +2147,13 @@ pub const Key = union(enum) { | ... | @@ -2146,6 +2147,13 @@ pub const Key = union(enum) { |
| 2146 | }; | 2147 | }; |
| 2147 | }; | 2148 | }; |
| 2148 | 2149 | ||
| 2150 | pub const SpirvType = struct { | ||
| 2151 | /// A `spirv_reify` instruction. | ||
| 2152 | zir_index: TrackedInst.Index, | ||
| 2153 | /// A hash of this type's attributes generated by Sema. | ||
| 2154 | type_hash: u64, | ||
| 2155 | }; | ||
| 2156 | |||
| 2149 | pub const FuncType = struct { | 2157 | pub const FuncType = struct { |
| 2150 | param_types: Index.Slice, | 2158 | param_types: Index.Slice, |
| 2151 | return_type: Index, | 2159 | return_type: Index, |
| ... | @@ -2590,6 +2598,7 @@ pub const Key = union(enum) { | ... | @@ -2590,6 +2598,7 @@ pub const Key = union(enum) { |
| 2590 | .opt_type, | 2598 | .opt_type, |
| 2591 | .anyframe_type, | 2599 | .anyframe_type, |
| 2592 | .error_union_type, | 2600 | .error_union_type, |
| 2601 | .spirv_type, | ||
| 2593 | .simple_type, | 2602 | .simple_type, |
| 2594 | .simple_value, | 2603 | .simple_value, |
| 2595 | .opt, | 2604 | .opt, |
| ... | @@ -2841,6 +2850,10 @@ pub const Key = union(enum) { | ... | @@ -2841,6 +2850,10 @@ pub const Key = union(enum) { |
| 2841 | const b_info = b.error_union_type; | 2850 | const b_info = b.error_union_type; |
| 2842 | return std.meta.eql(a_info, b_info); | 2851 | return std.meta.eql(a_info, b_info); |
| 2843 | }, | 2852 | }, |
| 2853 | .spirv_type => |a_info| { | ||
| 2854 | const b_info = b.spirv_type; | ||
| 2855 | return std.meta.eql(a_info, b_info); | ||
| 2856 | }, | ||
| 2844 | .simple_type => |a_info| { | 2857 | .simple_type => |a_info| { |
| 2845 | const b_info = b.simple_type; | 2858 | const b_info = b.simple_type; |
| 2846 | return a_info == b_info; | 2859 | return a_info == b_info; |
| ... | @@ -3130,6 +3143,7 @@ pub const Key = union(enum) { | ... | @@ -3130,6 +3143,7 @@ pub const Key = union(enum) { |
| 3130 | .simple_type, | 3143 | .simple_type, |
| 3131 | .struct_type, | 3144 | .struct_type, |
| 3132 | .union_type, | 3145 | .union_type, |
| 3146 | .spirv_type, | ||
| 3133 | .opaque_type, | 3147 | .opaque_type, |
| 3134 | .enum_type, | 3148 | .enum_type, |
| 3135 | .tuple_type, | 3149 | .tuple_type, |
| ... | @@ -3877,6 +3891,14 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType { | ... | @@ -3877,6 +3891,14 @@ pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType { |
| 3877 | }; | 3891 | }; |
| 3878 | } | 3892 | } |
| 3879 | 3893 | ||
| 3894 | pub fn loadSpirvType(ip: *const InternPool, index: Index) Tag.TypeSpirv { | ||
| 3895 | const unwrapped_index = index.unwrap(ip); | ||
| 3896 | const item = unwrapped_index.getItem(ip); | ||
| 3897 | assert(item.tag == .type_spirv); | ||
| 3898 | const extra = extraData(unwrapped_index.getExtra(ip), Tag.TypeSpirv, item.data); | ||
| 3899 | return extra; | ||
| 3900 | } | ||
| 3901 | |||
| 3880 | pub const Item = struct { | 3902 | pub const Item = struct { |
| 3881 | tag: Tag, | 3903 | tag: Tag, |
| 3882 | /// The doc comments on the respective Tag explain how to interpret this. | 3904 | /// The doc comments on the respective Tag explain how to interpret this. |
| ... | @@ -4214,6 +4236,8 @@ pub const Index = enum(u32) { | ... | @@ -4214,6 +4236,8 @@ pub const Index = enum(u32) { |
| 4214 | type_enum_nonexhaustive: struct { data: *Tag.TypeEnum }, | 4236 | type_enum_nonexhaustive: struct { data: *Tag.TypeEnum }, |
| 4215 | type_opaque: struct { data: *Tag.TypeOpaque }, | 4237 | type_opaque: struct { data: *Tag.TypeOpaque }, |
| 4216 | 4238 | ||
| 4239 | type_spirv: struct { data: *Tag.TypeSpirv }, | ||
| 4240 | |||
| 4217 | undef: DataIsIndex, | 4241 | undef: DataIsIndex, |
| 4218 | simple_value: void, | 4242 | simple_value: void, |
| 4219 | ptr_nav: struct { data: *PtrNav }, | 4243 | ptr_nav: struct { data: *PtrNav }, |
| ... | @@ -4841,6 +4865,10 @@ pub const Tag = enum(u8) { | ... | @@ -4841,6 +4865,10 @@ pub const Tag = enum(u8) { |
| 4841 | /// data is extra index of `TypeEnum`. | 4865 | /// data is extra index of `TypeEnum`. |
| 4842 | type_enum_nonexhaustive, | 4866 | type_enum_nonexhaustive, |
| 4843 | 4867 | ||
| 4868 | /// An spirv type. | ||
| 4869 | /// data is index of `TypeSpirv` in extra. | ||
| 4870 | type_spirv, | ||
| 4871 | |||
| 4844 | /// An opaque type. | 4872 | /// An opaque type. |
| 4845 | /// data is extra index of `TypeOpaque`. | 4873 | /// data is extra index of `TypeOpaque`. |
| 4846 | type_opaque, | 4874 | type_opaque, |
| ... | @@ -5231,6 +5259,7 @@ pub const Tag = enum(u8) { | ... | @@ -5231,6 +5259,7 @@ pub const Tag = enum(u8) { |
| 5231 | }, | 5259 | }, |
| 5232 | .type_enum_explicit = enum_explicit_encoding, | 5260 | .type_enum_explicit = enum_explicit_encoding, |
| 5233 | .type_enum_nonexhaustive = enum_explicit_encoding, | 5261 | .type_enum_nonexhaustive = enum_explicit_encoding, |
| 5262 | .type_spirv = .{ .summary = .@"{.payload.name%summary#\"}", .payload = Tag.TypeSpirv }, | ||
| 5234 | .type_opaque = .{ | 5263 | .type_opaque = .{ |
| 5235 | .summary = .@"{.payload.name%summary#\"}", | 5264 | .summary = .@"{.payload.name%summary#\"}", |
| 5236 | .payload = TypeOpaque, | 5265 | .payload = TypeOpaque, |
| ... | @@ -5688,6 +5717,34 @@ pub const Tag = enum(u8) { | ... | @@ -5688,6 +5717,34 @@ pub const Tag = enum(u8) { |
| 5688 | name_nav: Nav.Index.Optional, | 5717 | name_nav: Nav.Index.Optional, |
| 5689 | namespace: NamespaceIndex, | 5718 | namespace: NamespaceIndex, |
| 5690 | }; | 5719 | }; |
| 5720 | |||
| 5721 | /// Trailing: | ||
| 5722 | /// 0. type_hash: PackedU64 | ||
| 5723 | pub const TypeSpirv = struct { | ||
| 5724 | name: NullTerminatedString, | ||
| 5725 | /// The index of the `reify_spirv_type` instruction. | ||
| 5726 | zir_index: TrackedInst.Index, | ||
| 5727 | /// If tag is `.image`, this is the sampled type or `.none` if `usage` is `.storage`. | ||
| 5728 | /// If tag is `.sampled_image`, this is the image type. | ||
| 5729 | /// If tag is `.runtime_array`, this is the element type. | ||
| 5730 | /// Otherwise this is `.none`. | ||
| 5731 | ty: Index, | ||
| 5732 | flags: Flags, | ||
| 5733 | |||
| 5734 | pub const Flags = packed struct(u32) { | ||
| 5735 | tag: @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?, | ||
| 5736 | // Image type flags | ||
| 5737 | usage: @typeInfo(std.lang.Type.Spirv.Image.Usage).@"union".tag_type.?, | ||
| 5738 | format: std.lang.Type.Spirv.Image.Format, | ||
| 5739 | dim: std.lang.Type.Spirv.Image.Dimensionality, | ||
| 5740 | depth: std.lang.Type.Spirv.Image.Depth, | ||
| 5741 | access: std.lang.Type.Spirv.Image.Access, | ||
| 5742 | is_arrayed: bool, | ||
| 5743 | is_multisampled: bool, | ||
| 5744 | |||
| 5745 | _: u16 = 0, | ||
| 5746 | }; | ||
| 5747 | }; | ||
| 5691 | }; | 5748 | }; |
| 5692 | 5749 | ||
| 5693 | /// Differentiates between user-provided and compiler-generated backing types for packed and tagged types. | 5750 | /// Differentiates between user-provided and compiler-generated backing types for packed and tagged types. |
| ... | @@ -6573,6 +6630,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { | ... | @@ -6573,6 +6630,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6573 | } }, | 6630 | } }, |
| 6574 | }; | 6631 | }; |
| 6575 | } }, | 6632 | } }, |
| 6633 | .type_spirv => .{ .spirv_type = ns: { | ||
| 6634 | const extra_list = unwrapped_index.getExtra(ip); | ||
| 6635 | const extra = extraDataTrail(extra_list, Tag.TypeSpirv, data); | ||
| 6636 | break :ns .{ | ||
| 6637 | .zir_index = extra.data.zir_index, | ||
| 6638 | .type_hash = extraData(extra_list, PackedU64, extra.end).get(), | ||
| 6639 | }; | ||
| 6640 | } }, | ||
| 6576 | .type_opaque => .{ .opaque_type = ns: { | 6641 | .type_opaque => .{ .opaque_type = ns: { |
| 6577 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); | 6642 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); |
| 6578 | break :ns .{ .declared = .{ | 6643 | break :ns .{ .declared = .{ |
| ... | @@ -7345,6 +7410,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: | ... | @@ -7345,6 +7410,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 7345 | .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType | 7410 | .union_type => unreachable, // instead use: getDeclaredUnionType, getReifiedUnionType |
| 7346 | .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType | 7411 | .enum_type => unreachable, // instead use: getDeclaredEnumType, getReifiedEnumType, getGeneratedEnumTagType |
| 7347 | .opaque_type => unreachable, // instead use: getDeclaredOpaqueType | 7412 | .opaque_type => unreachable, // instead use: getDeclaredOpaqueType |
| 7413 | .spirv_type => unreachable, // instead use: getSpirvType | ||
| 7348 | 7414 | ||
| 7349 | .tuple_type => unreachable, // use getTupleType() instead | 7415 | .tuple_type => unreachable, // use getTupleType() instead |
| 7350 | .func_type => unreachable, // use getFuncType() instead | 7416 | .func_type => unreachable, // use getFuncType() instead |
| ... | @@ -8717,6 +8783,39 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT | ... | @@ -8717,6 +8783,39 @@ pub fn getReifiedEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerT |
| 8717 | } }; | 8783 | } }; |
| 8718 | } | 8784 | } |
| 8719 | 8785 | ||
| 8786 | pub fn getReifiedSpirvType( | ||
| 8787 | ip: *InternPool, | ||
| 8788 | gpa: Allocator, | ||
| 8789 | io: Io, | ||
| 8790 | tid: Zcu.PerThread.Id, | ||
| 8791 | ini: struct { | ||
| 8792 | zir_index: TrackedInst.Index, | ||
| 8793 | type_hash: u64, | ||
| 8794 | type_spirv: Tag.TypeSpirv, | ||
| 8795 | }, | ||
| 8796 | ) Allocator.Error!Index { | ||
| 8797 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .spirv_type = .{ | ||
| 8798 | .zir_index = ini.zir_index, | ||
| 8799 | .type_hash = ini.type_hash, | ||
| 8800 | } }); | ||
| 8801 | defer gop.deinit(); | ||
| 8802 | if (gop == .existing) return gop.existing; | ||
| 8803 | |||
| 8804 | const local = ip.getLocal(tid); | ||
| 8805 | const items = local.getMutableItems(gpa, io); | ||
| 8806 | const extra = local.getMutableExtra(gpa, io); | ||
| 8807 | try items.ensureUnusedCapacity(1); | ||
| 8808 | |||
| 8809 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeSpirv).@"struct".field_names.len + | ||
| 8810 | 2 // type_hash: PackedU64 | ||
| 8811 | ); | ||
| 8812 | const extra_index = addExtraAssumeCapacity(extra, ini.type_spirv); | ||
| 8813 | _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash)); | ||
| 8814 | |||
| 8815 | items.appendAssumeCapacity(.{ .tag = .type_spirv, .data = extra_index }); | ||
| 8816 | return gop.put(); | ||
| 8817 | } | ||
| 8818 | |||
| 8720 | pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | 8819 | pub fn getGeneratedEnumTagType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { |
| 8721 | /// The union type for which this enum is a generated tag. | 8820 | /// The union type for which this enum is a generated tag. |
| 8722 | union_type: Index, | 8821 | union_type: Index, |
| ... | @@ -9077,7 +9176,7 @@ pub fn getExtern( | ... | @@ -9077,7 +9176,7 @@ pub fn getExtern( |
| 9077 | }) catch unreachable; // capacity asserted above | 9176 | }) catch unreachable; // capacity asserted above |
| 9078 | const decoration_type, const location_or_descriptor_set, const descriptor_binding = if (key.decoration) |decoration| switch (decoration) { | 9177 | const decoration_type, const location_or_descriptor_set, const descriptor_binding = if (key.decoration) |decoration| switch (decoration) { |
| 9079 | .location => |location| .{ Tag.Extern.Flags.DecorationType.location, location, undefined }, | 9178 | .location => |location| .{ Tag.Extern.Flags.DecorationType.location, location, undefined }, |
| 9080 | .descriptor => |descriptor| .{ Tag.Extern.Flags.DecorationType.descriptor, descriptor.binding, descriptor.set }, | 9179 | .descriptor => |descriptor| .{ Tag.Extern.Flags.DecorationType.descriptor, descriptor.set, descriptor.binding }, |
| 9081 | } else .{ Tag.Extern.Flags.DecorationType.none, undefined, undefined }; | 9180 | } else .{ Tag.Extern.Flags.DecorationType.none, undefined, undefined }; |
| 9082 | const extra_index = addExtraAssumeCapacity(extra, Tag.Extern{ | 9181 | const extra_index = addExtraAssumeCapacity(extra, Tag.Extern{ |
| 9083 | .ty = key.ty, | 9182 | .ty = key.ty, |
| ... | @@ -9810,6 +9909,7 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { | ... | @@ -9810,6 +9909,7 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { |
| 9810 | Tag.TypeStructPacked.Bits, | 9909 | Tag.TypeStructPacked.Bits, |
| 9811 | Tag.TypeUnionPacked.Bits, | 9910 | Tag.TypeUnionPacked.Bits, |
| 9812 | Tag.TypeEnum.Bits, | 9911 | Tag.TypeEnum.Bits, |
| 9912 | Tag.TypeSpirv.Flags, | ||
| 9813 | => @bitCast(@field(item, field_name)), | 9913 | => @bitCast(@field(item, field_name)), |
| 9814 | 9914 | ||
| 9815 | else => @compileError("bad field type: " ++ @typeName(field_type)), | 9915 | else => @compileError("bad field type: " ++ @typeName(field_type)), |
| ... | @@ -9877,6 +9977,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat | ... | @@ -9877,6 +9977,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat |
| 9877 | Tag.TypeStructPacked.Bits, | 9977 | Tag.TypeStructPacked.Bits, |
| 9878 | Tag.TypeUnionPacked.Bits, | 9978 | Tag.TypeUnionPacked.Bits, |
| 9879 | Tag.TypeEnum.Bits, | 9979 | Tag.TypeEnum.Bits, |
| 9980 | Tag.TypeSpirv.Flags, | ||
| 9880 | => @bitCast(extra_item), | 9981 | => @bitCast(extra_item), |
| 9881 | 9982 | ||
| 9882 | else => @compileError("bad field type: " ++ @typeName(field_type)), | 9983 | else => @compileError("bad field type: " ++ @typeName(field_type)), |
| ... | @@ -9930,6 +10031,11 @@ pub fn childType(ip: *const InternPool, i: Index) Index { | ... | @@ -9930,6 +10031,11 @@ pub fn childType(ip: *const InternPool, i: Index) Index { |
| 9930 | .vector_type => |vector_type| vector_type.child, | 10031 | .vector_type => |vector_type| vector_type.child, |
| 9931 | .array_type => |array_type| array_type.child, | 10032 | .array_type => |array_type| array_type.child, |
| 9932 | .opt_type, .anyframe_type => |child| child, | 10033 | .opt_type, .anyframe_type => |child| child, |
| 10034 | .spirv_type => blk: { | ||
| 10035 | const info = ip.loadSpirvType(i); | ||
| 10036 | assert(info.flags.tag == .runtime_array); | ||
| 10037 | break :blk info.ty; | ||
| 10038 | }, | ||
| 9933 | else => unreachable, | 10039 | else => unreachable, |
| 9934 | }; | 10040 | }; |
| 9935 | } | 10041 | } |
| ... | @@ -10583,6 +10689,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo | ... | @@ -10583,6 +10689,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 10583 | .type_optional => 0, | 10689 | .type_optional => 0, |
| 10584 | .type_anyframe => 0, | 10690 | .type_anyframe => 0, |
| 10585 | .type_error_union => @sizeOf(Key.ErrorUnionType), | 10691 | .type_error_union => @sizeOf(Key.ErrorUnionType), |
| 10692 | .type_spirv => @sizeOf(Tag.TypeSpirv) + @sizeOf(PackedU64), | ||
| 10586 | .type_anyerror_union => 0, | 10693 | .type_anyerror_union => 0, |
| 10587 | .type_error_set => b: { | 10694 | .type_error_set => b: { |
| 10588 | const info = extraData(extra_list, Tag.ErrorSet, data); | 10695 | const info = extraData(extra_list, Tag.ErrorSet, data); |
| ... | @@ -10860,6 +10967,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { | ... | @@ -10860,6 +10967,7 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { |
| 10860 | .type_enum_explicit, | 10967 | .type_enum_explicit, |
| 10861 | .type_enum_nonexhaustive, | 10968 | .type_enum_nonexhaustive, |
| 10862 | .type_opaque, | 10969 | .type_opaque, |
| 10970 | .type_spirv, | ||
| 10863 | .undef, | 10971 | .undef, |
| 10864 | .ptr_nav, | 10972 | .ptr_nav, |
| 10865 | .ptr_comptime_alloc, | 10973 | .ptr_comptime_alloc, |
| ... | @@ -11598,6 +11706,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { | ... | @@ -11598,6 +11706,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 11598 | .type_enum_explicit, | 11706 | .type_enum_explicit, |
| 11599 | .type_enum_nonexhaustive, | 11707 | .type_enum_nonexhaustive, |
| 11600 | .type_opaque, | 11708 | .type_opaque, |
| 11709 | .type_spirv, | ||
| 11601 | => .type_type, | 11710 | => .type_type, |
| 11602 | 11711 | ||
| 11603 | .undef, | 11712 | .undef, |
| ... | @@ -11955,6 +12064,8 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.lang.TypeId { | ... | @@ -11955,6 +12064,8 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.lang.TypeId { |
| 11955 | .type_opaque, | 12064 | .type_opaque, |
| 11956 | => .@"opaque", | 12065 | => .@"opaque", |
| 11957 | 12066 | ||
| 12067 | .type_spirv => .spirv, | ||
| 12068 | |||
| 11958 | .type_function => .@"fn", | 12069 | .type_function => .@"fn", |
| 11959 | 12070 | ||
| 11960 | // values, not types | 12071 | // values, not types |
src/Sema.zig+442-1| ... | @@ -1434,6 +1434,7 @@ fn analyzeBodyInner( | ... | @@ -1434,6 +1434,7 @@ fn analyzeBodyInner( |
| 1434 | .reify_struct => try sema.zirReifyStruct( block, extended, inst), | 1434 | .reify_struct => try sema.zirReifyStruct( block, extended, inst), |
| 1435 | .reify_union => try sema.zirReifyUnion( block, extended, inst), | 1435 | .reify_union => try sema.zirReifyUnion( block, extended, inst), |
| 1436 | .reify_enum => try sema.zirReifyEnum( block, extended, inst), | 1436 | .reify_enum => try sema.zirReifyEnum( block, extended, inst), |
| 1437 | .reify_spirv_type => try sema.zirReifySpirvType( block, extended, inst), | ||
| 1437 | // zig fmt: on | 1438 | // zig fmt: on |
| 1438 | 1439 | ||
| 1439 | .set_float_mode => { | 1440 | .set_float_mode => { |
| ... | @@ -9273,6 +9274,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9273,6 +9274,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9273 | .noreturn, | 9274 | .noreturn, |
| 9274 | .null, | 9275 | .null, |
| 9275 | .@"opaque", | 9276 | .@"opaque", |
| 9277 | .spirv, | ||
| 9276 | .optional, | 9278 | .optional, |
| 9277 | .type, | 9279 | .type, |
| 9278 | .undefined, | 9280 | .undefined, |
| ... | @@ -9348,6 +9350,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -9348,6 +9350,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 9348 | .noreturn, | 9350 | .noreturn, |
| 9349 | .null, | 9351 | .null, |
| 9350 | .@"opaque", | 9352 | .@"opaque", |
| 9353 | .spirv, | ||
| 9351 | .optional, | 9354 | .optional, |
| 9352 | .type, | 9355 | .type, |
| 9353 | .undefined, | 9356 | .undefined, |
| ... | @@ -15531,6 +15534,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -15531,6 +15534,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 15531 | .undefined, | 15534 | .undefined, |
| 15532 | .null, | 15535 | .null, |
| 15533 | .@"opaque", | 15536 | .@"opaque", |
| 15537 | .spirv, | ||
| 15534 | .type, | 15538 | .type, |
| 15535 | .enum_literal, | 15539 | .enum_literal, |
| 15536 | .comptime_float, | 15540 | .comptime_float, |
| ... | @@ -16834,6 +16838,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -16834,6 +16838,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16834 | .val = (try pt.aggregateValue(type_opaque_ty, &field_values)).toIntern(), | 16838 | .val = (try pt.aggregateValue(type_opaque_ty, &field_values)).toIntern(), |
| 16835 | }))); | 16839 | }))); |
| 16836 | }, | 16840 | }, |
| 16841 | .spirv => unreachable, // TODO: ALI | ||
| 16837 | .frame => return sema.failWithUseOfAsync(block, src), | 16842 | .frame => return sema.failWithUseOfAsync(block, src), |
| 16838 | .@"anyframe" => return sema.failWithUseOfAsync(block, src), | 16843 | .@"anyframe" => return sema.failWithUseOfAsync(block, src), |
| 16839 | } | 16844 | } |
| ... | @@ -20449,6 +20454,306 @@ fn zirReifyEnum( | ... | @@ -20449,6 +20454,306 @@ fn zirReifyEnum( |
| 20449 | } | 20454 | } |
| 20450 | } | 20455 | } |
| 20451 | 20456 | ||
| 20457 | fn zirReifySpirvType( | ||
| 20458 | sema: *Sema, | ||
| 20459 | block: *Block, | ||
| 20460 | extended: Zir.Inst.Extended.InstData, | ||
| 20461 | inst: Zir.Inst.Index, | ||
| 20462 | ) CompileError!Air.Inst.Ref { | ||
| 20463 | const pt = sema.pt; | ||
| 20464 | const zcu = pt.zcu; | ||
| 20465 | const comp = zcu.comp; | ||
| 20466 | const gpa = comp.gpa; | ||
| 20467 | const io = comp.io; | ||
| 20468 | const ip = &zcu.intern_pool; | ||
| 20469 | const target = zcu.getTarget(); | ||
| 20470 | |||
| 20471 | const extra = sema.code.extraData(Zir.Inst.ReifySpirvType, extended.operand).data; | ||
| 20472 | const tracked_inst = try block.trackZir(inst); | ||
| 20473 | const src: LazySrcLoc = .{ | ||
| 20474 | .base_node_inst = tracked_inst, | ||
| 20475 | .offset = .nodeOffset(.zero), | ||
| 20476 | }; | ||
| 20477 | const operand_src: LazySrcLoc = .{ | ||
| 20478 | .base_node_inst = tracked_inst, | ||
| 20479 | .offset = .{ .node_offset_builtin_call_arg = .{ | ||
| 20480 | .builtin_call_node = .zero, | ||
| 20481 | .arg_index = 0, | ||
| 20482 | } }, | ||
| 20483 | }; | ||
| 20484 | |||
| 20485 | if (!target.cpu.arch.isSpirV()) { | ||
| 20486 | return sema.fail( | ||
| 20487 | block, | ||
| 20488 | src, | ||
| 20489 | "builtin @SpirvType is only available when targeting SPIR-V; targeted CPU architecture is {t}", | ||
| 20490 | .{target.cpu.arch}, | ||
| 20491 | ); | ||
| 20492 | } | ||
| 20493 | |||
| 20494 | const spirv_type_options_ty = try sema.getStdLangType(operand_src, .@"Type.Spirv"); | ||
| 20495 | const operand_uncoerced = sema.resolveInst(extra.operand); | ||
| 20496 | const operand_coerced = try sema.coerce(block, spirv_type_options_ty, operand_uncoerced, operand_src); | ||
| 20497 | const operand_val = try sema.resolveConstDefinedValue(block, operand_src, operand_coerced, .{ .simple = .type }); | ||
| 20498 | const union_val = ip.indexToKey(operand_val.toIntern()).un; | ||
| 20499 | |||
| 20500 | if (try sema.anyUndef(block, operand_src, .fromInterned(union_val.val))) { | ||
| 20501 | return sema.failWithUseOfUndef(block, operand_src, null); | ||
| 20502 | } | ||
| 20503 | |||
| 20504 | // TODO: use a longer hash! | ||
| 20505 | var hasher = std.hash.Wyhash.init(0); | ||
| 20506 | std.hash.autoHash(&hasher, union_val.tag); | ||
| 20507 | |||
| 20508 | const name = try ip.getOrPutStringFmt( | ||
| 20509 | gpa, | ||
| 20510 | io, | ||
| 20511 | pt.tid, | ||
| 20512 | "{f}__SpirvType_{d}", | ||
| 20513 | .{ block.type_name_ctx.fmt(ip), @intFromEnum(inst) }, | ||
| 20514 | .no_embedded_nulls, | ||
| 20515 | ); | ||
| 20516 | const tag = try sema.interpretStdLangType(block, src, .fromInterned(union_val.tag), @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?); | ||
| 20517 | const ip_data: InternPool.Tag.TypeSpirv = switch (tag) { | ||
| 20518 | .sampler => .{ | ||
| 20519 | .name = name, | ||
| 20520 | .zir_index = tracked_inst, | ||
| 20521 | .ty = .none, | ||
| 20522 | .flags = .{ | ||
| 20523 | .tag = .sampler, | ||
| 20524 | .usage = .unknown, | ||
| 20525 | .format = .unknown, | ||
| 20526 | .dim = .@"1d", | ||
| 20527 | .depth = .unknown, | ||
| 20528 | .access = .unknown, | ||
| 20529 | .is_arrayed = false, | ||
| 20530 | .is_multisampled = false, | ||
| 20531 | }, | ||
| 20532 | }, | ||
| 20533 | .image => ip_data: { | ||
| 20534 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); | ||
| 20535 | const usage_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | ||
| 20536 | ip, | ||
| 20537 | try ip.getOrPutString(gpa, io, pt.tid, "usage", .no_embedded_nulls), | ||
| 20538 | ).?); | ||
| 20539 | const format_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | ||
| 20540 | ip, | ||
| 20541 | try ip.getOrPutString(gpa, io, pt.tid, "format", .no_embedded_nulls), | ||
| 20542 | ).?); | ||
| 20543 | const dim_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | ||
| 20544 | ip, | ||
| 20545 | try ip.getOrPutString(gpa, io, pt.tid, "dim", .no_embedded_nulls), | ||
| 20546 | ).?); | ||
| 20547 | const depth_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | ||
| 20548 | ip, | ||
| 20549 | try ip.getOrPutString(gpa, io, pt.tid, "depth", .no_embedded_nulls), | ||
| 20550 | ).?); | ||
| 20551 | const access_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | ||
| 20552 | ip, | ||
| 20553 | try ip.getOrPutString(gpa, io, pt.tid, "access", .no_embedded_nulls), | ||
| 20554 | ).?); | ||
| 20555 | const arrayed_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | ||
| 20556 | ip, | ||
| 20557 | try ip.getOrPutString(gpa, io, pt.tid, "arrayed", .no_embedded_nulls), | ||
| 20558 | ).?); | ||
| 20559 | const multisampled_val = try Value.fromInterned(union_val.val).fieldValue(pt, struct_type.nameIndex( | ||
| 20560 | ip, | ||
| 20561 | try ip.getOrPutString(gpa, io, pt.tid, "multisampled", .no_embedded_nulls), | ||
| 20562 | ).?); | ||
| 20563 | const format = try sema.interpretStdLangType(block, operand_src, format_val, std.lang.Type.Spirv.Image.Format); | ||
| 20564 | const dim = try sema.interpretStdLangType(block, operand_src, dim_val, std.lang.Type.Spirv.Image.Dimensionality); | ||
| 20565 | const depth = try sema.interpretStdLangType(block, operand_src, depth_val, std.lang.Type.Spirv.Image.Depth); | ||
| 20566 | const access = try sema.interpretStdLangType(block, operand_src, access_val, std.lang.Type.Spirv.Image.Access); | ||
| 20567 | |||
| 20568 | switch (target.os.tag) { | ||
| 20569 | .opencl => if (access == .unknown) { | ||
| 20570 | return sema.fail(block, operand_src, "'access' field must be specified under the 'opencl' os", .{}); | ||
| 20571 | }, | ||
| 20572 | else => if (access != .unknown) { | ||
| 20573 | return sema.fail(block, operand_src, "access qualifier '.{t}' is only valid under the 'opencl' os", .{access}); | ||
| 20574 | }, | ||
| 20575 | } | ||
| 20576 | |||
| 20577 | const arrayed = try sema.interpretStdLangType(block, operand_src, arrayed_val, bool); | ||
| 20578 | const multisampled = try sema.interpretStdLangType(block, operand_src, multisampled_val, bool); | ||
| 20579 | |||
| 20580 | const usage_tag_val = usage_val.unionTag(zcu).?; | ||
| 20581 | const usage_tag = try sema.interpretStdLangType(block, operand_src, usage_tag_val, @typeInfo(std.lang.Type.Spirv.Image.Usage).@"union".tag_type.?); | ||
| 20582 | |||
| 20583 | switch (target.os.tag) { | ||
| 20584 | .vulkan => { | ||
| 20585 | if (usage_tag == .unknown) { | ||
| 20586 | return sema.fail( | ||
| 20587 | block, | ||
| 20588 | operand_src, | ||
| 20589 | "'usage' must be '.sampled' or '.storage' under the 'vulkan' os (Sampled == 0 is forbidden)", | ||
| 20590 | .{}, | ||
| 20591 | ); | ||
| 20592 | } | ||
| 20593 | }, | ||
| 20594 | .opencl => { | ||
| 20595 | if (usage_tag != .unknown) { | ||
| 20596 | return sema.fail(block, operand_src, "'usage' must be '.unknown' under the 'opencl' os", .{}); | ||
| 20597 | } | ||
| 20598 | if (multisampled) { | ||
| 20599 | return sema.fail(block, operand_src, "'multisampled' must be 'false' under the 'opencl' os", .{}); | ||
| 20600 | } | ||
| 20601 | if (format != .unknown) { | ||
| 20602 | return sema.fail(block, operand_src, "'format' must be '.unknown' under the 'opencl' os", .{}); | ||
| 20603 | } | ||
| 20604 | if (dim == .cube) { | ||
| 20605 | return sema.fail(block, operand_src, "'dim' '.cube' is not allowed under the 'opencl' os", .{}); | ||
| 20606 | } | ||
| 20607 | if (arrayed and dim != .@"1d" and dim != .@"2d") { | ||
| 20608 | return sema.fail(block, operand_src, "'arrayed' may only be 'true' when 'dim' is '.1d' or '.2d' under the 'opencl' os", .{}); | ||
| 20609 | } | ||
| 20610 | }, | ||
| 20611 | else => {}, | ||
| 20612 | } | ||
| 20613 | |||
| 20614 | std.hash.autoHash(&hasher, usage_tag); | ||
| 20615 | std.hash.autoHash(&hasher, format); | ||
| 20616 | std.hash.autoHash(&hasher, dim); | ||
| 20617 | std.hash.autoHash(&hasher, depth); | ||
| 20618 | std.hash.autoHash(&hasher, access); | ||
| 20619 | std.hash.autoHash(&hasher, arrayed); | ||
| 20620 | std.hash.autoHash(&hasher, multisampled); | ||
| 20621 | |||
| 20622 | break :ip_data .{ | ||
| 20623 | .name = name, | ||
| 20624 | .zir_index = tracked_inst, | ||
| 20625 | .ty = switch (usage_tag) { | ||
| 20626 | .sampled, .unknown => blk: { | ||
| 20627 | const sampled_type = usage_val.unionPayload(zcu).toType(); | ||
| 20628 | std.hash.autoHash(&hasher, sampled_type.toIntern()); | ||
| 20629 | |||
| 20630 | if (target.os.tag != .opencl and sampled_type.toIntern() == .void_type) { | ||
| 20631 | return sema.fail(block, operand_src, "'void' type for '{t}' field is only valid under the 'opencl' os", .{usage_tag}); | ||
| 20632 | } | ||
| 20633 | if (target.os.tag == .opencl and sampled_type.toIntern() != .void_type) { | ||
| 20634 | return sema.fail(block, operand_src, "'{t}' field type must be 'void' under the 'opencl' os", .{usage_tag}); | ||
| 20635 | } | ||
| 20636 | |||
| 20637 | if (sampled_type.toIntern() != .void_type and | ||
| 20638 | (!sampled_type.hasRuntimeBits(zcu) or (!sampled_type.isRuntimeFloat() and !sampled_type.isInt(zcu)))) | ||
| 20639 | { | ||
| 20640 | return sema.fail(block, operand_src, "invalid '{t}' field value '{f}'", .{ usage_tag, sampled_type.fmt(pt) }); | ||
| 20641 | } | ||
| 20642 | |||
| 20643 | if (target.os.tag == .vulkan) { | ||
| 20644 | const ok = (sampled_type.isRuntimeFloat() and sampled_type.bitSize(zcu) == 32) or | ||
| 20645 | (sampled_type.isInt(zcu) and (sampled_type.bitSize(zcu) == 32 or sampled_type.bitSize(zcu) == 64)); | ||
| 20646 | if (!ok) { | ||
| 20647 | return sema.fail( | ||
| 20648 | block, | ||
| 20649 | operand_src, | ||
| 20650 | "'{t}' field value must be a 32-bit int, 64-bit int or 32-bit float under the 'vulkan' os", | ||
| 20651 | .{usage_tag}, | ||
| 20652 | ); | ||
| 20653 | } | ||
| 20654 | |||
| 20655 | if (format != .unknown) { | ||
| 20656 | const format_kind: enum { float, sint, uint } = switch (format) { | ||
| 20657 | .rgba32f, .rgba16f, .rgba8unorm, .rgba8snorm, .r32f => .float, | ||
| 20658 | .rgba32i, .rgba16i, .rgba8i, .r32i => .sint, | ||
| 20659 | .rgba32u, .rgba16u, .rgba8u, .r32u => .uint, | ||
| 20660 | .unknown => unreachable, | ||
| 20661 | }; | ||
| 20662 | const matches = switch (format_kind) { | ||
| 20663 | .float => sampled_type.isRuntimeFloat(), | ||
| 20664 | .sint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .signed, | ||
| 20665 | .uint => sampled_type.isInt(zcu) and sampled_type.intInfo(zcu).signedness == .unsigned, | ||
| 20666 | }; | ||
| 20667 | if (!matches) { | ||
| 20668 | return sema.fail( | ||
| 20669 | block, | ||
| 20670 | operand_src, | ||
| 20671 | "image 'format' '.{t}' does not match '{t}' type '{f}' under the 'vulkan' os", | ||
| 20672 | .{ format, usage_tag, sampled_type.fmt(pt) }, | ||
| 20673 | ); | ||
| 20674 | } | ||
| 20675 | } | ||
| 20676 | } | ||
| 20677 | |||
| 20678 | break :blk sampled_type.toIntern(); | ||
| 20679 | }, | ||
| 20680 | .storage => .none, | ||
| 20681 | }, | ||
| 20682 | .flags = .{ | ||
| 20683 | .tag = .image, | ||
| 20684 | .usage = usage_tag, | ||
| 20685 | .format = format, | ||
| 20686 | .dim = dim, | ||
| 20687 | .depth = depth, | ||
| 20688 | .access = access, | ||
| 20689 | .is_arrayed = arrayed, | ||
| 20690 | .is_multisampled = multisampled, | ||
| 20691 | }, | ||
| 20692 | }; | ||
| 20693 | }, | ||
| 20694 | .sampled_image => blk: { | ||
| 20695 | const image_ty = Value.fromInterned(union_val.val).toType(); | ||
| 20696 | if (image_ty.zigTypeTag(zcu) != .spirv or ip.loadSpirvType(image_ty.toIntern()).flags.tag != .image) { | ||
| 20697 | return sema.fail(block, operand_src, "'sampled_image' element must be an @SpirvType image, found '{f}'", .{image_ty.fmt(pt)}); | ||
| 20698 | } | ||
| 20699 | const image_info = ip.loadSpirvType(image_ty.toIntern()).flags; | ||
| 20700 | if (image_info.usage != .sampled) { | ||
| 20701 | return sema.fail(block, operand_src, "'sampled_image' element must be an image with 'usage = .sampled'", .{}); | ||
| 20702 | } | ||
| 20703 | std.hash.autoHash(&hasher, union_val.val); | ||
| 20704 | break :blk .{ | ||
| 20705 | .name = name, | ||
| 20706 | .zir_index = tracked_inst, | ||
| 20707 | .ty = union_val.val, | ||
| 20708 | .flags = .{ | ||
| 20709 | .tag = tag, | ||
| 20710 | .usage = .unknown, | ||
| 20711 | .format = .unknown, | ||
| 20712 | .dim = .@"1d", | ||
| 20713 | .depth = .unknown, | ||
| 20714 | .access = .unknown, | ||
| 20715 | .is_arrayed = false, | ||
| 20716 | .is_multisampled = false, | ||
| 20717 | }, | ||
| 20718 | }; | ||
| 20719 | }, | ||
| 20720 | .runtime_array => blk: { | ||
| 20721 | const elem_ty = Value.fromInterned(union_val.val).toType(); | ||
| 20722 | if (elem_ty.toIntern() == .void_type) { | ||
| 20723 | return sema.fail(block, operand_src, "'runtime_array' element type must not be 'void'", .{}); | ||
| 20724 | } | ||
| 20725 | if (target.os.tag == .vulkan and | ||
| 20726 | elem_ty.zigTypeTag(zcu) == .spirv and | ||
| 20727 | ip.loadSpirvType(elem_ty.toIntern()).flags.tag == .runtime_array) | ||
| 20728 | { | ||
| 20729 | return sema.fail(block, operand_src, "'runtime_array' of 'runtime_array' is not allowed under the 'vulkan' os", .{}); | ||
| 20730 | } | ||
| 20731 | std.hash.autoHash(&hasher, union_val.val); | ||
| 20732 | break :blk .{ | ||
| 20733 | .name = name, | ||
| 20734 | .zir_index = tracked_inst, | ||
| 20735 | .ty = union_val.val, | ||
| 20736 | .flags = .{ | ||
| 20737 | .tag = tag, | ||
| 20738 | .usage = .unknown, | ||
| 20739 | .format = .unknown, | ||
| 20740 | .dim = .@"1d", | ||
| 20741 | .depth = .unknown, | ||
| 20742 | .access = .unknown, | ||
| 20743 | .is_arrayed = false, | ||
| 20744 | .is_multisampled = false, | ||
| 20745 | }, | ||
| 20746 | }; | ||
| 20747 | }, | ||
| 20748 | }; | ||
| 20749 | |||
| 20750 | return .fromIntern(try ip.getReifiedSpirvType(gpa, io, pt.tid, .{ | ||
| 20751 | .zir_index = tracked_inst, | ||
| 20752 | .type_hash = hasher.final(), | ||
| 20753 | .type_spirv = ip_data, | ||
| 20754 | })); | ||
| 20755 | } | ||
| 20756 | |||
| 20452 | fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { | 20757 | fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { |
| 20453 | const pt = sema.pt; | 20758 | const pt = sema.pt; |
| 20454 | const va_list_ty = try sema.getStdLangType(src, .VaList); | 20759 | const va_list_ty = try sema.getStdLangType(src, .VaList); |
| ... | @@ -24760,6 +25065,7 @@ fn zirStdLangValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD | ... | @@ -24760,6 +25065,7 @@ fn zirStdLangValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 24760 | .fn_attributes, => .@"Type.Fn.Attributes", | 25065 | .fn_attributes, => .@"Type.Fn.Attributes", |
| 24761 | .container_layout => .@"Type.ContainerLayout", | 25066 | .container_layout => .@"Type.ContainerLayout", |
| 24762 | .enum_mode => .@"Type.Enum.Mode", | 25067 | .enum_mode => .@"Type.Enum.Mode", |
| 25068 | .spirv_type_options => .@"Type.Spirv", | ||
| 24763 | // zig fmt: on | 25069 | // zig fmt: on |
| 24764 | 25070 | ||
| 24765 | // Values are handled here. | 25071 | // Values are handled here. |
| ... | @@ -24957,6 +25263,7 @@ fn explainWhyTypeIsComptime( | ... | @@ -24957,6 +25263,7 @@ fn explainWhyTypeIsComptime( |
| 24957 | .void, | 25263 | .void, |
| 24958 | .@"enum", | 25264 | .@"enum", |
| 24959 | .@"opaque", | 25265 | .@"opaque", |
| 25266 | .spirv, | ||
| 24960 | .pointer, | 25267 | .pointer, |
| 24961 | => unreachable, // not comptime-only | 25268 | => unreachable, // not comptime-only |
| 24962 | 25269 | ||
| ... | @@ -25043,6 +25350,7 @@ pub fn explainWhyTypeIsNotExtern( | ... | @@ -25043,6 +25350,7 @@ pub fn explainWhyTypeIsNotExtern( |
| 25043 | .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), | 25350 | .noreturn => try sema.errNote(src_loc, msg, "'noreturn' is only allowed as a return type", .{}), |
| 25044 | 25351 | ||
| 25045 | .@"opaque", | 25352 | .@"opaque", |
| 25353 | .spirv, | ||
| 25046 | .bool, | 25354 | .bool, |
| 25047 | .float, | 25355 | .float, |
| 25048 | .@"anyframe", | 25356 | .@"anyframe", |
| ... | @@ -25483,9 +25791,13 @@ fn fieldPtrLoad( | ... | @@ -25483,9 +25791,13 @@ fn fieldPtrLoad( |
| 25483 | ) CompileError!Air.Inst.Ref { | 25791 | ) CompileError!Air.Inst.Ref { |
| 25484 | const pt = sema.pt; | 25792 | const pt = sema.pt; |
| 25485 | const zcu = pt.zcu; | 25793 | const zcu = pt.zcu; |
| 25794 | const ip = &zcu.intern_pool; | ||
| 25486 | const object_ptr_ty = sema.typeOf(object_ptr); | 25795 | const object_ptr_ty = sema.typeOf(object_ptr); |
| 25487 | assert(object_ptr_ty.zigTypeTag(zcu) == .pointer); | 25796 | assert(object_ptr_ty.zigTypeTag(zcu) == .pointer); |
| 25488 | const pointee_ty = object_ptr_ty.childType(zcu); | 25797 | const pointee_ty = object_ptr_ty.childType(zcu); |
| 25798 | if (pointee_ty.isSpirvRuntimeArray(zcu) and field_name.eqlSlice("len", ip)) { | ||
| 25799 | return sema.analyzeSpirvRuntimeArrayLen(block, src, object_ptr, field_name_src); | ||
| 25800 | } | ||
| 25489 | try sema.ensureLayoutResolved(pointee_ty, src, .ptr_access); | 25801 | try sema.ensureLayoutResolved(pointee_ty, src, .ptr_access); |
| 25490 | if (try pointee_ty.onePossibleValue(pt)) |opv| { | 25802 | if (try pointee_ty.onePossibleValue(pt)) |opv| { |
| 25491 | const object: Air.Inst.Ref = .fromValue(opv); | 25803 | const object: Air.Inst.Ref = .fromValue(opv); |
| ... | @@ -25675,11 +25987,123 @@ fn fieldVal( | ... | @@ -25675,11 +25987,123 @@ fn fieldVal( |
| 25675 | } else { | 25987 | } else { |
| 25676 | return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); | 25988 | return sema.unionFieldVal(block, src, object, field_name, field_name_src, inner_ty); |
| 25677 | }, | 25989 | }, |
| 25990 | .spirv => if (inner_ty.isSpirvRuntimeArray(zcu) and field_name.eqlSlice("len", ip)) { | ||
| 25991 | if (!is_pointer_to) { | ||
| 25992 | return sema.fail( | ||
| 25993 | block, | ||
| 25994 | src, | ||
| 25995 | "accessing 'len' field on a SPIR-V runtime_array requires a pointer to the array field", | ||
| 25996 | .{}, | ||
| 25997 | ); | ||
| 25998 | } | ||
| 25999 | return sema.analyzeSpirvRuntimeArrayLen(block, src, object, field_name_src); | ||
| 26000 | }, | ||
| 25678 | else => {}, | 26001 | else => {}, |
| 25679 | } | 26002 | } |
| 25680 | return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); | 26003 | return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name); |
| 25681 | } | 26004 | } |
| 25682 | 26005 | ||
| 26006 | fn analyzeSpirvRuntimeArrayLen( | ||
| 26007 | sema: *Sema, | ||
| 26008 | block: *Block, | ||
| 26009 | src: LazySrcLoc, | ||
| 26010 | runtime_array_ptr: Air.Inst.Ref, | ||
| 26011 | src_for_err: LazySrcLoc, | ||
| 26012 | ) CompileError!Air.Inst.Ref { | ||
| 26013 | const pt = sema.pt; | ||
| 26014 | const zcu = pt.zcu; | ||
| 26015 | const ip = &zcu.intern_pool; | ||
| 26016 | |||
| 26017 | const struct_operand: Air.Inst.Ref, const field_index: u32 = sf: { | ||
| 26018 | if (runtime_array_ptr.toIndex()) |inst| { | ||
| 26019 | const tag = sema.air_instructions.items(.tag)[@intFromEnum(inst)]; | ||
| 26020 | const data = sema.air_instructions.items(.data)[@intFromEnum(inst)]; | ||
| 26021 | switch (tag) { | ||
| 26022 | .struct_field_ptr => { | ||
| 26023 | const extra = sema.getTmpAir().extraData(Air.StructField, data.ty_pl.payload).data; | ||
| 26024 | break :sf .{ extra.struct_operand, extra.field_index }; | ||
| 26025 | }, | ||
| 26026 | .struct_field_ptr_index_0 => break :sf .{ data.ty_op.operand, 0 }, | ||
| 26027 | .struct_field_ptr_index_1 => break :sf .{ data.ty_op.operand, 1 }, | ||
| 26028 | .struct_field_ptr_index_2 => break :sf .{ data.ty_op.operand, 2 }, | ||
| 26029 | .struct_field_ptr_index_3 => break :sf .{ data.ty_op.operand, 3 }, | ||
| 26030 | else => {}, | ||
| 26031 | } | ||
| 26032 | } | ||
| 26033 | |||
| 26034 | const ptr_val = sema.resolveValue(runtime_array_ptr) orelse return sema.fail( | ||
| 26035 | block, | ||
| 26036 | src_for_err, | ||
| 26037 | "'len' field on a SPIR-V runtime_array requires direct struct field access", | ||
| 26038 | .{}, | ||
| 26039 | ); | ||
| 26040 | const ptr_key = ip.indexToKey(ptr_val.toIntern()).ptr; | ||
| 26041 | if (ptr_key.base_addr == .field and ptr_key.byte_offset == 0) { | ||
| 26042 | const field = ptr_key.base_addr.field; | ||
| 26043 | break :sf .{ .fromIntern(field.base), @intCast(field.index) }; | ||
| 26044 | } | ||
| 26045 | |||
| 26046 | const parent_ty: Type = switch (ptr_key.base_addr) { | ||
| 26047 | .nav => |nav| .fromInterned(ip.getNav(nav).resolved.?.type), | ||
| 26048 | .uav => |uav| .fromInterned(ip.typeOf(uav.val)), | ||
| 26049 | .comptime_alloc, | ||
| 26050 | .comptime_field, | ||
| 26051 | .eu_payload, | ||
| 26052 | .opt_payload, | ||
| 26053 | .arr_elem, | ||
| 26054 | .field, | ||
| 26055 | .int, | ||
| 26056 | => return sema.fail( | ||
| 26057 | block, | ||
| 26058 | src_for_err, | ||
| 26059 | "'len' field on a SPIR-V runtime_array requires direct struct field access", | ||
| 26060 | .{}, | ||
| 26061 | ), | ||
| 26062 | }; | ||
| 26063 | if (parent_ty.zigTypeTag(zcu) != .@"struct") return sema.fail( | ||
| 26064 | block, | ||
| 26065 | src_for_err, | ||
| 26066 | "'len' field on a SPIR-V runtime_array requires the array to be a struct field", | ||
| 26067 | .{}, | ||
| 26068 | ); | ||
| 26069 | |||
| 26070 | const field_ptr_info = ip.indexToKey(ptr_key.ty).ptr_type; | ||
| 26071 | const rtarr_ty_ip = field_ptr_info.child; | ||
| 26072 | const struct_obj = ip.loadStructType(parent_ty.toIntern()); | ||
| 26073 | const field_idx: u32 = for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, i| { | ||
| 26074 | if (field_ty_ip == rtarr_ty_ip and | ||
| 26075 | struct_obj.field_offsets.get(ip)[i] == ptr_key.byte_offset) | ||
| 26076 | { | ||
| 26077 | break @intCast(i); | ||
| 26078 | } | ||
| 26079 | } else unreachable; | ||
| 26080 | const struct_ptr_ty = try pt.ptrType(.{ | ||
| 26081 | .child = parent_ty.toIntern(), | ||
| 26082 | .flags = field_ptr_info.flags, | ||
| 26083 | }); | ||
| 26084 | const struct_ptr_val = try sema.ptrSubtract( | ||
| 26085 | block, | ||
| 26086 | src_for_err, | ||
| 26087 | ptr_val, | ||
| 26088 | ptr_key.byte_offset, | ||
| 26089 | struct_ptr_ty, | ||
| 26090 | ); | ||
| 26091 | break :sf .{ .fromIntern(struct_ptr_val.toIntern()), field_idx }; | ||
| 26092 | }; | ||
| 26093 | |||
| 26094 | try sema.requireRuntimeBlock(block, src, null); | ||
| 26095 | return block.addInst(.{ | ||
| 26096 | .tag = .spirv_runtime_array_len, | ||
| 26097 | .data = .{ .ty_pl = .{ | ||
| 26098 | .ty = .u32_type, | ||
| 26099 | .payload = try sema.addExtra(Air.StructField{ | ||
| 26100 | .struct_operand = struct_operand, | ||
| 26101 | .field_index = field_index, | ||
| 26102 | }), | ||
| 26103 | } }, | ||
| 26104 | }); | ||
| 26105 | } | ||
| 26106 | |||
| 25683 | fn fieldPtr( | 26107 | fn fieldPtr( |
| 25684 | sema: *Sema, | 26108 | sema: *Sema, |
| 25685 | block: *Block, | 26109 | block: *Block, |
| ... | @@ -26540,6 +26964,7 @@ fn elemPtr( | ... | @@ -26540,6 +26964,7 @@ fn elemPtr( |
| 26540 | .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), | 26964 | .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init), |
| 26541 | .array => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), | 26965 | .array => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| 26542 | .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src), | 26966 | .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src), |
| 26967 | .spirv => try sema.elemPtrSpirvRuntimeArray(block, indexable_ptr, elem_index), | ||
| 26543 | else => { | 26968 | else => { |
| 26544 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); | 26969 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); |
| 26545 | try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src, .ptr_access); | 26970 | try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src, .ptr_access); |
| ... | @@ -26964,6 +27389,22 @@ fn elemPtrVector( | ... | @@ -26964,6 +27389,22 @@ fn elemPtrVector( |
| 26964 | return block.addPtrElemPtr(vector_ptr, elem_index, elem_ptr_ty); | 27389 | return block.addPtrElemPtr(vector_ptr, elem_index, elem_ptr_ty); |
| 26965 | } | 27390 | } |
| 26966 | 27391 | ||
| 27392 | fn elemPtrSpirvRuntimeArray( | ||
| 27393 | sema: *Sema, | ||
| 27394 | block: *Block, | ||
| 27395 | array_ptr: Air.Inst.Ref, | ||
| 27396 | elem_index: Air.Inst.Ref, | ||
| 27397 | ) CompileError!Air.Inst.Ref { | ||
| 27398 | const pt = sema.pt; | ||
| 27399 | const zcu = pt.zcu; | ||
| 27400 | const array_ptr_ty = sema.typeOf(array_ptr); | ||
| 27401 | assert(array_ptr_ty.ptrSize(zcu) == .one); | ||
| 27402 | const array_ty = array_ptr_ty.childType(zcu); | ||
| 27403 | assert(array_ty.isSpirvRuntimeArray(zcu)); | ||
| 27404 | const elem_ptr_ty = try array_ptr_ty.elemPtrType(null, pt); | ||
| 27405 | return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); | ||
| 27406 | } | ||
| 27407 | |||
| 26967 | /// Asserts that the layout of the array is already resolved. | 27408 | /// Asserts that the layout of the array is already resolved. |
| 26968 | fn elemPtrArray( | 27409 | fn elemPtrArray( |
| 26969 | sema: *Sema, | 27410 | sema: *Sema, |
| ... | @@ -31496,7 +31937,7 @@ const PeerResolveStrategy = enum { | ... | @@ -31496,7 +31937,7 @@ const PeerResolveStrategy = enum { |
| 31496 | 31937 | ||
| 31497 | fn select(ty: Type, zcu: *Zcu) PeerResolveStrategy { | 31938 | fn select(ty: Type, zcu: *Zcu) PeerResolveStrategy { |
| 31498 | return switch (ty.zigTypeTag(zcu)) { | 31939 | return switch (ty.zigTypeTag(zcu)) { |
| 31499 | .type, .void, .bool, .@"opaque", .frame, .@"anyframe" => .exact, | 31940 | .type, .void, .bool, .@"opaque", .spirv, .frame, .@"anyframe" => .exact, |
| 31500 | .noreturn, .undefined => .unknown, | 31941 | .noreturn, .undefined => .unknown, |
| 31501 | .null => .nullable, | 31942 | .null => .nullable, |
| 31502 | .comptime_int => .comptime_int, | 31943 | .comptime_int => .comptime_int, |
src/Sema/LowerZon.zig+2| ... | @@ -244,6 +244,7 @@ fn checkTypeInner( | ... | @@ -244,6 +244,7 @@ fn checkTypeInner( |
| 244 | .frame, | 244 | .frame, |
| 245 | .@"anyframe", | 245 | .@"anyframe", |
| 246 | .@"opaque", | 246 | .@"opaque", |
| 247 | .spirv, | ||
| 247 | => return self.failUnsupportedResultType(ty, null), | 248 | => return self.failUnsupportedResultType(ty, null), |
| 248 | 249 | ||
| 249 | .pointer => { | 250 | .pointer => { |
| ... | @@ -408,6 +409,7 @@ fn lowerExprKnownResTyInner( | ... | @@ -408,6 +409,7 @@ fn lowerExprKnownResTyInner( |
| 408 | .error_set, | 409 | .error_set, |
| 409 | .@"fn", | 410 | .@"fn", |
| 410 | .@"opaque", | 411 | .@"opaque", |
| 412 | .spirv, | ||
| 411 | .frame, | 413 | .frame, |
| 412 | .@"anyframe", | 414 | .@"anyframe", |
| 413 | .void, | 415 | .void, |
src/Sema/bitcast.zig+1| ... | @@ -249,6 +249,7 @@ const UnpackValueBits = struct { | ... | @@ -249,6 +249,7 @@ const UnpackValueBits = struct { |
| 249 | .tuple_type, | 249 | .tuple_type, |
| 250 | .union_type, | 250 | .union_type, |
| 251 | .opaque_type, | 251 | .opaque_type, |
| 252 | .spirv_type, | ||
| 252 | .enum_type, | 253 | .enum_type, |
| 253 | .func_type, | 254 | .func_type, |
| 254 | .error_set_type, | 255 | .error_set_type, |
src/Sema/comptime_ptr_access.zig+2| ... | @@ -422,6 +422,7 @@ fn loadComptimePtrInner( | ... | @@ -422,6 +422,7 @@ fn loadComptimePtrInner( |
| 422 | .undefined, | 422 | .undefined, |
| 423 | .enum_literal, | 423 | .enum_literal, |
| 424 | .@"opaque", | 424 | .@"opaque", |
| 425 | .spirv, | ||
| 425 | .@"fn", | 426 | .@"fn", |
| 426 | .error_union, | 427 | .error_union, |
| 427 | => unreachable, // ill-defined layout | 428 | => unreachable, // ill-defined layout |
| ... | @@ -854,6 +855,7 @@ fn prepareComptimePtrStore( | ... | @@ -854,6 +855,7 @@ fn prepareComptimePtrStore( |
| 854 | .undefined, | 855 | .undefined, |
| 855 | .enum_literal, | 856 | .enum_literal, |
| 856 | .@"opaque", | 857 | .@"opaque", |
| 858 | .spirv, | ||
| 857 | .@"fn", | 859 | .@"fn", |
| 858 | .error_union, | 860 | .error_union, |
| 859 | => unreachable, // ill-defined layout | 861 | => unreachable, // ill-defined layout |
src/Sema/type_resolution.zig+44-1| ... | @@ -87,6 +87,7 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons | ... | @@ -87,6 +87,7 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons |
| 87 | .ptr_type, | 87 | .ptr_type, |
| 88 | .anyframe_type, | 88 | .anyframe_type, |
| 89 | .simple_type, | 89 | .simple_type, |
| 90 | .spirv_type, | ||
| 90 | .opaque_type, | 91 | .opaque_type, |
| 91 | .error_set_type, | 92 | .error_set_type, |
| 92 | .inferred_error_set_type, | 93 | .inferred_error_set_type, |
| ... | @@ -288,10 +289,12 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -288,10 +289,12 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 288 | } | 289 | } |
| 289 | 290 | ||
| 290 | // Resolve the layout of all fields, and check their types are allowed. | 291 | // Resolve the layout of all fields, and check their types are allowed. |
| 292 | const fields_len = struct_obj.field_types.len; | ||
| 291 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { | 293 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { |
| 292 | const field_ty: Type = .fromInterned(field_ty_ip); | 294 | const field_ty: Type = .fromInterned(field_ty_ip); |
| 293 | assert(!field_ty.isGenericPoison()); | 295 | assert(!field_ty.isGenericPoison()); |
| 294 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); | 296 | const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) }); |
| 297 | const field_name_src = block.src(.{ .container_field_name = @intCast(field_index) }); | ||
| 295 | try sema.ensureLayoutResolved(field_ty, field_ty_src, .field); | 298 | try sema.ensureLayoutResolved(field_ty, field_ty_src, .field); |
| 296 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | 299 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { |
| 297 | return sema.failWithOwnedErrorMsg(&block, msg: { | 300 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| ... | @@ -302,6 +305,35 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -302,6 +305,35 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 302 | break :msg msg; | 305 | break :msg msg; |
| 303 | }); | 306 | }); |
| 304 | } | 307 | } |
| 308 | if (field_ty.zigTypeTag(zcu) == .spirv) { | ||
| 309 | if (field_ty.isSpirvRuntimeArray(zcu)) { | ||
| 310 | if (struct_obj.layout != .@"extern") { | ||
| 311 | return sema.failWithOwnedErrorMsg(&block, msg: { | ||
| 312 | const msg = try sema.errMsg(struct_ty.srcLoc(zcu), "non-extern struct cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | ||
| 313 | errdefer msg.destroy(gpa); | ||
| 314 | try sema.errNote(field_name_src, msg, "while checking this field", .{}); | ||
| 315 | break :msg msg; | ||
| 316 | }); | ||
| 317 | } | ||
| 318 | if (field_index != fields_len - 1) { | ||
| 319 | return sema.failWithOwnedErrorMsg(&block, msg: { | ||
| 320 | const msg = try sema.errMsg(struct_ty.srcLoc(zcu), "struct field of type '{f}' must be the last field", .{field_ty.fmt(pt)}); | ||
| 321 | errdefer msg.destroy(gpa); | ||
| 322 | try sema.errNote(field_name_src, msg, "while checking this field", .{}); | ||
| 323 | break :msg msg; | ||
| 324 | }); | ||
| 325 | } | ||
| 326 | } else { | ||
| 327 | return sema.failWithOwnedErrorMsg(&block, msg: { | ||
| 328 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed SPIR-V type '{f}' in struct", .{field_ty.fmt(pt)}); | ||
| 329 | errdefer msg.destroy(gpa); | ||
| 330 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | ||
| 331 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 332 | break :msg msg; | ||
| 333 | }); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 305 | if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) { | 337 | if (struct_obj.layout == .@"extern" and !field_ty.validateExtern(.struct_field, zcu)) { |
| 306 | return sema.failWithOwnedErrorMsg(&block, msg: { | 338 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 307 | const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | 339 | const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| ... | @@ -413,7 +445,10 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | ... | @@ -413,7 +445,10 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { |
| 413 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]); | 445 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]); |
| 414 | const offset = resolved_field_aligns[field_idx].forward(cur_offset); | 446 | const offset = resolved_field_aligns[field_idx].forward(cur_offset); |
| 415 | struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below | 447 | struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below |
| 416 | cur_offset = offset + field_ty.abiSize(zcu); | 448 | // A SPIR-V `runtime_array` always trails the struct and |
| 449 | // contributes nothing to the struct's static size. | ||
| 450 | const field_size = if (field_ty.isSpirvRuntimeArray(zcu)) 0 else field_ty.abiSize(zcu); | ||
| 451 | cur_offset = offset + field_size; | ||
| 417 | } | 452 | } |
| 418 | const struct_size: u32 = switch (class) { | 453 | const struct_size: u32 = switch (class) { |
| 419 | .no_possible_value => 0, | 454 | .no_possible_value => 0, |
| ... | @@ -858,6 +893,14 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | ... | @@ -858,6 +893,14 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { |
| 858 | break :msg msg; | 893 | break :msg msg; |
| 859 | }); | 894 | }); |
| 860 | } | 895 | } |
| 896 | if (field_ty.zigTypeTag(zcu) == .spirv) { | ||
| 897 | return sema.failWithOwnedErrorMsg(&block, msg: { | ||
| 898 | const msg = try sema.errMsg(field_ty_src, "SPIR-V type '{f}' have unknown size and therefore cannot be directly embedded in unions", .{field_ty.fmt(pt)}); | ||
| 899 | errdefer msg.destroy(gpa); | ||
| 900 | try sema.addDeclaredHereNote(msg, field_ty); | ||
| 901 | break :msg msg; | ||
| 902 | }); | ||
| 903 | } | ||
| 861 | if (union_obj.layout == .@"extern" and !field_ty.validateExtern(.union_field, zcu)) { | 904 | if (union_obj.layout == .@"extern" and !field_ty.validateExtern(.union_field, zcu)) { |
| 862 | return sema.failWithOwnedErrorMsg(&block, msg: { | 905 | return sema.failWithOwnedErrorMsg(&block, msg: { |
| 863 | const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | 906 | const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
src/Type.zig+30-1| ... | @@ -170,6 +170,7 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class { | ... | @@ -170,6 +170,7 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class { |
| 170 | 170 | ||
| 171 | .func_type => .fully_comptime, | 171 | .func_type => .fully_comptime, |
| 172 | 172 | ||
| 173 | .spirv_type => if (cur_ty.isSpirvRuntimeArray(zcu)) .runtime else .no_possible_value, | ||
| 173 | .opaque_type => .no_possible_value, | 174 | .opaque_type => .no_possible_value, |
| 174 | 175 | ||
| 175 | .error_union_type => |eu| { | 176 | .error_union_type => |eu| { |
| ... | @@ -323,6 +324,7 @@ pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool { | ... | @@ -323,6 +324,7 @@ pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool { |
| 323 | .error_set, | 324 | .error_set, |
| 324 | .@"fn", | 325 | .@"fn", |
| 325 | .@"opaque", | 326 | .@"opaque", |
| 327 | .spirv, | ||
| 326 | .@"anyframe", | 328 | .@"anyframe", |
| 327 | .@"enum", | 329 | .@"enum", |
| 328 | .enum_literal, | 330 | .enum_literal, |
| ... | @@ -617,6 +619,10 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari | ... | @@ -617,6 +619,10 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari |
| 617 | const name = ip.loadEnumType(ty.toIntern()).name; | 619 | const name = ip.loadEnumType(ty.toIntern()).name; |
| 618 | try writer.print("{f}", .{name.fmt(ip)}); | 620 | try writer.print("{f}", .{name.fmt(ip)}); |
| 619 | }, | 621 | }, |
| 622 | .spirv_type => { | ||
| 623 | const name = ip.loadSpirvType(ty.toIntern()).name; | ||
| 624 | try writer.print("{f}", .{name.fmt(ip)}); | ||
| 625 | }, | ||
| 620 | .func_type => |fn_info| { | 626 | .func_type => |fn_info| { |
| 621 | if (fn_info.is_noinline) { | 627 | if (fn_info.is_noinline) { |
| 622 | try writer.writeAll("noinline "); | 628 | try writer.writeAll("noinline "); |
| ... | @@ -704,6 +710,14 @@ pub fn toIntern(ty: Type) InternPool.Index { | ... | @@ -704,6 +710,14 @@ pub fn toIntern(ty: Type) InternPool.Index { |
| 704 | return ty.ip_index; | 710 | return ty.ip_index; |
| 705 | } | 711 | } |
| 706 | 712 | ||
| 713 | pub fn isSpirvRuntimeArray(ty: Type, zcu: *const Zcu) bool { | ||
| 714 | const ip = &zcu.intern_pool; | ||
| 715 | return switch (ip.indexToKey(ty.toIntern())) { | ||
| 716 | .spirv_type => ip.loadSpirvType(ty.toIntern()).flags.tag == .runtime_array, | ||
| 717 | else => false, | ||
| 718 | }; | ||
| 719 | } | ||
| 720 | |||
| 707 | pub fn toValue(self: Type) Value { | 721 | pub fn toValue(self: Type) Value { |
| 708 | return .fromInterned(self.toIntern()); | 722 | return .fromInterned(self.toIntern()); |
| 709 | } | 723 | } |
| ... | @@ -751,6 +765,7 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { | ... | @@ -751,6 +765,7 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { |
| 751 | .error_set_type, | 765 | .error_set_type, |
| 752 | .inferred_error_set_type, | 766 | .inferred_error_set_type, |
| 753 | .tuple_type, | 767 | .tuple_type, |
| 768 | .spirv_type, | ||
| 754 | .opaque_type, | 769 | .opaque_type, |
| 755 | .anyframe_type, | 770 | .anyframe_type, |
| 756 | // These are function bodies, not function pointers. | 771 | // These are function bodies, not function pointers. |
| ... | @@ -1038,6 +1053,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { | ... | @@ -1038,6 +1053,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 1038 | } | 1053 | } |
| 1039 | }, | 1054 | }, |
| 1040 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu), | 1055 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu), |
| 1056 | .spirv_type => if (ty.isSpirvRuntimeArray(zcu)) ty.childType(zcu).abiAlignment(zcu) else .@"1", | ||
| 1041 | .opaque_type => .@"1", | 1057 | .opaque_type => .@"1", |
| 1042 | 1058 | ||
| 1043 | // values, not types | 1059 | // values, not types |
| ... | @@ -1183,6 +1199,7 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { | ... | @@ -1183,6 +1199,7 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { |
| 1183 | } | 1199 | } |
| 1184 | }, | 1200 | }, |
| 1185 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiSize(zcu), | 1201 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiSize(zcu), |
| 1202 | .spirv_type => unreachable, | ||
| 1186 | .opaque_type => unreachable, | 1203 | .opaque_type => unreachable, |
| 1187 | 1204 | ||
| 1188 | // values, not types | 1205 | // values, not types |
| ... | @@ -1309,7 +1326,7 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 { | ... | @@ -1309,7 +1326,7 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 { |
| 1309 | .tuple_type, | 1326 | .tuple_type, |
| 1310 | => ty.abiSize(zcu) * 8, | 1327 | => ty.abiSize(zcu) * 8, |
| 1311 | 1328 | ||
| 1312 | .opaque_type => unreachable, | 1329 | .opaque_type, .spirv_type => unreachable, |
| 1313 | 1330 | ||
| 1314 | // values, not types | 1331 | // values, not types |
| 1315 | .undef, | 1332 | .undef, |
| ... | @@ -1511,14 +1528,17 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type { | ... | @@ -1511,14 +1528,17 @@ pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type { |
| 1511 | /// * `[]T` | 1528 | /// * `[]T` |
| 1512 | /// * `[*]T` | 1529 | /// * `[*]T` |
| 1513 | /// * `[*c]T` | 1530 | /// * `[*c]T` |
| 1531 | /// * `@SpirvType(.{ .runtime_array = T })` | ||
| 1514 | pub fn indexableElem(ty: Type, zcu: *const Zcu) Type { | 1532 | pub fn indexableElem(ty: Type, zcu: *const Zcu) Type { |
| 1515 | const ip = &zcu.intern_pool; | 1533 | const ip = &zcu.intern_pool; |
| 1516 | return switch (ip.indexToKey(ty.toIntern())) { | 1534 | return switch (ip.indexToKey(ty.toIntern())) { |
| 1517 | inline .array_type, .vector_type => |arr| .fromInterned(arr.child), | 1535 | inline .array_type, .vector_type => |arr| .fromInterned(arr.child), |
| 1536 | .spirv_type => ty.childType(zcu), | ||
| 1518 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | 1537 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 1519 | .many, .slice, .c => .fromInterned(ptr_type.child), | 1538 | .many, .slice, .c => .fromInterned(ptr_type.child), |
| 1520 | .one => switch (ip.indexToKey(ptr_type.child)) { | 1539 | .one => switch (ip.indexToKey(ptr_type.child)) { |
| 1521 | inline .array_type, .vector_type => |arr| .fromInterned(arr.child), | 1540 | inline .array_type, .vector_type => |arr| .fromInterned(arr.child), |
| 1541 | .spirv_type => Type.fromInterned(ptr_type.child).childType(zcu), | ||
| 1522 | else => unreachable, | 1542 | else => unreachable, |
| 1523 | }, | 1543 | }, |
| 1524 | }, | 1544 | }, |
| ... | @@ -1864,6 +1884,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { | ... | @@ -1864,6 +1884,7 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { |
| 1864 | .func_type => unreachable, | 1884 | .func_type => unreachable, |
| 1865 | .simple_type => unreachable, // handled via Index enum tag above | 1885 | .simple_type => unreachable, // handled via Index enum tag above |
| 1866 | 1886 | ||
| 1887 | .spirv_type => unreachable, | ||
| 1867 | .opaque_type => unreachable, | 1888 | .opaque_type => unreachable, |
| 1868 | 1889 | ||
| 1869 | // values, not types | 1890 | // values, not types |
| ... | @@ -2032,6 +2053,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value { | ... | @@ -2032,6 +2053,7 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value { |
| 2032 | .error_set_type, | 2053 | .error_set_type, |
| 2033 | .inferred_error_set_type, | 2054 | .inferred_error_set_type, |
| 2034 | .opaque_type, | 2055 | .opaque_type, |
| 2056 | .spirv_type, | ||
| 2035 | => null, | 2057 | => null, |
| 2036 | 2058 | ||
| 2037 | .simple_type => |t| switch (t) { | 2059 | .simple_type => |t| switch (t) { |
| ... | @@ -2219,10 +2241,12 @@ pub fn isIndexable(ty: Type, zcu: *const Zcu) bool { | ... | @@ -2219,10 +2241,12 @@ pub fn isIndexable(ty: Type, zcu: *const Zcu) bool { |
| 2219 | .one => switch (ty.childType(zcu).zigTypeTag(zcu)) { | 2241 | .one => switch (ty.childType(zcu).zigTypeTag(zcu)) { |
| 2220 | .array, .vector => true, | 2242 | .array, .vector => true, |
| 2221 | .@"struct" => ty.childType(zcu).isTuple(zcu), | 2243 | .@"struct" => ty.childType(zcu).isTuple(zcu), |
| 2244 | .spirv => ty.childType(zcu).isSpirvRuntimeArray(zcu), | ||
| 2222 | else => false, | 2245 | else => false, |
| 2223 | }, | 2246 | }, |
| 2224 | }, | 2247 | }, |
| 2225 | .@"struct" => ty.isTuple(zcu), | 2248 | .@"struct" => ty.isTuple(zcu), |
| 2249 | .spirv => ty.isSpirvRuntimeArray(zcu), | ||
| 2226 | else => false, | 2250 | else => false, |
| 2227 | }; | 2251 | }; |
| 2228 | } | 2252 | } |
| ... | @@ -2844,6 +2868,7 @@ pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error | ... | @@ -2844,6 +2868,7 @@ pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error |
| 2844 | .slice, .many, .c => .fromInterned(ptr_info.child), | 2868 | .slice, .many, .c => .fromInterned(ptr_info.child), |
| 2845 | .one => switch (ip.indexToKey(ptr_info.child)) { | 2869 | .one => switch (ip.indexToKey(ptr_info.child)) { |
| 2846 | .array_type => |array_type| .fromInterned(array_type.child), | 2870 | .array_type => |array_type| .fromInterned(array_type.child), |
| 2871 | .spirv_type => Type.fromInterned(ptr_info.child).childType(zcu), | ||
| 2847 | else => unreachable, | 2872 | else => unreachable, |
| 2848 | }, | 2873 | }, |
| 2849 | }; | 2874 | }; |
| ... | @@ -3095,6 +3120,7 @@ pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { | ... | @@ -3095,6 +3120,7 @@ pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { |
| 3095 | 3120 | ||
| 3096 | .noreturn, | 3121 | .noreturn, |
| 3097 | .@"opaque", | 3122 | .@"opaque", |
| 3123 | .spirv, | ||
| 3098 | .error_union, | 3124 | .error_union, |
| 3099 | .error_set, | 3125 | .error_set, |
| 3100 | .frame, | 3126 | .frame, |
| ... | @@ -3170,6 +3196,7 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool | ... | @@ -3170,6 +3196,7 @@ pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool |
| 3170 | .noreturn => position == .ret_ty, | 3196 | .noreturn => position == .ret_ty, |
| 3171 | 3197 | ||
| 3172 | .@"opaque", | 3198 | .@"opaque", |
| 3199 | .spirv, | ||
| 3173 | .bool, | 3200 | .bool, |
| 3174 | .float, | 3201 | .float, |
| 3175 | .@"anyframe", | 3202 | .@"anyframe", |
| ... | @@ -3261,6 +3288,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { | ... | @@ -3261,6 +3288,7 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { |
| 3261 | .simple_type, | 3288 | .simple_type, |
| 3262 | .opaque_type, | 3289 | .opaque_type, |
| 3263 | .error_set_type, | 3290 | .error_set_type, |
| 3291 | .spirv_type, | ||
| 3264 | .inferred_error_set_type, | 3292 | .inferred_error_set_type, |
| 3265 | => {}, | 3293 | => {}, |
| 3266 | .func_type => |func_type| { | 3294 | .func_type => |func_type| { |
| ... | @@ -3362,6 +3390,7 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn | ... | @@ -3362,6 +3390,7 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn |
| 3362 | .union_type, | 3390 | .union_type, |
| 3363 | .opaque_type, | 3391 | .opaque_type, |
| 3364 | .enum_type, | 3392 | .enum_type, |
| 3393 | .spirv_type, | ||
| 3365 | .simple_type, | 3394 | .simple_type, |
| 3366 | .int_type, | 3395 | .int_type, |
| 3367 | => {}, | 3396 | => {}, |
src/Value.zig+7-1| ... | @@ -2046,7 +2046,10 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op | ... | @@ -2046,7 +2046,10 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op |
| 2046 | 2046 | ||
| 2047 | const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu); | 2047 | const ptr_ty_info = Type.fromInterned(ptr.ty).ptrInfo(zcu); |
| 2048 | const need_child: Type = .fromInterned(ptr_ty_info.child); | 2048 | const need_child: Type = .fromInterned(ptr_ty_info.child); |
| 2049 | if (need_child.comptimeOnly(zcu) or need_child.zigTypeTag(zcu) == .@"opaque") { | 2049 | if (need_child.comptimeOnly(zcu) or |
| 2050 | need_child.zigTypeTag(zcu) == .@"opaque" or | ||
| 2051 | need_child.isSpirvRuntimeArray(zcu)) | ||
| 2052 | { | ||
| 2050 | // No refinement can happen - this pointer is presumably invalid. | 2053 | // No refinement can happen - this pointer is presumably invalid. |
| 2051 | // Just offset it. | 2054 | // Just offset it. |
| 2052 | const parent = try arena.create(PointerDeriveStep); | 2055 | const parent = try arena.create(PointerDeriveStep); |
| ... | @@ -2078,6 +2081,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op | ... | @@ -2078,6 +2081,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, op |
| 2078 | .undefined, | 2081 | .undefined, |
| 2079 | .enum_literal, | 2082 | .enum_literal, |
| 2080 | .@"opaque", | 2083 | .@"opaque", |
| 2084 | .spirv, | ||
| 2081 | .@"fn", | 2085 | .@"fn", |
| 2082 | .error_union, | 2086 | .error_union, |
| 2083 | .int, | 2087 | .int, |
| ... | @@ -2229,6 +2233,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe | ... | @@ -2229,6 +2233,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe |
| 2229 | .null, | 2233 | .null, |
| 2230 | .@"fn", | 2234 | .@"fn", |
| 2231 | .@"opaque", | 2235 | .@"opaque", |
| 2236 | .spirv, | ||
| 2232 | .enum_literal, | 2237 | .enum_literal, |
| 2233 | => comptime unreachable, // comptime-only or otherwise impossible | 2238 | => comptime unreachable, // comptime-only or otherwise impossible |
| 2234 | 2239 | ||
| ... | @@ -2332,6 +2337,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory | ... | @@ -2332,6 +2337,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory |
| 2332 | .null, | 2337 | .null, |
| 2333 | .@"fn", | 2338 | .@"fn", |
| 2334 | .@"opaque", | 2339 | .@"opaque", |
| 2340 | .spirv, | ||
| 2335 | .enum_literal, | 2341 | .enum_literal, |
| 2336 | => comptime unreachable, // comptime-only or otherwise impossible | 2342 | => comptime unreachable, // comptime-only or otherwise impossible |
| 2337 | 2343 |
src/Zcu.zig+4-1| ... | @@ -468,6 +468,7 @@ pub const StdLangDecl = enum { | ... | @@ -468,6 +468,7 @@ pub const StdLangDecl = enum { |
| 468 | @"Type.Struct.FieldAttributes", | 468 | @"Type.Struct.FieldAttributes", |
| 469 | @"Type.ContainerLayout", | 469 | @"Type.ContainerLayout", |
| 470 | @"Type.Opaque", | 470 | @"Type.Opaque", |
| 471 | @"Type.Spirv", | ||
| 471 | 472 | ||
| 472 | panic, | 473 | panic, |
| 473 | @"panic.call", | 474 | @"panic.call", |
| ... | @@ -548,6 +549,7 @@ pub const StdLangDecl = enum { | ... | @@ -548,6 +549,7 @@ pub const StdLangDecl = enum { |
| 548 | .@"Type.Struct.FieldAttributes", | 549 | .@"Type.Struct.FieldAttributes", |
| 549 | .@"Type.ContainerLayout", | 550 | .@"Type.ContainerLayout", |
| 550 | .@"Type.Opaque", | 551 | .@"Type.Opaque", |
| 552 | .@"Type.Spirv", | ||
| 551 | => .type, | 553 | => .type, |
| 552 | 554 | ||
| 553 | .panic => .type, | 555 | .panic => .type, |
| ... | @@ -601,7 +603,7 @@ pub const StdLangDecl = enum { | ... | @@ -601,7 +603,7 @@ pub const StdLangDecl = enum { |
| 601 | .VaList => .va_list, | 603 | .VaList => .va_list, |
| 602 | .assembly, .@"assembly.Clobbers" => .assembly, | 604 | .assembly, .@"assembly.Clobbers" => .assembly, |
| 603 | else => { | 605 | else => { |
| 604 | if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Opaque")) { | 606 | if (@intFromEnum(decl) <= @intFromEnum(StdLangDecl.@"Type.Spirv")) { |
| 605 | return .main; | 607 | return .main; |
| 606 | } else { | 608 | } else { |
| 607 | return .panic; | 609 | return .panic; |
| ... | @@ -2740,6 +2742,7 @@ pub const LazySrcLoc = struct { | ... | @@ -2740,6 +2742,7 @@ pub const LazySrcLoc = struct { |
| 2740 | .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node, | 2742 | .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node, |
| 2741 | .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node, | 2743 | .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node, |
| 2742 | .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node, | 2744 | .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node, |
| 2745 | .reify_spirv_type => zir.extraData(Zir.Inst.ReifySpirvType, inst.data.extended.operand).data.node, | ||
| 2743 | else => unreachable, | 2746 | else => unreachable, |
| 2744 | }, | 2747 | }, |
| 2745 | else => unreachable, | 2748 | else => unreachable, |
src/codegen.zig+1| ... | @@ -329,6 +329,7 @@ pub fn generateSymbol( | ... | @@ -329,6 +329,7 @@ pub fn generateSymbol( |
| 329 | .tuple_type, | 329 | .tuple_type, |
| 330 | .union_type, | 330 | .union_type, |
| 331 | .opaque_type, | 331 | .opaque_type, |
| 332 | .spirv_type, | ||
| 332 | .enum_type, | 333 | .enum_type, |
| 333 | .func_type, | 334 | .func_type, |
| 334 | .error_set_type, | 335 | .error_set_type, |
src/codegen/aarch64/Select.zig+2-1| ... | @@ -255,6 +255,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | ... | @@ -255,6 +255,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { |
| 255 | .work_item_id, | 255 | .work_item_id, |
| 256 | .work_group_size, | 256 | .work_group_size, |
| 257 | .work_group_id, | 257 | .work_group_id, |
| 258 | .spirv_runtime_array_len, | ||
| 258 | => unreachable, | 259 | => unreachable, |
| 259 | .ret_ptr => { | 260 | .ret_ptr => { |
| 260 | const ty = air_data[@intFromEnum(air_inst_index)].ty; | 261 | const ty = air_data[@intFromEnum(air_inst_index)].ty; |
| ... | @@ -7491,7 +7492,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, | ... | @@ -7491,7 +7492,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 7491 | } | 7492 | } |
| 7492 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | 7493 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; |
| 7493 | }, | 7494 | }, |
| 7494 | .work_item_id, .work_group_size, .work_group_id => unreachable, | 7495 | .work_item_id, .work_group_size, .work_group_id, .spirv_runtime_array_len => unreachable, |
| 7495 | } | 7496 | } |
| 7496 | assert(air.body_index == 0); | 7497 | assert(air.body_index == 0); |
| 7497 | } | 7498 | } |
src/codegen/aarch64/abi.zig+1| ... | @@ -62,6 +62,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { | ... | @@ -62,6 +62,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { |
| 62 | .null, | 62 | .null, |
| 63 | .@"fn", | 63 | .@"fn", |
| 64 | .@"opaque", | 64 | .@"opaque", |
| 65 | .spirv, | ||
| 65 | .enum_literal, | 66 | .enum_literal, |
| 66 | .array, | 67 | .array, |
| 67 | => unreachable, | 68 | => unreachable, |
src/codegen/arm/abi.zig+1| ... | @@ -113,6 +113,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { | ... | @@ -113,6 +113,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { |
| 113 | .null, | 113 | .null, |
| 114 | .@"fn", | 114 | .@"fn", |
| 115 | .@"opaque", | 115 | .@"opaque", |
| 116 | .spirv, | ||
| 116 | .enum_literal, | 117 | .enum_literal, |
| 117 | .array, | 118 | .array, |
| 118 | => unreachable, | 119 | => unreachable, |
src/codegen/c.zig+3| ... | @@ -902,6 +902,7 @@ pub const DeclGen = struct { | ... | @@ -902,6 +902,7 @@ pub const DeclGen = struct { |
| 902 | .tuple_type, | 902 | .tuple_type, |
| 903 | .union_type, | 903 | .union_type, |
| 904 | .opaque_type, | 904 | .opaque_type, |
| 905 | .spirv_type, | ||
| 905 | .enum_type, | 906 | .enum_type, |
| 906 | .func_type, | 907 | .func_type, |
| 907 | .error_set_type, | 908 | .error_set_type, |
| ... | @@ -1565,6 +1566,7 @@ pub const DeclGen = struct { | ... | @@ -1565,6 +1566,7 @@ pub const DeclGen = struct { |
| 1565 | }, | 1566 | }, |
| 1566 | .anyframe_type, | 1567 | .anyframe_type, |
| 1567 | .opaque_type, | 1568 | .opaque_type, |
| 1569 | .spirv_type, | ||
| 1568 | .func_type, | 1570 | .func_type, |
| 1569 | => unreachable, | 1571 | => unreachable, |
| 1570 | 1572 | ||
| ... | @@ -2877,6 +2879,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { | ... | @@ -2877,6 +2879,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void { |
| 2877 | .work_item_id, | 2879 | .work_item_id, |
| 2878 | .work_group_size, | 2880 | .work_group_size, |
| 2879 | .work_group_id, | 2881 | .work_group_id, |
| 2882 | .spirv_runtime_array_len, | ||
| 2880 | => unreachable, | 2883 | => unreachable, |
| 2881 | 2884 | ||
| 2882 | // Instructions that are known to always be `noreturn` based on their tag. | 2885 | // Instructions that are known to always be `noreturn` based on their tag. |
src/codegen/c/type.zig+3| ... | @@ -249,6 +249,7 @@ pub const CType = union(enum) { | ... | @@ -249,6 +249,7 @@ pub const CType = union(enum) { |
| 249 | .null, | 249 | .null, |
| 250 | .enum_literal, | 250 | .enum_literal, |
| 251 | .@"opaque", | 251 | .@"opaque", |
| 252 | .spirv, | ||
| 252 | .noreturn, | 253 | .noreturn, |
| 253 | .void, | 254 | .void, |
| 254 | => return .void, | 255 | => return .void, |
| ... | @@ -865,6 +866,7 @@ pub const CType = union(enum) { | ... | @@ -865,6 +866,7 @@ pub const CType = union(enum) { |
| 865 | switch (ty.zigTypeTag(zcu)) { | 866 | switch (ty.zigTypeTag(zcu)) { |
| 866 | .frame => unreachable, | 867 | .frame => unreachable, |
| 867 | .@"anyframe" => unreachable, | 868 | .@"anyframe" => unreachable, |
| 869 | .spirv => unreachable, | ||
| 868 | 870 | ||
| 869 | .type => try w.writeAll("type"), | 871 | .type => try w.writeAll("type"), |
| 870 | .void => try w.writeAll("void"), | 872 | .void => try w.writeAll("void"), |
| ... | @@ -988,6 +990,7 @@ pub const CType = union(enum) { | ... | @@ -988,6 +990,7 @@ pub const CType = union(enum) { |
| 988 | .anyframe_type, | 990 | .anyframe_type, |
| 989 | .simple_type, | 991 | .simple_type, |
| 990 | .opaque_type, | 992 | .opaque_type, |
| 993 | .spirv_type, | ||
| 991 | .error_set_type, | 994 | .error_set_type, |
| 992 | .inferred_error_set_type, | 995 | .inferred_error_set_type, |
| 993 | => true, | 996 | => true, |
src/codegen/llvm.zig+3-1| ... | @@ -2662,6 +2662,7 @@ pub const Object = struct { | ... | @@ -2662,6 +2662,7 @@ pub const Object = struct { |
| 2662 | }, | 2662 | }, |
| 2663 | .frame => @panic("TODO implement lowerDebugType for Frame types"), | 2663 | .frame => @panic("TODO implement lowerDebugType for Frame types"), |
| 2664 | .@"anyframe" => @panic("TODO implement lowerDebugType for AnyFrame types"), | 2664 | .@"anyframe" => @panic("TODO implement lowerDebugType for AnyFrame types"), |
| 2665 | .spirv => unreachable, | ||
| 2665 | } | 2666 | } |
| 2666 | } | 2667 | } |
| 2667 | 2668 | ||
| ... | @@ -3375,7 +3376,7 @@ pub const Object = struct { | ... | @@ -3375,7 +3376,7 @@ pub const Object = struct { |
| 3375 | ); | 3376 | ); |
| 3376 | return ty; | 3377 | return ty; |
| 3377 | }, | 3378 | }, |
| 3378 | .opaque_type => unreachable, // no runtime bits | 3379 | .opaque_type, .spirv_type => unreachable, // no runtime bits |
| 3379 | .enum_type => try o.lowerType(t.intTagType(zcu)), | 3380 | .enum_type => try o.lowerType(t.intTagType(zcu)), |
| 3380 | .func_type => |func_type| try o.lowerFnType(t, func_type), | 3381 | .func_type => |func_type| try o.lowerFnType(t, func_type), |
| 3381 | .error_set_type, .inferred_error_set_type => try o.errorIntType(), | 3382 | .error_set_type, .inferred_error_set_type => try o.errorIntType(), |
| ... | @@ -3497,6 +3498,7 @@ pub const Object = struct { | ... | @@ -3497,6 +3498,7 @@ pub const Object = struct { |
| 3497 | .tuple_type, | 3498 | .tuple_type, |
| 3498 | .union_type, | 3499 | .union_type, |
| 3499 | .opaque_type, | 3500 | .opaque_type, |
| 3501 | .spirv_type, | ||
| 3500 | .enum_type, | 3502 | .enum_type, |
| 3501 | .func_type, | 3503 | .func_type, |
| 3502 | .error_set_type, | 3504 | .error_set_type, |
src/codegen/llvm/FuncGen.zig+2| ... | @@ -434,6 +434,7 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air | ... | @@ -434,6 +434,7 @@ pub fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air |
| 434 | .work_item_id => try self.airWorkItemId(inst), | 434 | .work_item_id => try self.airWorkItemId(inst), |
| 435 | .work_group_size => try self.airWorkGroupSize(inst), | 435 | .work_group_size => try self.airWorkGroupSize(inst), |
| 436 | .work_group_id => try self.airWorkGroupId(inst), | 436 | .work_group_id => try self.airWorkGroupId(inst), |
| 437 | .spirv_runtime_array_len => unreachable, | ||
| 437 | 438 | ||
| 438 | // Instructions that are known to always be `noreturn` based on their tag. | 439 | // Instructions that are known to always be `noreturn` based on their tag. |
| 439 | .br => return self.airBr(inst), | 440 | .br => return self.airBr(inst), |
| ... | @@ -7255,6 +7256,7 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool { | ... | @@ -7255,6 +7256,7 @@ pub fn isByRef(ty: Type, zcu: *const Zcu) bool { |
| 7255 | .undefined, | 7256 | .undefined, |
| 7256 | .null, | 7257 | .null, |
| 7257 | .@"opaque", | 7258 | .@"opaque", |
| 7259 | .spirv, | ||
| 7258 | => unreachable, | 7260 | => unreachable, |
| 7259 | 7261 | ||
| 7260 | .noreturn, | 7262 | .noreturn, |
src/codegen/mips/abi.zig+1| ... | @@ -77,6 +77,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { | ... | @@ -77,6 +77,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { |
| 77 | .null, | 77 | .null, |
| 78 | .@"fn", | 78 | .@"fn", |
| 79 | .@"opaque", | 79 | .@"opaque", |
| 80 | .spirv, | ||
| 80 | .enum_literal, | 81 | .enum_literal, |
| 81 | .array, | 82 | .array, |
| 82 | => unreachable, | 83 | => unreachable, |
src/codegen/riscv64/CodeGen.zig+1| ... | @@ -1642,6 +1642,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1642,6 +1642,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void { |
| 1642 | .work_item_id => unreachable, | 1642 | .work_item_id => unreachable, |
| 1643 | .work_group_size => unreachable, | 1643 | .work_group_size => unreachable, |
| 1644 | .work_group_id => unreachable, | 1644 | .work_group_id => unreachable, |
| 1645 | .spirv_runtime_array_len => unreachable, | ||
| 1645 | // zig fmt: on | 1646 | // zig fmt: on |
| 1646 | } | 1647 | } |
| 1647 | 1648 |
src/codegen/riscv64/abi.zig+1| ... | @@ -87,6 +87,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { | ... | @@ -87,6 +87,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { |
| 87 | .null, | 87 | .null, |
| 88 | .@"fn", | 88 | .@"fn", |
| 89 | .@"opaque", | 89 | .@"opaque", |
| 90 | .spirv, | ||
| 90 | .enum_literal, | 91 | .enum_literal, |
| 91 | .array, | 92 | .array, |
| 92 | => unreachable, | 93 | => unreachable, |
src/codegen/sparc64/CodeGen.zig+1| ... | @@ -709,6 +709,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -709,6 +709,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 709 | .work_item_id => unreachable, | 709 | .work_item_id => unreachable, |
| 710 | .work_group_size => unreachable, | 710 | .work_group_size => unreachable, |
| 711 | .work_group_id => unreachable, | 711 | .work_group_id => unreachable, |
| 712 | .spirv_runtime_array_len => unreachable, | ||
| 712 | // zig fmt: on | 713 | // zig fmt: on |
| 713 | } | 714 | } |
| 714 | 715 |
src/codegen/spirv/Assembler.zig+1-1| ... | @@ -269,7 +269,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { | ... | @@ -269,7 +269,7 @@ fn processTypeInstruction(ass: *Assembler) !AsmValue { |
| 269 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); | 269 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| 270 | const ids = try cg.id_scratch.addManyAsSlice(gpa, operands[1..].len); | 270 | const ids = try cg.id_scratch.addManyAsSlice(gpa, operands[1..].len); |
| 271 | for (operands[1..], ids) |op, *id| id.* = try ass.resolveRefId(op.ref_id); | 271 | for (operands[1..], ids) |op, *id| id.* = try ass.resolveRefId(op.ref_id); |
| 272 | break :blk try module.structType(ids, null, null, .none); | 272 | break :blk try module.structType(ids, null, .none); |
| 273 | }, | 273 | }, |
| 274 | .OpTypeImage => blk: { | 274 | .OpTypeImage => blk: { |
| 275 | const sampled_type = try ass.resolveRefId(operands[1].ref_id); | 275 | const sampled_type = try ass.resolveRefId(operands[1].ref_id); |
src/codegen/spirv/CodeGen.zig+141-26| ... | @@ -271,7 +271,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { | ... | @@ -271,7 +271,13 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 271 | .vulkan, .opengl => { | 271 | .vulkan, .opengl => { |
| 272 | if (ty.zigTypeTag(zcu) == .@"struct") { | 272 | if (ty.zigTypeTag(zcu) == .@"struct") { |
| 273 | switch (storage_class) { | 273 | switch (storage_class) { |
| 274 | .uniform, .push_constant => try cg.module.decorate(ty_id, .block), | 274 | .uniform, |
| 275 | .push_constant, | ||
| 276 | .storage_buffer, | ||
| 277 | => { | ||
| 278 | try cg.module.decorate(ty_id, .block); | ||
| 279 | try cg.decorateBlockOffsets(ty, ty_id); | ||
| 280 | }, | ||
| 275 | else => {}, | 281 | else => {}, |
| 276 | } | 282 | } |
| 277 | } | 283 | } |
| ... | @@ -313,6 +319,18 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { | ... | @@ -313,6 +319,18 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 313 | try cg.module.debugName(result_id, nav.fqn.toSlice(ip)); | 319 | try cg.module.debugName(result_id, nav.fqn.toSlice(ip)); |
| 314 | }, | 320 | }, |
| 315 | .invocation_global => { | 321 | .invocation_global => { |
| 322 | // `@extern()` produces an invocation_global whose value is a | ||
| 323 | // comptime-known pointer to an underlying extern symbol's Nav. | ||
| 324 | // The pointer is inlined at use sites so we don't need a Function-scope wrapper here. | ||
| 325 | if (ip.indexToKey(val.toIntern()) == .ptr) alias: { | ||
| 326 | const ptr_key = ip.indexToKey(val.toIntern()).ptr; | ||
| 327 | if (ptr_key.base_addr != .nav or ptr_key.byte_offset != 0) break :alias; | ||
| 328 | const underlying_nav = ip.getNav(ptr_key.base_addr.nav); | ||
| 329 | if (!underlying_nav.resolved.?.is_extern_decl) break :alias; | ||
| 330 | cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len; | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | |||
| 316 | const ty_id = try cg.resolveType(ty, .indirect); | 334 | const ty_id = try cg.resolveType(ty, .indirect); |
| 317 | const ptr_ty_id = try cg.module.ptrType(ty_id, .function); | 335 | const ptr_ty_id = try cg.module.ptrType(ty_id, .function); |
| 318 | 336 | ||
| ... | @@ -360,6 +378,21 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { | ... | @@ -360,6 +378,21 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 360 | cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len; | 378 | cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len; |
| 361 | } | 379 | } |
| 362 | 380 | ||
| 381 | fn decorateBlockOffsets(cg: *CodeGen, ty: Type, ty_id: spec.Id) !void { | ||
| 382 | const zcu = cg.module.zcu; | ||
| 383 | const ip = &zcu.intern_pool; | ||
| 384 | const struct_type = ip.loadStructType(ty.toIntern()); | ||
| 385 | var it = struct_type.iterateRuntimeOrder(ip); | ||
| 386 | var member: u32 = 0; | ||
| 387 | while (it.next()) |field_index| { | ||
| 388 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); | ||
| 389 | if (!field_ty.hasRuntimeBits(zcu)) continue; | ||
| 390 | const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu)); | ||
| 391 | try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } }); | ||
| 392 | member += 1; | ||
| 393 | } | ||
| 394 | } | ||
| 395 | |||
| 363 | pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error { | 396 | pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error { |
| 364 | @branchHint(.cold); | 397 | @branchHint(.cold); |
| 365 | return cg.module.zcu.codegenFail(cg.owner_nav, format, args); | 398 | return cg.module.zcu.codegenFail(cg.owner_nav, format, args); |
| ... | @@ -779,6 +812,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { | ... | @@ -779,6 +812,7 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 779 | .tuple_type, | 812 | .tuple_type, |
| 780 | .union_type, | 813 | .union_type, |
| 781 | .opaque_type, | 814 | .opaque_type, |
| 815 | .spirv_type, | ||
| 782 | .enum_type, | 816 | .enum_type, |
| 783 | .func_type, | 817 | .func_type, |
| 784 | .error_set_type, | 818 | .error_set_type, |
| ... | @@ -1065,16 +1099,18 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { | ... | @@ -1065,16 +1099,18 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { |
| 1065 | const parent_ptr_id = try cg.derivePtr(oac.parent.*); | 1099 | const parent_ptr_id = try cg.derivePtr(oac.parent.*); |
| 1066 | const parent_ptr_ty = try oac.parent.ptrType(pt); | 1100 | const parent_ptr_ty = try oac.parent.ptrType(pt); |
| 1067 | const result_ty_id = try cg.resolveType(oac.new_ptr_ty, .direct); | 1101 | const result_ty_id = try cg.resolveType(oac.new_ptr_ty, .direct); |
| 1068 | const child_size = oac.new_ptr_ty.childType(zcu).abiSize(zcu); | ||
| 1069 | 1102 | ||
| 1070 | if (parent_ptr_ty.childType(zcu).isVector(zcu) and oac.byte_offset % child_size == 0) { | 1103 | if (parent_ptr_ty.childType(zcu).isVector(zcu)) { |
| 1071 | // Vector element ptr accesses are derived as offset_and_cast. | 1104 | // Vector element ptr accesses are derived as offset_and_cast. |
| 1072 | // We can just use OpAccessChain. | 1105 | // We can just use OpAccessChain. |
| 1073 | return cg.accessChain( | 1106 | const child_size = oac.new_ptr_ty.childType(zcu).abiSize(zcu); |
| 1074 | result_ty_id, | 1107 | if (oac.byte_offset % child_size == 0) { |
| 1075 | parent_ptr_id, | 1108 | return cg.accessChain( |
| 1076 | &.{@intCast(@divExact(oac.byte_offset, child_size))}, | 1109 | result_ty_id, |
| 1077 | ); | 1110 | parent_ptr_id, |
| 1111 | &.{@intCast(@divExact(oac.byte_offset, child_size))}, | ||
| 1112 | ); | ||
| 1113 | } | ||
| 1078 | } | 1114 | } |
| 1079 | 1115 | ||
| 1080 | if (oac.byte_offset == 0) { | 1116 | if (oac.byte_offset == 0) { |
| ... | @@ -1269,7 +1305,6 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id { | ... | @@ -1269,7 +1305,6 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id { |
| 1269 | const result_id = try cg.module.structType( | 1305 | const result_id = try cg.module.structType( |
| 1270 | member_types[0..layout.total_fields], | 1306 | member_types[0..layout.total_fields], |
| 1271 | member_names[0..layout.total_fields], | 1307 | member_names[0..layout.total_fields], |
| 1272 | null, | ||
| 1273 | .none, | 1308 | .none, |
| 1274 | ); | 1309 | ); |
| 1275 | 1310 | ||
| ... | @@ -1450,7 +1485,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1450,7 +1485,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1450 | return try cg.module.structType( | 1485 | return try cg.module.structType( |
| 1451 | &.{ ptr_ty_id, size_ty_id }, | 1486 | &.{ ptr_ty_id, size_ty_id }, |
| 1452 | &.{ "ptr", "len" }, | 1487 | &.{ "ptr", "len" }, |
| 1453 | null, | ||
| 1454 | .none, | 1488 | .none, |
| 1455 | ); | 1489 | ); |
| 1456 | }, | 1490 | }, |
| ... | @@ -1472,7 +1506,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1472,7 +1506,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1472 | const result_id = try cg.module.structType( | 1506 | const result_id = try cg.module.structType( |
| 1473 | member_types[0..member_index], | 1507 | member_types[0..member_index], |
| 1474 | null, | 1508 | null, |
| 1475 | null, | ||
| 1476 | .none, | 1509 | .none, |
| 1477 | ); | 1510 | ); |
| 1478 | const type_name = try cg.resolveTypeName(ty); | 1511 | const type_name = try cg.resolveTypeName(ty); |
| ... | @@ -1494,9 +1527,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1494,9 +1527,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1494 | var member_names = std.array_list.Managed([]const u8).init(gpa); | 1527 | var member_names = std.array_list.Managed([]const u8).init(gpa); |
| 1495 | defer member_names.deinit(); | 1528 | defer member_names.deinit(); |
| 1496 | 1529 | ||
| 1497 | var member_offsets = std.array_list.Managed(u32).init(gpa); | ||
| 1498 | defer member_offsets.deinit(); | ||
| 1499 | |||
| 1500 | var it = struct_type.iterateRuntimeOrder(ip); | 1530 | var it = struct_type.iterateRuntimeOrder(ip); |
| 1501 | while (it.next()) |field_index| { | 1531 | while (it.next()) |field_index| { |
| 1502 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); | 1532 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); |
| ... | @@ -1505,13 +1535,11 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1505,13 +1535,11 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1505 | const field_name = struct_type.field_names.get(ip)[field_index]; | 1535 | const field_name = struct_type.field_names.get(ip)[field_index]; |
| 1506 | try member_types.append(try cg.resolveType(field_ty, .indirect)); | 1536 | try member_types.append(try cg.resolveType(field_ty, .indirect)); |
| 1507 | try member_names.append(field_name.toSlice(ip)); | 1537 | try member_names.append(field_name.toSlice(ip)); |
| 1508 | try member_offsets.append(@intCast(ty.structFieldOffset(field_index, zcu))); | ||
| 1509 | } | 1538 | } |
| 1510 | 1539 | ||
| 1511 | const result_id = try cg.module.structType( | 1540 | const result_id = try cg.module.structType( |
| 1512 | member_types.items, | 1541 | member_types.items, |
| 1513 | member_names.items, | 1542 | member_names.items, |
| 1514 | member_offsets.items, | ||
| 1515 | ty.toIntern(), | 1543 | ty.toIntern(), |
| 1516 | ); | 1544 | ); |
| 1517 | 1545 | ||
| ... | @@ -1541,7 +1569,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1541,7 +1569,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1541 | return try cg.module.structType( | 1569 | return try cg.module.structType( |
| 1542 | &.{ payload_ty_id, bool_ty_id }, | 1570 | &.{ payload_ty_id, bool_ty_id }, |
| 1543 | &.{ "payload", "valid" }, | 1571 | &.{ "payload", "valid" }, |
| 1544 | null, | ||
| 1545 | .none, | 1572 | .none, |
| 1546 | ); | 1573 | ); |
| 1547 | }, | 1574 | }, |
| ... | @@ -1576,7 +1603,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1576,7 +1603,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1576 | // TODO: ABI padding? | 1603 | // TODO: ABI padding? |
| 1577 | } | 1604 | } |
| 1578 | 1605 | ||
| 1579 | return try cg.module.structType(&member_types, &member_names, null, .none); | 1606 | return try cg.module.structType(&member_types, &member_names, .none); |
| 1580 | }, | 1607 | }, |
| 1581 | .@"opaque" => { | 1608 | .@"opaque" => { |
| 1582 | if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); | 1609 | if (target.os.tag != .opencl) return cg.fail("cannot generate opaque type", .{}); |
| ... | @@ -1584,6 +1611,77 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1584,6 +1611,77 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1584 | defer gpa.free(type_name); | 1611 | defer gpa.free(type_name); |
| 1585 | return try cg.module.opaqueType(type_name); | 1612 | return try cg.module.opaqueType(type_name); |
| 1586 | }, | 1613 | }, |
| 1614 | .spirv => { | ||
| 1615 | const ip_index = ty.toIntern(); | ||
| 1616 | const spirv_type = ip.loadSpirvType(ip_index); | ||
| 1617 | switch (spirv_type.flags.tag) { | ||
| 1618 | .sampler => return try cg.module.samplerType(ip_index), | ||
| 1619 | .image => { | ||
| 1620 | const sampled_type_id = blk: { | ||
| 1621 | if (spirv_type.ty == .none) break :blk try cg.module.intType(.unsigned, 32); | ||
| 1622 | break :blk try cg.resolveType(Type.fromInterned(spirv_type.ty), .direct); | ||
| 1623 | }; | ||
| 1624 | return try cg.module.imageType( | ||
| 1625 | ip_index, | ||
| 1626 | sampled_type_id, | ||
| 1627 | switch (spirv_type.flags.dim) { | ||
| 1628 | .@"1d" => .@"1d", | ||
| 1629 | .@"2d" => .@"2d", | ||
| 1630 | .@"3d" => .@"3d", | ||
| 1631 | .cube => .cube, | ||
| 1632 | }, | ||
| 1633 | switch (spirv_type.flags.depth) { | ||
| 1634 | .not_depth => 0, | ||
| 1635 | .depth => 1, | ||
| 1636 | .unknown => 2, | ||
| 1637 | }, | ||
| 1638 | @intFromBool(spirv_type.flags.is_arrayed), | ||
| 1639 | @intFromBool(spirv_type.flags.is_multisampled), | ||
| 1640 | switch (spirv_type.flags.usage) { | ||
| 1641 | .unknown => 1, | ||
| 1642 | .sampled => 1, | ||
| 1643 | .storage => 2, | ||
| 1644 | }, | ||
| 1645 | switch (spirv_type.flags.format) { | ||
| 1646 | .unknown => .unknown, | ||
| 1647 | .rgba32f => .rgba32f, | ||
| 1648 | .rgba32i => .rgba32i, | ||
| 1649 | .rgba32u => .rgba32ui, | ||
| 1650 | .rgba16f => .rgba16f, | ||
| 1651 | .rgba16i => .rgba16i, | ||
| 1652 | .rgba16u => .rgba16ui, | ||
| 1653 | .rgba8unorm => .rgba8, | ||
| 1654 | .rgba8snorm => .rgba8snorm, | ||
| 1655 | .rgba8i => .rgba8i, | ||
| 1656 | .rgba8u => .rgba8ui, | ||
| 1657 | .r32f => .r32f, | ||
| 1658 | .r32i => .r32i, | ||
| 1659 | .r32u => .r32ui, | ||
| 1660 | }, | ||
| 1661 | switch (spirv_type.flags.access) { | ||
| 1662 | .unknown => null, | ||
| 1663 | .read_only => .read_only, | ||
| 1664 | .write_only => .write_only, | ||
| 1665 | .read_write => .read_write, | ||
| 1666 | }, | ||
| 1667 | ); | ||
| 1668 | }, | ||
| 1669 | .sampled_image => { | ||
| 1670 | const image_ty_id = try cg.resolveType(.fromInterned(spirv_type.ty), .indirect); | ||
| 1671 | return try cg.module.sampledImageType(ip_index, image_ty_id); | ||
| 1672 | }, | ||
| 1673 | .runtime_array => { | ||
| 1674 | const elem_ty: Type = .fromInterned(spirv_type.ty); | ||
| 1675 | const elem_ty_id = try cg.resolveType(elem_ty, .indirect); | ||
| 1676 | const result_id = try cg.module.runtimeArrayType(ip_index, elem_ty_id); | ||
| 1677 | try cg.module.decorate( | ||
| 1678 | result_id, | ||
| 1679 | .{ .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) } }, | ||
| 1680 | ); | ||
| 1681 | return result_id; | ||
| 1682 | }, | ||
| 1683 | } | ||
| 1684 | }, | ||
| 1587 | 1685 | ||
| 1588 | .null, | 1686 | .null, |
| 1589 | .undefined, | 1687 | .undefined, |
| ... | @@ -2421,7 +2519,6 @@ fn generateTestEntryPoint( | ... | @@ -2421,7 +2519,6 @@ fn generateTestEntryPoint( |
| 2421 | const buffer_struct_ty_id = try cg.module.structType( | 2519 | const buffer_struct_ty_id = try cg.module.structType( |
| 2422 | &.{anyerror_ty_id}, | 2520 | &.{anyerror_ty_id}, |
| 2423 | &.{"error_out"}, | 2521 | &.{"error_out"}, |
| 2424 | null, | ||
| 2425 | .none, | 2522 | .none, |
| 2426 | ); | 2523 | ); |
| 2427 | try cg.module.decorate(buffer_struct_ty_id, .block); | 2524 | try cg.module.decorate(buffer_struct_ty_id, .block); |
| ... | @@ -2708,13 +2805,14 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -2708,13 +2805,14 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { |
| 2708 | .memcpy => return cg.airMemcpy(inst), | 2805 | .memcpy => return cg.airMemcpy(inst), |
| 2709 | .memmove => return cg.airMemmove(inst), | 2806 | .memmove => return cg.airMemmove(inst), |
| 2710 | 2807 | ||
| 2711 | .slice_ptr => try cg.airSliceField(inst, 0), | 2808 | .slice_ptr => try cg.airSliceField(inst, 0), |
| 2712 | .slice_len => try cg.airSliceField(inst, 1), | 2809 | .slice_len => try cg.airSliceField(inst, 1), |
| 2713 | .slice_elem_ptr => try cg.airSliceElemPtr(inst), | 2810 | .spirv_runtime_array_len => try cg.airSpirvRuntimeArrayLen(inst), |
| 2714 | .slice_elem_val => try cg.airSliceElemVal(inst), | 2811 | .slice_elem_ptr => try cg.airSliceElemPtr(inst), |
| 2715 | .ptr_elem_ptr => try cg.airPtrElemPtr(inst), | 2812 | .slice_elem_val => try cg.airSliceElemVal(inst), |
| 2716 | .ptr_elem_val => try cg.airPtrElemVal(inst), | 2813 | .ptr_elem_ptr => try cg.airPtrElemPtr(inst), |
| 2717 | .array_elem_val => try cg.airArrayElemVal(inst), | 2814 | .ptr_elem_val => try cg.airPtrElemVal(inst), |
| 2815 | .array_elem_val => try cg.airArrayElemVal(inst), | ||
| 2718 | 2816 | ||
| 2719 | .set_union_tag => return cg.airSetUnionTag(inst), | 2817 | .set_union_tag => return cg.airSetUnionTag(inst), |
| 2720 | .get_union_tag => try cg.airGetUnionTag(inst), | 2818 | .get_union_tag => try cg.airGetUnionTag(inst), |
| ... | @@ -4305,6 +4403,22 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id { | ... | @@ -4305,6 +4403,22 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id { |
| 4305 | return try cg.extractField(field_ty, operand_id, field); | 4403 | return try cg.extractField(field_ty, operand_id, field); |
| 4306 | } | 4404 | } |
| 4307 | 4405 | ||
| 4406 | fn airSpirvRuntimeArrayLen(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ||
| 4407 | const gpa = cg.module.gpa; | ||
| 4408 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | ||
| 4409 | const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data; | ||
| 4410 | const struct_ptr_id = try cg.resolve(extra.struct_operand); | ||
| 4411 | const u32_ty_id = try cg.module.intType(.unsigned, 32); | ||
| 4412 | const result_id = cg.module.allocId(); | ||
| 4413 | try cg.body.emit(gpa, .OpArrayLength, .{ | ||
| 4414 | .id_result_type = u32_ty_id, | ||
| 4415 | .id_result = result_id, | ||
| 4416 | .structure = struct_ptr_id, | ||
| 4417 | .array_member = extra.field_index, | ||
| 4418 | }); | ||
| 4419 | return result_id; | ||
| 4420 | } | ||
| 4421 | |||
| 4308 | fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | 4422 | fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4309 | const zcu = cg.module.zcu; | 4423 | const zcu = cg.module.zcu; |
| 4310 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 4424 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | @@ -5884,6 +5998,7 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -5884,6 +5998,7 @@ fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 5884 | .struct_type, | 5998 | .struct_type, |
| 5885 | .union_type, | 5999 | .union_type, |
| 5886 | .opaque_type, | 6000 | .opaque_type, |
| 6001 | .spirv_type, | ||
| 5887 | .enum_type, | 6002 | .enum_type, |
| 5888 | .func_type, | 6003 | .func_type, |
| 5889 | .error_set_type, | 6004 | .error_set_type, |
src/codegen/spirv/Module.zig+72-18| ... | @@ -70,6 +70,8 @@ cache: struct { | ... | @@ -70,6 +70,8 @@ cache: struct { |
| 70 | 70 | ||
| 71 | bool_const: [2]?Id = .{ null, null }, | 71 | bool_const: [2]?Id = .{ null, null }, |
| 72 | constants: std.ArrayHashMapUnmanaged(Constant, Id, Constant.HashContext, true) = .empty, | 72 | constants: std.ArrayHashMapUnmanaged(Constant, Id, Constant.HashContext, true) = .empty, |
| 73 | |||
| 74 | spirv_types: std.AutoHashMapUnmanaged(InternPool.Index, Id) = .empty, | ||
| 73 | } = .{}, | 75 | } = .{}, |
| 74 | /// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module". | 76 | /// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module". |
| 75 | sections: struct { | 77 | sections: struct { |
| ... | @@ -229,6 +231,7 @@ pub fn deinit(module: *Module) void { | ... | @@ -229,6 +231,7 @@ pub fn deinit(module: *Module) void { |
| 229 | module.cache.array_types.deinit(module.gpa); | 231 | module.cache.array_types.deinit(module.gpa); |
| 230 | module.cache.struct_types.deinit(module.gpa); | 232 | module.cache.struct_types.deinit(module.gpa); |
| 231 | module.cache.fn_types.deinit(module.gpa); | 233 | module.cache.fn_types.deinit(module.gpa); |
| 234 | module.cache.spirv_types.deinit(module.gpa); | ||
| 232 | module.cache.capabilities.deinit(module.gpa); | 235 | module.cache.capabilities.deinit(module.gpa); |
| 233 | module.cache.extensions.deinit(module.gpa); | 236 | module.cache.extensions.deinit(module.gpa); |
| 234 | module.cache.extended_instruction_set.deinit(module.gpa); | 237 | module.cache.extended_instruction_set.deinit(module.gpa); |
| ... | @@ -683,10 +686,8 @@ pub fn structType( | ... | @@ -683,10 +686,8 @@ pub fn structType( |
| 683 | module: *Module, | 686 | module: *Module, |
| 684 | types: []const Id, | 687 | types: []const Id, |
| 685 | maybe_names: ?[]const []const u8, | 688 | maybe_names: ?[]const []const u8, |
| 686 | maybe_offsets: ?[]const u32, | ||
| 687 | ip_index: InternPool.Index, | 689 | ip_index: InternPool.Index, |
| 688 | ) !Id { | 690 | ) !Id { |
| 689 | const target = module.zcu.getTarget(); | ||
| 690 | const actual_ip_index = if (module.zcu.comp.config.root_strip) .none else ip_index; | 691 | const actual_ip_index = if (module.zcu.comp.config.root_strip) .none else ip_index; |
| 691 | 692 | ||
| 692 | if (module.cache.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id; | 693 | if (module.cache.struct_types.get(.{ .fields = types, .ip_index = actual_ip_index })) |id| return id; |
| ... | @@ -704,22 +705,6 @@ pub fn structType( | ... | @@ -704,22 +705,6 @@ pub fn structType( |
| 704 | } | 705 | } |
| 705 | } | 706 | } |
| 706 | 707 | ||
| 707 | switch (target.os.tag) { | ||
| 708 | .vulkan, .opengl => { | ||
| 709 | if (maybe_offsets) |offsets| { | ||
| 710 | assert(offsets.len == types.len); | ||
| 711 | for (offsets, 0..) |offset, i| { | ||
| 712 | try module.decorateMember( | ||
| 713 | result_id, | ||
| 714 | @intCast(i), | ||
| 715 | .{ .offset = .{ .byte_offset = offset } }, | ||
| 716 | ); | ||
| 717 | } | ||
| 718 | } | ||
| 719 | }, | ||
| 720 | else => {}, | ||
| 721 | } | ||
| 722 | |||
| 723 | try module.cache.struct_types.put( | 708 | try module.cache.struct_types.put( |
| 724 | module.gpa, | 709 | module.gpa, |
| 725 | .{ .fields = types_dup, .ip_index = actual_ip_index }, | 710 | .{ .fields = types_dup, .ip_index = actual_ip_index }, |
| ... | @@ -747,6 +732,75 @@ pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const I | ... | @@ -747,6 +732,75 @@ pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const I |
| 747 | return result_id; | 732 | return result_id; |
| 748 | } | 733 | } |
| 749 | 734 | ||
| 735 | pub fn samplerType(module: *Module, ip_index: InternPool.Index) !Id { | ||
| 736 | const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index); | ||
| 737 | if (!entry.found_existing) { | ||
| 738 | const result_id = module.allocId(); | ||
| 739 | entry.value_ptr.* = result_id; | ||
| 740 | try module.sections.globals.emit(module.gpa, .OpTypeSampler, .{ | ||
| 741 | .id_result = result_id, | ||
| 742 | }); | ||
| 743 | } | ||
| 744 | return entry.value_ptr.*; | ||
| 745 | } | ||
| 746 | |||
| 747 | pub fn imageType( | ||
| 748 | module: *Module, | ||
| 749 | ip_index: InternPool.Index, | ||
| 750 | sampled_ty_id: Id, | ||
| 751 | dim: spec.Dim, | ||
| 752 | depth: spec.LiteralInteger, | ||
| 753 | arrayed: spec.LiteralInteger, | ||
| 754 | ms: spec.LiteralInteger, | ||
| 755 | sampled: spec.LiteralInteger, | ||
| 756 | image_format: spec.ImageFormat, | ||
| 757 | access_qualifier: ?spec.AccessQualifier, | ||
| 758 | ) !Id { | ||
| 759 | const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index); | ||
| 760 | if (!entry.found_existing) { | ||
| 761 | const result_id = module.allocId(); | ||
| 762 | entry.value_ptr.* = result_id; | ||
| 763 | try module.sections.globals.emit(module.gpa, .OpTypeImage, .{ | ||
| 764 | .id_result = result_id, | ||
| 765 | .sampled_type = sampled_ty_id, | ||
| 766 | .dim = dim, | ||
| 767 | .depth = depth, | ||
| 768 | .arrayed = arrayed, | ||
| 769 | .ms = ms, | ||
| 770 | .sampled = sampled, | ||
| 771 | .image_format = image_format, | ||
| 772 | .access_qualifier = access_qualifier, | ||
| 773 | }); | ||
| 774 | } | ||
| 775 | return entry.value_ptr.*; | ||
| 776 | } | ||
| 777 | |||
| 778 | pub fn sampledImageType(module: *Module, ip_index: InternPool.Index, image_ty_id: Id) !Id { | ||
| 779 | const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index); | ||
| 780 | if (!entry.found_existing) { | ||
| 781 | const result_id = module.allocId(); | ||
| 782 | entry.value_ptr.* = result_id; | ||
| 783 | try module.sections.globals.emit(module.gpa, .OpTypeSampledImage, .{ | ||
| 784 | .id_result = result_id, | ||
| 785 | .image_type = image_ty_id, | ||
| 786 | }); | ||
| 787 | } | ||
| 788 | return entry.value_ptr.*; | ||
| 789 | } | ||
| 790 | |||
| 791 | pub fn runtimeArrayType(module: *Module, ip_index: InternPool.Index, elem_ty_id: Id) !Id { | ||
| 792 | const entry = try module.cache.spirv_types.getOrPut(module.gpa, ip_index); | ||
| 793 | if (!entry.found_existing) { | ||
| 794 | const result_id = module.allocId(); | ||
| 795 | entry.value_ptr.* = result_id; | ||
| 796 | try module.sections.globals.emit(module.gpa, .OpTypeRuntimeArray, .{ | ||
| 797 | .id_result = result_id, | ||
| 798 | .element_type = elem_ty_id, | ||
| 799 | }); | ||
| 800 | } | ||
| 801 | return entry.value_ptr.*; | ||
| 802 | } | ||
| 803 | |||
| 750 | pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id { | 804 | pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id { |
| 751 | const gop = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value }); | 805 | const gop = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value }); |
| 752 | if (!gop.found_existing) { | 806 | if (!gop.found_existing) { |
src/codegen/wasm/CodeGen.zig+3| ... | @@ -1195,6 +1195,7 @@ fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool { | ... | @@ -1195,6 +1195,7 @@ fn isByRef(ty: Type, zcu: *const Zcu, target: *const std.Target) bool { |
| 1195 | .undefined, | 1195 | .undefined, |
| 1196 | .null, | 1196 | .null, |
| 1197 | .@"opaque", | 1197 | .@"opaque", |
| 1198 | .spirv, | ||
| 1198 | => unreachable, | 1199 | => unreachable, |
| 1199 | 1200 | ||
| 1200 | .noreturn, | 1201 | .noreturn, |
| ... | @@ -1882,6 +1883,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1882,6 +1883,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1882 | .work_item_id, | 1883 | .work_item_id, |
| 1883 | .work_group_size, | 1884 | .work_group_size, |
| 1884 | .work_group_id, | 1885 | .work_group_id, |
| 1886 | .spirv_runtime_array_len, | ||
| 1885 | => unreachable, | 1887 | => unreachable, |
| 1886 | }; | 1888 | }; |
| 1887 | } | 1889 | } |
| ... | @@ -4698,6 +4700,7 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { | ... | @@ -4698,6 +4700,7 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { |
| 4698 | .tuple_type, | 4700 | .tuple_type, |
| 4699 | .union_type, | 4701 | .union_type, |
| 4700 | .opaque_type, | 4702 | .opaque_type, |
| 4703 | .spirv_type, | ||
| 4701 | .enum_type, | 4704 | .enum_type, |
| 4702 | .func_type, | 4705 | .func_type, |
| 4703 | .error_set_type, | 4706 | .error_set_type, |
src/codegen/wasm/abi.zig+1| ... | @@ -77,6 +77,7 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class { | ... | @@ -77,6 +77,7 @@ pub fn classifyType(ty: Type, zcu: *const Zcu) Class { |
| 77 | .null, | 77 | .null, |
| 78 | .@"fn", | 78 | .@"fn", |
| 79 | .@"opaque", | 79 | .@"opaque", |
| 80 | .spirv, | ||
| 80 | .enum_literal, | 81 | .enum_literal, |
| 81 | => unreachable, | 82 | => unreachable, |
| 82 | } | 83 | } |
src/codegen/x86_64/CodeGen.zig+1-1| ... | @@ -173719,7 +173719,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -173719,7 +173719,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 173719 | // No soft-float `Legalize` features are enabled, so this instruction never appears. | 173719 | // No soft-float `Legalize` features are enabled, so this instruction never appears. |
| 173720 | .legalize_compiler_rt_call => unreachable, | 173720 | .legalize_compiler_rt_call => unreachable, |
| 173721 | 173721 | ||
| 173722 | .work_item_id, .work_group_size, .work_group_id => unreachable, | 173722 | .work_item_id, .work_group_size, .work_group_id, .spirv_runtime_array_len => unreachable, |
| 173723 | } | 173723 | } |
| 173724 | try cg.resetTemps(@enumFromInt(0)); | 173724 | try cg.resetTemps(@enumFromInt(0)); |
| 173725 | cg.checkInvariantsAfterAirInst(); | 173725 | cg.checkInvariantsAfterAirInst(); |
src/codegen/x86_64/abi.zig+1| ... | @@ -164,6 +164,7 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont | ... | @@ -164,6 +164,7 @@ pub fn classifyWindows(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont |
| 164 | .null, | 164 | .null, |
| 165 | .@"fn", | 165 | .@"fn", |
| 166 | .@"opaque", | 166 | .@"opaque", |
| 167 | .spirv, | ||
| 167 | .enum_literal, | 168 | .enum_literal, |
| 168 | => unreachable, | 169 | => unreachable, |
| 169 | }; | 170 | }; |
src/link/ConstPool.zig+2| ... | @@ -196,6 +196,7 @@ fn checkType(pool: *const ConstPool, ty: Type, zcu: *const Zcu) bool { | ... | @@ -196,6 +196,7 @@ fn checkType(pool: *const ConstPool, ty: Type, zcu: *const Zcu) bool { |
| 196 | .null, | 196 | .null, |
| 197 | .error_set, | 197 | .error_set, |
| 198 | .@"opaque", | 198 | .@"opaque", |
| 199 | .spirv, | ||
| 199 | .frame, | 200 | .frame, |
| 200 | .@"anyframe", | 201 | .@"anyframe", |
| 201 | .enum_literal, | 202 | .enum_literal, |
| ... | @@ -241,6 +242,7 @@ fn registerTypeDeps(pool: *ConstPool, root: Index, ty: Type, zcu: *const Zcu) Al | ... | @@ -241,6 +242,7 @@ fn registerTypeDeps(pool: *ConstPool, root: Index, ty: Type, zcu: *const Zcu) Al |
| 241 | .null, | 242 | .null, |
| 242 | .error_set, | 243 | .error_set, |
| 243 | .@"opaque", | 244 | .@"opaque", |
| 245 | .spirv, | ||
| 244 | .frame, | 246 | .frame, |
| 245 | .@"anyframe", | 247 | .@"anyframe", |
| 246 | .enum_literal, | 248 | .enum_literal, |
src/link/Dwarf.zig+2| ... | @@ -3047,6 +3047,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo | ... | @@ -3047,6 +3047,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo |
| 3047 | .func_type, | 3047 | .func_type, |
| 3048 | .error_set_type, | 3048 | .error_set_type, |
| 3049 | .inferred_error_set_type, | 3049 | .inferred_error_set_type, |
| 3050 | .spirv_type, | ||
| 3050 | => .alias, | 3051 | => .alias, |
| 3051 | 3052 | ||
| 3052 | .struct_type => tag: { | 3053 | .struct_type => tag: { |
| ... | @@ -3533,6 +3534,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co | ... | @@ -3533,6 +3534,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co |
| 3533 | switch (value_ip_key) { | 3534 | switch (value_ip_key) { |
| 3534 | .func => unreachable, // handled above | 3535 | .func => unreachable, // handled above |
| 3535 | .@"extern" => unreachable, // handled above | 3536 | .@"extern" => unreachable, // handled above |
| 3537 | .spirv_type => unreachable, | ||
| 3536 | 3538 | ||
| 3537 | .int_type => |int_type| { | 3539 | .int_type => |int_type| { |
| 3538 | try wip_nav.abbrevCode(.numeric_type); | 3540 | try wip_nav.abbrevCode(.numeric_type); |
src/print_value.zig+1| ... | @@ -60,6 +60,7 @@ pub fn print( | ... | @@ -60,6 +60,7 @@ pub fn print( |
| 60 | .union_type, | 60 | .union_type, |
| 61 | .opaque_type, | 61 | .opaque_type, |
| 62 | .enum_type, | 62 | .enum_type, |
| 63 | .spirv_type, | ||
| 63 | .func_type, | 64 | .func_type, |
| 64 | .error_set_type, | 65 | .error_set_type, |
| 65 | .inferred_error_set_type, | 66 | .inferred_error_set_type, |
src/print_zir.zig+10| ... | @@ -685,6 +685,16 @@ const Writer = struct { | ... | @@ -685,6 +685,16 @@ const Writer = struct { |
| 685 | defer self.parent_decl_node = prev_parent_decl_node; | 685 | defer self.parent_decl_node = prev_parent_decl_node; |
| 686 | try self.writeSrcNode(stream, .zero); | 686 | try self.writeSrcNode(stream, .zero); |
| 687 | }, | 687 | }, |
| 688 | .reify_spirv_type => { | ||
| 689 | const extra = self.code.extraData(Zir.Inst.ReifySpirvType, extended.operand).data; | ||
| 690 | try stream.print("line({d}), ", .{extra.src_line}); | ||
| 691 | try self.writeInstRef(stream, extra.operand); | ||
| 692 | try stream.writeAll(")) "); | ||
| 693 | const prev_parent_decl_node = self.parent_decl_node; | ||
| 694 | self.parent_decl_node = extra.node; | ||
| 695 | defer self.parent_decl_node = prev_parent_decl_node; | ||
| 696 | try self.writeSrcNode(stream, .zero); | ||
| 697 | }, | ||
| 688 | 698 | ||
| 689 | .cmpxchg => try self.writeCmpxchg(stream, extended), | 699 | .cmpxchg => try self.writeCmpxchg(stream, extended), |
| 690 | .ptr_cast_full => try self.writePtrCastFull(stream, extended), | 700 | .ptr_cast_full => try self.writePtrCastFull(stream, extended), |
test/behavior.zig+4| ... | @@ -112,6 +112,10 @@ test { | ... | @@ -112,6 +112,10 @@ test { |
| 112 | _ = @import("behavior/wasm.zig"); | 112 | _ = @import("behavior/wasm.zig"); |
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | if (builtin.zig_backend == .stage2_spirv) { | ||
| 116 | _ = @import("behavior/spirv.zig"); | ||
| 117 | } | ||
| 118 | |||
| 115 | if (builtin.zig_backend != .stage2_spirv and builtin.os.tag != .wasi) { | 119 | if (builtin.zig_backend != .stage2_spirv and builtin.os.tag != .wasi) { |
| 116 | _ = @import("behavior/asm.zig"); | 120 | _ = @import("behavior/asm.zig"); |
| 117 | } | 121 | } |
test/behavior/spirv.zig created+47| ... | @@ -0,0 +1,47 @@ | ||
| 1 | const Sampler = @SpirvType(.sampler); | ||
| 2 | const Image = @SpirvType(.{ .image = .{ | ||
| 3 | .usage = .{ .sampled = u32 }, | ||
| 4 | .format = .unknown, | ||
| 5 | .dim = .@"2d", | ||
| 6 | .depth = .unknown, | ||
| 7 | .arrayed = false, | ||
| 8 | .multisampled = false, | ||
| 9 | .access = .unknown, | ||
| 10 | } }); | ||
| 11 | const SampledImage = @SpirvType(.{ .sampled_image = Image }); | ||
| 12 | const StorageImage = @SpirvType(.{ .image = .{ | ||
| 13 | .usage = .storage, | ||
| 14 | .format = .unknown, | ||
| 15 | .dim = .@"2d", | ||
| 16 | .depth = .unknown, | ||
| 17 | .arrayed = false, | ||
| 18 | .multisampled = false, | ||
| 19 | .access = .unknown, | ||
| 20 | } }); | ||
| 21 | const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); | ||
| 22 | |||
| 23 | const RuntimeArrayBuf = extern struct { e: RuntimeArray }; | ||
| 24 | |||
| 25 | const sampler = @extern(*addrspace(.constant) const Sampler, .{ | ||
| 26 | .name = "sampler", | ||
| 27 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 0 } }, | ||
| 28 | }); | ||
| 29 | const sampled_image = @extern(*addrspace(.constant) const SampledImage, .{ | ||
| 30 | .name = "sampled_image", | ||
| 31 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 1 } }, | ||
| 32 | }); | ||
| 33 | const storage_image = @extern(*addrspace(.constant) const StorageImage, .{ | ||
| 34 | .name = "storage_image", | ||
| 35 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 2 } }, | ||
| 36 | }); | ||
| 37 | const runtime_array = @extern(*addrspace(.storage_buffer) const RuntimeArrayBuf, .{ | ||
| 38 | .name = "runtime_array", | ||
| 39 | .decoration = .{ .descriptor = .{ .set = 0, .binding = 3 } }, | ||
| 40 | }); | ||
| 41 | |||
| 42 | test "@SpirvType" { | ||
| 43 | _ = sampler; | ||
| 44 | _ = sampled_image; | ||
| 45 | _ = storage_image; | ||
| 46 | _ = runtime_array; | ||
| 47 | } | ||
test/behavior/type_info.zig+2-2| ... | @@ -253,11 +253,11 @@ fn testUnion() !void { | ... | @@ -253,11 +253,11 @@ fn testUnion() !void { |
| 253 | try expect(typeinfo_info == .@"union"); | 253 | try expect(typeinfo_info == .@"union"); |
| 254 | try expect(typeinfo_info.@"union".layout == .auto); | 254 | try expect(typeinfo_info.@"union".layout == .auto); |
| 255 | try expect(typeinfo_info.@"union".tag_type.? == TypeId); | 255 | try expect(typeinfo_info.@"union".tag_type.? == TypeId); |
| 256 | try expect(typeinfo_info.@"union".field_names.len == 24); | 256 | try expect(typeinfo_info.@"union".field_names.len == 25); |
| 257 | try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_types.len); | 257 | try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_types.len); |
| 258 | try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_attrs.len); | 258 | try expect(typeinfo_info.@"union".field_names.len == typeinfo_info.@"union".field_attrs.len); |
| 259 | try expect(typeinfo_info.@"union".field_types[4] == @TypeOf(@typeInfo(u8).int)); | 259 | try expect(typeinfo_info.@"union".field_types[4] == @TypeOf(@typeInfo(u8).int)); |
| 260 | try expect(typeinfo_info.@"union".decl_names.len == 16); | 260 | try expect(typeinfo_info.@"union".decl_names.len == 17); |
| 261 | 261 | ||
| 262 | const TestNoTagUnion = union { | 262 | const TestNoTagUnion = union { |
| 263 | Foo: void, | 263 | Foo: void, |
test/cases/compile_errors/SpirvType_is_a_compile_error_in_non-SPIRV_targets.zig created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | comptime { | ||
| 2 | _ = @SpirvType(.{ .runtime_array = u32 }); | ||
| 3 | } | ||
| 4 | |||
| 5 | // error | ||
| 6 | // backend=selfhosted | ||
| 7 | // target=x86_64-native | ||
| 8 | // | ||
| 9 | // :2:9: error: builtin @SpirvType is only available when targeting SPIR-V; targeted CPU architecture is x86_64 | ||
test/cases/compile_errors/SpirvType_vulkan_target.zig created+56| ... | @@ -0,0 +1,56 @@ | ||
| 1 | comptime { | ||
| 2 | _ = @SpirvType(.{ .image = .{ | ||
| 3 | .usage = .storage, | ||
| 4 | .format = .unknown, | ||
| 5 | .dim = .@"2d", | ||
| 6 | .depth = .unknown, | ||
| 7 | .arrayed = false, | ||
| 8 | .multisampled = false, | ||
| 9 | .access = .read_only, | ||
| 10 | } }); | ||
| 11 | } | ||
| 12 | |||
| 13 | comptime { | ||
| 14 | _ = @SpirvType(.{ .image = .{ | ||
| 15 | .usage = .{ .sampled = bool }, | ||
| 16 | .format = .unknown, | ||
| 17 | .dim = .@"2d", | ||
| 18 | .depth = .unknown, | ||
| 19 | .arrayed = false, | ||
| 20 | .multisampled = false, | ||
| 21 | .access = .unknown, | ||
| 22 | } }); | ||
| 23 | } | ||
| 24 | |||
| 25 | comptime { | ||
| 26 | _ = @SpirvType(.{ .image = .{ | ||
| 27 | .usage = .{ .sampled = void }, | ||
| 28 | .format = .unknown, | ||
| 29 | .dim = .@"2d", | ||
| 30 | .depth = .unknown, | ||
| 31 | .arrayed = false, | ||
| 32 | .multisampled = false, | ||
| 33 | .access = .unknown, | ||
| 34 | } }); | ||
| 35 | } | ||
| 36 | |||
| 37 | comptime { | ||
| 38 | _ = @SpirvType(.{ .image = .{ | ||
| 39 | .usage = .{ .sampled = u24 }, | ||
| 40 | .format = .unknown, | ||
| 41 | .dim = .@"2d", | ||
| 42 | .depth = .unknown, | ||
| 43 | .arrayed = false, | ||
| 44 | .multisampled = false, | ||
| 45 | .access = .unknown, | ||
| 46 | } }); | ||
| 47 | } | ||
| 48 | |||
| 49 | // error | ||
| 50 | // backend=selfhosted | ||
| 51 | // target=spirv64-vulkan | ||
| 52 | // | ||
| 53 | // :2:21: error: access qualifier '.read_only' is only valid under the 'opencl' os | ||
| 54 | // :14:21: error: invalid 'sampled' field value 'bool' | ||
| 55 | // :26:21: error: 'void' type for 'sampled' field is only valid under the 'opencl' os | ||
| 56 | // :38:21: error: 'sampled' field value must be a 32-bit int, 64-bit int or 32-bit float under the 'vulkan' os | ||
test/cases/compile_errors/directly_embedding_spirv_type_in_struct_and_union.zig created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | const Sampler = @SpirvType(.sampler); | ||
| 2 | const RuntimeArray = @SpirvType(.{ .runtime_array = u32 }); | ||
| 3 | const Foo = struct { | ||
| 4 | s: Sampler, | ||
| 5 | }; | ||
| 6 | const Baz = struct { | ||
| 7 | a: RuntimeArray, | ||
| 8 | }; | ||
| 9 | const Qux = extern struct { | ||
| 10 | a: RuntimeArray, | ||
| 11 | b: u32, | ||
| 12 | }; | ||
| 13 | export fn a() void { | ||
| 14 | var foo: Foo = undefined; | ||
| 15 | _ = &foo; | ||
| 16 | } | ||
| 17 | export fn c() void { | ||
| 18 | var baz: Baz = undefined; | ||
| 19 | _ = &baz; | ||
| 20 | } | ||
| 21 | export fn d() void { | ||
| 22 | var qux: Qux = undefined; | ||
| 23 | _ = &qux; | ||
| 24 | } | ||
| 25 | |||
| 26 | // error | ||
| 27 | // backend=selfhosted | ||
| 28 | // target=spirv64-vulkan | ||
| 29 | // | ||
| 30 | // :4:8: error: cannot directly embed SPIR-V type 'tmp.Sampler__SpirvType_4' in struct | ||
| 31 | // :4:8: note: opaque types have unknown size | ||
| 32 | // :6:13: error: non-extern struct cannot contain fields of type 'tmp.RuntimeArray__SpirvType_11' | ||
| 33 | // :7:5: note: while checking this field | ||
| 34 | // :9:20: error: struct field of type 'tmp.RuntimeArray__SpirvType_11' must be the last field | ||
| 35 | // :10:5: note: while checking this field | ||