| author | |
| committer | |
| log | 5105c3c7fa46969dc731b7447415436fd7572e87 |
| tree | f3bdcc2b4f9193476cfc738a25b6d8869908999a |
| parent | 074dd4d083b8ddefc370425568b61c890efe905d |
| parent | ee06b2ce760d927b62726de1e2e3cb33b48d4932 |
| signature |
spirv: miscellaneous stuff #222 files changed, 407 insertions(+), 186 deletions(-)
lib/std/Target/spirv.zig+19-19| ... | @@ -10,18 +10,18 @@ pub const Feature = enum { | ... | @@ -10,18 +10,18 @@ pub const Feature = enum { |
| 10 | v1_4, | 10 | v1_4, |
| 11 | v1_5, | 11 | v1_5, |
| 12 | v1_6, | 12 | v1_6, |
| 13 | int8, | ||
| 14 | int16, | ||
| 15 | int64, | 13 | int64, |
| 16 | float16, | 14 | float16, |
| 17 | float64, | 15 | float64, |
| 18 | addresses, | ||
| 19 | matrix, | 16 | matrix, |
| 20 | storage_push_constant16, | 17 | storage_push_constant16, |
| 18 | arbitrary_precision_integers, | ||
| 21 | kernel, | 19 | kernel, |
| 20 | addresses, | ||
| 22 | generic_pointer, | 21 | generic_pointer, |
| 23 | vector16, | 22 | vector16, |
| 24 | shader, | 23 | shader, |
| 24 | physical_storage_buffer, | ||
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet; | 27 | pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet; |
| ... | @@ -69,16 +69,6 @@ pub const all_features = blk: { | ... | @@ -69,16 +69,6 @@ pub const all_features = blk: { |
| 69 | .description = "Enable version 1.6", | 69 | .description = "Enable version 1.6", |
| 70 | .dependencies = featureSet(&[_]Feature{.v1_5}), | 70 | .dependencies = featureSet(&[_]Feature{.v1_5}), |
| 71 | }; | 71 | }; |
| 72 | result[@intFromEnum(Feature.int8)] = .{ | ||
| 73 | .llvm_name = null, | ||
| 74 | .description = "Enable Int8 capability", | ||
| 75 | .dependencies = featureSet(&[_]Feature{.v1_0}), | ||
| 76 | }; | ||
| 77 | result[@intFromEnum(Feature.int16)] = .{ | ||
| 78 | .llvm_name = null, | ||
| 79 | .description = "Enable Int16 capability", | ||
| 80 | .dependencies = featureSet(&[_]Feature{.v1_0}), | ||
| 81 | }; | ||
| 82 | result[@intFromEnum(Feature.int64)] = .{ | 72 | result[@intFromEnum(Feature.int64)] = .{ |
| 83 | .llvm_name = null, | 73 | .llvm_name = null, |
| 84 | .description = "Enable Int64 capability", | 74 | .description = "Enable Int64 capability", |
| ... | @@ -94,11 +84,6 @@ pub const all_features = blk: { | ... | @@ -94,11 +84,6 @@ pub const all_features = blk: { |
| 94 | .description = "Enable Float64 capability", | 84 | .description = "Enable Float64 capability", |
| 95 | .dependencies = featureSet(&[_]Feature{.v1_0}), | 85 | .dependencies = featureSet(&[_]Feature{.v1_0}), |
| 96 | }; | 86 | }; |
| 97 | result[@intFromEnum(Feature.addresses)] = .{ | ||
| 98 | .llvm_name = null, | ||
| 99 | .description = "Enable either the Addresses capability or, SPV_KHR_physical_storage_buffer extension and the PhysicalStorageBufferAddresses capability", | ||
| 100 | .dependencies = featureSet(&[_]Feature{.v1_0}), | ||
| 101 | }; | ||
| 102 | result[@intFromEnum(Feature.matrix)] = .{ | 87 | result[@intFromEnum(Feature.matrix)] = .{ |
| 103 | .llvm_name = null, | 88 | .llvm_name = null, |
| 104 | .description = "Enable Matrix capability", | 89 | .description = "Enable Matrix capability", |
| ... | @@ -109,11 +94,21 @@ pub const all_features = blk: { | ... | @@ -109,11 +94,21 @@ pub const all_features = blk: { |
| 109 | .description = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability", | 94 | .description = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability", |
| 110 | .dependencies = featureSet(&[_]Feature{.v1_3}), | 95 | .dependencies = featureSet(&[_]Feature{.v1_3}), |
| 111 | }; | 96 | }; |
| 97 | result[@intFromEnum(Feature.arbitrary_precision_integers)] = .{ | ||
| 98 | .llvm_name = null, | ||
| 99 | .description = "Enable SPV_INTEL_arbitrary_precision_integers extension and the ArbitraryPrecisionIntegersINTEL capability", | ||
| 100 | .dependencies = featureSet(&[_]Feature{.v1_5}), | ||
| 101 | }; | ||
| 112 | result[@intFromEnum(Feature.kernel)] = .{ | 102 | result[@intFromEnum(Feature.kernel)] = .{ |
| 113 | .llvm_name = null, | 103 | .llvm_name = null, |
| 114 | .description = "Enable Kernel capability", | 104 | .description = "Enable Kernel capability", |
| 115 | .dependencies = featureSet(&[_]Feature{.v1_0}), | 105 | .dependencies = featureSet(&[_]Feature{.v1_0}), |
| 116 | }; | 106 | }; |
| 107 | result[@intFromEnum(Feature.addresses)] = .{ | ||
| 108 | .llvm_name = null, | ||
| 109 | .description = "Enable Addresses capability", | ||
| 110 | .dependencies = featureSet(&[_]Feature{.v1_0}), | ||
| 111 | }; | ||
| 117 | result[@intFromEnum(Feature.generic_pointer)] = .{ | 112 | result[@intFromEnum(Feature.generic_pointer)] = .{ |
| 118 | .llvm_name = null, | 113 | .llvm_name = null, |
| 119 | .description = "Enable GenericPointer capability", | 114 | .description = "Enable GenericPointer capability", |
| ... | @@ -129,6 +124,11 @@ pub const all_features = blk: { | ... | @@ -129,6 +124,11 @@ pub const all_features = blk: { |
| 129 | .description = "Enable Shader capability", | 124 | .description = "Enable Shader capability", |
| 130 | .dependencies = featureSet(&[_]Feature{ .v1_0, .matrix }), | 125 | .dependencies = featureSet(&[_]Feature{ .v1_0, .matrix }), |
| 131 | }; | 126 | }; |
| 127 | result[@intFromEnum(Feature.physical_storage_buffer)] = .{ | ||
| 128 | .llvm_name = null, | ||
| 129 | .description = "Enable SPV_KHR_physical_storage_buffer extension and the PhysicalStorageBufferAddresses capability", | ||
| 130 | .dependencies = featureSet(&[_]Feature{.v1_0}), | ||
| 131 | }; | ||
| 132 | const ti = @typeInfo(Feature); | 132 | const ti = @typeInfo(Feature); |
| 133 | for (&result, 0..) |*elem, i| { | 133 | for (&result, 0..) |*elem, i| { |
| 134 | elem.index = i; | 134 | elem.index = i; |
| ... | @@ -147,7 +147,7 @@ pub const cpu = struct { | ... | @@ -147,7 +147,7 @@ pub const cpu = struct { |
| 147 | pub const vulkan_v1_2: CpuModel = .{ | 147 | pub const vulkan_v1_2: CpuModel = .{ |
| 148 | .name = "vulkan_v1_2", | 148 | .name = "vulkan_v1_2", |
| 149 | .llvm_name = null, | 149 | .llvm_name = null, |
| 150 | .features = featureSet(&[_]Feature{ .v1_5, .shader, .addresses }), | 150 | .features = featureSet(&[_]Feature{ .v1_5, .shader, .physical_storage_buffer }), |
| 151 | }; | 151 | }; |
| 152 | 152 | ||
| 153 | pub const opencl_v2: CpuModel = .{ | 153 | pub const opencl_v2: CpuModel = .{ |
lib/std/gpu.zig+10-5| ... | @@ -80,7 +80,8 @@ pub fn fragmentDepth(comptime ptr: *addrspace(.output) f32) void { | ... | @@ -80,7 +80,8 @@ pub fn fragmentDepth(comptime ptr: *addrspace(.output) f32) void { |
| 80 | /// Forms the main linkage for `input` and `output` address spaces. | 80 | /// Forms the main linkage for `input` and `output` address spaces. |
| 81 | /// `ptr` must be a reference to variable or struct field. | 81 | /// `ptr` must be a reference to variable or struct field. |
| 82 | pub fn location(comptime ptr: anytype, comptime loc: u32) void { | 82 | pub fn location(comptime ptr: anytype, comptime loc: u32) void { |
| 83 | asm volatile ("OpDecorate %ptr Location $loc" | 83 | asm volatile ( |
| 84 | \\OpDecorate %ptr Location $loc | ||
| 84 | : | 85 | : |
| 85 | : [ptr] "" (ptr), | 86 | : [ptr] "" (ptr), |
| 86 | [loc] "c" (loc), | 87 | [loc] "c" (loc), |
| ... | @@ -110,7 +111,8 @@ pub const Origin = enum(u32) { | ... | @@ -110,7 +111,8 @@ pub const Origin = enum(u32) { |
| 110 | /// The coordinates appear to originate in the specified `origin`. | 111 | /// The coordinates appear to originate in the specified `origin`. |
| 111 | /// Only valid with the `Fragment` calling convention. | 112 | /// Only valid with the `Fragment` calling convention. |
| 112 | pub fn fragmentOrigin(comptime entry_point: anytype, comptime origin: Origin) void { | 113 | pub fn fragmentOrigin(comptime entry_point: anytype, comptime origin: Origin) void { |
| 113 | asm volatile ("OpExecutionMode %entry_point $origin" | 114 | asm volatile ( |
| 115 | \\OpExecutionMode %entry_point $origin | ||
| 114 | : | 116 | : |
| 115 | : [entry_point] "" (entry_point), | 117 | : [entry_point] "" (entry_point), |
| 116 | [origin] "c" (@intFromEnum(origin)), | 118 | [origin] "c" (@intFromEnum(origin)), |
| ... | @@ -137,7 +139,8 @@ pub const DepthMode = enum(u32) { | ... | @@ -137,7 +139,8 @@ pub const DepthMode = enum(u32) { |
| 137 | 139 | ||
| 138 | /// Only valid with the `Fragment` calling convention. | 140 | /// Only valid with the `Fragment` calling convention. |
| 139 | pub fn depthMode(comptime entry_point: anytype, comptime mode: DepthMode) void { | 141 | pub fn depthMode(comptime entry_point: anytype, comptime mode: DepthMode) void { |
| 140 | asm volatile ("OpExecutionMode %entry_point $mode" | 142 | asm volatile ( |
| 143 | \\OpExecutionMode %entry_point $mode | ||
| 141 | : | 144 | : |
| 142 | : [entry_point] "" (entry_point), | 145 | : [entry_point] "" (entry_point), |
| 143 | [mode] "c" (mode), | 146 | [mode] "c" (mode), |
| ... | @@ -147,7 +150,8 @@ pub fn depthMode(comptime entry_point: anytype, comptime mode: DepthMode) void { | ... | @@ -147,7 +150,8 @@ pub fn depthMode(comptime entry_point: anytype, comptime mode: DepthMode) void { |
| 147 | /// Indicates the workgroup size in the `x`, `y`, and `z` dimensions. | 150 | /// Indicates the workgroup size in the `x`, `y`, and `z` dimensions. |
| 148 | /// Only valid with the `GLCompute` or `Kernel` calling conventions. | 151 | /// Only valid with the `GLCompute` or `Kernel` calling conventions. |
| 149 | pub fn workgroupSize(comptime entry_point: anytype, comptime size: @Vector(3, u32)) void { | 152 | pub fn workgroupSize(comptime entry_point: anytype, comptime size: @Vector(3, u32)) void { |
| 150 | asm volatile ("OpExecutionMode %entry_point LocalSize %x %y %z" | 153 | asm volatile ( |
| 154 | \\OpExecutionMode %entry_point LocalSize %x %y %z | ||
| 151 | : | 155 | : |
| 152 | : [entry_point] "" (entry_point), | 156 | : [entry_point] "" (entry_point), |
| 153 | [x] "c" (size[0]), | 157 | [x] "c" (size[0]), |
| ... | @@ -159,7 +163,8 @@ pub fn workgroupSize(comptime entry_point: anytype, comptime size: @Vector(3, u3 | ... | @@ -159,7 +163,8 @@ pub fn workgroupSize(comptime entry_point: anytype, comptime size: @Vector(3, u3 |
| 159 | /// A hint to the client, which indicates the workgroup size in the `x`, `y`, and `z` dimensions. | 163 | /// A hint to the client, which indicates the workgroup size in the `x`, `y`, and `z` dimensions. |
| 160 | /// Only valid with the `GLCompute` or `Kernel` calling conventions. | 164 | /// Only valid with the `GLCompute` or `Kernel` calling conventions. |
| 161 | pub fn workgroupSizeHint(comptime entry_point: anytype, comptime size: @Vector(3, u32)) void { | 165 | pub fn workgroupSizeHint(comptime entry_point: anytype, comptime size: @Vector(3, u32)) void { |
| 162 | asm volatile ("OpExecutionMode %entry_point LocalSizeHint %x %y %z" | 166 | asm volatile ( |
| 167 | \\OpExecutionMode %entry_point LocalSizeHint %x %y %z | ||
| 163 | : | 168 | : |
| 164 | : [entry_point] "" (entry_point), | 169 | : [entry_point] "" (entry_point), |
| 165 | [x] "c" (size[0]), | 170 | [x] "c" (size[0]), |
src/Sema.zig+53-24| ... | @@ -3648,7 +3648,7 @@ fn indexablePtrLen( | ... | @@ -3648,7 +3648,7 @@ fn indexablePtrLen( |
| 3648 | const object_ty = sema.typeOf(object); | 3648 | const object_ty = sema.typeOf(object); |
| 3649 | const is_pointer_to = object_ty.isSinglePointer(zcu); | 3649 | const is_pointer_to = object_ty.isSinglePointer(zcu); |
| 3650 | const indexable_ty = if (is_pointer_to) object_ty.childType(zcu) else object_ty; | 3650 | const indexable_ty = if (is_pointer_to) object_ty.childType(zcu) else object_ty; |
| 3651 | try checkIndexable(sema, block, src, indexable_ty); | 3651 | try sema.checkIndexable(block, src, indexable_ty); |
| 3652 | const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "len", .no_embedded_nulls); | 3652 | const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "len", .no_embedded_nulls); |
| 3653 | return sema.fieldVal(block, src, object, field_name, src); | 3653 | return sema.fieldVal(block, src, object, field_name, src); |
| 3654 | } | 3654 | } |
| ... | @@ -10103,6 +10103,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -10103,6 +10103,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 10103 | } | 10103 | } |
| 10104 | try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), ptr_src); | 10104 | try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), ptr_src); |
| 10105 | try sema.validateRuntimeValue(block, ptr_src, operand); | 10105 | try sema.validateRuntimeValue(block, ptr_src, operand); |
| 10106 | try sema.checkLogicalPtrOperation(block, ptr_src, ptr_ty); | ||
| 10106 | if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) { | 10107 | if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) { |
| 10107 | return block.addBitCast(dest_ty, operand); | 10108 | return block.addBitCast(dest_ty, operand); |
| 10108 | } | 10109 | } |
| ... | @@ -16389,6 +16390,8 @@ fn analyzeArithmetic( | ... | @@ -16389,6 +16390,8 @@ fn analyzeArithmetic( |
| 16389 | }; | 16390 | }; |
| 16390 | 16391 | ||
| 16391 | try sema.requireRuntimeBlock(block, src, runtime_src); | 16392 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 16393 | try sema.checkLogicalPtrOperation(block, src, lhs_ty); | ||
| 16394 | try sema.checkLogicalPtrOperation(block, src, rhs_ty); | ||
| 16392 | const lhs_int = try block.addBitCast(.usize, lhs); | 16395 | const lhs_int = try block.addBitCast(.usize, lhs); |
| 16393 | const rhs_int = try block.addBitCast(.usize, rhs); | 16396 | const rhs_int = try block.addBitCast(.usize, rhs); |
| 16394 | const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int); | 16397 | const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int); |
| ... | @@ -16620,24 +16623,7 @@ fn analyzePtrArithmetic( | ... | @@ -16620,24 +16623,7 @@ fn analyzePtrArithmetic( |
| 16620 | }; | 16623 | }; |
| 16621 | 16624 | ||
| 16622 | try sema.requireRuntimeBlock(block, op_src, runtime_src); | 16625 | try sema.requireRuntimeBlock(block, op_src, runtime_src); |
| 16623 | 16626 | try sema.checkLogicalPtrOperation(block, op_src, ptr_ty); | |
| 16624 | const target = zcu.getTarget(); | ||
| 16625 | if (target_util.arePointersLogical(target, ptr_info.flags.address_space)) { | ||
| 16626 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 16627 | const msg = try sema.errMsg(op_src, "illegal pointer arithmetic on pointer of type '{}'", .{ptr_ty.fmt(pt)}); | ||
| 16628 | errdefer msg.destroy(sema.gpa); | ||
| 16629 | |||
| 16630 | const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm); | ||
| 16631 | try sema.errNote(op_src, msg, "arithmetic cannot be performed on pointers with address space '{s}' on target {s}-{s} by compiler backend {s}", .{ | ||
| 16632 | @tagName(ptr_info.flags.address_space), | ||
| 16633 | target.cpu.arch.genericName(), | ||
| 16634 | @tagName(target.os.tag), | ||
| 16635 | @tagName(backend), | ||
| 16636 | }); | ||
| 16637 | |||
| 16638 | break :msg msg; | ||
| 16639 | }); | ||
| 16640 | } | ||
| 16641 | 16627 | ||
| 16642 | return block.addInst(.{ | 16628 | return block.addInst(.{ |
| 16643 | .tag = air_tag, | 16629 | .tag = air_tag, |
| ... | @@ -22501,6 +22487,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! | ... | @@ -22501,6 +22487,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 22501 | }); | 22487 | }); |
| 22502 | } | 22488 | } |
| 22503 | try sema.requireRuntimeBlock(block, src, operand_src); | 22489 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 22490 | try sema.checkLogicalPtrOperation(block, src, ptr_ty); | ||
| 22504 | if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) { | 22491 | if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) { |
| 22505 | if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) { | 22492 | if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) { |
| 22506 | if (!ptr_ty.isAllowzeroPtr(zcu)) { | 22493 | if (!ptr_ty.isAllowzeroPtr(zcu)) { |
| ... | @@ -23165,8 +23152,9 @@ fn ptrCastFull( | ... | @@ -23165,8 +23152,9 @@ fn ptrCastFull( |
| 23165 | 23152 | ||
| 23166 | try sema.validateRuntimeValue(block, operand_src, operand); | 23153 | try sema.validateRuntimeValue(block, operand_src, operand); |
| 23167 | 23154 | ||
| 23168 | const need_null_check = block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu); | 23155 | const can_cast_to_int = !target_util.arePointersLogical(zcu.getTarget(), operand_ty.ptrAddressSpace(zcu)); |
| 23169 | const need_align_check = block.wantSafety() and dest_align.compare(.gt, src_align); | 23156 | const need_null_check = can_cast_to_int and block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu); |
| 23157 | const need_align_check = can_cast_to_int and block.wantSafety() and dest_align.compare(.gt, src_align); | ||
| 23170 | 23158 | ||
| 23171 | // `operand` might be a slice. If `need_operand_ptr`, we'll populate `operand_ptr` with the raw pointer. | 23159 | // `operand` might be a slice. If `need_operand_ptr`, we'll populate `operand_ptr` with the raw pointer. |
| 23172 | const need_operand_ptr = src_info.flags.size != .slice or // we already have it | 23160 | const need_operand_ptr = src_info.flags.size != .slice or // we already have it |
| ... | @@ -23832,6 +23820,32 @@ fn checkPtrType( | ... | @@ -23832,6 +23820,32 @@ fn checkPtrType( |
| 23832 | return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)}); | 23820 | return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(pt)}); |
| 23833 | } | 23821 | } |
| 23834 | 23822 | ||
| 23823 | fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { | ||
| 23824 | const pt = sema.pt; | ||
| 23825 | const zcu = pt.zcu; | ||
| 23826 | if (zcu.intern_pool.indexToKey(ty.toIntern()) == .ptr_type) { | ||
| 23827 | const target = zcu.getTarget(); | ||
| 23828 | const as = ty.ptrAddressSpace(zcu); | ||
| 23829 | if (target_util.arePointersLogical(target, as)) { | ||
| 23830 | return sema.failWithOwnedErrorMsg(block, msg: { | ||
| 23831 | const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{}'", .{ty.fmt(pt)}); | ||
| 23832 | errdefer msg.destroy(sema.gpa); | ||
| 23833 | try sema.errNote( | ||
| 23834 | src, | ||
| 23835 | msg, | ||
| 23836 | "cannot perform arithmetic on pointers with address space '{s}' on target {s}-{s}", | ||
| 23837 | .{ | ||
| 23838 | @tagName(as), | ||
| 23839 | target.cpu.arch.genericName(), | ||
| 23840 | @tagName(target.os.tag), | ||
| 23841 | }, | ||
| 23842 | ); | ||
| 23843 | break :msg msg; | ||
| 23844 | }); | ||
| 23845 | } | ||
| 23846 | } | ||
| 23847 | } | ||
| 23848 | |||
| 23835 | fn checkVectorElemType( | 23849 | fn checkVectorElemType( |
| 23836 | sema: *Sema, | 23850 | sema: *Sema, |
| 23837 | block: *Block, | 23851 | block: *Block, |
| ... | @@ -28326,7 +28340,7 @@ fn elemPtr( | ... | @@ -28326,7 +28340,7 @@ fn elemPtr( |
| 28326 | .pointer => indexable_ptr_ty.childType(zcu), | 28340 | .pointer => indexable_ptr_ty.childType(zcu), |
| 28327 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(pt)}), | 28341 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(pt)}), |
| 28328 | }; | 28342 | }; |
| 28329 | try checkIndexable(sema, block, src, indexable_ty); | 28343 | try sema.checkIndexable(block, src, indexable_ty); |
| 28330 | 28344 | ||
| 28331 | const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) { | 28345 | const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) { |
| 28332 | .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), | 28346 | .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| ... | @@ -28362,7 +28376,7 @@ fn elemPtrOneLayerOnly( | ... | @@ -28362,7 +28376,7 @@ fn elemPtrOneLayerOnly( |
| 28362 | const pt = sema.pt; | 28376 | const pt = sema.pt; |
| 28363 | const zcu = pt.zcu; | 28377 | const zcu = pt.zcu; |
| 28364 | 28378 | ||
| 28365 | try checkIndexable(sema, block, src, indexable_ty); | 28379 | try sema.checkIndexable(block, src, indexable_ty); |
| 28366 | 28380 | ||
| 28367 | switch (indexable_ty.ptrSize(zcu)) { | 28381 | switch (indexable_ty.ptrSize(zcu)) { |
| 28368 | .slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), | 28382 | .slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| ... | @@ -28376,6 +28390,8 @@ fn elemPtrOneLayerOnly( | ... | @@ -28376,6 +28390,8 @@ fn elemPtrOneLayerOnly( |
| 28376 | const elem_ptr = try ptr_val.ptrElem(index, pt); | 28390 | const elem_ptr = try ptr_val.ptrElem(index, pt); |
| 28377 | return Air.internedToRef(elem_ptr.toIntern()); | 28391 | return Air.internedToRef(elem_ptr.toIntern()); |
| 28378 | } | 28392 | } |
| 28393 | |||
| 28394 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); | ||
| 28379 | const result_ty = try indexable_ty.elemPtrType(null, pt); | 28395 | const result_ty = try indexable_ty.elemPtrType(null, pt); |
| 28380 | 28396 | ||
| 28381 | return block.addPtrElemPtr(indexable, elem_index, result_ty); | 28397 | return block.addPtrElemPtr(indexable, elem_index, result_ty); |
| ... | @@ -28412,7 +28428,7 @@ fn elemVal( | ... | @@ -28412,7 +28428,7 @@ fn elemVal( |
| 28412 | const pt = sema.pt; | 28428 | const pt = sema.pt; |
| 28413 | const zcu = pt.zcu; | 28429 | const zcu = pt.zcu; |
| 28414 | 28430 | ||
| 28415 | try checkIndexable(sema, block, src, indexable_ty); | 28431 | try sema.checkIndexable(block, src, indexable_ty); |
| 28416 | 28432 | ||
| 28417 | // TODO in case of a vector of pointers, we need to detect whether the element | 28433 | // TODO in case of a vector of pointers, we need to detect whether the element |
| 28418 | // index is a scalar or vector instead of unconditionally casting to usize. | 28434 | // index is a scalar or vector instead of unconditionally casting to usize. |
| ... | @@ -28438,6 +28454,7 @@ fn elemVal( | ... | @@ -28438,6 +28454,7 @@ fn elemVal( |
| 28438 | return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern()); | 28454 | return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern()); |
| 28439 | } | 28455 | } |
| 28440 | 28456 | ||
| 28457 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); | ||
| 28441 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); | 28458 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); |
| 28442 | }, | 28459 | }, |
| 28443 | .one => { | 28460 | .one => { |
| ... | @@ -28477,6 +28494,9 @@ fn validateRuntimeElemAccess( | ... | @@ -28477,6 +28494,9 @@ fn validateRuntimeElemAccess( |
| 28477 | parent_ty: Type, | 28494 | parent_ty: Type, |
| 28478 | parent_src: LazySrcLoc, | 28495 | parent_src: LazySrcLoc, |
| 28479 | ) CompileError!void { | 28496 | ) CompileError!void { |
| 28497 | const pt = sema.pt; | ||
| 28498 | const zcu = pt.zcu; | ||
| 28499 | |||
| 28480 | if (try elem_ty.comptimeOnlySema(sema.pt)) { | 28500 | if (try elem_ty.comptimeOnlySema(sema.pt)) { |
| 28481 | const msg = msg: { | 28501 | const msg = msg: { |
| 28482 | const msg = try sema.errMsg( | 28502 | const msg = try sema.errMsg( |
| ... | @@ -28492,6 +28512,14 @@ fn validateRuntimeElemAccess( | ... | @@ -28492,6 +28512,14 @@ fn validateRuntimeElemAccess( |
| 28492 | }; | 28512 | }; |
| 28493 | return sema.failWithOwnedErrorMsg(block, msg); | 28513 | return sema.failWithOwnedErrorMsg(block, msg); |
| 28494 | } | 28514 | } |
| 28515 | |||
| 28516 | if (zcu.intern_pool.indexToKey(parent_ty.toIntern()) == .ptr_type) { | ||
| 28517 | const target = zcu.getTarget(); | ||
| 28518 | const as = parent_ty.ptrAddressSpace(zcu); | ||
| 28519 | if (target_util.arePointersLogical(target, as)) { | ||
| 28520 | return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{}'", .{parent_ty.fmt(pt)}); | ||
| 28521 | } | ||
| 28522 | } | ||
| 28495 | } | 28523 | } |
| 28496 | 28524 | ||
| 28497 | fn tupleFieldPtr( | 28525 | fn tupleFieldPtr( |
| ... | @@ -31158,6 +31186,7 @@ fn coerceCompatiblePtrs( | ... | @@ -31158,6 +31186,7 @@ fn coerceCompatiblePtrs( |
| 31158 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and | 31186 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and |
| 31159 | (try dest_ty.elemType2(zcu).hasRuntimeBitsSema(pt) or dest_ty.elemType2(zcu).zigTypeTag(zcu) == .@"fn")) | 31187 | (try dest_ty.elemType2(zcu).hasRuntimeBitsSema(pt) or dest_ty.elemType2(zcu).zigTypeTag(zcu) == .@"fn")) |
| 31160 | { | 31188 | { |
| 31189 | try sema.checkLogicalPtrOperation(block, inst_src, inst_ty); | ||
| 31161 | const actual_ptr = if (inst_ty.isSlice(zcu)) | 31190 | const actual_ptr = if (inst_ty.isSlice(zcu)) |
| 31162 | try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) | 31191 | try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) |
| 31163 | else | 31192 | else |
src/codegen/spirv.zig+190-77| ... | @@ -464,7 +464,7 @@ const NavGen = struct { | ... | @@ -464,7 +464,7 @@ const NavGen = struct { |
| 464 | 464 | ||
| 465 | const zcu = self.pt.zcu; | 465 | const zcu = self.pt.zcu; |
| 466 | const ty = Type.fromInterned(zcu.intern_pool.typeOf(val)); | 466 | const ty = Type.fromInterned(zcu.intern_pool.typeOf(val)); |
| 467 | const decl_ptr_ty_id = try self.ptrType(ty, .Generic, .indirect); | 467 | const decl_ptr_ty_id = try self.ptrType(ty, self.spvStorageClass(.generic), .indirect); |
| 468 | 468 | ||
| 469 | const spv_decl_index = blk: { | 469 | const spv_decl_index = blk: { |
| 470 | const entry = try self.object.uav_link.getOrPut(self.object.gpa, .{ val, .Function }); | 470 | const entry = try self.object.uav_link.getOrPut(self.object.gpa, .{ val, .Function }); |
| ... | @@ -581,18 +581,18 @@ const NavGen = struct { | ... | @@ -581,18 +581,18 @@ const NavGen = struct { |
| 581 | /// that size. In this case, multiple elements of the largest type should be used. | 581 | /// that size. In this case, multiple elements of the largest type should be used. |
| 582 | /// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits. | 582 | /// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits. |
| 583 | /// The result is valid to be used with OpTypeInt. | 583 | /// The result is valid to be used with OpTypeInt. |
| 584 | /// TODO: The extension SPV_INTEL_arbitrary_precision_integers allows any integer size (at least up to 32 bits). | ||
| 585 | /// TODO: This probably needs an ABI-version as well (especially in combination with SPV_INTEL_arbitrary_precision_integers). | ||
| 586 | /// TODO: Should the result of this function be cached? | 584 | /// TODO: Should the result of this function be cached? |
| 587 | fn backingIntBits(self: *NavGen, bits: u16) ?u16 { | 585 | fn backingIntBits(self: *NavGen, bits: u16) ?u16 { |
| 588 | // The backend will never be asked to compiler a 0-bit integer, so we won't have to handle those in this function. | 586 | // The backend will never be asked to compiler a 0-bit integer, so we won't have to handle those in this function. |
| 589 | assert(bits != 0); | 587 | assert(bits != 0); |
| 590 | 588 | ||
| 591 | // 8, 16 and 64-bit integers require the Int8, Int16 and Inr64 capabilities respectively. | 589 | if (self.spv.hasFeature(.arbitrary_precision_integers) and bits <= 32) return bits; |
| 590 | |||
| 591 | // We require Int8 and Int16 capabilities and benefit Int64 when available. | ||
| 592 | // 32-bit integers are always supported (see spec, 2.16.1, Data rules). | 592 | // 32-bit integers are always supported (see spec, 2.16.1, Data rules). |
| 593 | const ints = [_]struct { bits: u16, feature: ?Target.spirv.Feature }{ | 593 | const ints = [_]struct { bits: u16, feature: ?Target.spirv.Feature }{ |
| 594 | .{ .bits = 8, .feature = .int8 }, | 594 | .{ .bits = 8, .feature = null }, |
| 595 | .{ .bits = 16, .feature = .int16 }, | 595 | .{ .bits = 16, .feature = null }, |
| 596 | .{ .bits = 32, .feature = null }, | 596 | .{ .bits = 32, .feature = null }, |
| 597 | .{ .bits = 64, .feature = .int64 }, | 597 | .{ .bits = 64, .feature = .int64 }, |
| 598 | }; | 598 | }; |
| ... | @@ -714,6 +714,7 @@ const NavGen = struct { | ... | @@ -714,6 +714,7 @@ const NavGen = struct { |
| 714 | const int_info = scalar_ty.intInfo(zcu); | 714 | const int_info = scalar_ty.intInfo(zcu); |
| 715 | // Use backing bits so that negatives are sign extended | 715 | // Use backing bits so that negatives are sign extended |
| 716 | const backing_bits = self.backingIntBits(int_info.bits).?; // Assertion failure means big int | 716 | const backing_bits = self.backingIntBits(int_info.bits).?; // Assertion failure means big int |
| 717 | assert(backing_bits != 0); // u0 is comptime | ||
| 717 | 718 | ||
| 718 | const signedness: Signedness = switch (@typeInfo(@TypeOf(value))) { | 719 | const signedness: Signedness = switch (@typeInfo(@TypeOf(value))) { |
| 719 | .int => |int| int.signedness, | 720 | .int => |int| int.signedness, |
| ... | @@ -721,35 +722,35 @@ const NavGen = struct { | ... | @@ -721,35 +722,35 @@ const NavGen = struct { |
| 721 | else => unreachable, | 722 | else => unreachable, |
| 722 | }; | 723 | }; |
| 723 | 724 | ||
| 724 | const value64: u64 = switch (signedness) { | 725 | const final_value: spec.LiteralContextDependentNumber = blk: { |
| 725 | .signed => @bitCast(@as(i64, @intCast(value))), | 726 | if (self.spv.hasFeature(.kernel)) { |
| 726 | .unsigned => @as(u64, @intCast(value)), | 727 | const value64: u64 = switch (signedness) { |
| 727 | }; | 728 | .signed => @bitCast(@as(i64, @intCast(value))), |
| 729 | .unsigned => @as(u64, @intCast(value)), | ||
| 730 | }; | ||
| 728 | 731 | ||
| 729 | // Manually truncate the value to the right amount of bits. | 732 | // Manually truncate the value to the right amount of bits. |
| 730 | const truncated_value = if (backing_bits == 64) | 733 | const truncated_value = if (backing_bits == 64) |
| 731 | value64 | 734 | value64 |
| 732 | else | 735 | else |
| 733 | value64 & (@as(u64, 1) << @intCast(backing_bits)) - 1; | 736 | value64 & (@as(u64, 1) << @intCast(backing_bits)) - 1; |
| 734 | 737 | ||
| 735 | const result_ty_id = try self.resolveType(scalar_ty, .indirect); | 738 | break :blk switch (backing_bits) { |
| 736 | const result_id = self.spv.allocId(); | 739 | 1...32 => .{ .uint32 = @truncate(truncated_value) }, |
| 740 | 33...64 => .{ .uint64 = truncated_value }, | ||
| 741 | else => unreachable, // TODO: Large integer constants | ||
| 742 | }; | ||
| 743 | } | ||
| 737 | 744 | ||
| 738 | const section = &self.spv.sections.types_globals_constants; | 745 | break :blk switch (backing_bits) { |
| 739 | switch (backing_bits) { | 746 | 1...32 => if (signedness == .signed) .{ .int32 = @intCast(value) } else .{ .uint32 = @intCast(value) }, |
| 740 | 0 => unreachable, // u0 is comptime | 747 | 33...64 => if (signedness == .signed) .{ .int64 = value } else .{ .uint64 = value }, |
| 741 | 1...32 => try section.emit(self.spv.gpa, .OpConstant, .{ | 748 | else => unreachable, // TODO: Large integer constants |
| 742 | .id_result_type = result_ty_id, | 749 | }; |
| 743 | .id_result = result_id, | 750 | }; |
| 744 | .value = .{ .uint32 = @truncate(truncated_value) }, | 751 | |
| 745 | }), | 752 | const result_ty_id = try self.resolveType(scalar_ty, .indirect); |
| 746 | 33...64 => try section.emit(self.spv.gpa, .OpConstant, .{ | 753 | const result_id = try self.spv.constant(result_ty_id, final_value); |
| 747 | .id_result_type = result_ty_id, | ||
| 748 | .id_result = result_id, | ||
| 749 | .value = .{ .uint64 = truncated_value }, | ||
| 750 | }), | ||
| 751 | else => unreachable, // TODO: Large integer constants | ||
| 752 | } | ||
| 753 | 754 | ||
| 754 | if (!ty.isVector(zcu)) return result_id; | 755 | if (!ty.isVector(zcu)) return result_id; |
| 755 | return self.constructCompositeSplat(ty, result_id); | 756 | return self.constructCompositeSplat(ty, result_id); |
| ... | @@ -804,8 +805,6 @@ const NavGen = struct { | ... | @@ -804,8 +805,6 @@ const NavGen = struct { |
| 804 | return self.spv.constUndef(result_ty_id); | 805 | return self.spv.constUndef(result_ty_id); |
| 805 | } | 806 | } |
| 806 | 807 | ||
| 807 | const section = &self.spv.sections.types_globals_constants; | ||
| 808 | |||
| 809 | const cacheable_id = cache: { | 808 | const cacheable_id = cache: { |
| 810 | switch (ip.indexToKey(val.toIntern())) { | 809 | switch (ip.indexToKey(val.toIntern())) { |
| 811 | .int_type, | 810 | .int_type, |
| ... | @@ -860,13 +859,7 @@ const NavGen = struct { | ... | @@ -860,13 +859,7 @@ const NavGen = struct { |
| 860 | 80, 128 => unreachable, // TODO | 859 | 80, 128 => unreachable, // TODO |
| 861 | else => unreachable, | 860 | else => unreachable, |
| 862 | }; | 861 | }; |
| 863 | const result_id = self.spv.allocId(); | 862 | break :cache try self.spv.constant(result_ty_id, lit); |
| 864 | try section.emit(self.spv.gpa, .OpConstant, .{ | ||
| 865 | .id_result_type = result_ty_id, | ||
| 866 | .id_result = result_id, | ||
| 867 | .value = lit, | ||
| 868 | }); | ||
| 869 | break :cache result_id; | ||
| 870 | }, | 863 | }, |
| 871 | .err => |err| { | 864 | .err => |err| { |
| 872 | const value = try pt.getErrorValue(err.name); | 865 | const value = try pt.getErrorValue(err.name); |
| ... | @@ -989,8 +982,17 @@ const NavGen = struct { | ... | @@ -989,8 +982,17 @@ const NavGen = struct { |
| 989 | }, | 982 | }, |
| 990 | .struct_type => { | 983 | .struct_type => { |
| 991 | const struct_type = zcu.typeToStruct(ty).?; | 984 | const struct_type = zcu.typeToStruct(ty).?; |
| 985 | |||
| 992 | if (struct_type.layout == .@"packed") { | 986 | if (struct_type.layout == .@"packed") { |
| 993 | return self.todo("packed struct constants", .{}); | 987 | // TODO: composite int |
| 988 | // TODO: endianness | ||
| 989 | const bits: u16 = @intCast(ty.bitSize(zcu)); | ||
| 990 | const bytes = std.mem.alignForward(u16, self.backingIntBits(bits).?, 8) / 8; | ||
| 991 | var limbs: [8]u8 = undefined; | ||
| 992 | @memset(&limbs, 0); | ||
| 993 | val.writeToPackedMemory(ty, pt, limbs[0..bytes], 0) catch unreachable; | ||
| 994 | const backing_ty = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)); | ||
| 995 | return try self.constInt(backing_ty, @as(u64, @bitCast(limbs))); | ||
| 994 | } | 996 | } |
| 995 | 997 | ||
| 996 | var types = std.ArrayList(Type).init(self.gpa); | 998 | var types = std.ArrayList(Type).init(self.gpa); |
| ... | @@ -1022,6 +1024,11 @@ const NavGen = struct { | ... | @@ -1022,6 +1024,11 @@ const NavGen = struct { |
| 1022 | else => unreachable, | 1024 | else => unreachable, |
| 1023 | }, | 1025 | }, |
| 1024 | .un => |un| { | 1026 | .un => |un| { |
| 1027 | if (un.tag == .none) { | ||
| 1028 | assert(ty.containerLayout(zcu) == .@"packed"); // TODO | ||
| 1029 | const int_ty = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu))); | ||
| 1030 | return try self.constant(int_ty, Value.fromInterned(un.val), .direct); | ||
| 1031 | } | ||
| 1025 | const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; | 1032 | const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; |
| 1026 | const union_obj = zcu.typeToUnion(ty).?; | 1033 | const union_obj = zcu.typeToUnion(ty).?; |
| 1027 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]); | 1034 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]); |
| ... | @@ -1354,7 +1361,7 @@ const NavGen = struct { | ... | @@ -1354,7 +1361,7 @@ const NavGen = struct { |
| 1354 | const union_obj = zcu.typeToUnion(ty).?; | 1361 | const union_obj = zcu.typeToUnion(ty).?; |
| 1355 | 1362 | ||
| 1356 | if (union_obj.flagsUnordered(ip).layout == .@"packed") { | 1363 | if (union_obj.flagsUnordered(ip).layout == .@"packed") { |
| 1357 | return self.todo("packed union types", .{}); | 1364 | return try self.intType(.unsigned, @intCast(ty.bitSize(zcu))); |
| 1358 | } | 1365 | } |
| 1359 | 1366 | ||
| 1360 | const layout = self.unionLayout(ty); | 1367 | const layout = self.unionLayout(ty); |
| ... | @@ -1366,7 +1373,7 @@ const NavGen = struct { | ... | @@ -1366,7 +1373,7 @@ const NavGen = struct { |
| 1366 | var member_types: [4]IdRef = undefined; | 1373 | var member_types: [4]IdRef = undefined; |
| 1367 | var member_names: [4][]const u8 = undefined; | 1374 | var member_names: [4][]const u8 = undefined; |
| 1368 | 1375 | ||
| 1369 | const u8_ty_id = try self.resolveType(Type.u8, .direct); // TODO: What if Int8Type is not enabled? | 1376 | const u8_ty_id = try self.resolveType(Type.u8, .direct); |
| 1370 | 1377 | ||
| 1371 | if (layout.tag_size != 0) { | 1378 | if (layout.tag_size != 0) { |
| 1372 | const tag_ty_id = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect); | 1379 | const tag_ty_id = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect); |
| ... | @@ -2821,6 +2828,7 @@ const NavGen = struct { | ... | @@ -2821,6 +2828,7 @@ const NavGen = struct { |
| 2821 | /// TODO is to also write out the error as a function call parameter, and to somehow fetch | 2828 | /// TODO is to also write out the error as a function call parameter, and to somehow fetch |
| 2822 | /// the name of an error in the text executor. | 2829 | /// the name of an error in the text executor. |
| 2823 | fn generateTestEntryPoint(self: *NavGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { | 2830 | fn generateTestEntryPoint(self: *NavGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { |
| 2831 | const zcu = self.pt.zcu; | ||
| 2824 | const target = self.spv.target; | 2832 | const target = self.spv.target; |
| 2825 | 2833 | ||
| 2826 | const anyerror_ty_id = try self.resolveType(Type.anyerror, .direct); | 2834 | const anyerror_ty_id = try self.resolveType(Type.anyerror, .direct); |
| ... | @@ -2950,7 +2958,7 @@ const NavGen = struct { | ... | @@ -2950,7 +2958,7 @@ const NavGen = struct { |
| 2950 | .pointer = p_error_id, | 2958 | .pointer = p_error_id, |
| 2951 | .object = error_id, | 2959 | .object = error_id, |
| 2952 | .memory_access = .{ | 2960 | .memory_access = .{ |
| 2953 | .Aligned = .{ .literal_integer = @sizeOf(u16) }, | 2961 | .Aligned = .{ .literal_integer = @intCast(Type.abiAlignment(.anyerror, zcu).toByteUnits().?) }, |
| 2954 | }, | 2962 | }, |
| 2955 | }); | 2963 | }); |
| 2956 | try section.emit(self.spv.gpa, .OpReturn, {}); | 2964 | try section.emit(self.spv.gpa, .OpReturn, {}); |
| ... | @@ -3223,10 +3231,13 @@ const NavGen = struct { | ... | @@ -3223,10 +3231,13 @@ const NavGen = struct { |
| 3223 | }; | 3231 | }; |
| 3224 | 3232 | ||
| 3225 | fn load(self: *NavGen, value_ty: Type, ptr_id: IdRef, options: MemoryOptions) !IdRef { | 3233 | fn load(self: *NavGen, value_ty: Type, ptr_id: IdRef, options: MemoryOptions) !IdRef { |
| 3234 | const zcu = self.pt.zcu; | ||
| 3235 | const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?); | ||
| 3226 | const indirect_value_ty_id = try self.resolveType(value_ty, .indirect); | 3236 | const indirect_value_ty_id = try self.resolveType(value_ty, .indirect); |
| 3227 | const result_id = self.spv.allocId(); | 3237 | const result_id = self.spv.allocId(); |
| 3228 | const access = spec.MemoryAccess.Extended{ | 3238 | const access = spec.MemoryAccess.Extended{ |
| 3229 | .Volatile = options.is_volatile, | 3239 | .Volatile = options.is_volatile, |
| 3240 | .Aligned = .{ .literal_integer = alignment }, | ||
| 3230 | }; | 3241 | }; |
| 3231 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ | 3242 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 3232 | .id_result_type = indirect_value_ty_id, | 3243 | .id_result_type = indirect_value_ty_id, |
| ... | @@ -4229,7 +4240,7 @@ const NavGen = struct { | ... | @@ -4229,7 +4240,7 @@ const NavGen = struct { |
| 4229 | defer self.gpa.free(ids); | 4240 | defer self.gpa.free(ids); |
| 4230 | 4241 | ||
| 4231 | const result_id = self.spv.allocId(); | 4242 | const result_id = self.spv.allocId(); |
| 4232 | if (self.spv.hasFeature(.kernel)) { | 4243 | if (self.spv.hasFeature(.addresses)) { |
| 4233 | try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{ | 4244 | try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{ |
| 4234 | .id_result_type = result_ty_id, | 4245 | .id_result_type = result_ty_id, |
| 4235 | .id_result = result_id, | 4246 | .id_result = result_id, |
| ... | @@ -4308,6 +4319,7 @@ const NavGen = struct { | ... | @@ -4308,6 +4319,7 @@ const NavGen = struct { |
| 4308 | ) !Temporary { | 4319 | ) !Temporary { |
| 4309 | const pt = self.pt; | 4320 | const pt = self.pt; |
| 4310 | const zcu = pt.zcu; | 4321 | const zcu = pt.zcu; |
| 4322 | const ip = &zcu.intern_pool; | ||
| 4311 | const scalar_ty = lhs.ty.scalarType(zcu); | 4323 | const scalar_ty = lhs.ty.scalarType(zcu); |
| 4312 | const is_vector = lhs.ty.isVector(zcu); | 4324 | const is_vector = lhs.ty.isVector(zcu); |
| 4313 | 4325 | ||
| ... | @@ -4318,6 +4330,11 @@ const NavGen = struct { | ... | @@ -4318,6 +4330,11 @@ const NavGen = struct { |
| 4318 | const ty = lhs.ty.intTagType(zcu); | 4330 | const ty = lhs.ty.intTagType(zcu); |
| 4319 | return try self.cmp(op, lhs.pun(ty), rhs.pun(ty)); | 4331 | return try self.cmp(op, lhs.pun(ty), rhs.pun(ty)); |
| 4320 | }, | 4332 | }, |
| 4333 | .@"struct" => { | ||
| 4334 | const struct_ty = zcu.typeToPackedStruct(scalar_ty).?; | ||
| 4335 | const ty = Type.fromInterned(struct_ty.backingIntTypeUnordered(ip)); | ||
| 4336 | return try self.cmp(op, lhs.pun(ty), rhs.pun(ty)); | ||
| 4337 | }, | ||
| 4321 | .error_set => { | 4338 | .error_set => { |
| 4322 | assert(!is_vector); | 4339 | assert(!is_vector); |
| 4323 | const err_int_ty = try pt.errorIntType(); | 4340 | const err_int_ty = try pt.errorIntType(); |
| ... | @@ -4745,8 +4762,42 @@ const NavGen = struct { | ... | @@ -4745,8 +4762,42 @@ const NavGen = struct { |
| 4745 | switch (result_ty.zigTypeTag(zcu)) { | 4762 | switch (result_ty.zigTypeTag(zcu)) { |
| 4746 | .@"struct" => { | 4763 | .@"struct" => { |
| 4747 | if (zcu.typeToPackedStruct(result_ty)) |struct_type| { | 4764 | if (zcu.typeToPackedStruct(result_ty)) |struct_type| { |
| 4748 | _ = struct_type; | 4765 | comptime assert(Type.packed_struct_layout_version == 2); |
| 4749 | unreachable; // TODO | 4766 | const backing_int_ty = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)); |
| 4767 | var running_int_id = try self.constInt(backing_int_ty, 0); | ||
| 4768 | var running_bits: u16 = 0; | ||
| 4769 | for (struct_type.field_types.get(ip), elements) |field_ty_ip, element| { | ||
| 4770 | const field_ty = Type.fromInterned(field_ty_ip); | ||
| 4771 | if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue; | ||
| 4772 | const field_id = try self.resolve(element); | ||
| 4773 | const ty_bit_size: u16 = @intCast(field_ty.bitSize(zcu)); | ||
| 4774 | const field_int_ty = try self.pt.intType(.unsigned, ty_bit_size); | ||
| 4775 | const field_int_id = blk: { | ||
| 4776 | if (field_ty.isPtrAtRuntime(zcu)) { | ||
| 4777 | assert(self.spv.hasFeature(.addresses) or | ||
| 4778 | (self.spv.hasFeature(.physical_storage_buffer) and field_ty.ptrAddressSpace(zcu) == .storage_buffer)); | ||
| 4779 | break :blk try self.intFromPtr(field_id); | ||
| 4780 | } | ||
| 4781 | break :blk try self.bitCast(field_int_ty, field_ty, field_id); | ||
| 4782 | }; | ||
| 4783 | const shift_rhs = try self.constInt(backing_int_ty, running_bits); | ||
| 4784 | const extended_int_conv = try self.buildIntConvert(backing_int_ty, .{ | ||
| 4785 | .ty = field_int_ty, | ||
| 4786 | .value = .{ .singleton = field_int_id }, | ||
| 4787 | }); | ||
| 4788 | const shifted = try self.buildBinary(.sll, extended_int_conv, .{ | ||
| 4789 | .ty = backing_int_ty, | ||
| 4790 | .value = .{ .singleton = shift_rhs }, | ||
| 4791 | }); | ||
| 4792 | const running_int_tmp = try self.buildBinary( | ||
| 4793 | .bit_or, | ||
| 4794 | .{ .ty = backing_int_ty, .value = .{ .singleton = running_int_id } }, | ||
| 4795 | shifted, | ||
| 4796 | ); | ||
| 4797 | running_int_id = try running_int_tmp.materialize(self); | ||
| 4798 | running_bits += ty_bit_size; | ||
| 4799 | } | ||
| 4800 | return running_int_id; | ||
| 4750 | } | 4801 | } |
| 4751 | 4802 | ||
| 4752 | const types = try self.gpa.alloc(Type, elements.len); | 4803 | const types = try self.gpa.alloc(Type, elements.len); |
| ... | @@ -5087,11 +5138,33 @@ const NavGen = struct { | ... | @@ -5087,11 +5138,33 @@ const NavGen = struct { |
| 5087 | const union_ty = zcu.typeToUnion(ty).?; | 5138 | const union_ty = zcu.typeToUnion(ty).?; |
| 5088 | const tag_ty = Type.fromInterned(union_ty.enum_tag_ty); | 5139 | const tag_ty = Type.fromInterned(union_ty.enum_tag_ty); |
| 5089 | 5140 | ||
| 5141 | const layout = self.unionLayout(ty); | ||
| 5142 | const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]); | ||
| 5143 | |||
| 5090 | if (union_ty.flagsUnordered(ip).layout == .@"packed") { | 5144 | if (union_ty.flagsUnordered(ip).layout == .@"packed") { |
| 5091 | unreachable; // TODO | 5145 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 5092 | } | 5146 | const int_ty = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu))); |
| 5147 | return self.constInt(int_ty, 0); | ||
| 5148 | } | ||
| 5093 | 5149 | ||
| 5094 | const layout = self.unionLayout(ty); | 5150 | assert(payload != null); |
| 5151 | if (payload_ty.isInt(zcu)) { | ||
| 5152 | if (ty.bitSize(zcu) == payload_ty.bitSize(zcu)) { | ||
| 5153 | return self.bitCast(ty, payload_ty, payload.?); | ||
| 5154 | } | ||
| 5155 | |||
| 5156 | const trunc = try self.buildIntConvert(ty, .{ .ty = payload_ty, .value = .{ .singleton = payload.? } }); | ||
| 5157 | return try trunc.materialize(self); | ||
| 5158 | } | ||
| 5159 | |||
| 5160 | const payload_int_ty = try pt.intType(.unsigned, @intCast(payload_ty.bitSize(zcu))); | ||
| 5161 | const payload_int = if (payload_ty.ip_index == .bool_type) | ||
| 5162 | try self.convertToIndirect(payload_ty, payload.?) | ||
| 5163 | else | ||
| 5164 | try self.bitCast(payload_int_ty, payload_ty, payload.?); | ||
| 5165 | const trunc = try self.buildIntConvert(ty, .{ .ty = payload_int_ty, .value = .{ .singleton = payload_int } }); | ||
| 5166 | return try trunc.materialize(self); | ||
| 5167 | } | ||
| 5095 | 5168 | ||
| 5096 | const tag_int = if (layout.tag_size != 0) blk: { | 5169 | const tag_int = if (layout.tag_size != 0) blk: { |
| 5097 | const tag_val = try pt.enumValueFieldIndex(tag_ty, active_field); | 5170 | const tag_val = try pt.enumValueFieldIndex(tag_ty, active_field); |
| ... | @@ -5112,7 +5185,6 @@ const NavGen = struct { | ... | @@ -5112,7 +5185,6 @@ const NavGen = struct { |
| 5112 | try self.store(tag_ty, ptr_id, tag_id, .{}); | 5185 | try self.store(tag_ty, ptr_id, tag_id, .{}); |
| 5113 | } | 5186 | } |
| 5114 | 5187 | ||
| 5115 | const payload_ty = Type.fromInterned(union_ty.field_types.get(ip)[active_field]); | ||
| 5116 | if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 5188 | if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 5117 | const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function, .indirect); | 5189 | const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function, .indirect); |
| 5118 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index}); | 5190 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, tmp_id, &.{layout.payload_index}); |
| ... | @@ -5167,11 +5239,51 @@ const NavGen = struct { | ... | @@ -5167,11 +5239,51 @@ const NavGen = struct { |
| 5167 | 5239 | ||
| 5168 | switch (object_ty.zigTypeTag(zcu)) { | 5240 | switch (object_ty.zigTypeTag(zcu)) { |
| 5169 | .@"struct" => switch (object_ty.containerLayout(zcu)) { | 5241 | .@"struct" => switch (object_ty.containerLayout(zcu)) { |
| 5170 | .@"packed" => unreachable, // TODO | 5242 | .@"packed" => { |
| 5243 | const struct_ty = zcu.typeToPackedStruct(object_ty).?; | ||
| 5244 | const bit_offset = pt.structPackedFieldBitOffset(struct_ty, field_index); | ||
| 5245 | const bit_offset_id = try self.constInt(.u16, bit_offset); | ||
| 5246 | const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned; | ||
| 5247 | const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu)); | ||
| 5248 | const field_int_ty = try pt.intType(signedness, field_bit_size); | ||
| 5249 | const shift_lhs: Temporary = .{ .ty = object_ty, .value = .{ .singleton = object_id } }; | ||
| 5250 | const shift = try self.buildBinary(.srl, shift_lhs, .{ .ty = .u16, .value = .{ .singleton = bit_offset_id } }); | ||
| 5251 | const mask_id = try self.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); | ||
| 5252 | const masked = try self.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } }); | ||
| 5253 | const result_id = blk: { | ||
| 5254 | if (self.backingIntBits(field_bit_size).? == self.backingIntBits(@intCast(object_ty.bitSize(zcu))).?) | ||
| 5255 | break :blk try self.bitCast(field_int_ty, object_ty, try masked.materialize(self)); | ||
| 5256 | const trunc = try self.buildIntConvert(field_int_ty, masked); | ||
| 5257 | break :blk try trunc.materialize(self); | ||
| 5258 | }; | ||
| 5259 | if (field_ty.ip_index == .bool_type) return try self.convertToDirect(.bool, result_id); | ||
| 5260 | if (field_ty.isInt(zcu)) return result_id; | ||
| 5261 | return try self.bitCast(field_ty, field_int_ty, result_id); | ||
| 5262 | }, | ||
| 5171 | else => return try self.extractField(field_ty, object_id, field_index), | 5263 | else => return try self.extractField(field_ty, object_id, field_index), |
| 5172 | }, | 5264 | }, |
| 5173 | .@"union" => switch (object_ty.containerLayout(zcu)) { | 5265 | .@"union" => switch (object_ty.containerLayout(zcu)) { |
| 5174 | .@"packed" => unreachable, // TODO | 5266 | .@"packed" => { |
| 5267 | const backing_int_ty = try pt.intType(.unsigned, @intCast(object_ty.bitSize(zcu))); | ||
| 5268 | const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned; | ||
| 5269 | const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu)); | ||
| 5270 | const int_ty = try pt.intType(signedness, field_bit_size); | ||
| 5271 | const mask_id = try self.constInt(backing_int_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); | ||
| 5272 | const masked = try self.buildBinary( | ||
| 5273 | .bit_and, | ||
| 5274 | .{ .ty = backing_int_ty, .value = .{ .singleton = object_id } }, | ||
| 5275 | .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } }, | ||
| 5276 | ); | ||
| 5277 | const result_id = blk: { | ||
| 5278 | if (self.backingIntBits(field_bit_size).? == self.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).?) | ||
| 5279 | break :blk try self.bitCast(int_ty, backing_int_ty, try masked.materialize(self)); | ||
| 5280 | const trunc = try self.buildIntConvert(int_ty, masked); | ||
| 5281 | break :blk try trunc.materialize(self); | ||
| 5282 | }; | ||
| 5283 | if (field_ty.ip_index == .bool_type) return try self.convertToDirect(.bool, result_id); | ||
| 5284 | if (field_ty.isInt(zcu)) return result_id; | ||
| 5285 | return try self.bitCast(field_ty, int_ty, result_id); | ||
| 5286 | }, | ||
| 5175 | else => { | 5287 | else => { |
| 5176 | // Store, ptr-elem-ptr, pointer-cast, load | 5288 | // Store, ptr-elem-ptr, pointer-cast, load |
| 5177 | const layout = self.unionLayout(object_ty); | 5289 | const layout = self.unionLayout(object_ty); |
| ... | @@ -5252,28 +5364,28 @@ const NavGen = struct { | ... | @@ -5252,28 +5364,28 @@ const NavGen = struct { |
| 5252 | return try self.accessChain(result_ty_id, object_ptr, &.{field_index}); | 5364 | return try self.accessChain(result_ty_id, object_ptr, &.{field_index}); |
| 5253 | }, | 5365 | }, |
| 5254 | }, | 5366 | }, |
| 5255 | .@"union" => switch (object_ty.containerLayout(zcu)) { | 5367 | .@"union" => { |
| 5256 | .@"packed" => return self.todo("implement field access for packed unions", .{}), | 5368 | const layout = self.unionLayout(object_ty); |
| 5257 | else => { | 5369 | if (!layout.has_payload) { |
| 5258 | const layout = self.unionLayout(object_ty); | 5370 | // Asked to get a pointer to a zero-sized field. Just lower this |
| 5259 | if (!layout.has_payload) { | 5371 | // to undefined, there is no reason to make it be a valid pointer. |
| 5260 | // Asked to get a pointer to a zero-sized field. Just lower this | 5372 | return try self.spv.constUndef(result_ty_id); |
| 5261 | // to undefined, there is no reason to make it be a valid pointer. | 5373 | } |
| 5262 | return try self.spv.constUndef(result_ty_id); | ||
| 5263 | } | ||
| 5264 | 5374 | ||
| 5265 | const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu)); | 5375 | const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu)); |
| 5266 | const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class, .indirect); | 5376 | const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class, .indirect); |
| 5267 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index}); | 5377 | const pl_ptr_id = blk: { |
| 5378 | if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr; | ||
| 5379 | break :blk try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index}); | ||
| 5380 | }; | ||
| 5268 | 5381 | ||
| 5269 | const active_pl_ptr_id = self.spv.allocId(); | 5382 | const active_pl_ptr_id = self.spv.allocId(); |
| 5270 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | 5383 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 5271 | .id_result_type = result_ty_id, | 5384 | .id_result_type = result_ty_id, |
| 5272 | .id_result = active_pl_ptr_id, | 5385 | .id_result = active_pl_ptr_id, |
| 5273 | .operand = pl_ptr_id, | 5386 | .operand = pl_ptr_id, |
| 5274 | }); | 5387 | }); |
| 5275 | return active_pl_ptr_id; | 5388 | return active_pl_ptr_id; |
| 5276 | }, | ||
| 5277 | }, | 5389 | }, |
| 5278 | else => unreachable, | 5390 | else => unreachable, |
| 5279 | } | 5391 | } |
| ... | @@ -5292,7 +5404,7 @@ const NavGen = struct { | ... | @@ -5292,7 +5404,7 @@ const NavGen = struct { |
| 5292 | /// The final storage class of the pointer. This may be either `.Generic` or `.Function`. | 5404 | /// The final storage class of the pointer. This may be either `.Generic` or `.Function`. |
| 5293 | /// In either case, the local is allocated in the `.Function` storage class, and optionally | 5405 | /// In either case, the local is allocated in the `.Function` storage class, and optionally |
| 5294 | /// cast back to `.Generic`. | 5406 | /// cast back to `.Generic`. |
| 5295 | storage_class: StorageClass = .Generic, | 5407 | storage_class: StorageClass, |
| 5296 | }; | 5408 | }; |
| 5297 | 5409 | ||
| 5298 | // Allocate a function-local variable, with possible initializer. | 5410 | // Allocate a function-local variable, with possible initializer. |
| ... | @@ -5332,9 +5444,10 @@ const NavGen = struct { | ... | @@ -5332,9 +5444,10 @@ const NavGen = struct { |
| 5332 | fn airAlloc(self: *NavGen, inst: Air.Inst.Index) !?IdRef { | 5444 | fn airAlloc(self: *NavGen, inst: Air.Inst.Index) !?IdRef { |
| 5333 | const zcu = self.pt.zcu; | 5445 | const zcu = self.pt.zcu; |
| 5334 | const ptr_ty = self.typeOfIndex(inst); | 5446 | const ptr_ty = self.typeOfIndex(inst); |
| 5335 | assert(ptr_ty.ptrAddressSpace(zcu) == .generic); | ||
| 5336 | const child_ty = ptr_ty.childType(zcu); | 5447 | const child_ty = ptr_ty.childType(zcu); |
| 5337 | return try self.alloc(child_ty, .{}); | 5448 | return try self.alloc(child_ty, .{ |
| 5449 | .storage_class = self.spvStorageClass(ptr_ty.ptrAddressSpace(zcu)), | ||
| 5450 | }); | ||
| 5338 | } | 5451 | } |
| 5339 | 5452 | ||
| 5340 | fn airArg(self: *NavGen) IdRef { | 5453 | fn airArg(self: *NavGen) IdRef { |
src/codegen/spirv/Assembler.zig+45-11| ... | @@ -368,6 +368,40 @@ fn processTypeInstruction(self: *Assembler) !AsmValue { | ... | @@ -368,6 +368,40 @@ fn processTypeInstruction(self: *Assembler) !AsmValue { |
| 368 | }); | 368 | }); |
| 369 | break :blk result_id; | 369 | break :blk result_id; |
| 370 | }, | 370 | }, |
| 371 | .OpTypeStruct => blk: { | ||
| 372 | const ids = try self.gpa.alloc(IdRef, operands[1..].len); | ||
| 373 | defer self.gpa.free(ids); | ||
| 374 | for (operands[1..], ids) |op, *id| id.* = try self.resolveRefId(op.ref_id); | ||
| 375 | const result_id = self.spv.allocId(); | ||
| 376 | try self.spv.structType(result_id, ids, null); | ||
| 377 | break :blk result_id; | ||
| 378 | }, | ||
| 379 | .OpTypeImage => blk: { | ||
| 380 | const sampled_type = try self.resolveRefId(operands[1].ref_id); | ||
| 381 | const result_id = self.spv.allocId(); | ||
| 382 | try section.emit(self.gpa, .OpTypeImage, .{ | ||
| 383 | .id_result = result_id, | ||
| 384 | .sampled_type = sampled_type, | ||
| 385 | .dim = @enumFromInt(operands[2].value), | ||
| 386 | .depth = operands[3].literal32, | ||
| 387 | .arrayed = operands[4].literal32, | ||
| 388 | .ms = operands[5].literal32, | ||
| 389 | .sampled = operands[6].literal32, | ||
| 390 | .image_format = @enumFromInt(operands[7].value), | ||
| 391 | }); | ||
| 392 | break :blk result_id; | ||
| 393 | }, | ||
| 394 | .OpTypeSampler => blk: { | ||
| 395 | const result_id = self.spv.allocId(); | ||
| 396 | try section.emit(self.gpa, .OpTypeSampler, .{ .id_result = result_id }); | ||
| 397 | break :blk result_id; | ||
| 398 | }, | ||
| 399 | .OpTypeSampledImage => blk: { | ||
| 400 | const image_type = try self.resolveRefId(operands[1].ref_id); | ||
| 401 | const result_id = self.spv.allocId(); | ||
| 402 | try section.emit(self.gpa, .OpTypeSampledImage, .{ .id_result = result_id, .image_type = image_type }); | ||
| 403 | break :blk result_id; | ||
| 404 | }, | ||
| 371 | .OpTypeFunction => blk: { | 405 | .OpTypeFunction => blk: { |
| 372 | const param_operands = operands[2..]; | 406 | const param_operands = operands[2..]; |
| 373 | const return_type = try self.resolveRefId(operands[1].ref_id); | 407 | const return_type = try self.resolveRefId(operands[1].ref_id); |
| ... | @@ -406,18 +440,18 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { | ... | @@ -406,18 +440,18 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { |
| 406 | else => switch (self.inst.opcode) { | 440 | else => switch (self.inst.opcode) { |
| 407 | .OpEntryPoint => unreachable, | 441 | .OpEntryPoint => unreachable, |
| 408 | .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes, | 442 | .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes, |
| 409 | .OpVariable => switch (@as(spec.StorageClass, @enumFromInt(operands[2].value))) { | 443 | .OpVariable => section: { |
| 410 | .Function => &self.func.prologue, | 444 | const storage_class: spec.StorageClass = @enumFromInt(operands[2].value); |
| 411 | .Input, .Output => section: { | 445 | if (storage_class == .Function) break :section &self.func.prologue; |
| 412 | maybe_spv_decl_index = try self.spv.allocDecl(.global); | 446 | maybe_spv_decl_index = try self.spv.allocDecl(.global); |
| 413 | try self.func.decl_deps.put(self.spv.gpa, maybe_spv_decl_index.?, {}); | 447 | if (self.spv.version.minor < 4 and storage_class != .Input and storage_class != .Output) { |
| 414 | // TODO: In theory this can be non-empty if there is an initializer which depends on another global... | 448 | // Before version 1.4, the interface’s storage classes are limited to the Input and Output |
| 415 | try self.spv.declareDeclDeps(maybe_spv_decl_index.?, &.{}); | ||
| 416 | break :section &self.spv.sections.types_globals_constants; | 449 | break :section &self.spv.sections.types_globals_constants; |
| 417 | }, | 450 | } |
| 418 | // These don't need to be marked in the dependency system. | 451 | try self.func.decl_deps.put(self.spv.gpa, maybe_spv_decl_index.?, {}); |
| 419 | // Probably we should add them anyway, then filter out PushConstant globals. | 452 | // TODO: In theory this can be non-empty if there is an initializer which depends on another global... |
| 420 | else => &self.spv.sections.types_globals_constants, | 453 | try self.spv.declareDeclDeps(maybe_spv_decl_index.?, &.{}); |
| 454 | break :section &self.spv.sections.types_globals_constants; | ||
| 421 | }, | 455 | }, |
| 422 | // Default case - to be worked out further. | 456 | // Default case - to be worked out further. |
| 423 | else => &self.func.body, | 457 | else => &self.func.body, |
src/codegen/spirv/Module.zig+22-7| ... | @@ -333,8 +333,6 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word { | ... | @@ -333,8 +333,6 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word { |
| 333 | // Versions | 333 | // Versions |
| 334 | .v1_0, .v1_1, .v1_2, .v1_3, .v1_4, .v1_5, .v1_6 => {}, | 334 | .v1_0, .v1_1, .v1_2, .v1_3, .v1_4, .v1_5, .v1_6 => {}, |
| 335 | // Features with no dependencies | 335 | // Features with no dependencies |
| 336 | .int8 => try self.addCapability(.Int8), | ||
| 337 | .int16 => try self.addCapability(.Int16), | ||
| 338 | .int64 => try self.addCapability(.Int64), | 336 | .int64 => try self.addCapability(.Int64), |
| 339 | .float16 => try self.addCapability(.Float16), | 337 | .float16 => try self.addCapability(.Float16), |
| 340 | .float64 => try self.addCapability(.Float64), | 338 | .float64 => try self.addCapability(.Float64), |
| ... | @@ -343,21 +341,27 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word { | ... | @@ -343,21 +341,27 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word { |
| 343 | try self.addExtension("SPV_KHR_16bit_storage"); | 341 | try self.addExtension("SPV_KHR_16bit_storage"); |
| 344 | try self.addCapability(.StoragePushConstant16); | 342 | try self.addCapability(.StoragePushConstant16); |
| 345 | }, | 343 | }, |
| 346 | .addresses => if (self.hasFeature(.shader)) { | 344 | .arbitrary_precision_integers => { |
| 347 | try self.addExtension("SPV_KHR_physical_storage_buffer"); | 345 | try self.addExtension("SPV_INTEL_arbitrary_precision_integers"); |
| 348 | try self.addCapability(.PhysicalStorageBufferAddresses); | 346 | try self.addCapability(.ArbitraryPrecisionIntegersINTEL); |
| 349 | } else { | ||
| 350 | try self.addCapability(.Addresses); | ||
| 351 | }, | 347 | }, |
| 348 | .addresses => try self.addCapability(.Addresses), | ||
| 352 | // Kernel | 349 | // Kernel |
| 353 | .kernel => try self.addCapability(.Kernel), | 350 | .kernel => try self.addCapability(.Kernel), |
| 354 | .generic_pointer => try self.addCapability(.GenericPointer), | 351 | .generic_pointer => try self.addCapability(.GenericPointer), |
| 355 | .vector16 => try self.addCapability(.Vector16), | 352 | .vector16 => try self.addCapability(.Vector16), |
| 356 | // Shader | 353 | // Shader |
| 357 | .shader => try self.addCapability(.Shader), | 354 | .shader => try self.addCapability(.Shader), |
| 355 | .physical_storage_buffer => { | ||
| 356 | try self.addExtension("SPV_KHR_physical_storage_buffer"); | ||
| 357 | try self.addCapability(.PhysicalStorageBufferAddresses); | ||
| 358 | }, | ||
| 358 | } | 359 | } |
| 359 | } | 360 | } |
| 360 | } | 361 | } |
| 362 | // These are well supported | ||
| 363 | try self.addCapability(.Int8); | ||
| 364 | try self.addCapability(.Int16); | ||
| 361 | 365 | ||
| 362 | // Emit memory model | 366 | // Emit memory model |
| 363 | const addressing_model: spec.AddressingModel = blk: { | 367 | const addressing_model: spec.AddressingModel = blk: { |
| ... | @@ -610,6 +614,17 @@ pub fn functionType(self: *Module, return_ty_id: IdRef, param_type_ids: []const | ... | @@ -610,6 +614,17 @@ pub fn functionType(self: *Module, return_ty_id: IdRef, param_type_ids: []const |
| 610 | return result_id; | 614 | return result_id; |
| 611 | } | 615 | } |
| 612 | 616 | ||
| 617 | pub fn constant(self: *Module, result_ty_id: IdRef, value: spec.LiteralContextDependentNumber) !IdRef { | ||
| 618 | const result_id = self.allocId(); | ||
| 619 | const section = &self.sections.types_globals_constants; | ||
| 620 | try section.emit(self.gpa, .OpConstant, .{ | ||
| 621 | .id_result_type = result_ty_id, | ||
| 622 | .id_result = result_id, | ||
| 623 | .value = value, | ||
| 624 | }); | ||
| 625 | return result_id; | ||
| 626 | } | ||
| 627 | |||
| 613 | pub fn constBool(self: *Module, value: bool) !IdRef { | 628 | pub fn constBool(self: *Module, value: bool) !IdRef { |
| 614 | if (self.cache.bool_const[@intFromBool(value)]) |b| return b; | 629 | if (self.cache.bool_const[@intFromBool(value)]) |b| return b; |
| 615 | 630 |
test/behavior.zig+2| ... | @@ -140,6 +140,8 @@ test { | ... | @@ -140,6 +140,8 @@ test { |
| 140 | 140 | ||
| 141 | // This bug only repros in the root file | 141 | // This bug only repros in the root file |
| 142 | test "deference @embedFile() of a file full of zero bytes" { | 142 | test "deference @embedFile() of a file full of zero bytes" { |
| 143 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 144 | |||
| 143 | const contents = @embedFile("behavior/zero.bin").*; | 145 | const contents = @embedFile("behavior/zero.bin").*; |
| 144 | try @import("std").testing.expect(contents.len == 456); | 146 | try @import("std").testing.expect(contents.len == 456); |
| 145 | for (contents) |byte| try @import("std").testing.expect(byte == 0); | 147 | for (contents) |byte| try @import("std").testing.expect(byte == 0); |
test/behavior/bitcast.zig-2| ... | @@ -165,7 +165,6 @@ test "@bitCast packed structs at runtime and comptime" { | ... | @@ -165,7 +165,6 @@ test "@bitCast packed structs at runtime and comptime" { |
| 165 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 165 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 166 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 166 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 167 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 167 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 168 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 169 | 168 | ||
| 170 | const Full = packed struct { | 169 | const Full = packed struct { |
| 171 | number: u16, | 170 | number: u16, |
| ... | @@ -226,7 +225,6 @@ test "bitcast packed struct to integer and back" { | ... | @@ -226,7 +225,6 @@ test "bitcast packed struct to integer and back" { |
| 226 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 225 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 227 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 226 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 228 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 227 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 229 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 230 | 228 | ||
| 231 | const LevelUpMove = packed struct { | 229 | const LevelUpMove = packed struct { |
| 232 | move_id: u9, | 230 | move_id: u9, |
test/behavior/cast_int.zig-4| ... | @@ -22,7 +22,6 @@ test "coerce i8 to i32 and @intCast back" { | ... | @@ -22,7 +22,6 @@ test "coerce i8 to i32 and @intCast back" { |
| 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 26 | 25 | ||
| 27 | var x: i8 = -5; | 26 | var x: i8 = -5; |
| 28 | var y: i32 = -5; | 27 | var y: i32 = -5; |
| ... | @@ -36,8 +35,6 @@ test "coerce i8 to i32 and @intCast back" { | ... | @@ -36,8 +35,6 @@ test "coerce i8 to i32 and @intCast back" { |
| 36 | } | 35 | } |
| 37 | 36 | ||
| 38 | test "coerce non byte-sized integers accross 32bits boundary" { | 37 | test "coerce non byte-sized integers accross 32bits boundary" { |
| 39 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 40 | |||
| 41 | { | 38 | { |
| 42 | var v: u21 = 6417; | 39 | var v: u21 = 6417; |
| 43 | _ = &v; | 40 | _ = &v; |
| ... | @@ -217,7 +214,6 @@ test "load non byte-sized value in union" { | ... | @@ -217,7 +214,6 @@ test "load non byte-sized value in union" { |
| 217 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 218 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 215 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 219 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | 216 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 220 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 221 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 217 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 222 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 218 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 223 | 219 |
test/behavior/export_keyword.zig-1| ... | @@ -25,7 +25,6 @@ const PackedUnion = packed union { | ... | @@ -25,7 +25,6 @@ const PackedUnion = packed union { |
| 25 | 25 | ||
| 26 | test "packed struct, enum, union parameters in extern function" { | 26 | test "packed struct, enum, union parameters in extern function" { |
| 27 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 27 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 28 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 29 | 28 | ||
| 30 | testPackedStuff(&(PackedStruct{ | 29 | testPackedStuff(&(PackedStruct{ |
| 31 | .a = 1, | 30 | .a = 1, |
test/behavior/floatop.zig+3| ... | @@ -133,6 +133,7 @@ test "cmp f16" { | ... | @@ -133,6 +133,7 @@ test "cmp f16" { |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | test "cmp f32" { | 135 | test "cmp f32" { |
| 136 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 137 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 | 138 | if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 |
| 138 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 139 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| ... | @@ -142,6 +143,7 @@ test "cmp f32" { | ... | @@ -142,6 +143,7 @@ test "cmp f32" { |
| 142 | } | 143 | } |
| 143 | 144 | ||
| 144 | test "cmp f64" { | 145 | test "cmp f64" { |
| 146 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 145 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 147 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 146 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; | 148 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 147 | if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 | 149 | if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 |
| ... | @@ -245,6 +247,7 @@ test "vector cmp f16" { | ... | @@ -245,6 +247,7 @@ test "vector cmp f16" { |
| 245 | } | 247 | } |
| 246 | 248 | ||
| 247 | test "vector cmp f32" { | 249 | test "vector cmp f32" { |
| 250 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 248 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 251 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 249 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 252 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 250 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 253 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
test/behavior/globals.zig+4| ... | @@ -69,6 +69,8 @@ test "global loads can affect liveness" { | ... | @@ -69,6 +69,8 @@ test "global loads can affect liveness" { |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | test "global const can be self-referential" { | 71 | test "global const can be self-referential" { |
| 72 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 73 | |||
| 72 | const S = struct { | 74 | const S = struct { |
| 73 | self: *const @This(), | 75 | self: *const @This(), |
| 74 | x: u32, | 76 | x: u32, |
| ... | @@ -113,6 +115,8 @@ test "global var can be self-referential" { | ... | @@ -113,6 +115,8 @@ test "global var can be self-referential" { |
| 113 | } | 115 | } |
| 114 | 116 | ||
| 115 | test "global const can be indirectly self-referential" { | 117 | test "global const can be indirectly self-referential" { |
| 118 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 119 | |||
| 116 | const S = struct { | 120 | const S = struct { |
| 117 | other: *const @This(), | 121 | other: *const @This(), |
| 118 | x: u32, | 122 | x: u32, |
test/behavior/packed-struct.zig-14| ... | @@ -123,7 +123,6 @@ test "correct sizeOf and offsets in packed structs" { | ... | @@ -123,7 +123,6 @@ test "correct sizeOf and offsets in packed structs" { |
| 123 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 123 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 124 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 124 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 125 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 125 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 126 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 127 | 126 | ||
| 128 | const PStruct = packed struct { | 127 | const PStruct = packed struct { |
| 129 | bool_a: bool, | 128 | bool_a: bool, |
| ... | @@ -191,7 +190,6 @@ test "nested packed structs" { | ... | @@ -191,7 +190,6 @@ test "nested packed structs" { |
| 191 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 190 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 192 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 191 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 193 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 192 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 194 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 195 | 193 | ||
| 196 | const S1 = packed struct { a: u8, b: u8, c: u8 }; | 194 | const S1 = packed struct { a: u8, b: u8, c: u8 }; |
| 197 | 195 | ||
| ... | @@ -257,7 +255,6 @@ test "nested packed struct unaligned" { | ... | @@ -257,7 +255,6 @@ test "nested packed struct unaligned" { |
| 257 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 255 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 258 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 256 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 259 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 257 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 260 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 261 | if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet | 258 | if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet |
| 262 | 259 | ||
| 263 | const S1 = packed struct { | 260 | const S1 = packed struct { |
| ... | @@ -895,7 +892,6 @@ test "packed struct passed to callconv(.c) function" { | ... | @@ -895,7 +892,6 @@ test "packed struct passed to callconv(.c) function" { |
| 895 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 892 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 896 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 893 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 897 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 894 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 898 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 899 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 895 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 900 | 896 | ||
| 901 | const S = struct { | 897 | const S = struct { |
| ... | @@ -944,7 +940,6 @@ test "packed struct initialized in bitcast" { | ... | @@ -944,7 +940,6 @@ test "packed struct initialized in bitcast" { |
| 944 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 940 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 945 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 941 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 946 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 942 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 947 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 948 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 943 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 949 | 944 | ||
| 950 | const T = packed struct { val: u8 }; | 945 | const T = packed struct { val: u8 }; |
| ... | @@ -982,7 +977,6 @@ test "pointer to container level packed struct field" { | ... | @@ -982,7 +977,6 @@ test "pointer to container level packed struct field" { |
| 982 | test "store undefined to packed result location" { | 977 | test "store undefined to packed result location" { |
| 983 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 978 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 984 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 979 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 985 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 986 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 980 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 987 | 981 | ||
| 988 | var x: u4 = 0; | 982 | var x: u4 = 0; |
| ... | @@ -992,8 +986,6 @@ test "store undefined to packed result location" { | ... | @@ -992,8 +986,6 @@ test "store undefined to packed result location" { |
| 992 | } | 986 | } |
| 993 | 987 | ||
| 994 | test "bitcast back and forth" { | 988 | test "bitcast back and forth" { |
| 995 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 996 | |||
| 997 | // Originally reported at https://github.com/ziglang/zig/issues/9914 | 989 | // Originally reported at https://github.com/ziglang/zig/issues/9914 |
| 998 | const S = packed struct { one: u6, two: u1 }; | 990 | const S = packed struct { one: u6, two: u1 }; |
| 999 | const s = S{ .one = 0b110101, .two = 0b1 }; | 991 | const s = S{ .one = 0b110101, .two = 0b1 }; |
| ... | @@ -1290,8 +1282,6 @@ test "2-byte packed struct argument in C calling convention" { | ... | @@ -1290,8 +1282,6 @@ test "2-byte packed struct argument in C calling convention" { |
| 1290 | } | 1282 | } |
| 1291 | 1283 | ||
| 1292 | test "packed struct contains optional pointer" { | 1284 | test "packed struct contains optional pointer" { |
| 1293 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1294 | |||
| 1295 | const foo: packed struct { | 1285 | const foo: packed struct { |
| 1296 | a: ?*@This() = null, | 1286 | a: ?*@This() = null, |
| 1297 | } = .{}; | 1287 | } = .{}; |
| ... | @@ -1299,8 +1289,6 @@ test "packed struct contains optional pointer" { | ... | @@ -1299,8 +1289,6 @@ test "packed struct contains optional pointer" { |
| 1299 | } | 1289 | } |
| 1300 | 1290 | ||
| 1301 | test "packed struct equality" { | 1291 | test "packed struct equality" { |
| 1302 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1303 | |||
| 1304 | const Foo = packed struct { | 1292 | const Foo = packed struct { |
| 1305 | a: u4, | 1293 | a: u4, |
| 1306 | b: u4, | 1294 | b: u4, |
| ... | @@ -1321,8 +1309,6 @@ test "packed struct equality" { | ... | @@ -1321,8 +1309,6 @@ test "packed struct equality" { |
| 1321 | } | 1309 | } |
| 1322 | 1310 | ||
| 1323 | test "packed struct with signed field" { | 1311 | test "packed struct with signed field" { |
| 1324 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1325 | |||
| 1326 | var s: packed struct { | 1312 | var s: packed struct { |
| 1327 | a: i2, | 1313 | a: i2, |
| 1328 | b: u6, | 1314 | b: u6, |
test/behavior/packed-union.zig-3| ... | @@ -137,7 +137,6 @@ test "packed union initialized with a runtime value" { | ... | @@ -137,7 +137,6 @@ test "packed union initialized with a runtime value" { |
| 137 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 137 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 138 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 138 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 139 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 139 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 140 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 141 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 140 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 142 | 141 | ||
| 143 | const Fields = packed struct { | 142 | const Fields = packed struct { |
| ... | @@ -174,8 +173,6 @@ test "assigning to non-active field at comptime" { | ... | @@ -174,8 +173,6 @@ test "assigning to non-active field at comptime" { |
| 174 | } | 173 | } |
| 175 | 174 | ||
| 176 | test "comptime packed union of pointers" { | 175 | test "comptime packed union of pointers" { |
| 177 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 178 | |||
| 179 | const U = packed union { | 176 | const U = packed union { |
| 180 | a: *const u32, | 177 | a: *const u32, |
| 181 | b: *const [1]u32, | 178 | b: *const [1]u32, |
test/behavior/packed_struct_explicit_backing_int.zig-1| ... | @@ -9,7 +9,6 @@ test "packed struct explicit backing integer" { | ... | @@ -9,7 +9,6 @@ test "packed struct explicit backing integer" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 12 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 13 | 12 | ||
| 14 | const S1 = packed struct { a: u8, b: u8, c: u8 }; | 13 | const S1 = packed struct { a: u8, b: u8, c: u8 }; |
| 15 | 14 |
test/behavior/ptrcast.zig-2| ... | @@ -287,8 +287,6 @@ test "@ptrCast undefined value at comptime" { | ... | @@ -287,8 +287,6 @@ test "@ptrCast undefined value at comptime" { |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | test "comptime @ptrCast with packed struct leaves value unmodified" { | 289 | test "comptime @ptrCast with packed struct leaves value unmodified" { |
| 290 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 291 | |||
| 292 | const S = packed struct { three: u3 }; | 290 | const S = packed struct { three: u3 }; |
| 293 | const st: S = .{ .three = 6 }; | 291 | const st: S = .{ .three = 6 }; |
| 294 | try expect(st.three == 6); | 292 | try expect(st.three == 6); |
test/behavior/ptrfromint.zig+2| ... | @@ -3,6 +3,8 @@ const builtin = @import("builtin"); | ... | @@ -3,6 +3,8 @@ const builtin = @import("builtin"); |
| 3 | const expectEqual = std.testing.expectEqual; | 3 | const expectEqual = std.testing.expectEqual; |
| 4 | 4 | ||
| 5 | test "casting integer address to function pointer" { | 5 | test "casting integer address to function pointer" { |
| 6 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 7 | |||
| 6 | addressToFunction(); | 8 | addressToFunction(); |
| 7 | comptime addressToFunction(); | 9 | comptime addressToFunction(); |
| 8 | } | 10 | } |
test/behavior/sizeof_and_typeof.zig+2| ... | @@ -233,6 +233,8 @@ test "@sizeOf comparison against zero" { | ... | @@ -233,6 +233,8 @@ test "@sizeOf comparison against zero" { |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | test "hardcoded address in typeof expression" { | 235 | test "hardcoded address in typeof expression" { |
| 236 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 237 | |||
| 236 | const S = struct { | 238 | const S = struct { |
| 237 | fn func() @TypeOf(@as(*[]u8, @ptrFromInt(0x10)).*[0]) { | 239 | fn func() @TypeOf(@as(*[]u8, @ptrFromInt(0x10)).*[0]) { |
| 238 | return 0; | 240 | return 0; |
test/behavior/struct.zig-3| ... | @@ -1023,7 +1023,6 @@ test "packed struct with undefined initializers" { | ... | @@ -1023,7 +1023,6 @@ test "packed struct with undefined initializers" { |
| 1023 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1023 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1024 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1024 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1025 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1025 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1026 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1027 | 1026 | ||
| 1028 | const S = struct { | 1027 | const S = struct { |
| 1029 | const P = packed struct { | 1028 | const P = packed struct { |
| ... | @@ -1221,7 +1220,6 @@ test "packed struct aggregate init" { | ... | @@ -1221,7 +1220,6 @@ test "packed struct aggregate init" { |
| 1221 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1220 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1222 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1221 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1223 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1222 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1224 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1225 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | 1223 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1226 | 1224 | ||
| 1227 | const S = struct { | 1225 | const S = struct { |
| ... | @@ -1971,7 +1969,6 @@ test "struct field default value is a call" { | ... | @@ -1971,7 +1969,6 @@ test "struct field default value is a call" { |
| 1971 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1969 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1972 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1970 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1973 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1971 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1974 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1975 | 1972 | ||
| 1976 | const Z = packed struct { | 1973 | const Z = packed struct { |
| 1977 | a: u32, | 1974 | a: u32, |
test/behavior/union.zig+2-12| ... | @@ -1372,14 +1372,13 @@ test "packed union in packed struct" { | ... | @@ -1372,14 +1372,13 @@ test "packed union in packed struct" { |
| 1372 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1372 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1374 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1374 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1375 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1376 | 1375 | ||
| 1377 | const S = packed struct { | 1376 | const S = packed struct { |
| 1378 | nested: packed union { | 1377 | nested: packed union { |
| 1379 | val: usize, | 1378 | val: u16, |
| 1380 | foo: u32, | 1379 | foo: u32, |
| 1381 | }, | 1380 | }, |
| 1382 | bar: u32, | 1381 | bar: u16, |
| 1383 | 1382 | ||
| 1384 | fn unpack(self: @This()) usize { | 1383 | fn unpack(self: @This()) usize { |
| 1385 | return self.nested.foo; | 1384 | return self.nested.foo; |
| ... | @@ -1460,7 +1459,6 @@ test "packed union with zero-bit field" { | ... | @@ -1460,7 +1459,6 @@ test "packed union with zero-bit field" { |
| 1460 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1459 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1461 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1460 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1462 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1461 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1463 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1464 | 1462 | ||
| 1465 | const S = packed struct { | 1463 | const S = packed struct { |
| 1466 | nested: packed union { | 1464 | nested: packed union { |
| ... | @@ -1479,7 +1477,6 @@ test "packed union with zero-bit field" { | ... | @@ -1479,7 +1477,6 @@ test "packed union with zero-bit field" { |
| 1479 | test "reinterpreting enum value inside packed union" { | 1477 | test "reinterpreting enum value inside packed union" { |
| 1480 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1478 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1481 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1479 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1482 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1483 | 1480 | ||
| 1484 | const U = packed union { | 1481 | const U = packed union { |
| 1485 | tag: enum(u8) { a, b }, | 1482 | tag: enum(u8) { a, b }, |
| ... | @@ -1527,7 +1524,6 @@ test "defined-layout union field pointer has correct alignment" { | ... | @@ -1527,7 +1524,6 @@ test "defined-layout union field pointer has correct alignment" { |
| 1527 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1524 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1528 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1529 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1526 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1530 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO | ||
| 1531 | 1527 | ||
| 1532 | const S = struct { | 1528 | const S = struct { |
| 1533 | fn doTheTest(comptime U: type) !void { | 1529 | fn doTheTest(comptime U: type) !void { |
| ... | @@ -1901,8 +1897,6 @@ test "inner struct initializer uses union layout" { | ... | @@ -1901,8 +1897,6 @@ test "inner struct initializer uses union layout" { |
| 1901 | } | 1897 | } |
| 1902 | 1898 | ||
| 1903 | test "inner struct initializer uses packed union layout" { | 1899 | test "inner struct initializer uses packed union layout" { |
| 1904 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1905 | |||
| 1906 | const namespace = struct { | 1900 | const namespace = struct { |
| 1907 | const U = packed union { | 1901 | const U = packed union { |
| 1908 | a: packed struct { | 1902 | a: packed struct { |
| ... | @@ -1946,8 +1940,6 @@ test "extern union initialized via reintepreted struct field initializer" { | ... | @@ -1946,8 +1940,6 @@ test "extern union initialized via reintepreted struct field initializer" { |
| 1946 | } | 1940 | } |
| 1947 | 1941 | ||
| 1948 | test "packed union initialized via reintepreted struct field initializer" { | 1942 | test "packed union initialized via reintepreted struct field initializer" { |
| 1949 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1950 | |||
| 1951 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; | 1943 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1952 | 1944 | ||
| 1953 | const U = packed union { | 1945 | const U = packed union { |
| ... | @@ -1988,8 +1980,6 @@ test "store of comptime reinterpreted memory to extern union" { | ... | @@ -1988,8 +1980,6 @@ test "store of comptime reinterpreted memory to extern union" { |
| 1988 | } | 1980 | } |
| 1989 | 1981 | ||
| 1990 | test "store of comptime reinterpreted memory to packed union" { | 1982 | test "store of comptime reinterpreted memory to packed union" { |
| 1991 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 1992 | |||
| 1993 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; | 1983 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1994 | 1984 | ||
| 1995 | const U = packed union { | 1985 | const U = packed union { |
test/cases/compile_errors/illegal_operation_on_logical_ptr.zig created+52| ... | @@ -0,0 +1,52 @@ | ||
| 1 | export fn elemPtr() void { | ||
| 2 | var ptr: [*]u8 = undefined; | ||
| 3 | ptr[0] = 0; | ||
| 4 | } | ||
| 5 | |||
| 6 | export fn elemVal() void { | ||
| 7 | var ptr: [*]u8 = undefined; | ||
| 8 | var val = ptr[0]; | ||
| 9 | _ = &ptr; | ||
| 10 | _ = &val; | ||
| 11 | } | ||
| 12 | |||
| 13 | export fn intFromPtr() void { | ||
| 14 | var value: u8 = 0; | ||
| 15 | _ = @intFromPtr(&value); | ||
| 16 | } | ||
| 17 | |||
| 18 | export fn ptrFromInt() void { | ||
| 19 | var v: u32 = 0x1234; | ||
| 20 | var ptr: *u8 = @ptrFromInt(v); | ||
| 21 | _ = &v; | ||
| 22 | _ = &ptr; | ||
| 23 | } | ||
| 24 | |||
| 25 | export fn ptrPtrArithmetic() void { | ||
| 26 | var value0: u8 = 0; | ||
| 27 | var value1: u8 = 0; | ||
| 28 | _ = &value0 - &value1; | ||
| 29 | } | ||
| 30 | |||
| 31 | export fn ptrIntArithmetic() void { | ||
| 32 | var ptr0: [*]u8 = undefined; | ||
| 33 | _ = &ptr0; | ||
| 34 | _ = ptr0 - 10; | ||
| 35 | } | ||
| 36 | |||
| 37 | // error | ||
| 38 | // backend=stage2 | ||
| 39 | // target=spirv64-vulkan | ||
| 40 | // | ||
| 41 | // :3:8: error: illegal operation on logical pointer of type '[*]u8' | ||
| 42 | // :3:8: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan | ||
| 43 | // :8:18: error: illegal operation on logical pointer of type '[*]u8' | ||
| 44 | // :8:18: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan | ||
| 45 | // :15:21: error: illegal operation on logical pointer of type '*u8' | ||
| 46 | // :15:21: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan | ||
| 47 | // :20:20: error: illegal operation on logical pointer of type '*u8' | ||
| 48 | // :20:20: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan | ||
| 49 | // :28:17: error: illegal operation on logical pointer of type '*u8' | ||
| 50 | // :28:17: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan | ||
| 51 | // :34:14: error: illegal operation on logical pointer of type '[*]u8' | ||
| 52 | // :34:14: note: cannot perform arithmetic on pointers with address space 'generic' on target spirv-vulkan | ||
test/tests.zig+1-1| ... | @@ -143,7 +143,7 @@ const test_targets = blk: { | ... | @@ -143,7 +143,7 @@ const test_targets = blk: { |
| 143 | .{ | 143 | .{ |
| 144 | .target = std.Target.Query.parse(.{ | 144 | .target = std.Target.Query.parse(.{ |
| 145 | .arch_os_abi = "spirv64-vulkan", | 145 | .arch_os_abi = "spirv64-vulkan", |
| 146 | .cpu_features = "vulkan_v1_2+int8+int16+int64+float16+float64", | 146 | .cpu_features = "vulkan_v1_2+int64+float16+float64", |
| 147 | }) catch unreachable, | 147 | }) catch unreachable, |
| 148 | .use_llvm = false, | 148 | .use_llvm = false, |
| 149 | .use_lld = false, | 149 | .use_lld = false, |