| 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 | 10 | v1_4, |
| 11 | 11 | v1_5, |
| 12 | 12 | v1_6, |
| 13 | int8, | |
| 14 | int16, | |
| 15 | 13 | int64, |
| 16 | 14 | float16, |
| 17 | 15 | float64, |
| 18 | addresses, | |
| 19 | 16 | matrix, |
| 20 | 17 | storage_push_constant16, |
| 18 | arbitrary_precision_integers, | |
| 21 | 19 | kernel, |
| 20 | addresses, | |
| 22 | 21 | generic_pointer, |
| 23 | 22 | vector16, |
| 24 | 23 | shader, |
| 24 | physical_storage_buffer, | |
| 25 | 25 | }; |
| 26 | 26 | |
| 27 | 27 | pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet; |
| ... | ... | @@ -69,16 +69,6 @@ pub const all_features = blk: { |
| 69 | 69 | .description = "Enable version 1.6", |
| 70 | 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 | 72 | result[@intFromEnum(Feature.int64)] = .{ |
| 83 | 73 | .llvm_name = null, |
| 84 | 74 | .description = "Enable Int64 capability", |
| ... | ... | @@ -94,11 +84,6 @@ pub const all_features = blk: { |
| 94 | 84 | .description = "Enable Float64 capability", |
| 95 | 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 | 87 | result[@intFromEnum(Feature.matrix)] = .{ |
| 103 | 88 | .llvm_name = null, |
| 104 | 89 | .description = "Enable Matrix capability", |
| ... | ... | @@ -109,11 +94,21 @@ pub const all_features = blk: { |
| 109 | 94 | .description = "Enable SPV_KHR_16bit_storage extension and the StoragePushConstant16 capability", |
| 110 | 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 | 102 | result[@intFromEnum(Feature.kernel)] = .{ |
| 113 | 103 | .llvm_name = null, |
| 114 | 104 | .description = "Enable Kernel capability", |
| 115 | 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 | 112 | result[@intFromEnum(Feature.generic_pointer)] = .{ |
| 118 | 113 | .llvm_name = null, |
| 119 | 114 | .description = "Enable GenericPointer capability", |
| ... | ... | @@ -129,6 +124,11 @@ pub const all_features = blk: { |
| 129 | 124 | .description = "Enable Shader capability", |
| 130 | 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 | 132 | const ti = @typeInfo(Feature); |
| 133 | 133 | for (&result, 0..) |*elem, i| { |
| 134 | 134 | elem.index = i; |
| ... | ... | @@ -147,7 +147,7 @@ pub const cpu = struct { |
| 147 | 147 | pub const vulkan_v1_2: CpuModel = .{ |
| 148 | 148 | .name = "vulkan_v1_2", |
| 149 | 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 | 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 | 80 | /// Forms the main linkage for `input` and `output` address spaces. |
| 81 | 81 | /// `ptr` must be a reference to variable or struct field. |
| 82 | 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 | 86 | : [ptr] "" (ptr), |
| 86 | 87 | [loc] "c" (loc), |
| ... | ... | @@ -110,7 +111,8 @@ pub const Origin = enum(u32) { |
| 110 | 111 | /// The coordinates appear to originate in the specified `origin`. |
| 111 | 112 | /// Only valid with the `Fragment` calling convention. |
| 112 | 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 | 117 | : [entry_point] "" (entry_point), |
| 116 | 118 | [origin] "c" (@intFromEnum(origin)), |
| ... | ... | @@ -137,7 +139,8 @@ pub const DepthMode = enum(u32) { |
| 137 | 139 | |
| 138 | 140 | /// Only valid with the `Fragment` calling convention. |
| 139 | 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 | 145 | : [entry_point] "" (entry_point), |
| 143 | 146 | [mode] "c" (mode), |
| ... | ... | @@ -147,7 +150,8 @@ pub fn depthMode(comptime entry_point: anytype, comptime mode: DepthMode) void { |
| 147 | 150 | /// Indicates the workgroup size in the `x`, `y`, and `z` dimensions. |
| 148 | 151 | /// Only valid with the `GLCompute` or `Kernel` calling conventions. |
| 149 | 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 | 156 | : [entry_point] "" (entry_point), |
| 153 | 157 | [x] "c" (size[0]), |
| ... | ... | @@ -159,7 +163,8 @@ pub fn workgroupSize(comptime entry_point: anytype, comptime size: @Vector(3, u3 |
| 159 | 163 | /// A hint to the client, which indicates the workgroup size in the `x`, `y`, and `z` dimensions. |
| 160 | 164 | /// Only valid with the `GLCompute` or `Kernel` calling conventions. |
| 161 | 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 | 169 | : [entry_point] "" (entry_point), |
| 165 | 170 | [x] "c" (size[0]), |
src/Sema.zig+53-24| ... | ... | @@ -3648,7 +3648,7 @@ fn indexablePtrLen( |
| 3648 | 3648 | const object_ty = sema.typeOf(object); |
| 3649 | 3649 | const is_pointer_to = object_ty.isSinglePointer(zcu); |
| 3650 | 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 | 3652 | const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "len", .no_embedded_nulls); |
| 3653 | 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 | 10103 | } |
| 10104 | 10104 | try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), ptr_src); |
| 10105 | 10105 | try sema.validateRuntimeValue(block, ptr_src, operand); |
| 10106 | try sema.checkLogicalPtrOperation(block, ptr_src, ptr_ty); | |
| 10106 | 10107 | if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) { |
| 10107 | 10108 | return block.addBitCast(dest_ty, operand); |
| 10108 | 10109 | } |
| ... | ... | @@ -16389,6 +16390,8 @@ fn analyzeArithmetic( |
| 16389 | 16390 | }; |
| 16390 | 16391 | |
| 16391 | 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 | 16395 | const lhs_int = try block.addBitCast(.usize, lhs); |
| 16393 | 16396 | const rhs_int = try block.addBitCast(.usize, rhs); |
| 16394 | 16397 | const address = try block.addBinOp(.sub_wrap, lhs_int, rhs_int); |
| ... | ... | @@ -16620,24 +16623,7 @@ fn analyzePtrArithmetic( |
| 16620 | 16623 | }; |
| 16621 | 16624 | |
| 16622 | 16625 | try sema.requireRuntimeBlock(block, op_src, runtime_src); |
| 16623 | ||
| 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 | } | |
| 16626 | try sema.checkLogicalPtrOperation(block, op_src, ptr_ty); | |
| 16641 | 16627 | |
| 16642 | 16628 | return block.addInst(.{ |
| 16643 | 16629 | .tag = air_tag, |
| ... | ... | @@ -22501,6 +22487,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 22501 | 22487 | }); |
| 22502 | 22488 | } |
| 22503 | 22489 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 22490 | try sema.checkLogicalPtrOperation(block, src, ptr_ty); | |
| 22504 | 22491 | if (!is_vector or zcu.backendSupportsFeature(.all_vector_instructions)) { |
| 22505 | 22492 | if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) { |
| 22506 | 22493 | if (!ptr_ty.isAllowzeroPtr(zcu)) { |
| ... | ... | @@ -23165,8 +23152,9 @@ fn ptrCastFull( |
| 23165 | 23152 | |
| 23166 | 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); | |
| 23169 | const need_align_check = block.wantSafety() and dest_align.compare(.gt, src_align); | |
| 23155 | const can_cast_to_int = !target_util.arePointersLogical(zcu.getTarget(), operand_ty.ptrAddressSpace(zcu)); | |
| 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 | 23159 | // `operand` might be a slice. If `need_operand_ptr`, we'll populate `operand_ptr` with the raw pointer. |
| 23172 | 23160 | const need_operand_ptr = src_info.flags.size != .slice or // we already have it |
| ... | ... | @@ -23832,6 +23820,32 @@ fn checkPtrType( |
| 23832 | 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 | 23849 | fn checkVectorElemType( |
| 23836 | 23850 | sema: *Sema, |
| 23837 | 23851 | block: *Block, |
| ... | ... | @@ -28326,7 +28340,7 @@ fn elemPtr( |
| 28326 | 28340 | .pointer => indexable_ptr_ty.childType(zcu), |
| 28327 | 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 | 28345 | const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) { |
| 28332 | 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 | 28376 | const pt = sema.pt; |
| 28363 | 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 | 28381 | switch (indexable_ty.ptrSize(zcu)) { |
| 28368 | 28382 | .slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| ... | ... | @@ -28376,6 +28390,8 @@ fn elemPtrOneLayerOnly( |
| 28376 | 28390 | const elem_ptr = try ptr_val.ptrElem(index, pt); |
| 28377 | 28391 | return Air.internedToRef(elem_ptr.toIntern()); |
| 28378 | 28392 | } |
| 28393 | ||
| 28394 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); | |
| 28379 | 28395 | const result_ty = try indexable_ty.elemPtrType(null, pt); |
| 28380 | 28396 | |
| 28381 | 28397 | return block.addPtrElemPtr(indexable, elem_index, result_ty); |
| ... | ... | @@ -28412,7 +28428,7 @@ fn elemVal( |
| 28412 | 28428 | const pt = sema.pt; |
| 28413 | 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 | 28433 | // TODO in case of a vector of pointers, we need to detect whether the element |
| 28418 | 28434 | // index is a scalar or vector instead of unconditionally casting to usize. |
| ... | ... | @@ -28438,6 +28454,7 @@ fn elemVal( |
| 28438 | 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 | 28458 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); |
| 28442 | 28459 | }, |
| 28443 | 28460 | .one => { |
| ... | ... | @@ -28477,6 +28494,9 @@ fn validateRuntimeElemAccess( |
| 28477 | 28494 | parent_ty: Type, |
| 28478 | 28495 | parent_src: LazySrcLoc, |
| 28479 | 28496 | ) CompileError!void { |
| 28497 | const pt = sema.pt; | |
| 28498 | const zcu = pt.zcu; | |
| 28499 | ||
| 28480 | 28500 | if (try elem_ty.comptimeOnlySema(sema.pt)) { |
| 28481 | 28501 | const msg = msg: { |
| 28482 | 28502 | const msg = try sema.errMsg( |
| ... | ... | @@ -28492,6 +28512,14 @@ fn validateRuntimeElemAccess( |
| 28492 | 28512 | }; |
| 28493 | 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 | 28525 | fn tupleFieldPtr( |
| ... | ... | @@ -31158,6 +31186,7 @@ fn coerceCompatiblePtrs( |
| 31158 | 31186 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and |
| 31159 | 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 | 31190 | const actual_ptr = if (inst_ty.isSlice(zcu)) |
| 31162 | 31191 | try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) |
| 31163 | 31192 | else |
src/codegen/spirv.zig+190-77| ... | ... | @@ -464,7 +464,7 @@ const NavGen = struct { |
| 464 | 464 | |
| 465 | 465 | const zcu = self.pt.zcu; |
| 466 | 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 | 469 | const spv_decl_index = blk: { |
| 470 | 470 | const entry = try self.object.uav_link.getOrPut(self.object.gpa, .{ val, .Function }); |
| ... | ... | @@ -581,18 +581,18 @@ const NavGen = struct { |
| 581 | 581 | /// that size. In this case, multiple elements of the largest type should be used. |
| 582 | 582 | /// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits. |
| 583 | 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 | 584 | /// TODO: Should the result of this function be cached? |
| 587 | 585 | fn backingIntBits(self: *NavGen, bits: u16) ?u16 { |
| 588 | 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 | 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 | 592 | // 32-bit integers are always supported (see spec, 2.16.1, Data rules). |
| 593 | 593 | const ints = [_]struct { bits: u16, feature: ?Target.spirv.Feature }{ |
| 594 | .{ .bits = 8, .feature = .int8 }, | |
| 595 | .{ .bits = 16, .feature = .int16 }, | |
| 594 | .{ .bits = 8, .feature = null }, | |
| 595 | .{ .bits = 16, .feature = null }, | |
| 596 | 596 | .{ .bits = 32, .feature = null }, |
| 597 | 597 | .{ .bits = 64, .feature = .int64 }, |
| 598 | 598 | }; |
| ... | ... | @@ -714,6 +714,7 @@ const NavGen = struct { |
| 714 | 714 | const int_info = scalar_ty.intInfo(zcu); |
| 715 | 715 | // Use backing bits so that negatives are sign extended |
| 716 | 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 | 719 | const signedness: Signedness = switch (@typeInfo(@TypeOf(value))) { |
| 719 | 720 | .int => |int| int.signedness, |
| ... | ... | @@ -721,35 +722,35 @@ const NavGen = struct { |
| 721 | 722 | else => unreachable, |
| 722 | 723 | }; |
| 723 | 724 | |
| 724 | const value64: u64 = switch (signedness) { | |
| 725 | .signed => @bitCast(@as(i64, @intCast(value))), | |
| 726 | .unsigned => @as(u64, @intCast(value)), | |
| 727 | }; | |
| 725 | const final_value: spec.LiteralContextDependentNumber = blk: { | |
| 726 | if (self.spv.hasFeature(.kernel)) { | |
| 727 | const value64: u64 = switch (signedness) { | |
| 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. | |
| 730 | const truncated_value = if (backing_bits == 64) | |
| 731 | value64 | |
| 732 | else | |
| 733 | value64 & (@as(u64, 1) << @intCast(backing_bits)) - 1; | |
| 732 | // Manually truncate the value to the right amount of bits. | |
| 733 | const truncated_value = if (backing_bits == 64) | |
| 734 | value64 | |
| 735 | else | |
| 736 | value64 & (@as(u64, 1) << @intCast(backing_bits)) - 1; | |
| 734 | 737 | |
| 735 | const result_ty_id = try self.resolveType(scalar_ty, .indirect); | |
| 736 | const result_id = self.spv.allocId(); | |
| 738 | break :blk switch (backing_bits) { | |
| 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; | |
| 739 | switch (backing_bits) { | |
| 740 | 0 => unreachable, // u0 is comptime | |
| 741 | 1...32 => try section.emit(self.spv.gpa, .OpConstant, .{ | |
| 742 | .id_result_type = result_ty_id, | |
| 743 | .id_result = result_id, | |
| 744 | .value = .{ .uint32 = @truncate(truncated_value) }, | |
| 745 | }), | |
| 746 | 33...64 => try section.emit(self.spv.gpa, .OpConstant, .{ | |
| 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 | } | |
| 745 | break :blk switch (backing_bits) { | |
| 746 | 1...32 => if (signedness == .signed) .{ .int32 = @intCast(value) } else .{ .uint32 = @intCast(value) }, | |
| 747 | 33...64 => if (signedness == .signed) .{ .int64 = value } else .{ .uint64 = value }, | |
| 748 | else => unreachable, // TODO: Large integer constants | |
| 749 | }; | |
| 750 | }; | |
| 751 | ||
| 752 | const result_ty_id = try self.resolveType(scalar_ty, .indirect); | |
| 753 | const result_id = try self.spv.constant(result_ty_id, final_value); | |
| 753 | 754 | |
| 754 | 755 | if (!ty.isVector(zcu)) return result_id; |
| 755 | 756 | return self.constructCompositeSplat(ty, result_id); |
| ... | ... | @@ -804,8 +805,6 @@ const NavGen = struct { |
| 804 | 805 | return self.spv.constUndef(result_ty_id); |
| 805 | 806 | } |
| 806 | 807 | |
| 807 | const section = &self.spv.sections.types_globals_constants; | |
| 808 | ||
| 809 | 808 | const cacheable_id = cache: { |
| 810 | 809 | switch (ip.indexToKey(val.toIntern())) { |
| 811 | 810 | .int_type, |
| ... | ... | @@ -860,13 +859,7 @@ const NavGen = struct { |
| 860 | 859 | 80, 128 => unreachable, // TODO |
| 861 | 860 | else => unreachable, |
| 862 | 861 | }; |
| 863 | const result_id = self.spv.allocId(); | |
| 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; | |
| 862 | break :cache try self.spv.constant(result_ty_id, lit); | |
| 870 | 863 | }, |
| 871 | 864 | .err => |err| { |
| 872 | 865 | const value = try pt.getErrorValue(err.name); |
| ... | ... | @@ -989,8 +982,17 @@ const NavGen = struct { |
| 989 | 982 | }, |
| 990 | 983 | .struct_type => { |
| 991 | 984 | const struct_type = zcu.typeToStruct(ty).?; |
| 985 | ||
| 992 | 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 | 998 | var types = std.ArrayList(Type).init(self.gpa); |
| ... | ... | @@ -1022,6 +1024,11 @@ const NavGen = struct { |
| 1022 | 1024 | else => unreachable, |
| 1023 | 1025 | }, |
| 1024 | 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 | 1032 | const active_field = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; |
| 1026 | 1033 | const union_obj = zcu.typeToUnion(ty).?; |
| 1027 | 1034 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[active_field]); |
| ... | ... | @@ -1354,7 +1361,7 @@ const NavGen = struct { |
| 1354 | 1361 | const union_obj = zcu.typeToUnion(ty).?; |
| 1355 | 1362 | |
| 1356 | 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 | 1367 | const layout = self.unionLayout(ty); |
| ... | ... | @@ -1366,7 +1373,7 @@ const NavGen = struct { |
| 1366 | 1373 | var member_types: [4]IdRef = undefined; |
| 1367 | 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 | 1378 | if (layout.tag_size != 0) { |
| 1372 | 1379 | const tag_ty_id = try self.resolveType(Type.fromInterned(union_obj.enum_tag_ty), .indirect); |
| ... | ... | @@ -2821,6 +2828,7 @@ const NavGen = struct { |
| 2821 | 2828 | /// TODO is to also write out the error as a function call parameter, and to somehow fetch |
| 2822 | 2829 | /// the name of an error in the text executor. |
| 2823 | 2830 | fn generateTestEntryPoint(self: *NavGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { |
| 2831 | const zcu = self.pt.zcu; | |
| 2824 | 2832 | const target = self.spv.target; |
| 2825 | 2833 | |
| 2826 | 2834 | const anyerror_ty_id = try self.resolveType(Type.anyerror, .direct); |
| ... | ... | @@ -2950,7 +2958,7 @@ const NavGen = struct { |
| 2950 | 2958 | .pointer = p_error_id, |
| 2951 | 2959 | .object = error_id, |
| 2952 | 2960 | .memory_access = .{ |
| 2953 | .Aligned = .{ .literal_integer = @sizeOf(u16) }, | |
| 2961 | .Aligned = .{ .literal_integer = @intCast(Type.abiAlignment(.anyerror, zcu).toByteUnits().?) }, | |
| 2954 | 2962 | }, |
| 2955 | 2963 | }); |
| 2956 | 2964 | try section.emit(self.spv.gpa, .OpReturn, {}); |
| ... | ... | @@ -3223,10 +3231,13 @@ const NavGen = struct { |
| 3223 | 3231 | }; |
| 3224 | 3232 | |
| 3225 | 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 | 3236 | const indirect_value_ty_id = try self.resolveType(value_ty, .indirect); |
| 3227 | 3237 | const result_id = self.spv.allocId(); |
| 3228 | 3238 | const access = spec.MemoryAccess.Extended{ |
| 3229 | 3239 | .Volatile = options.is_volatile, |
| 3240 | .Aligned = .{ .literal_integer = alignment }, | |
| 3230 | 3241 | }; |
| 3231 | 3242 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 3232 | 3243 | .id_result_type = indirect_value_ty_id, |
| ... | ... | @@ -4229,7 +4240,7 @@ const NavGen = struct { |
| 4229 | 4240 | defer self.gpa.free(ids); |
| 4230 | 4241 | |
| 4231 | 4242 | const result_id = self.spv.allocId(); |
| 4232 | if (self.spv.hasFeature(.kernel)) { | |
| 4243 | if (self.spv.hasFeature(.addresses)) { | |
| 4233 | 4244 | try self.func.body.emit(self.spv.gpa, .OpInBoundsPtrAccessChain, .{ |
| 4234 | 4245 | .id_result_type = result_ty_id, |
| 4235 | 4246 | .id_result = result_id, |
| ... | ... | @@ -4308,6 +4319,7 @@ const NavGen = struct { |
| 4308 | 4319 | ) !Temporary { |
| 4309 | 4320 | const pt = self.pt; |
| 4310 | 4321 | const zcu = pt.zcu; |
| 4322 | const ip = &zcu.intern_pool; | |
| 4311 | 4323 | const scalar_ty = lhs.ty.scalarType(zcu); |
| 4312 | 4324 | const is_vector = lhs.ty.isVector(zcu); |
| 4313 | 4325 | |
| ... | ... | @@ -4318,6 +4330,11 @@ const NavGen = struct { |
| 4318 | 4330 | const ty = lhs.ty.intTagType(zcu); |
| 4319 | 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 | 4338 | .error_set => { |
| 4322 | 4339 | assert(!is_vector); |
| 4323 | 4340 | const err_int_ty = try pt.errorIntType(); |
| ... | ... | @@ -4745,8 +4762,42 @@ const NavGen = struct { |
| 4745 | 4762 | switch (result_ty.zigTypeTag(zcu)) { |
| 4746 | 4763 | .@"struct" => { |
| 4747 | 4764 | if (zcu.typeToPackedStruct(result_ty)) |struct_type| { |
| 4748 | _ = struct_type; | |
| 4749 | unreachable; // TODO | |
| 4765 | comptime assert(Type.packed_struct_layout_version == 2); | |
| 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 | 4803 | const types = try self.gpa.alloc(Type, elements.len); |
| ... | ... | @@ -5087,11 +5138,33 @@ const NavGen = struct { |
| 5087 | 5138 | const union_ty = zcu.typeToUnion(ty).?; |
| 5088 | 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 | 5144 | if (union_ty.flagsUnordered(ip).layout == .@"packed") { |
| 5091 | unreachable; // TODO | |
| 5092 | } | |
| 5145 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | |
| 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 | 5169 | const tag_int = if (layout.tag_size != 0) blk: { |
| 5097 | 5170 | const tag_val = try pt.enumValueFieldIndex(tag_ty, active_field); |
| ... | ... | @@ -5112,7 +5185,6 @@ const NavGen = struct { |
| 5112 | 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 | 5188 | if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 5117 | 5189 | const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, .Function, .indirect); |
| 5118 | 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 | 5239 | |
| 5168 | 5240 | switch (object_ty.zigTypeTag(zcu)) { |
| 5169 | 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 | 5263 | else => return try self.extractField(field_ty, object_id, field_index), |
| 5172 | 5264 | }, |
| 5173 | 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 | 5287 | else => { |
| 5176 | 5288 | // Store, ptr-elem-ptr, pointer-cast, load |
| 5177 | 5289 | const layout = self.unionLayout(object_ty); |
| ... | ... | @@ -5252,28 +5364,28 @@ const NavGen = struct { |
| 5252 | 5364 | return try self.accessChain(result_ty_id, object_ptr, &.{field_index}); |
| 5253 | 5365 | }, |
| 5254 | 5366 | }, |
| 5255 | .@"union" => switch (object_ty.containerLayout(zcu)) { | |
| 5256 | .@"packed" => return self.todo("implement field access for packed unions", .{}), | |
| 5257 | else => { | |
| 5258 | const layout = self.unionLayout(object_ty); | |
| 5259 | if (!layout.has_payload) { | |
| 5260 | // Asked to get a pointer to a zero-sized field. Just lower this | |
| 5261 | // to undefined, there is no reason to make it be a valid pointer. | |
| 5262 | return try self.spv.constUndef(result_ty_id); | |
| 5263 | } | |
| 5367 | .@"union" => { | |
| 5368 | const layout = self.unionLayout(object_ty); | |
| 5369 | if (!layout.has_payload) { | |
| 5370 | // Asked to get a pointer to a zero-sized field. Just lower this | |
| 5371 | // to undefined, there is no reason to make it be a valid pointer. | |
| 5372 | return try self.spv.constUndef(result_ty_id); | |
| 5373 | } | |
| 5264 | 5374 | |
| 5265 | 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); | |
| 5267 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index}); | |
| 5375 | const storage_class = self.spvStorageClass(object_ptr_ty.ptrAddressSpace(zcu)); | |
| 5376 | const pl_ptr_ty_id = try self.ptrType(layout.payload_ty, storage_class, .indirect); | |
| 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(); | |
| 5270 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | |
| 5271 | .id_result_type = result_ty_id, | |
| 5272 | .id_result = active_pl_ptr_id, | |
| 5273 | .operand = pl_ptr_id, | |
| 5274 | }); | |
| 5275 | return active_pl_ptr_id; | |
| 5276 | }, | |
| 5382 | const active_pl_ptr_id = self.spv.allocId(); | |
| 5383 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | |
| 5384 | .id_result_type = result_ty_id, | |
| 5385 | .id_result = active_pl_ptr_id, | |
| 5386 | .operand = pl_ptr_id, | |
| 5387 | }); | |
| 5388 | return active_pl_ptr_id; | |
| 5277 | 5389 | }, |
| 5278 | 5390 | else => unreachable, |
| 5279 | 5391 | } |
| ... | ... | @@ -5292,7 +5404,7 @@ const NavGen = struct { |
| 5292 | 5404 | /// The final storage class of the pointer. This may be either `.Generic` or `.Function`. |
| 5293 | 5405 | /// In either case, the local is allocated in the `.Function` storage class, and optionally |
| 5294 | 5406 | /// cast back to `.Generic`. |
| 5295 | storage_class: StorageClass = .Generic, | |
| 5407 | storage_class: StorageClass, | |
| 5296 | 5408 | }; |
| 5297 | 5409 | |
| 5298 | 5410 | // Allocate a function-local variable, with possible initializer. |
| ... | ... | @@ -5332,9 +5444,10 @@ const NavGen = struct { |
| 5332 | 5444 | fn airAlloc(self: *NavGen, inst: Air.Inst.Index) !?IdRef { |
| 5333 | 5445 | const zcu = self.pt.zcu; |
| 5334 | 5446 | const ptr_ty = self.typeOfIndex(inst); |
| 5335 | assert(ptr_ty.ptrAddressSpace(zcu) == .generic); | |
| 5336 | 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 | 5453 | fn airArg(self: *NavGen) IdRef { |
src/codegen/spirv/Assembler.zig+45-11| ... | ... | @@ -368,6 +368,40 @@ fn processTypeInstruction(self: *Assembler) !AsmValue { |
| 368 | 368 | }); |
| 369 | 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 | 405 | .OpTypeFunction => blk: { |
| 372 | 406 | const param_operands = operands[2..]; |
| 373 | 407 | const return_type = try self.resolveRefId(operands[1].ref_id); |
| ... | ... | @@ -406,18 +440,18 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue { |
| 406 | 440 | else => switch (self.inst.opcode) { |
| 407 | 441 | .OpEntryPoint => unreachable, |
| 408 | 442 | .OpExecutionMode, .OpExecutionModeId => &self.spv.sections.execution_modes, |
| 409 | .OpVariable => switch (@as(spec.StorageClass, @enumFromInt(operands[2].value))) { | |
| 410 | .Function => &self.func.prologue, | |
| 411 | .Input, .Output => section: { | |
| 412 | maybe_spv_decl_index = try self.spv.allocDecl(.global); | |
| 413 | try self.func.decl_deps.put(self.spv.gpa, maybe_spv_decl_index.?, {}); | |
| 414 | // TODO: In theory this can be non-empty if there is an initializer which depends on another global... | |
| 415 | try self.spv.declareDeclDeps(maybe_spv_decl_index.?, &.{}); | |
| 443 | .OpVariable => section: { | |
| 444 | const storage_class: spec.StorageClass = @enumFromInt(operands[2].value); | |
| 445 | if (storage_class == .Function) break :section &self.func.prologue; | |
| 446 | maybe_spv_decl_index = try self.spv.allocDecl(.global); | |
| 447 | if (self.spv.version.minor < 4 and storage_class != .Input and storage_class != .Output) { | |
| 448 | // Before version 1.4, the interface’s storage classes are limited to the Input and Output | |
| 416 | 449 | break :section &self.spv.sections.types_globals_constants; |
| 417 | }, | |
| 418 | // These don't need to be marked in the dependency system. | |
| 419 | // Probably we should add them anyway, then filter out PushConstant globals. | |
| 420 | else => &self.spv.sections.types_globals_constants, | |
| 450 | } | |
| 451 | try self.func.decl_deps.put(self.spv.gpa, maybe_spv_decl_index.?, {}); | |
| 452 | // TODO: In theory this can be non-empty if there is an initializer which depends on another global... | |
| 453 | try self.spv.declareDeclDeps(maybe_spv_decl_index.?, &.{}); | |
| 454 | break :section &self.spv.sections.types_globals_constants; | |
| 421 | 455 | }, |
| 422 | 456 | // Default case - to be worked out further. |
| 423 | 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 | 333 | // Versions |
| 334 | 334 | .v1_0, .v1_1, .v1_2, .v1_3, .v1_4, .v1_5, .v1_6 => {}, |
| 335 | 335 | // Features with no dependencies |
| 336 | .int8 => try self.addCapability(.Int8), | |
| 337 | .int16 => try self.addCapability(.Int16), | |
| 338 | 336 | .int64 => try self.addCapability(.Int64), |
| 339 | 337 | .float16 => try self.addCapability(.Float16), |
| 340 | 338 | .float64 => try self.addCapability(.Float64), |
| ... | ... | @@ -343,21 +341,27 @@ pub fn finalize(self: *Module, a: Allocator) ![]Word { |
| 343 | 341 | try self.addExtension("SPV_KHR_16bit_storage"); |
| 344 | 342 | try self.addCapability(.StoragePushConstant16); |
| 345 | 343 | }, |
| 346 | .addresses => if (self.hasFeature(.shader)) { | |
| 347 | try self.addExtension("SPV_KHR_physical_storage_buffer"); | |
| 348 | try self.addCapability(.PhysicalStorageBufferAddresses); | |
| 349 | } else { | |
| 350 | try self.addCapability(.Addresses); | |
| 344 | .arbitrary_precision_integers => { | |
| 345 | try self.addExtension("SPV_INTEL_arbitrary_precision_integers"); | |
| 346 | try self.addCapability(.ArbitraryPrecisionIntegersINTEL); | |
| 351 | 347 | }, |
| 348 | .addresses => try self.addCapability(.Addresses), | |
| 352 | 349 | // Kernel |
| 353 | 350 | .kernel => try self.addCapability(.Kernel), |
| 354 | 351 | .generic_pointer => try self.addCapability(.GenericPointer), |
| 355 | 352 | .vector16 => try self.addCapability(.Vector16), |
| 356 | 353 | // Shader |
| 357 | 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 | 366 | // Emit memory model |
| 363 | 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 | 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 | 628 | pub fn constBool(self: *Module, value: bool) !IdRef { |
| 614 | 629 | if (self.cache.bool_const[@intFromBool(value)]) |b| return b; |
| 615 | 630 |
test/behavior.zig+2| ... | ... | @@ -140,6 +140,8 @@ test { |
| 140 | 140 | |
| 141 | 141 | // This bug only repros in the root file |
| 142 | 142 | test "deference @embedFile() of a file full of zero bytes" { |
| 143 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 144 | ||
| 143 | 145 | const contents = @embedFile("behavior/zero.bin").*; |
| 144 | 146 | try @import("std").testing.expect(contents.len == 456); |
| 145 | 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 | 165 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 166 | 166 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 167 | 167 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 168 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 169 | 168 | |
| 170 | 169 | const Full = packed struct { |
| 171 | 170 | number: u16, |
| ... | ... | @@ -226,7 +225,6 @@ test "bitcast packed struct to integer and back" { |
| 226 | 225 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 227 | 226 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 228 | 227 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 229 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 230 | 228 | |
| 231 | 229 | const LevelUpMove = packed struct { |
| 232 | 230 | move_id: u9, |
test/behavior/cast_int.zig-4| ... | ... | @@ -22,7 +22,6 @@ test "coerce i8 to i32 and @intCast back" { |
| 22 | 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 23 | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 24 | 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 26 | 25 | |
| 27 | 26 | var x: i8 = -5; |
| 28 | 27 | var y: i32 = -5; |
| ... | ... | @@ -36,8 +35,6 @@ test "coerce i8 to i32 and @intCast back" { |
| 36 | 35 | } |
| 37 | 36 | |
| 38 | 37 | test "coerce non byte-sized integers accross 32bits boundary" { |
| 39 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 40 | ||
| 41 | 38 | { |
| 42 | 39 | var v: u21 = 6417; |
| 43 | 40 | _ = &v; |
| ... | ... | @@ -217,7 +214,6 @@ test "load non byte-sized value in union" { |
| 217 | 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 218 | 215 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 219 | 216 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 220 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 221 | 217 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 222 | 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 | 25 | |
| 26 | 26 | test "packed struct, enum, union parameters in extern function" { |
| 27 | 27 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 28 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 29 | 28 | |
| 30 | 29 | testPackedStuff(&(PackedStruct{ |
| 31 | 30 | .a = 1, |
test/behavior/floatop.zig+3| ... | ... | @@ -133,6 +133,7 @@ test "cmp f16" { |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | 135 | test "cmp f32" { |
| 136 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 136 | 137 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | 138 | if (builtin.cpu.arch.isArm() and builtin.target.abi.float() == .soft) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/21234 |
| 138 | 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 | 143 | } |
| 143 | 144 | |
| 144 | 145 | test "cmp f64" { |
| 146 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 145 | 147 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 146 | 148 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| 147 | 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 | 247 | } |
| 246 | 248 | |
| 247 | 249 | test "vector cmp f32" { |
| 250 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 248 | 251 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 249 | 252 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 250 | 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 | 69 | } |
| 70 | 70 | |
| 71 | 71 | test "global const can be self-referential" { |
| 72 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 73 | ||
| 72 | 74 | const S = struct { |
| 73 | 75 | self: *const @This(), |
| 74 | 76 | x: u32, |
| ... | ... | @@ -113,6 +115,8 @@ test "global var can be self-referential" { |
| 113 | 115 | } |
| 114 | 116 | |
| 115 | 117 | test "global const can be indirectly self-referential" { |
| 118 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 119 | ||
| 116 | 120 | const S = struct { |
| 117 | 121 | other: *const @This(), |
| 118 | 122 | x: u32, |
test/behavior/packed-struct.zig-14| ... | ... | @@ -123,7 +123,6 @@ test "correct sizeOf and offsets in packed structs" { |
| 123 | 123 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 124 | 124 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 125 | 125 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 126 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 127 | 126 | |
| 128 | 127 | const PStruct = packed struct { |
| 129 | 128 | bool_a: bool, |
| ... | ... | @@ -191,7 +190,6 @@ test "nested packed structs" { |
| 191 | 190 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 192 | 191 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 193 | 192 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 194 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 195 | 193 | |
| 196 | 194 | const S1 = packed struct { a: u8, b: u8, c: u8 }; |
| 197 | 195 | |
| ... | ... | @@ -257,7 +255,6 @@ test "nested packed struct unaligned" { |
| 257 | 255 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 258 | 256 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 259 | 257 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 260 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 261 | 258 | if (native_endian != .little) return error.SkipZigTest; // Byte aligned packed struct field pointers have not been implemented yet |
| 262 | 259 | |
| 263 | 260 | const S1 = packed struct { |
| ... | ... | @@ -895,7 +892,6 @@ test "packed struct passed to callconv(.c) function" { |
| 895 | 892 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 896 | 893 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 897 | 894 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 898 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 899 | 895 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 900 | 896 | |
| 901 | 897 | const S = struct { |
| ... | ... | @@ -944,7 +940,6 @@ test "packed struct initialized in bitcast" { |
| 944 | 940 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 945 | 941 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 946 | 942 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 947 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 948 | 943 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 949 | 944 | |
| 950 | 945 | const T = packed struct { val: u8 }; |
| ... | ... | @@ -982,7 +977,6 @@ test "pointer to container level packed struct field" { |
| 982 | 977 | test "store undefined to packed result location" { |
| 983 | 978 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 984 | 979 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 985 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 986 | 980 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 987 | 981 | |
| 988 | 982 | var x: u4 = 0; |
| ... | ... | @@ -992,8 +986,6 @@ test "store undefined to packed result location" { |
| 992 | 986 | } |
| 993 | 987 | |
| 994 | 988 | test "bitcast back and forth" { |
| 995 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 996 | ||
| 997 | 989 | // Originally reported at https://github.com/ziglang/zig/issues/9914 |
| 998 | 990 | const S = packed struct { one: u6, two: u1 }; |
| 999 | 991 | const s = S{ .one = 0b110101, .two = 0b1 }; |
| ... | ... | @@ -1290,8 +1282,6 @@ test "2-byte packed struct argument in C calling convention" { |
| 1290 | 1282 | } |
| 1291 | 1283 | |
| 1292 | 1284 | test "packed struct contains optional pointer" { |
| 1293 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1294 | ||
| 1295 | 1285 | const foo: packed struct { |
| 1296 | 1286 | a: ?*@This() = null, |
| 1297 | 1287 | } = .{}; |
| ... | ... | @@ -1299,8 +1289,6 @@ test "packed struct contains optional pointer" { |
| 1299 | 1289 | } |
| 1300 | 1290 | |
| 1301 | 1291 | test "packed struct equality" { |
| 1302 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1303 | ||
| 1304 | 1292 | const Foo = packed struct { |
| 1305 | 1293 | a: u4, |
| 1306 | 1294 | b: u4, |
| ... | ... | @@ -1321,8 +1309,6 @@ test "packed struct equality" { |
| 1321 | 1309 | } |
| 1322 | 1310 | |
| 1323 | 1311 | test "packed struct with signed field" { |
| 1324 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1325 | ||
| 1326 | 1312 | var s: packed struct { |
| 1327 | 1313 | a: i2, |
| 1328 | 1314 | b: u6, |
test/behavior/packed-union.zig-3| ... | ... | @@ -137,7 +137,6 @@ test "packed union initialized with a runtime value" { |
| 137 | 137 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 138 | 138 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 139 | 139 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 140 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 141 | 140 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 142 | 141 | |
| 143 | 142 | const Fields = packed struct { |
| ... | ... | @@ -174,8 +173,6 @@ test "assigning to non-active field at comptime" { |
| 174 | 173 | } |
| 175 | 174 | |
| 176 | 175 | test "comptime packed union of pointers" { |
| 177 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 178 | ||
| 179 | 176 | const U = packed union { |
| 180 | 177 | a: *const u32, |
| 181 | 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 | 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 10 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 12 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 13 | 12 | |
| 14 | 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 | 287 | } |
| 288 | 288 | |
| 289 | 289 | test "comptime @ptrCast with packed struct leaves value unmodified" { |
| 290 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 291 | ||
| 292 | 290 | const S = packed struct { three: u3 }; |
| 293 | 291 | const st: S = .{ .three = 6 }; |
| 294 | 292 | try expect(st.three == 6); |
test/behavior/ptrfromint.zig+2| ... | ... | @@ -3,6 +3,8 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expectEqual = std.testing.expectEqual; |
| 4 | 4 | |
| 5 | 5 | test "casting integer address to function pointer" { |
| 6 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 7 | ||
| 6 | 8 | addressToFunction(); |
| 7 | 9 | comptime addressToFunction(); |
| 8 | 10 | } |
test/behavior/sizeof_and_typeof.zig+2| ... | ... | @@ -233,6 +233,8 @@ test "@sizeOf comparison against zero" { |
| 233 | 233 | } |
| 234 | 234 | |
| 235 | 235 | test "hardcoded address in typeof expression" { |
| 236 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 237 | ||
| 236 | 238 | const S = struct { |
| 237 | 239 | fn func() @TypeOf(@as(*[]u8, @ptrFromInt(0x10)).*[0]) { |
| 238 | 240 | return 0; |
test/behavior/struct.zig-3| ... | ... | @@ -1023,7 +1023,6 @@ test "packed struct with undefined initializers" { |
| 1023 | 1023 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1024 | 1024 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1025 | 1025 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1026 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1027 | 1026 | |
| 1028 | 1027 | const S = struct { |
| 1029 | 1028 | const P = packed struct { |
| ... | ... | @@ -1221,7 +1220,6 @@ test "packed struct aggregate init" { |
| 1221 | 1220 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1222 | 1221 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1223 | 1222 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1224 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1225 | 1223 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1226 | 1224 | |
| 1227 | 1225 | const S = struct { |
| ... | ... | @@ -1971,7 +1969,6 @@ test "struct field default value is a call" { |
| 1971 | 1969 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1972 | 1970 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1973 | 1971 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1974 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1975 | 1972 | |
| 1976 | 1973 | const Z = packed struct { |
| 1977 | 1974 | a: u32, |
test/behavior/union.zig+2-12| ... | ... | @@ -1372,14 +1372,13 @@ test "packed union in packed struct" { |
| 1372 | 1372 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1373 | 1373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1374 | 1374 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1375 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1376 | 1375 | |
| 1377 | 1376 | const S = packed struct { |
| 1378 | 1377 | nested: packed union { |
| 1379 | val: usize, | |
| 1378 | val: u16, | |
| 1380 | 1379 | foo: u32, |
| 1381 | 1380 | }, |
| 1382 | bar: u32, | |
| 1381 | bar: u16, | |
| 1383 | 1382 | |
| 1384 | 1383 | fn unpack(self: @This()) usize { |
| 1385 | 1384 | return self.nested.foo; |
| ... | ... | @@ -1460,7 +1459,6 @@ test "packed union with zero-bit field" { |
| 1460 | 1459 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1461 | 1460 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1462 | 1461 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1463 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1464 | 1462 | |
| 1465 | 1463 | const S = packed struct { |
| 1466 | 1464 | nested: packed union { |
| ... | ... | @@ -1479,7 +1477,6 @@ test "packed union with zero-bit field" { |
| 1479 | 1477 | test "reinterpreting enum value inside packed union" { |
| 1480 | 1478 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1481 | 1479 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1482 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1483 | 1480 | |
| 1484 | 1481 | const U = packed union { |
| 1485 | 1482 | tag: enum(u8) { a, b }, |
| ... | ... | @@ -1527,7 +1524,6 @@ test "defined-layout union field pointer has correct alignment" { |
| 1527 | 1524 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1528 | 1525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1529 | 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 | 1528 | const S = struct { |
| 1533 | 1529 | fn doTheTest(comptime U: type) !void { |
| ... | ... | @@ -1901,8 +1897,6 @@ test "inner struct initializer uses union layout" { |
| 1901 | 1897 | } |
| 1902 | 1898 | |
| 1903 | 1899 | test "inner struct initializer uses packed union layout" { |
| 1904 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1905 | ||
| 1906 | 1900 | const namespace = struct { |
| 1907 | 1901 | const U = packed union { |
| 1908 | 1902 | a: packed struct { |
| ... | ... | @@ -1946,8 +1940,6 @@ test "extern union initialized via reintepreted struct field initializer" { |
| 1946 | 1940 | } |
| 1947 | 1941 | |
| 1948 | 1942 | test "packed union initialized via reintepreted struct field initializer" { |
| 1949 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1950 | ||
| 1951 | 1943 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1952 | 1944 | |
| 1953 | 1945 | const U = packed union { |
| ... | ... | @@ -1988,8 +1980,6 @@ test "store of comptime reinterpreted memory to extern union" { |
| 1988 | 1980 | } |
| 1989 | 1981 | |
| 1990 | 1982 | test "store of comptime reinterpreted memory to packed union" { |
| 1991 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | |
| 1992 | ||
| 1993 | 1983 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1994 | 1984 | |
| 1995 | 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 | 143 | .{ |
| 144 | 144 | .target = std.Target.Query.parse(.{ |
| 145 | 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 | 147 | }) catch unreachable, |
| 148 | 148 | .use_llvm = false, |
| 149 | 149 | .use_lld = false, |