authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-02-05 09:24:49+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-05 09:24:49+01:00
log7634a115c50ef66edbdd5644c4ba310eb31e6343
treeb8be56f0db16691e2939e87bac1222ba2c9fd4a8
parentaebf20cc9a0469a778d6276d3797525660746e91
parent25111061504a652bfed45b26252349f363b109af
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18580 from Snektron/spirv-more-vectors

spirv: more vector operations

37 files changed, 956 insertions(+), 516 deletions(-)

lib/std/mem.zig+11-1
...@@ -632,10 +632,16 @@ test "lessThan" {...@@ -632,10 +632,16 @@ test "lessThan" {
632 try testing.expect(lessThan(u8, "", "a"));632 try testing.expect(lessThan(u8, "", "a"));
633}633}
634634
635const backend_can_use_eql_bytes = switch (builtin.zig_backend) {
636 // The SPIR-V backend does not support the optimized path yet.
637 .stage2_spirv64 => false,
638 else => true,
639};
640
635/// Compares two slices and returns whether they are equal.641/// Compares two slices and returns whether they are equal.
636pub fn eql(comptime T: type, a: []const T, b: []const T) bool {642pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
637 if (@sizeOf(T) == 0) return true;643 if (@sizeOf(T) == 0) return true;
638 if (!@inComptime() and std.meta.hasUniqueRepresentation(T)) return eqlBytes(sliceAsBytes(a), sliceAsBytes(b));644 if (!@inComptime() and std.meta.hasUniqueRepresentation(T) and backend_can_use_eql_bytes) return eqlBytes(sliceAsBytes(a), sliceAsBytes(b));
639645
640 if (a.len != b.len) return false;646 if (a.len != b.len) return false;
641 if (a.len == 0 or a.ptr == b.ptr) return true;647 if (a.len == 0 or a.ptr == b.ptr) return true;
...@@ -648,6 +654,10 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -648,6 +654,10 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
648654
649/// std.mem.eql heavily optimized for slices of bytes.655/// std.mem.eql heavily optimized for slices of bytes.
650fn eqlBytes(a: []const u8, b: []const u8) bool {656fn eqlBytes(a: []const u8, b: []const u8) bool {
657 if (!backend_can_use_eql_bytes) {
658 return eql(u8, a, b);
659 }
660
651 if (a.len != b.len) return false;661 if (a.len != b.len) return false;
652 if (a.len == 0 or a.ptr == b.ptr) return true;662 if (a.len == 0 or a.ptr == b.ptr) return true;
653663
src/codegen/spirv.zig+891-433
...@@ -373,8 +373,9 @@ const DeclGen = struct {...@@ -373,8 +373,9 @@ const DeclGen = struct {
373 /// For `composite_integer` this is 0 (TODO)373 /// For `composite_integer` this is 0 (TODO)
374 backing_bits: u16,374 backing_bits: u16,
375375
376 /// Whether the type is a vector.376 /// Null if this type is a scalar, or the length
377 is_vector: bool,377 /// of the vector otherwise.
378 vector_len: ?u32,
378379
379 /// Whether the inner type is signed. Only relevant for integers.380 /// Whether the inner type is signed. Only relevant for integers.
380 signedness: std.builtin.Signedness,381 signedness: std.builtin.Signedness,
...@@ -597,32 +598,37 @@ const DeclGen = struct {...@@ -597,32 +598,37 @@ const DeclGen = struct {
597 return self.backingIntBits(ty) == null;598 return self.backingIntBits(ty) == null;
598 }599 }
599600
600 fn arithmeticTypeInfo(self: *DeclGen, ty: Type) !ArithmeticTypeInfo {601 fn arithmeticTypeInfo(self: *DeclGen, ty: Type) ArithmeticTypeInfo {
601 const mod = self.module;602 const mod = self.module;
602 const target = self.getTarget();603 const target = self.getTarget();
603 return switch (ty.zigTypeTag(mod)) {604 var scalar_ty = ty.scalarType(mod);
605 if (scalar_ty.zigTypeTag(mod) == .Enum) {
606 scalar_ty = scalar_ty.intTagType(mod);
607 }
608 const vector_len = if (ty.isVector(mod)) ty.vectorLen(mod) else null;
609 return switch (scalar_ty.zigTypeTag(mod)) {
604 .Bool => ArithmeticTypeInfo{610 .Bool => ArithmeticTypeInfo{
605 .bits = 1, // Doesn't matter for this class.611 .bits = 1, // Doesn't matter for this class.
606 .backing_bits = self.backingIntBits(1).?,612 .backing_bits = self.backingIntBits(1).?,
607 .is_vector = false,613 .vector_len = vector_len,
608 .signedness = .unsigned, // Technically, but doesn't matter for this class.614 .signedness = .unsigned, // Technically, but doesn't matter for this class.
609 .class = .bool,615 .class = .bool,
610 },616 },
611 .Float => ArithmeticTypeInfo{617 .Float => ArithmeticTypeInfo{
612 .bits = ty.floatBits(target),618 .bits = scalar_ty.floatBits(target),
613 .backing_bits = ty.floatBits(target), // TODO: F80?619 .backing_bits = scalar_ty.floatBits(target), // TODO: F80?
614 .is_vector = false,620 .vector_len = vector_len,
615 .signedness = .signed, // Technically, but doesn't matter for this class.621 .signedness = .signed, // Technically, but doesn't matter for this class.
616 .class = .float,622 .class = .float,
617 },623 },
618 .Int => blk: {624 .Int => blk: {
619 const int_info = ty.intInfo(mod);625 const int_info = scalar_ty.intInfo(mod);
620 // TODO: Maybe it's useful to also return this value.626 // TODO: Maybe it's useful to also return this value.
621 const maybe_backing_bits = self.backingIntBits(int_info.bits);627 const maybe_backing_bits = self.backingIntBits(int_info.bits);
622 break :blk ArithmeticTypeInfo{628 break :blk ArithmeticTypeInfo{
623 .bits = int_info.bits,629 .bits = int_info.bits,
624 .backing_bits = maybe_backing_bits orelse 0,630 .backing_bits = maybe_backing_bits orelse 0,
625 .is_vector = false,631 .vector_len = vector_len,
626 .signedness = int_info.signedness,632 .signedness = int_info.signedness,
627 .class = if (maybe_backing_bits) |backing_bits|633 .class = if (maybe_backing_bits) |backing_bits|
628 if (backing_bits == int_info.bits)634 if (backing_bits == int_info.bits)
...@@ -633,22 +639,9 @@ const DeclGen = struct {...@@ -633,22 +639,9 @@ const DeclGen = struct {
633 .composite_integer,639 .composite_integer,
634 };640 };
635 },641 },
636 .Enum => return self.arithmeticTypeInfo(ty.intTagType(mod)),642 .Enum => unreachable,
637 // As of yet, there is no vector support in the self-hosted compiler.643 .Vector => unreachable,
638 .Vector => blk: {644 else => unreachable, // Unhandled arithmetic type
639 const child_type = ty.childType(mod);
640 const child_ty_info = try self.arithmeticTypeInfo(child_type);
641 break :blk ArithmeticTypeInfo{
642 .bits = child_ty_info.bits,
643 .backing_bits = child_ty_info.backing_bits,
644 .is_vector = true,
645 .signedness = child_ty_info.signedness,
646 .class = child_ty_info.class,
647 };
648 },
649 // TODO: For which types is this the case?
650 // else => self.todo("implement arithmeticTypeInfo for {}", .{ty.fmt(self.module)}),
651 else => unreachable,
652 };645 };
653 }646 }
654647
...@@ -685,6 +678,18 @@ const DeclGen = struct {...@@ -685,6 +678,18 @@ const DeclGen = struct {
685 }678 }
686 }679 }
687680
681 /// Emits a float constant
682 fn constFloat(self: *DeclGen, ty_ref: CacheRef, value: f128) !IdRef {
683 const ty = self.spv.cache.lookup(ty_ref).float_type;
684 return switch (ty.bits) {
685 16 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float16 = @floatCast(value) } } }),
686 32 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float32 = @floatCast(value) } } }),
687 64 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float64 = @floatCast(value) } } }),
688 80, 128 => unreachable, // TODO
689 else => unreachable,
690 };
691 }
692
688 /// Construct a struct at runtime.693 /// Construct a struct at runtime.
689 /// ty must be a struct type.694 /// ty must be a struct type.
690 /// Constituents should be in `indirect` representation (as the elements of a struct should be).695 /// Constituents should be in `indirect` representation (as the elements of a struct should be).
...@@ -1760,6 +1765,92 @@ const DeclGen = struct {...@@ -1760,6 +1765,92 @@ const DeclGen = struct {
1760 return union_layout;1765 return union_layout;
1761 }1766 }
17621767
1768 /// This structure is used as helper for element-wise operations. It is intended
1769 /// to be used with both vectors and single elements.
1770 const WipElementWise = struct {
1771 dg: *DeclGen,
1772 result_ty: Type,
1773 /// Always in direct representation.
1774 result_ty_ref: CacheRef,
1775 scalar_ty: Type,
1776 /// Always in direct representation.
1777 scalar_ty_ref: CacheRef,
1778 scalar_ty_id: IdRef,
1779 /// True if the input is actually a vector type.
1780 is_vector: bool,
1781 /// The element-wise operation should fill these results before calling finalize().
1782 /// These should all be in **direct** representation! `finalize()` will convert
1783 /// them to indirect if required.
1784 results: []IdRef,
1785
1786 fn deinit(wip: *WipElementWise) void {
1787 wip.dg.gpa.free(wip.results);
1788 }
1789
1790 /// Utility function to extract the element at a particular index in an
1791 /// input vector. This type is expected to be a vector if `wip.is_vector`, and
1792 /// a scalar otherwise.
1793 fn elementAt(wip: WipElementWise, ty: Type, value: IdRef, index: usize) !IdRef {
1794 const mod = wip.dg.module;
1795 if (wip.is_vector) {
1796 assert(ty.isVector(mod));
1797 return try wip.dg.extractField(ty.childType(mod), value, @intCast(index));
1798 } else {
1799 assert(!ty.isVector(mod));
1800 assert(index == 0);
1801 return value;
1802 }
1803 }
1804
1805 /// Turns the results of this WipElementWise into a result. This can either
1806 /// be a vector or single element, depending on `result_ty`.
1807 /// After calling this function, this WIP is no longer usable.
1808 /// Results is in `direct` representation.
1809 fn finalize(wip: *WipElementWise) !IdRef {
1810 if (wip.is_vector) {
1811 // Convert all the constituents to indirect, as required for the array.
1812 for (wip.results) |*result| {
1813 result.* = try wip.dg.convertToIndirect(wip.scalar_ty, result.*);
1814 }
1815 return try wip.dg.constructArray(wip.result_ty, wip.results);
1816 } else {
1817 return wip.results[0];
1818 }
1819 }
1820
1821 /// Allocate a result id at a particular index, and return it.
1822 fn allocId(wip: *WipElementWise, index: usize) IdRef {
1823 assert(wip.is_vector or index == 0);
1824 wip.results[index] = wip.dg.spv.allocId();
1825 return wip.results[index];
1826 }
1827 };
1828
1829 /// Create a new element-wise operation.
1830 fn elementWise(self: *DeclGen, result_ty: Type) !WipElementWise {
1831 const mod = self.module;
1832 // For now, this operation also reasons in terms of `.direct` representation.
1833 const result_ty_ref = try self.resolveType(result_ty, .direct);
1834 const is_vector = result_ty.isVector(mod);
1835 const num_results = if (is_vector) result_ty.vectorLen(mod) else 1;
1836 const results = try self.gpa.alloc(IdRef, num_results);
1837 for (results) |*result| result.* = undefined;
1838
1839 const scalar_ty = result_ty.scalarType(mod);
1840 const scalar_ty_ref = try self.resolveType(scalar_ty, .direct);
1841
1842 return .{
1843 .dg = self,
1844 .result_ty = result_ty,
1845 .result_ty_ref = result_ty_ref,
1846 .scalar_ty = scalar_ty,
1847 .scalar_ty_ref = scalar_ty_ref,
1848 .scalar_ty_id = self.typeId(scalar_ty_ref),
1849 .is_vector = is_vector,
1850 .results = results,
1851 };
1852 }
1853
1763 /// The SPIR-V backend is not yet advanced enough to support the std testing infrastructure.1854 /// The SPIR-V backend is not yet advanced enough to support the std testing infrastructure.
1764 /// In order to be able to run tests, we "temporarily" lower test kernels into separate entry-1855 /// In order to be able to run tests, we "temporarily" lower test kernels into separate entry-
1765 /// points. The test executor will then be able to invoke these to run the tests.1856 /// points. The test executor will then be able to invoke these to run the tests.
...@@ -2081,25 +2172,31 @@ const DeclGen = struct {...@@ -2081,25 +2172,31 @@ const DeclGen = struct {
2081 const air_tags = self.air.instructions.items(.tag);2172 const air_tags = self.air.instructions.items(.tag);
2082 const maybe_result_id: ?IdRef = switch (air_tags[@intFromEnum(inst)]) {2173 const maybe_result_id: ?IdRef = switch (air_tags[@intFromEnum(inst)]) {
2083 // zig fmt: off2174 // zig fmt: off
2084 .add, .add_wrap => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd, true),2175 .add, .add_wrap, .add_optimized => try self.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd),
2085 .sub, .sub_wrap => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub, true),2176 .sub, .sub_wrap, .sub_optimized => try self.airArithOp(inst, .OpFSub, .OpISub, .OpISub),
2086 .mul, .mul_wrap => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul, true),2177 .mul, .mul_wrap, .mul_optimized => try self.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul),
2178
2179 .abs => try self.airAbs(inst),
20872180
2088 .div_float,2181 .div_float,
2089 .div_float_optimized,2182 .div_float_optimized,
2090 // TODO: Check that this is the right operation.2183 // TODO: Check that this is the right operation.
2091 .div_trunc,2184 .div_trunc,
2092 .div_trunc_optimized,2185 .div_trunc_optimized,
2093 => try self.airArithOp(inst, .OpFDiv, .OpSDiv, .OpUDiv, false),2186 => try self.airArithOp(inst, .OpFDiv, .OpSDiv, .OpUDiv),
2094 // TODO: Check if this is the right operation2187 // TODO: Check if this is the right operation
2095 // TODO: Make airArithOp for rem not emit a mask for the LHS.
2096 .rem,2188 .rem,
2097 .rem_optimized,2189 .rem_optimized,
2098 => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem, false),2190 => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem),
20992191
2100 .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan),2192 .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan),
2101 .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan),2193 .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan),
2194 .shl_with_overflow => try self.airShlOverflow(inst),
21022195
2196 .mul_add => try self.airMulAdd(inst),
2197
2198 .splat => try self.airSplat(inst),
2199 .reduce, .reduce_optimized => try self.airReduce(inst),
2103 .shuffle => try self.airShuffle(inst),2200 .shuffle => try self.airShuffle(inst),
21042201
2105 .ptr_add => try self.airPtrAdd(inst),2202 .ptr_add => try self.airPtrAdd(inst),
...@@ -2111,7 +2208,8 @@ const DeclGen = struct {...@@ -2111,7 +2208,8 @@ const DeclGen = struct {
2111 .bool_and => try self.airBinOpSimple(inst, .OpLogicalAnd),2208 .bool_and => try self.airBinOpSimple(inst, .OpLogicalAnd),
2112 .bool_or => try self.airBinOpSimple(inst, .OpLogicalOr),2209 .bool_or => try self.airBinOpSimple(inst, .OpLogicalOr),
21132210
2114 .shl => try self.airShift(inst, .OpShiftLeftLogical),2211 .shl, .shl_exact => try self.airShift(inst, .OpShiftLeftLogical, .OpShiftLeftLogical),
2212 .shr, .shr_exact => try self.airShift(inst, .OpShiftRightLogical, .OpShiftRightArithmetic),
21152213
2116 .min => try self.airMinMax(inst, .lt),2214 .min => try self.airMinMax(inst, .lt),
2117 .max => try self.airMinMax(inst, .gt),2215 .max => try self.airMinMax(inst, .gt),
...@@ -2121,6 +2219,7 @@ const DeclGen = struct {...@@ -2121,6 +2219,7 @@ const DeclGen = struct {
2121 .int_from_ptr => try self.airIntFromPtr(inst),2219 .int_from_ptr => try self.airIntFromPtr(inst),
2122 .float_from_int => try self.airFloatFromInt(inst),2220 .float_from_int => try self.airFloatFromInt(inst),
2123 .int_from_float => try self.airIntFromFloat(inst),2221 .int_from_float => try self.airIntFromFloat(inst),
2222 .int_from_bool => try self.airIntFromBool(inst),
2124 .fpext, .fptrunc => try self.airFloatCast(inst),2223 .fpext, .fptrunc => try self.airFloatCast(inst),
2125 .not => try self.airNot(inst),2224 .not => try self.airNot(inst),
21262225
...@@ -2137,6 +2236,8 @@ const DeclGen = struct {...@@ -2137,6 +2236,8 @@ const DeclGen = struct {
2137 .ptr_elem_val => try self.airPtrElemVal(inst),2236 .ptr_elem_val => try self.airPtrElemVal(inst),
2138 .array_elem_val => try self.airArrayElemVal(inst),2237 .array_elem_val => try self.airArrayElemVal(inst),
21392238
2239 .vector_store_elem => return self.airVectorStoreElem(inst),
2240
2140 .set_union_tag => return self.airSetUnionTag(inst),2241 .set_union_tag => return self.airSetUnionTag(inst),
2141 .get_union_tag => try self.airGetUnionTag(inst),2242 .get_union_tag => try self.airGetUnionTag(inst),
2142 .union_init => try self.airUnionInit(inst),2243 .union_init => try self.airUnionInit(inst),
...@@ -2189,13 +2290,16 @@ const DeclGen = struct {...@@ -2189,13 +2290,16 @@ const DeclGen = struct {
2189 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),2290 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
2190 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),2291 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
21912292
2192 .is_null => try self.airIsNull(inst, .is_null),2293 .is_null => try self.airIsNull(inst, false, .is_null),
2193 .is_non_null => try self.airIsNull(inst, .is_non_null),2294 .is_non_null => try self.airIsNull(inst, false, .is_non_null),
2194 .is_err => try self.airIsErr(inst, .is_err),2295 .is_null_ptr => try self.airIsNull(inst, true, .is_null),
2195 .is_non_err => try self.airIsErr(inst, .is_non_err),2296 .is_non_null_ptr => try self.airIsNull(inst, true, .is_non_null),
2297 .is_err => try self.airIsErr(inst, .is_err),
2298 .is_non_err => try self.airIsErr(inst, .is_non_err),
21962299
2197 .optional_payload => try self.airUnwrapOptional(inst),2300 .optional_payload => try self.airUnwrapOptional(inst),
2198 .wrap_optional => try self.airWrapOptional(inst),2301 .optional_payload_ptr => try self.airUnwrapOptionalPtr(inst),
2302 .wrap_optional => try self.airWrapOptional(inst),
21992303
2200 .assembly => try self.airAssembly(inst),2304 .assembly => try self.airAssembly(inst),
22012305
...@@ -2213,34 +2317,17 @@ const DeclGen = struct {...@@ -2213,34 +2317,17 @@ const DeclGen = struct {
2213 }2317 }
22142318
2215 fn binOpSimple(self: *DeclGen, ty: Type, lhs_id: IdRef, rhs_id: IdRef, comptime opcode: Opcode) !IdRef {2319 fn binOpSimple(self: *DeclGen, ty: Type, lhs_id: IdRef, rhs_id: IdRef, comptime opcode: Opcode) !IdRef {
2216 const mod = self.module;2320 var wip = try self.elementWise(ty);
22172321 defer wip.deinit();
2218 if (ty.isVector(mod)) {2322 for (0..wip.results.len) |i| {
2219 const child_ty = ty.childType(mod);2323 try self.func.body.emit(self.spv.gpa, opcode, .{
2220 const vector_len = ty.vectorLen(mod);2324 .id_result_type = wip.scalar_ty_id,
22212325 .id_result = wip.allocId(i),
2222 const constituents = try self.gpa.alloc(IdRef, vector_len);2326 .operand_1 = try wip.elementAt(ty, lhs_id, i),
2223 defer self.gpa.free(constituents);2327 .operand_2 = try wip.elementAt(ty, rhs_id, i),
22242328 });
2225 for (constituents, 0..) |*constituent, i| {
2226 const lhs_index_id = try self.extractField(child_ty, lhs_id, @intCast(i));
2227 const rhs_index_id = try self.extractField(child_ty, rhs_id, @intCast(i));
2228 const result_id = try self.binOpSimple(child_ty, lhs_index_id, rhs_index_id, opcode);
2229 constituent.* = try self.convertToIndirect(child_ty, result_id);
2230 }
2231
2232 return try self.constructArray(ty, constituents);
2233 }2329 }
22342330 return try wip.finalize();
2235 const result_id = self.spv.allocId();
2236 const result_type_id = try self.resolveTypeId(ty);
2237 try self.func.body.emit(self.spv.gpa, opcode, .{
2238 .id_result_type = result_type_id,
2239 .id_result = result_id,
2240 .operand_1 = lhs_id,
2241 .operand_2 = rhs_id,
2242 });
2243 return result_id;
2244 }2331 }
22452332
2246 fn airBinOpSimple(self: *DeclGen, inst: Air.Inst.Index, comptime opcode: Opcode) !?IdRef {2333 fn airBinOpSimple(self: *DeclGen, inst: Air.Inst.Index, comptime opcode: Opcode) !?IdRef {
...@@ -2254,29 +2341,59 @@ const DeclGen = struct {...@@ -2254,29 +2341,59 @@ const DeclGen = struct {
2254 return try self.binOpSimple(ty, lhs_id, rhs_id, opcode);2341 return try self.binOpSimple(ty, lhs_id, rhs_id, opcode);
2255 }2342 }
22562343
2257 fn airShift(self: *DeclGen, inst: Air.Inst.Index, comptime opcode: Opcode) !?IdRef {2344 fn airShift(self: *DeclGen, inst: Air.Inst.Index, comptime unsigned: Opcode, comptime signed: Opcode) !?IdRef {
2258 if (self.liveness.isUnused(inst)) return null;2345 if (self.liveness.isUnused(inst)) return null;
2346 const mod = self.module;
2259 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2347 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2260 const lhs_id = try self.resolve(bin_op.lhs);2348 const lhs_id = try self.resolve(bin_op.lhs);
2261 const rhs_id = try self.resolve(bin_op.rhs);2349 const rhs_id = try self.resolve(bin_op.rhs);
2262 const result_type_id = try self.resolveTypeId(self.typeOfIndex(inst));
22632350
2264 // the shift and the base must be the same type in SPIR-V, but in Zig the shift is a smaller int.2351 const result_ty = self.typeOfIndex(inst);
2265 const shift_id = self.spv.allocId();2352 const shift_ty = self.typeOf(bin_op.rhs);
2266 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{2353 const scalar_shift_ty_ref = try self.resolveType(shift_ty.scalarType(mod), .direct);
2267 .id_result_type = result_type_id,
2268 .id_result = shift_id,
2269 .unsigned_value = rhs_id,
2270 });
22712354
2272 const result_id = self.spv.allocId();2355 const info = self.arithmeticTypeInfo(result_ty);
2273 try self.func.body.emit(self.spv.gpa, opcode, .{2356 switch (info.class) {
2274 .id_result_type = result_type_id,2357 .composite_integer => return self.todo("shift ops for composite integers", .{}),
2275 .id_result = result_id,2358 .integer, .strange_integer => {},
2276 .base = lhs_id,2359 .float, .bool => unreachable,
2277 .shift = shift_id,2360 }
2278 });2361
2279 return result_id;2362 var wip = try self.elementWise(result_ty);
2363 defer wip.deinit();
2364 for (wip.results, 0..) |*result_id, i| {
2365 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);
2366 const rhs_elem_id = try wip.elementAt(shift_ty, rhs_id, i);
2367
2368 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
2369 // so just manually upcast it if required.
2370 const shift_id = if (scalar_shift_ty_ref != wip.scalar_ty_ref) blk: {
2371 const shift_id = self.spv.allocId();
2372 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
2373 .id_result_type = wip.scalar_ty_id,
2374 .id_result = shift_id,
2375 .unsigned_value = rhs_elem_id,
2376 });
2377 break :blk shift_id;
2378 } else rhs_elem_id;
2379
2380 const value_id = self.spv.allocId();
2381 const args = .{
2382 .id_result_type = wip.scalar_ty_id,
2383 .id_result = value_id,
2384 .base = lhs_elem_id,
2385 .shift = shift_id,
2386 };
2387
2388 if (result_ty.isSignedInt(mod)) {
2389 try self.func.body.emit(self.spv.gpa, signed, args);
2390 } else {
2391 try self.func.body.emit(self.spv.gpa, unsigned, args);
2392 }
2393
2394 result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, info);
2395 }
2396 return try wip.finalize();
2280 }2397 }
22812398
2282 fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {2399 fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {
...@@ -2286,88 +2403,102 @@ const DeclGen = struct {...@@ -2286,88 +2403,102 @@ const DeclGen = struct {
2286 const lhs_id = try self.resolve(bin_op.lhs);2403 const lhs_id = try self.resolve(bin_op.lhs);
2287 const rhs_id = try self.resolve(bin_op.rhs);2404 const rhs_id = try self.resolve(bin_op.rhs);
2288 const result_ty = self.typeOfIndex(inst);2405 const result_ty = self.typeOfIndex(inst);
2289 const result_ty_ref = try self.resolveType(result_ty, .direct);
2290
2291 const info = try self.arithmeticTypeInfo(result_ty);
2292 // TODO: Use fmin for OpenCL
2293 const cmp_id = try self.cmp(op, Type.bool, result_ty, lhs_id, rhs_id);
2294 const selection_id = switch (info.class) {
2295 .float => blk: {
2296 // cmp uses OpFOrd. When we have 0 [<>] nan this returns false,
2297 // but we want it to pick lhs. Therefore we also have to check if
2298 // rhs is nan. We don't need to care about the result when both
2299 // are nan.
2300 const rhs_is_nan_id = self.spv.allocId();
2301 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
2302 try self.func.body.emit(self.spv.gpa, .OpIsNan, .{
2303 .id_result_type = self.typeId(bool_ty_ref),
2304 .id_result = rhs_is_nan_id,
2305 .x = rhs_id,
2306 });
2307 const float_cmp_id = self.spv.allocId();
2308 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{
2309 .id_result_type = self.typeId(bool_ty_ref),
2310 .id_result = float_cmp_id,
2311 .operand_1 = cmp_id,
2312 .operand_2 = rhs_is_nan_id,
2313 });
2314 break :blk float_cmp_id;
2315 },
2316 else => cmp_id,
2317 };
23182406
2319 const result_id = self.spv.allocId();2407 return try self.minMax(result_ty, op, lhs_id, rhs_id);
2320 try self.func.body.emit(self.spv.gpa, .OpSelect, .{2408 }
2321 .id_result_type = self.typeId(result_ty_ref),2409
2322 .id_result = result_id,2410 fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef {
2323 .condition = selection_id,2411 const info = self.arithmeticTypeInfo(result_ty);
2324 .object_1 = lhs_id,2412
2325 .object_2 = rhs_id,2413 var wip = try self.elementWise(result_ty);
2326 });2414 defer wip.deinit();
2327 return result_id;2415 for (wip.results, 0..) |*result_id, i| {
2328 }2416 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);
2417 const rhs_elem_id = try wip.elementAt(result_ty, rhs_id, i);
2418
2419 // TODO: Use fmin for OpenCL
2420 const cmp_id = try self.cmp(op, Type.bool, wip.scalar_ty, lhs_elem_id, rhs_elem_id);
2421 const selection_id = switch (info.class) {
2422 .float => blk: {
2423 // cmp uses OpFOrd. When we have 0 [<>] nan this returns false,
2424 // but we want it to pick lhs. Therefore we also have to check if
2425 // rhs is nan. We don't need to care about the result when both
2426 // are nan.
2427 const rhs_is_nan_id = self.spv.allocId();
2428 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
2429 try self.func.body.emit(self.spv.gpa, .OpIsNan, .{
2430 .id_result_type = self.typeId(bool_ty_ref),
2431 .id_result = rhs_is_nan_id,
2432 .x = rhs_elem_id,
2433 });
2434 const float_cmp_id = self.spv.allocId();
2435 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{
2436 .id_result_type = self.typeId(bool_ty_ref),
2437 .id_result = float_cmp_id,
2438 .operand_1 = cmp_id,
2439 .operand_2 = rhs_is_nan_id,
2440 });
2441 break :blk float_cmp_id;
2442 },
2443 else => cmp_id,
2444 };
23292445
2330 /// This function canonicalizes a "strange" integer value:2446 result_id.* = self.spv.allocId();
2331 /// For unsigned integers, the value is masked so that only the relevant bits can contain2447 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2332 /// non-zeros.2448 .id_result_type = wip.scalar_ty_id,
2333 /// For signed integers, the value is also sign extended.2449 .id_result = result_id.*,
2334 fn normalizeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef {2450 .condition = selection_id,
2335 assert(info.class != .composite_integer); // TODO2451 .object_1 = lhs_elem_id,
2336 if (info.bits == info.backing_bits) {2452 .object_2 = rhs_elem_id,
2337 return value_id;2453 });
2338 }2454 }
23392455 return wip.finalize();
2340 switch (info.signedness) {2456 }
2341 .unsigned => {2457
2342 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;2458 /// This function normalizes values to a canonical representation
2343 const result_id = self.spv.allocId();2459 /// after some arithmetic operation. This mostly consists of wrapping
2344 const mask_id = try self.constInt(ty_ref, mask_value);2460 /// behavior for strange integers:
2345 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{2461 /// - Unsigned integers are bitwise masked with a mask that only passes
2346 .id_result_type = self.typeId(ty_ref),2462 /// the valid bits through.
2347 .id_result = result_id,2463 /// - Signed integers are also sign extended if they are negative.
2348 .operand_1 = value_id,2464 /// All other values are returned unmodified (this makes strange integer
2349 .operand_2 = mask_id,2465 /// wrapping easier to use in generic operations).
2350 });2466 fn normalize(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, info: ArithmeticTypeInfo) !IdRef {
2351 return result_id;2467 switch (info.class) {
2352 },2468 .integer, .bool, .float => return value_id,
2353 .signed => {2469 .composite_integer => unreachable, // TODO
2354 // Shift left and right so that we can copy the sight bit that way.2470 .strange_integer => switch (info.signedness) {
2355 const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits);2471 .unsigned => {
2356 const left_id = self.spv.allocId();2472 const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1;
2357 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{2473 const result_id = self.spv.allocId();
2358 .id_result_type = self.typeId(ty_ref),2474 const mask_id = try self.constInt(ty_ref, mask_value);
2359 .id_result = left_id,2475 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{
2360 .base = value_id,2476 .id_result_type = self.typeId(ty_ref),
2361 .shift = shift_amt_id,2477 .id_result = result_id,
2362 });2478 .operand_1 = value_id,
2363 const right_id = self.spv.allocId();2479 .operand_2 = mask_id,
2364 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{2480 });
2365 .id_result_type = self.typeId(ty_ref),2481 return result_id;
2366 .id_result = right_id,2482 },
2367 .base = left_id,2483 .signed => {
2368 .shift = shift_amt_id,2484 // Shift left and right so that we can copy the sight bit that way.
2369 });2485 const shift_amt_id = try self.constInt(ty_ref, info.backing_bits - info.bits);
2370 return right_id;2486 const left_id = self.spv.allocId();
2487 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{
2488 .id_result_type = self.typeId(ty_ref),
2489 .id_result = left_id,
2490 .base = value_id,
2491 .shift = shift_amt_id,
2492 });
2493 const right_id = self.spv.allocId();
2494 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{
2495 .id_result_type = self.typeId(ty_ref),
2496 .id_result = right_id,
2497 .base = left_id,
2498 .shift = shift_amt_id,
2499 });
2500 return right_id;
2501 },
2371 },2502 },
2372 }2503 }
2373 }2504 }
...@@ -2378,8 +2509,6 @@ const DeclGen = struct {...@@ -2378,8 +2509,6 @@ const DeclGen = struct {
2378 comptime fop: Opcode,2509 comptime fop: Opcode,
2379 comptime sop: Opcode,2510 comptime sop: Opcode,
2380 comptime uop: Opcode,2511 comptime uop: Opcode,
2381 /// true if this operation holds under modular arithmetic.
2382 comptime modular: bool,
2383 ) !?IdRef {2512 ) !?IdRef {
2384 if (self.liveness.isUnused(inst)) return null;2513 if (self.liveness.isUnused(inst)) return null;
23852514
...@@ -2393,60 +2522,27 @@ const DeclGen = struct {...@@ -2393,60 +2522,27 @@ const DeclGen = struct {
2393 assert(self.typeOf(bin_op.lhs).eql(ty, self.module));2522 assert(self.typeOf(bin_op.lhs).eql(ty, self.module));
2394 assert(self.typeOf(bin_op.rhs).eql(ty, self.module));2523 assert(self.typeOf(bin_op.rhs).eql(ty, self.module));
23952524
2396 return try self.arithOp(ty, lhs_id, rhs_id, fop, sop, uop, modular);2525 return try self.arithOp(ty, lhs_id, rhs_id, fop, sop, uop);
2397 }2526 }
23982527
2399 fn arithOp(2528 fn arithOp(
2400 self: *DeclGen,2529 self: *DeclGen,
2401 ty: Type,2530 ty: Type,
2402 lhs_id_: IdRef,2531 lhs_id: IdRef,
2403 rhs_id_: IdRef,2532 rhs_id: IdRef,
2404 comptime fop: Opcode,2533 comptime fop: Opcode,
2405 comptime sop: Opcode,2534 comptime sop: Opcode,
2406 comptime uop: Opcode,2535 comptime uop: Opcode,
2407 /// true if this operation holds under modular arithmetic.
2408 comptime modular: bool,
2409 ) !IdRef {2536 ) !IdRef {
2410 var rhs_id = rhs_id_;
2411 var lhs_id = lhs_id_;
2412
2413 const mod = self.module;
2414 const result_ty_ref = try self.resolveType(ty, .direct);
2415
2416 if (ty.isVector(mod)) {
2417 const child_ty = ty.childType(mod);
2418 const vector_len = ty.vectorLen(mod);
2419 const constituents = try self.gpa.alloc(IdRef, vector_len);
2420 defer self.gpa.free(constituents);
2421
2422 for (constituents, 0..) |*constituent, i| {
2423 const lhs_index_id = try self.extractField(child_ty, lhs_id, @intCast(i));
2424 const rhs_index_id = try self.extractField(child_ty, rhs_id, @intCast(i));
2425 constituent.* = try self.arithOp(child_ty, lhs_index_id, rhs_index_id, fop, sop, uop, modular);
2426 }
2427
2428 return self.constructArray(ty, constituents);
2429 }
2430
2431 // Binary operations are generally applicable to both scalar and vector operations2537 // Binary operations are generally applicable to both scalar and vector operations
2432 // in SPIR-V, but int and float versions of operations require different opcodes.2538 // in SPIR-V, but int and float versions of operations require different opcodes.
2433 const info = try self.arithmeticTypeInfo(ty);2539 const info = self.arithmeticTypeInfo(ty);
24342540
2435 const opcode_index: usize = switch (info.class) {2541 const opcode_index: usize = switch (info.class) {
2436 .composite_integer => {2542 .composite_integer => {
2437 return self.todo("binary operations for composite integers", .{});2543 return self.todo("binary operations for composite integers", .{});
2438 },2544 },
2439 .strange_integer => blk: {2545 .integer, .strange_integer => switch (info.signedness) {
2440 if (!modular) {
2441 lhs_id = try self.normalizeInt(result_ty_ref, lhs_id, info);
2442 rhs_id = try self.normalizeInt(result_ty_ref, rhs_id, info);
2443 }
2444 break :blk switch (info.signedness) {
2445 .signed => @as(usize, 1),
2446 .unsigned => @as(usize, 2),
2447 };
2448 },
2449 .integer => switch (info.signedness) {
2450 .signed => @as(usize, 1),2546 .signed => @as(usize, 1),
2451 .unsigned => @as(usize, 2),2547 .unsigned => @as(usize, 2),
2452 },2548 },
...@@ -2454,24 +2550,91 @@ const DeclGen = struct {...@@ -2454,24 +2550,91 @@ const DeclGen = struct {
2454 .bool => unreachable,2550 .bool => unreachable,
2455 };2551 };
24562552
2457 const result_id = self.spv.allocId();2553 var wip = try self.elementWise(ty);
2458 const operands = .{2554 defer wip.deinit();
2459 .id_result_type = self.typeId(result_ty_ref),2555 for (wip.results, 0..) |*result_id, i| {
2460 .id_result = result_id,2556 const lhs_elem_id = try wip.elementAt(ty, lhs_id, i);
2461 .operand_1 = lhs_id,2557 const rhs_elem_id = try wip.elementAt(ty, rhs_id, i);
2462 .operand_2 = rhs_id,2558
2463 };2559 const value_id = self.spv.allocId();
2560 const operands = .{
2561 .id_result_type = wip.scalar_ty_id,
2562 .id_result = value_id,
2563 .operand_1 = lhs_elem_id,
2564 .operand_2 = rhs_elem_id,
2565 };
24642566
2465 switch (opcode_index) {2567 switch (opcode_index) {
2466 0 => try self.func.body.emit(self.spv.gpa, fop, operands),2568 0 => try self.func.body.emit(self.spv.gpa, fop, operands),
2467 1 => try self.func.body.emit(self.spv.gpa, sop, operands),2569 1 => try self.func.body.emit(self.spv.gpa, sop, operands),
2468 2 => try self.func.body.emit(self.spv.gpa, uop, operands),2570 2 => try self.func.body.emit(self.spv.gpa, uop, operands),
2469 else => unreachable,2571 else => unreachable,
2572 }
2573
2574 // TODO: Trap on overflow? Probably going to be annoying.
2575 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.
2576 result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, info);
2470 }2577 }
2471 // TODO: Trap on overflow? Probably going to be annoying.
2472 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.
24732578
2474 return result_id;2579 return try wip.finalize();
2580 }
2581
2582 fn airAbs(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2583 if (self.liveness.isUnused(inst)) return null;
2584
2585 const mod = self.module;
2586 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2587 const operand_id = try self.resolve(ty_op.operand);
2588 // Note: operand_ty may be signed, while ty is always unsigned!
2589 const operand_ty = self.typeOf(ty_op.operand);
2590 const ty = self.typeOfIndex(inst);
2591 const info = self.arithmeticTypeInfo(ty);
2592 const operand_scalar_ty = operand_ty.scalarType(mod);
2593 const operand_scalar_ty_ref = try self.resolveType(operand_scalar_ty, .direct);
2594
2595 var wip = try self.elementWise(ty);
2596 defer wip.deinit();
2597
2598 const zero_id = switch (info.class) {
2599 .float => try self.constFloat(operand_scalar_ty_ref, 0),
2600 .integer, .strange_integer => try self.constInt(operand_scalar_ty_ref, 0),
2601 .composite_integer => unreachable, // TODO
2602 .bool => unreachable,
2603 };
2604 for (wip.results, 0..) |*result_id, i| {
2605 const elem_id = try wip.elementAt(operand_ty, operand_id, i);
2606 // Idk why spir-v doesn't have a dedicated abs() instruction in the base
2607 // instruction set. For now we're just going to negate and check to avoid
2608 // importing the extinst.
2609 // TODO: Make this a call to compiler rt / ext inst
2610 const neg_id = self.spv.allocId();
2611 const args = .{
2612 .id_result_type = self.typeId(operand_scalar_ty_ref),
2613 .id_result = neg_id,
2614 .operand_1 = zero_id,
2615 .operand_2 = elem_id,
2616 };
2617 switch (info.class) {
2618 .float => try self.func.body.emit(self.spv.gpa, .OpFSub, args),
2619 .integer, .strange_integer => try self.func.body.emit(self.spv.gpa, .OpISub, args),
2620 .composite_integer => unreachable, // TODO
2621 .bool => unreachable,
2622 }
2623 const neg_norm_id = try self.normalize(wip.scalar_ty_ref, neg_id, info);
2624
2625 const gt_zero_id = try self.cmp(.gt, Type.bool, operand_scalar_ty, elem_id, zero_id);
2626 const abs_id = self.spv.allocId();
2627 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2628 .id_result_type = self.typeId(operand_scalar_ty_ref),
2629 .id_result = abs_id,
2630 .condition = gt_zero_id,
2631 .object_1 = elem_id,
2632 .object_2 = neg_norm_id,
2633 });
2634 // For Shader, we may need to cast from signed to unsigned here.
2635 result_id.* = try self.bitCast(wip.scalar_ty, operand_scalar_ty, abs_id);
2636 }
2637 return try wip.finalize();
2475 }2638 }
24762639
2477 fn airAddSubOverflow(2640 fn airAddSubOverflow(
...@@ -2488,140 +2651,344 @@ const DeclGen = struct {...@@ -2488,140 +2651,344 @@ const DeclGen = struct {
2488 const lhs = try self.resolve(extra.lhs);2651 const lhs = try self.resolve(extra.lhs);
2489 const rhs = try self.resolve(extra.rhs);2652 const rhs = try self.resolve(extra.rhs);
24902653
2491 const operand_ty = self.typeOf(extra.lhs);
2492 const result_ty = self.typeOfIndex(inst);2654 const result_ty = self.typeOfIndex(inst);
2655 const operand_ty = self.typeOf(extra.lhs);
2656 const ov_ty = result_ty.structFieldType(1, self.module);
2657
2658 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
24932659
2494 const info = try self.arithmeticTypeInfo(operand_ty);2660 const info = self.arithmeticTypeInfo(operand_ty);
2495 switch (info.class) {2661 switch (info.class) {
2496 .composite_integer => return self.todo("overflow ops for composite integers", .{}),2662 .composite_integer => return self.todo("overflow ops for composite integers", .{}),
2497 .strange_integer => return self.todo("overflow ops for strange integers", .{}),2663 .strange_integer, .integer => {},
2498 .integer => {},
2499 .float, .bool => unreachable,2664 .float, .bool => unreachable,
2500 }2665 }
25012666
2502 // The operand type must be the same as the result type in SPIR-V, which2667 var wip_result = try self.elementWise(operand_ty);
2503 // is the same as in Zig.2668 defer wip_result.deinit();
2504 const operand_ty_ref = try self.resolveType(operand_ty, .direct);2669 var wip_ov = try self.elementWise(ov_ty);
2505 const operand_ty_id = self.typeId(operand_ty_ref);2670 defer wip_ov.deinit();
2671 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {
2672 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);
2673 const rhs_elem_id = try wip_result.elementAt(operand_ty, rhs, i);
2674
2675 // Normalize both so that we can properly check for overflow
2676 const value_id = self.spv.allocId();
2677
2678 try self.func.body.emit(self.spv.gpa, add, .{
2679 .id_result_type = wip_result.scalar_ty_id,
2680 .id_result = value_id,
2681 .operand_1 = lhs_elem_id,
2682 .operand_2 = rhs_elem_id,
2683 });
25062684
2507 const bool_ty_ref = try self.resolveType(Type.bool, .direct);2685 // Normalize the result so that the comparisons go well
2686 result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info);
2687
2688 const overflowed_id = switch (info.signedness) {
2689 .unsigned => blk: {
2690 // Overflow happened if the result is smaller than either of the operands. It doesn't matter which.
2691 // For subtraction the conditions need to be swapped.
2692 const overflowed_id = self.spv.allocId();
2693 try self.func.body.emit(self.spv.gpa, ucmp, .{
2694 .id_result_type = self.typeId(bool_ty_ref),
2695 .id_result = overflowed_id,
2696 .operand_1 = result_id.*,
2697 .operand_2 = lhs_elem_id,
2698 });
2699 break :blk overflowed_id;
2700 },
2701 .signed => blk: {
2702 // lhs - rhs
2703 // For addition, overflow happened if:
2704 // - rhs is negative and value > lhs
2705 // - rhs is positive and value < lhs
2706 // This can be shortened to:
2707 // (rhs < 0 and value > lhs) or (rhs >= 0 and value <= lhs)
2708 // = (rhs < 0) == (value > lhs)
2709 // = (rhs < 0) == (lhs < value)
2710 // Note that signed overflow is also wrapping in spir-v.
2711 // For subtraction, overflow happened if:
2712 // - rhs is negative and value < lhs
2713 // - rhs is positive and value > lhs
2714 // This can be shortened to:
2715 // (rhs < 0 and value < lhs) or (rhs >= 0 and value >= lhs)
2716 // = (rhs < 0) == (value < lhs)
2717 // = (rhs < 0) == (lhs > value)
2718
2719 const rhs_lt_zero_id = self.spv.allocId();
2720 const zero_id = try self.constInt(wip_result.scalar_ty_ref, 0);
2721 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
2722 .id_result_type = self.typeId(bool_ty_ref),
2723 .id_result = rhs_lt_zero_id,
2724 .operand_1 = rhs_elem_id,
2725 .operand_2 = zero_id,
2726 });
2727
2728 const value_gt_lhs_id = self.spv.allocId();
2729 try self.func.body.emit(self.spv.gpa, scmp, .{
2730 .id_result_type = self.typeId(bool_ty_ref),
2731 .id_result = value_gt_lhs_id,
2732 .operand_1 = lhs_elem_id,
2733 .operand_2 = result_id.*,
2734 });
2735
2736 const overflowed_id = self.spv.allocId();
2737 try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{
2738 .id_result_type = self.typeId(bool_ty_ref),
2739 .id_result = overflowed_id,
2740 .operand_1 = rhs_lt_zero_id,
2741 .operand_2 = value_gt_lhs_id,
2742 });
2743 break :blk overflowed_id;
2744 },
2745 };
2746
2747 ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id);
2748 }
2749
2750 return try self.constructStruct(
2751 result_ty,
2752 &.{ operand_ty, ov_ty },
2753 &.{ try wip_result.finalize(), try wip_ov.finalize() },
2754 );
2755 }
2756
2757 fn airShlOverflow(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2758 if (self.liveness.isUnused(inst)) return null;
2759 const mod = self.module;
2760 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2761 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2762 const lhs = try self.resolve(extra.lhs);
2763 const rhs = try self.resolve(extra.rhs);
2764
2765 const result_ty = self.typeOfIndex(inst);
2766 const operand_ty = self.typeOf(extra.lhs);
2767 const shift_ty = self.typeOf(extra.rhs);
2768 const scalar_shift_ty_ref = try self.resolveType(shift_ty.scalarType(mod), .direct);
25082769
2509 const ov_ty = result_ty.structFieldType(1, self.module);2770 const ov_ty = result_ty.structFieldType(1, self.module);
2510 // Note: result is stored in a struct, so indirect representation.
2511 const ov_ty_ref = try self.resolveType(ov_ty, .indirect);
2512
2513 // TODO: Operations other than addition.
2514 const value_id = self.spv.allocId();
2515 try self.func.body.emit(self.spv.gpa, add, .{
2516 .id_result_type = operand_ty_id,
2517 .id_result = value_id,
2518 .operand_1 = lhs,
2519 .operand_2 = rhs,
2520 });
25212771
2522 const overflowed_id = switch (info.signedness) {2772 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
2523 .unsigned => blk: {
2524 // Overflow happened if the result is smaller than either of the operands. It doesn't matter which.
2525 // For subtraction the conditions need to be swapped.
2526 const overflowed_id = self.spv.allocId();
2527 try self.func.body.emit(self.spv.gpa, ucmp, .{
2528 .id_result_type = self.typeId(bool_ty_ref),
2529 .id_result = overflowed_id,
2530 .operand_1 = value_id,
2531 .operand_2 = lhs,
2532 });
2533 break :blk overflowed_id;
2534 },
2535 .signed => blk: {
2536 // lhs - rhs
2537 // For addition, overflow happened if:
2538 // - rhs is negative and value > lhs
2539 // - rhs is positive and value < lhs
2540 // This can be shortened to:
2541 // (rhs < 0 and value > lhs) or (rhs >= 0 and value <= lhs)
2542 // = (rhs < 0) == (value > lhs)
2543 // = (rhs < 0) == (lhs < value)
2544 // Note that signed overflow is also wrapping in spir-v.
2545 // For subtraction, overflow happened if:
2546 // - rhs is negative and value < lhs
2547 // - rhs is positive and value > lhs
2548 // This can be shortened to:
2549 // (rhs < 0 and value < lhs) or (rhs >= 0 and value >= lhs)
2550 // = (rhs < 0) == (value < lhs)
2551 // = (rhs < 0) == (lhs > value)
2552
2553 const rhs_lt_zero_id = self.spv.allocId();
2554 const zero_id = try self.constInt(operand_ty_ref, 0);
2555 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
2556 .id_result_type = self.typeId(bool_ty_ref),
2557 .id_result = rhs_lt_zero_id,
2558 .operand_1 = rhs,
2559 .operand_2 = zero_id,
2560 });
25612773
2562 const value_gt_lhs_id = self.spv.allocId();2774 const info = self.arithmeticTypeInfo(operand_ty);
2563 try self.func.body.emit(self.spv.gpa, scmp, .{2775 switch (info.class) {
2564 .id_result_type = self.typeId(bool_ty_ref),2776 .composite_integer => return self.todo("overflow shift for composite integers", .{}),
2565 .id_result = value_gt_lhs_id,2777 .integer, .strange_integer => {},
2566 .operand_1 = lhs,2778 .float, .bool => unreachable,
2567 .operand_2 = value_id,2779 }
2568 });
25692780
2570 const overflowed_id = self.spv.allocId();2781 var wip_result = try self.elementWise(operand_ty);
2571 try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{2782 defer wip_result.deinit();
2572 .id_result_type = self.typeId(bool_ty_ref),2783 var wip_ov = try self.elementWise(ov_ty);
2573 .id_result = overflowed_id,2784 defer wip_ov.deinit();
2574 .operand_1 = rhs_lt_zero_id,2785 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {
2575 .operand_2 = value_gt_lhs_id,2786 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);
2787 const rhs_elem_id = try wip_result.elementAt(shift_ty, rhs, i);
2788
2789 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
2790 // so just manually upcast it if required.
2791 const shift_id = if (scalar_shift_ty_ref != wip_result.scalar_ty_ref) blk: {
2792 const shift_id = self.spv.allocId();
2793 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
2794 .id_result_type = wip_result.scalar_ty_id,
2795 .id_result = shift_id,
2796 .unsigned_value = rhs_elem_id,
2576 });2797 });
2577 break :blk overflowed_id;2798 break :blk shift_id;
2578 },2799 } else rhs_elem_id;
2579 };2800
2801 const value_id = self.spv.allocId();
2802 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{
2803 .id_result_type = wip_result.scalar_ty_id,
2804 .id_result = value_id,
2805 .base = lhs_elem_id,
2806 .shift = shift_id,
2807 });
2808 result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info);
2809
2810 const right_shift_id = self.spv.allocId();
2811 switch (info.signedness) {
2812 .signed => {
2813 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{
2814 .id_result_type = wip_result.scalar_ty_id,
2815 .id_result = right_shift_id,
2816 .base = result_id.*,
2817 .shift = shift_id,
2818 });
2819 },
2820 .unsigned => {
2821 try self.func.body.emit(self.spv.gpa, .OpShiftRightLogical, .{
2822 .id_result_type = wip_result.scalar_ty_id,
2823 .id_result = right_shift_id,
2824 .base = result_id.*,
2825 .shift = shift_id,
2826 });
2827 },
2828 }
2829
2830 const overflowed_id = self.spv.allocId();
2831 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
2832 .id_result_type = self.typeId(bool_ty_ref),
2833 .id_result = overflowed_id,
2834 .operand_1 = lhs_elem_id,
2835 .operand_2 = right_shift_id,
2836 });
2837
2838 ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id);
2839 }
25802840
2581 // Construct the struct that Zig wants as result.
2582 // The value should already be the correct type.
2583 const ov_id = try self.intFromBool(ov_ty_ref, overflowed_id);
2584 return try self.constructStruct(2841 return try self.constructStruct(
2585 result_ty,2842 result_ty,
2586 &.{ operand_ty, ov_ty },2843 &.{ operand_ty, ov_ty },
2587 &.{ value_id, ov_id },2844 &.{ try wip_result.finalize(), try wip_ov.finalize() },
2588 );2845 );
2589 }2846 }
25902847
2848 fn airMulAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2849 if (self.liveness.isUnused(inst)) return null;
2850
2851 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
2852 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
2853
2854 const mulend1 = try self.resolve(extra.lhs);
2855 const mulend2 = try self.resolve(extra.rhs);
2856 const addend = try self.resolve(pl_op.operand);
2857
2858 const ty = self.typeOfIndex(inst);
2859
2860 const info = self.arithmeticTypeInfo(ty);
2861 assert(info.class == .float); // .mul_add is only emitted for floats
2862
2863 var wip = try self.elementWise(ty);
2864 defer wip.deinit();
2865 for (0..wip.results.len) |i| {
2866 const mul_result = self.spv.allocId();
2867 try self.func.body.emit(self.spv.gpa, .OpFMul, .{
2868 .id_result_type = wip.scalar_ty_id,
2869 .id_result = mul_result,
2870 .operand_1 = try wip.elementAt(ty, mulend1, i),
2871 .operand_2 = try wip.elementAt(ty, mulend2, i),
2872 });
2873
2874 try self.func.body.emit(self.spv.gpa, .OpFAdd, .{
2875 .id_result_type = wip.scalar_ty_id,
2876 .id_result = wip.allocId(i),
2877 .operand_1 = mul_result,
2878 .operand_2 = try wip.elementAt(ty, addend, i),
2879 });
2880 }
2881 return try wip.finalize();
2882 }
2883
2884 fn airSplat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2885 if (self.liveness.isUnused(inst)) return null;
2886 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2887 const operand_id = try self.resolve(ty_op.operand);
2888 const result_ty = self.typeOfIndex(inst);
2889 var wip = try self.elementWise(result_ty);
2890 defer wip.deinit();
2891 for (wip.results) |*result_id| {
2892 result_id.* = operand_id;
2893 }
2894 return try wip.finalize();
2895 }
2896
2897 fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2898 if (self.liveness.isUnused(inst)) return null;
2899 const mod = self.module;
2900 const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
2901 const operand = try self.resolve(reduce.operand);
2902 const operand_ty = self.typeOf(reduce.operand);
2903 const scalar_ty = operand_ty.scalarType(mod);
2904 const scalar_ty_ref = try self.resolveType(scalar_ty, .direct);
2905 const scalar_ty_id = self.typeId(scalar_ty_ref);
2906
2907 const info = self.arithmeticTypeInfo(operand_ty);
2908
2909 var result_id = try self.extractField(scalar_ty, operand, 0);
2910 const len = operand_ty.vectorLen(mod);
2911
2912 switch (reduce.operation) {
2913 .Min, .Max => |op| {
2914 const cmp_op: std.math.CompareOperator = if (op == .Max) .gt else .lt;
2915 for (1..len) |i| {
2916 const lhs = result_id;
2917 const rhs = try self.extractField(scalar_ty, operand, @intCast(i));
2918 result_id = try self.minMax(scalar_ty, cmp_op, lhs, rhs);
2919 }
2920
2921 return result_id;
2922 },
2923 else => {},
2924 }
2925
2926 const opcode: Opcode = switch (info.class) {
2927 .bool => switch (reduce.operation) {
2928 .And => .OpLogicalAnd,
2929 .Or => .OpLogicalOr,
2930 .Xor => .OpLogicalNotEqual,
2931 else => unreachable,
2932 },
2933 .strange_integer, .integer => switch (reduce.operation) {
2934 .And => .OpBitwiseAnd,
2935 .Or => .OpBitwiseOr,
2936 .Xor => .OpBitwiseXor,
2937 .Add => .OpIAdd,
2938 .Mul => .OpIMul,
2939 else => unreachable,
2940 },
2941 .float => switch (reduce.operation) {
2942 .Add => .OpFAdd,
2943 .Mul => .OpFMul,
2944 else => unreachable,
2945 },
2946 .composite_integer => unreachable, // TODO
2947 };
2948
2949 for (1..len) |i| {
2950 const lhs = result_id;
2951 const rhs = try self.extractField(scalar_ty, operand, @intCast(i));
2952 result_id = self.spv.allocId();
2953
2954 try self.func.body.emitRaw(self.spv.gpa, opcode, 4);
2955 self.func.body.writeOperand(spec.IdResultType, scalar_ty_id);
2956 self.func.body.writeOperand(spec.IdResult, result_id);
2957 self.func.body.writeOperand(spec.IdResultType, lhs);
2958 self.func.body.writeOperand(spec.IdResultType, rhs);
2959 }
2960
2961 return result_id;
2962 }
2963
2591 fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2964 fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2592 const mod = self.module;2965 const mod = self.module;
2593 if (self.liveness.isUnused(inst)) return null;2966 if (self.liveness.isUnused(inst)) return null;
2594 const ty = self.typeOfIndex(inst);
2595 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;2967 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2596 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;2968 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
2597 const a = try self.resolve(extra.a);2969 const a = try self.resolve(extra.a);
2598 const b = try self.resolve(extra.b);2970 const b = try self.resolve(extra.b);
2599 const mask = Value.fromInterned(extra.mask);2971 const mask = Value.fromInterned(extra.mask);
2600 const mask_len = extra.mask_len;
2601 const a_len = self.typeOf(extra.a).vectorLen(mod);
26022972
2603 const result_id = self.spv.allocId();2973 const ty = self.typeOfIndex(inst);
2604 const result_type_id = try self.resolveTypeId(ty);
2605 // Similar to LLVM, SPIR-V uses indices larger than the length of the first vector
2606 // to index into the second vector.
2607 try self.func.body.emitRaw(self.spv.gpa, .OpVectorShuffle, 4 + mask_len);
2608 self.func.body.writeOperand(spec.IdResultType, result_type_id);
2609 self.func.body.writeOperand(spec.IdResult, result_id);
2610 self.func.body.writeOperand(spec.IdRef, a);
2611 self.func.body.writeOperand(spec.IdRef, b);
26122974
2613 var i: usize = 0;2975 var wip = try self.elementWise(ty);
2614 while (i < mask_len) : (i += 1) {2976 defer wip.deinit();
2977 for (wip.results, 0..) |*result_id, i| {
2615 const elem = try mask.elemValue(mod, i);2978 const elem = try mask.elemValue(mod, i);
2616 if (elem.isUndef(mod)) {2979 if (elem.isUndef(mod)) {
2617 self.func.body.writeOperand(spec.LiteralInteger, 0xFFFF_FFFF);2980 result_id.* = try self.spv.constUndef(wip.scalar_ty_ref);
2981 continue;
2982 }
2983
2984 const index = elem.toSignedInt(mod);
2985 if (index >= 0) {
2986 result_id.* = try self.extractField(wip.scalar_ty, a, @intCast(index));
2618 } else {2987 } else {
2619 const int = elem.toSignedInt(mod);2988 result_id.* = try self.extractField(wip.scalar_ty, b, @intCast(~index));
2620 const unsigned = if (int >= 0) @as(u32, @intCast(int)) else @as(u32, @intCast(~int + a_len));
2621 self.func.body.writeOperand(spec.LiteralInteger, unsigned);
2622 }2989 }
2623 }2990 }
2624 return result_id;2991 return try wip.finalize();
2625 }2992 }
26262993
2627 fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef {2994 fn indicesToIds(self: *DeclGen, indices: []const u32) ![]IdRef {
...@@ -2828,26 +3195,21 @@ const DeclGen = struct {...@@ -2828,26 +3195,21 @@ const DeclGen = struct {
2828 return result_id;3195 return result_id;
2829 },3196 },
2830 .Vector => {3197 .Vector => {
2831 const child_ty = ty.childType(mod);3198 var wip = try self.elementWise(result_ty);
2832 const vector_len = ty.vectorLen(mod);3199 defer wip.deinit();
28333200 const scalar_ty = ty.scalarType(mod);
2834 const constituents = try self.gpa.alloc(IdRef, vector_len);3201 for (wip.results, 0..) |*result_id, i| {
2835 defer self.gpa.free(constituents);3202 const lhs_elem_id = try wip.elementAt(ty, lhs_id, i);
28363203 const rhs_elem_id = try wip.elementAt(ty, rhs_id, i);
2837 for (constituents, 0..) |*constituent, i| {3204 result_id.* = try self.cmp(op, Type.bool, scalar_ty, lhs_elem_id, rhs_elem_id);
2838 const lhs_index_id = try self.extractField(child_ty, cmp_lhs_id, @intCast(i));
2839 const rhs_index_id = try self.extractField(child_ty, cmp_rhs_id, @intCast(i));
2840 const result_id = try self.cmp(op, Type.bool, child_ty, lhs_index_id, rhs_index_id);
2841 constituent.* = try self.convertToIndirect(Type.bool, result_id);
2842 }3205 }
28433206 return wip.finalize();
2844 return try self.constructArray(result_ty, constituents);
2845 },3207 },
2846 else => unreachable,3208 else => unreachable,
2847 };3209 };
28483210
2849 const opcode: Opcode = opcode: {3211 const opcode: Opcode = opcode: {
2850 const info = try self.arithmeticTypeInfo(op_ty);3212 const info = self.arithmeticTypeInfo(op_ty);
2851 const signedness = switch (info.class) {3213 const signedness = switch (info.class) {
2852 .composite_integer => {3214 .composite_integer => {
2853 return self.todo("binary operations for composite integers", .{});3215 return self.todo("binary operations for composite integers", .{});
...@@ -2865,14 +3227,7 @@ const DeclGen = struct {...@@ -2865,14 +3227,7 @@ const DeclGen = struct {
2865 .neq => .OpLogicalNotEqual,3227 .neq => .OpLogicalNotEqual,
2866 else => unreachable,3228 else => unreachable,
2867 },3229 },
2868 .strange_integer => sign: {3230 .integer, .strange_integer => info.signedness,
2869 const op_ty_ref = try self.resolveType(op_ty, .direct);
2870 // Mask operands before performing comparison.
2871 cmp_lhs_id = try self.normalizeInt(op_ty_ref, cmp_lhs_id, info);
2872 cmp_rhs_id = try self.normalizeInt(op_ty_ref, cmp_rhs_id, info);
2873 break :sign info.signedness;
2874 },
2875 .integer => info.signedness,
2876 };3231 };
28773232
2878 break :opcode switch (signedness) {3233 break :opcode switch (signedness) {
...@@ -2942,50 +3297,64 @@ const DeclGen = struct {...@@ -2942,50 +3297,64 @@ const DeclGen = struct {
2942 const mod = self.module;3297 const mod = self.module;
2943 const src_ty_ref = try self.resolveType(src_ty, .direct);3298 const src_ty_ref = try self.resolveType(src_ty, .direct);
2944 const dst_ty_ref = try self.resolveType(dst_ty, .direct);3299 const dst_ty_ref = try self.resolveType(dst_ty, .direct);
2945 if (src_ty_ref == dst_ty_ref) {3300 const src_key = self.spv.cache.lookup(src_ty_ref);
2946 return src_id;3301 const dst_key = self.spv.cache.lookup(dst_ty_ref);
2947 }
29483302
2949 // TODO: Some more cases are missing here3303 const result_id = blk: {
2950 // See fn bitCast in llvm.zig3304 if (src_ty_ref == dst_ty_ref) {
3305 break :blk src_id;
3306 }
29513307
2952 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {3308 // TODO: Some more cases are missing here
2953 const result_id = self.spv.allocId();3309 // See fn bitCast in llvm.zig
2954 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
2955 .id_result_type = self.typeId(dst_ty_ref),
2956 .id_result = result_id,
2957 .integer_value = src_id,
2958 });
2959 return result_id;
2960 }
29613310
2962 // We can only use OpBitcast for specific conversions: between numerical types, and3311 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {
2963 // between pointers. If the resolved spir-v types fall into this category then emit OpBitcast,3312 const result_id = self.spv.allocId();
2964 // otherwise use a temporary and perform a pointer cast.3313 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
2965 const src_key = self.spv.cache.lookup(src_ty_ref);3314 .id_result_type = self.typeId(dst_ty_ref),
2966 const dst_key = self.spv.cache.lookup(dst_ty_ref);3315 .id_result = result_id,
3316 .integer_value = src_id,
3317 });
3318 break :blk result_id;
3319 }
29673320
2968 if ((src_key.isNumericalType() and dst_key.isNumericalType()) or (src_key == .ptr_type and dst_key == .ptr_type)) {3321 // We can only use OpBitcast for specific conversions: between numerical types, and
2969 const result_id = self.spv.allocId();3322 // between pointers. If the resolved spir-v types fall into this category then emit OpBitcast,
3323 // otherwise use a temporary and perform a pointer cast.
3324 if ((src_key.isNumericalType() and dst_key.isNumericalType()) or (src_key == .ptr_type and dst_key == .ptr_type)) {
3325 const result_id = self.spv.allocId();
3326 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
3327 .id_result_type = self.typeId(dst_ty_ref),
3328 .id_result = result_id,
3329 .operand = src_id,
3330 });
3331
3332 break :blk result_id;
3333 }
3334
3335 const dst_ptr_ty_ref = try self.ptrType(dst_ty, .Function);
3336
3337 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });
3338 try self.store(src_ty, tmp_id, src_id, .{});
3339 const casted_ptr_id = self.spv.allocId();
2970 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{3340 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
2971 .id_result_type = self.typeId(dst_ty_ref),3341 .id_result_type = self.typeId(dst_ptr_ty_ref),
2972 .id_result = result_id,3342 .id_result = casted_ptr_id,
2973 .operand = src_id,3343 .operand = tmp_id,
2974 });3344 });
2975 return result_id;3345 break :blk try self.load(dst_ty, casted_ptr_id, .{});
2976 }3346 };
29773347
2978 const dst_ptr_ty_ref = try self.ptrType(dst_ty, .Function);3348 // Because strange integers use sign-extended representation, we may need to normalize
3349 // the result here.
3350 // TODO: This detail could cause stuff like @as(*const i1, @ptrCast(&@as(u1, 1))) to break
3351 // should we change the representation of strange integers?
3352 if (dst_ty.zigTypeTag(mod) == .Int) {
3353 const info = self.arithmeticTypeInfo(dst_ty);
3354 return try self.normalize(dst_ty_ref, result_id, info);
3355 }
29793356
2980 const tmp_id = try self.alloc(src_ty, .{ .storage_class = .Function });3357 return result_id;
2981 try self.store(src_ty, tmp_id, src_id, .{});
2982 const casted_ptr_id = self.spv.allocId();
2983 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
2984 .id_result_type = self.typeId(dst_ptr_ty_ref),
2985 .id_result = casted_ptr_id,
2986 .operand = tmp_id,
2987 });
2988 return try self.load(dst_ty, casted_ptr_id, .{});
2989 }3358 }
29903359
2991 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3360 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
...@@ -3004,34 +3373,43 @@ const DeclGen = struct {...@@ -3004,34 +3373,43 @@ const DeclGen = struct {
3004 const operand_id = try self.resolve(ty_op.operand);3373 const operand_id = try self.resolve(ty_op.operand);
3005 const src_ty = self.typeOf(ty_op.operand);3374 const src_ty = self.typeOf(ty_op.operand);
3006 const dst_ty = self.typeOfIndex(inst);3375 const dst_ty = self.typeOfIndex(inst);
3007 const src_ty_ref = try self.resolveType(src_ty, .direct);
3008 const dst_ty_ref = try self.resolveType(dst_ty, .direct);
3009
3010 const src_info = try self.arithmeticTypeInfo(src_ty);
3011 const dst_info = try self.arithmeticTypeInfo(dst_ty);
30123376
3013 // While intcast promises that the value already fits, the upper bits of a3377 const src_info = self.arithmeticTypeInfo(src_ty);
3014 // strange integer may contain garbage. Therefore, mask/sign extend it before.3378 const dst_info = self.arithmeticTypeInfo(dst_ty);
3015 const src_id = try self.normalizeInt(src_ty_ref, operand_id, src_info);
30163379
3017 if (src_info.backing_bits == dst_info.backing_bits) {3380 if (src_info.backing_bits == dst_info.backing_bits) {
3018 return src_id;3381 return operand_id;
3019 }3382 }
30203383
3021 const result_id = self.spv.allocId();3384 var wip = try self.elementWise(dst_ty);
3022 switch (dst_info.signedness) {3385 defer wip.deinit();
3023 .signed => try self.func.body.emit(self.spv.gpa, .OpSConvert, .{3386 for (wip.results, 0..) |*result_id, i| {
3024 .id_result_type = self.typeId(dst_ty_ref),3387 const elem_id = try wip.elementAt(src_ty, operand_id, i);
3025 .id_result = result_id,3388 const value_id = self.spv.allocId();
3026 .signed_value = src_id,3389 switch (dst_info.signedness) {
3027 }),3390 .signed => try self.func.body.emit(self.spv.gpa, .OpSConvert, .{
3028 .unsigned => try self.func.body.emit(self.spv.gpa, .OpUConvert, .{3391 .id_result_type = wip.scalar_ty_id,
3029 .id_result_type = self.typeId(dst_ty_ref),3392 .id_result = value_id,
3030 .id_result = result_id,3393 .signed_value = elem_id,
3031 .unsigned_value = src_id,3394 }),
3032 }),3395 .unsigned => try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
3396 .id_result_type = wip.scalar_ty_id,
3397 .id_result = value_id,
3398 .unsigned_value = elem_id,
3399 }),
3400 }
3401
3402 // Make sure to normalize the result if shrinking.
3403 // Because strange ints are sign extended in their backing
3404 // type, we don't need to normalize when growing the type. The
3405 // representation is already the same.
3406 if (dst_info.bits < src_info.bits) {
3407 result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, dst_info);
3408 } else {
3409 result_id.* = value_id;
3410 }
3033 }3411 }
3034 return result_id;3412 return try wip.finalize();
3035 }3413 }
30363414
3037 fn intFromPtr(self: *DeclGen, operand_id: IdRef) !IdRef {3415 fn intFromPtr(self: *DeclGen, operand_id: IdRef) !IdRef {
...@@ -3059,7 +3437,7 @@ const DeclGen = struct {...@@ -3059,7 +3437,7 @@ const DeclGen = struct {
3059 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3437 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3060 const operand_ty = self.typeOf(ty_op.operand);3438 const operand_ty = self.typeOf(ty_op.operand);
3061 const operand_id = try self.resolve(ty_op.operand);3439 const operand_id = try self.resolve(ty_op.operand);
3062 const operand_info = try self.arithmeticTypeInfo(operand_ty);3440 const operand_info = self.arithmeticTypeInfo(operand_ty);
3063 const dest_ty = self.typeOfIndex(inst);3441 const dest_ty = self.typeOfIndex(inst);
3064 const dest_ty_id = try self.resolveTypeId(dest_ty);3442 const dest_ty_id = try self.resolveTypeId(dest_ty);
30653443
...@@ -3085,7 +3463,7 @@ const DeclGen = struct {...@@ -3085,7 +3463,7 @@ const DeclGen = struct {
3085 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3463 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3086 const operand_id = try self.resolve(ty_op.operand);3464 const operand_id = try self.resolve(ty_op.operand);
3087 const dest_ty = self.typeOfIndex(inst);3465 const dest_ty = self.typeOfIndex(inst);
3088 const dest_info = try self.arithmeticTypeInfo(dest_ty);3466 const dest_info = self.arithmeticTypeInfo(dest_ty);
3089 const dest_ty_id = try self.resolveTypeId(dest_ty);3467 const dest_ty_id = try self.resolveTypeId(dest_ty);
30903468
3091 const result_id = self.spv.allocId();3469 const result_id = self.spv.allocId();
...@@ -3104,6 +3482,22 @@ const DeclGen = struct {...@@ -3104,6 +3482,22 @@ const DeclGen = struct {
3104 return result_id;3482 return result_id;
3105 }3483 }
31063484
3485 fn airIntFromBool(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3486 if (self.liveness.isUnused(inst)) return null;
3487
3488 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3489 const operand_id = try self.resolve(un_op);
3490 const result_ty = self.typeOfIndex(inst);
3491
3492 var wip = try self.elementWise(result_ty);
3493 defer wip.deinit();
3494 for (wip.results, 0..) |*result_id, i| {
3495 const elem_id = try wip.elementAt(Type.bool, operand_id, i);
3496 result_id.* = try self.intFromBool(wip.scalar_ty_ref, elem_id);
3497 }
3498 return try wip.finalize();
3499 }
3500
3107 fn airFloatCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3501 fn airFloatCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3108 if (self.liveness.isUnused(inst)) return null;3502 if (self.liveness.isUnused(inst)) return null;
31093503
...@@ -3126,31 +3520,31 @@ const DeclGen = struct {...@@ -3126,31 +3520,31 @@ const DeclGen = struct {
3126 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3520 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3127 const operand_id = try self.resolve(ty_op.operand);3521 const operand_id = try self.resolve(ty_op.operand);
3128 const result_ty = self.typeOfIndex(inst);3522 const result_ty = self.typeOfIndex(inst);
3129 const result_ty_id = try self.resolveTypeId(result_ty);3523 const info = self.arithmeticTypeInfo(result_ty);
3130 const info = try self.arithmeticTypeInfo(result_ty);
31313524
3132 const result_id = self.spv.allocId();3525 var wip = try self.elementWise(result_ty);
3133 switch (info.class) {3526 defer wip.deinit();
3134 .bool => {3527
3135 try self.func.body.emit(self.spv.gpa, .OpLogicalNot, .{3528 for (0..wip.results.len) |i| {
3136 .id_result_type = result_ty_id,3529 const args = .{
3137 .id_result = result_id,3530 .id_result_type = wip.scalar_ty_id,
3138 .operand = operand_id,3531 .id_result = wip.allocId(i),
3139 });3532 .operand = try wip.elementAt(result_ty, operand_id, i),
3140 },3533 };
3141 .float => unreachable,3534 switch (info.class) {
3142 .composite_integer => unreachable, // TODO3535 .bool => {
3143 .strange_integer, .integer => {3536 try self.func.body.emit(self.spv.gpa, .OpLogicalNot, args);
3144 // Note: strange integer bits will be masked before operations that do not hold under modulo.3537 },
3145 try self.func.body.emit(self.spv.gpa, .OpNot, .{3538 .float => unreachable,
3146 .id_result_type = result_ty_id,3539 .composite_integer => unreachable, // TODO
3147 .id_result = result_id,3540 .strange_integer, .integer => {
3148 .operand = operand_id,3541 // Note: strange integer bits will be masked before operations that do not hold under modulo.
3149 });3542 try self.func.body.emit(self.spv.gpa, .OpNot, args);
3150 },3543 },
3544 }
3151 }3545 }
31523546
3153 return result_id;3547 return try wip.finalize();
3154 }3548 }
31553549
3156 fn airArrayToSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3550 fn airArrayToSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
...@@ -3213,7 +3607,6 @@ const DeclGen = struct {...@@ -3213,7 +3607,6 @@ const DeclGen = struct {
3213 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);3607 const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);
32143608
3215 switch (result_ty.zigTypeTag(mod)) {3609 switch (result_ty.zigTypeTag(mod)) {
3216 .Vector => unreachable, // TODO
3217 .Struct => {3610 .Struct => {
3218 if (mod.typeToPackedStruct(result_ty)) |struct_type| {3611 if (mod.typeToPackedStruct(result_ty)) |struct_type| {
3219 _ = struct_type;3612 _ = struct_type;
...@@ -3261,7 +3654,7 @@ const DeclGen = struct {...@@ -3261,7 +3654,7 @@ const DeclGen = struct {
3261 constituents[0..index],3654 constituents[0..index],
3262 );3655 );
3263 },3656 },
3264 .Array => {3657 .Vector, .Array => {
3265 const array_info = result_ty.arrayInfo(mod);3658 const array_info = result_ty.arrayInfo(mod);
3266 const n_elems: usize = @intCast(result_ty.arrayLenIncludingSentinel(mod));3659 const n_elems: usize = @intCast(result_ty.arrayLenIncludingSentinel(mod));
3267 const elem_ids = try self.gpa.alloc(IdRef, n_elems);3660 const elem_ids = try self.gpa.alloc(IdRef, n_elems);
...@@ -3433,6 +3826,28 @@ const DeclGen = struct {...@@ -3433,6 +3826,28 @@ const DeclGen = struct {
3433 return try self.load(elem_ty, elem_ptr_id, .{ .is_volatile = ptr_ty.isVolatilePtr(mod) });3826 return try self.load(elem_ty, elem_ptr_id, .{ .is_volatile = ptr_ty.isVolatilePtr(mod) });
3434 }3827 }
34353828
3829 fn airVectorStoreElem(self: *DeclGen, inst: Air.Inst.Index) !void {
3830 const mod = self.module;
3831 const data = self.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;
3832 const extra = self.air.extraData(Air.Bin, data.payload).data;
3833
3834 const vector_ptr_ty = self.typeOf(data.vector_ptr);
3835 const vector_ty = vector_ptr_ty.childType(mod);
3836 const scalar_ty = vector_ty.scalarType(mod);
3837
3838 const storage_class = spvStorageClass(vector_ptr_ty.ptrAddressSpace(mod));
3839 const scalar_ptr_ty_ref = try self.ptrType(scalar_ty, storage_class);
3840
3841 const vector_ptr = try self.resolve(data.vector_ptr);
3842 const index = try self.resolve(extra.lhs);
3843 const operand = try self.resolve(extra.rhs);
3844
3845 const elem_ptr_id = try self.accessChainId(scalar_ptr_ty_ref, vector_ptr, &.{index});
3846 try self.store(scalar_ty, elem_ptr_id, operand, .{
3847 .is_volatile = vector_ptr_ty.isVolatilePtr(mod),
3848 });
3849 }
3850
3436 fn airSetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !void {3851 fn airSetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !void {
3437 const mod = self.module;3852 const mod = self.module;
3438 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3853 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
...@@ -4424,20 +4839,24 @@ const DeclGen = struct {...@@ -4424,20 +4839,24 @@ const DeclGen = struct {
4424 return try self.constructStruct(err_union_ty, &types, &members);4839 return try self.constructStruct(err_union_ty, &types, &members);
4425 }4840 }
44264841
4427 fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef {4842 fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef {
4428 if (self.liveness.isUnused(inst)) return null;4843 if (self.liveness.isUnused(inst)) return null;
44294844
4430 const mod = self.module;4845 const mod = self.module;
4431 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4846 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4432 const operand_id = try self.resolve(un_op);4847 const operand_id = try self.resolve(un_op);
4433 const optional_ty = self.typeOf(un_op);4848 const operand_ty = self.typeOf(un_op);
44344849 const optional_ty = if (is_pointer) operand_ty.childType(mod) else operand_ty;
4435 const payload_ty = optional_ty.optionalChild(mod);4850 const payload_ty = optional_ty.optionalChild(mod);
44364851
4437 const bool_ty_ref = try self.resolveType(Type.bool, .direct);4852 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
44384853
4439 if (optional_ty.optionalReprIsPayload(mod)) {4854 if (optional_ty.optionalReprIsPayload(mod)) {
4440 // Pointer payload represents nullability: pointer or slice.4855 // Pointer payload represents nullability: pointer or slice.
4856 const loaded_id = if (is_pointer)
4857 try self.load(optional_ty, operand_id, .{})
4858 else
4859 operand_id;
44414860
4442 const ptr_ty = if (payload_ty.isSlice(mod))4861 const ptr_ty = if (payload_ty.isSlice(mod))
4443 payload_ty.slicePtrFieldType(mod)4862 payload_ty.slicePtrFieldType(mod)
...@@ -4445,9 +4864,9 @@ const DeclGen = struct {...@@ -4445,9 +4864,9 @@ const DeclGen = struct {
4445 payload_ty;4864 payload_ty;
44464865
4447 const ptr_id = if (payload_ty.isSlice(mod))4866 const ptr_id = if (payload_ty.isSlice(mod))
4448 try self.extractField(ptr_ty, operand_id, 0)4867 try self.extractField(ptr_ty, loaded_id, 0)
4449 else4868 else
4450 operand_id;4869 loaded_id;
44514870
4452 const payload_ty_ref = try self.resolveType(ptr_ty, .direct);4871 const payload_ty_ref = try self.resolveType(ptr_ty, .direct);
4453 const null_id = try self.spv.constNull(payload_ty_ref);4872 const null_id = try self.spv.constNull(payload_ty_ref);
...@@ -4458,13 +4877,26 @@ const DeclGen = struct {...@@ -4458,13 +4877,26 @@ const DeclGen = struct {
4458 return try self.cmp(op, Type.bool, ptr_ty, ptr_id, null_id);4877 return try self.cmp(op, Type.bool, ptr_ty, ptr_id, null_id);
4459 }4878 }
44604879
4461 const is_non_null_id = if (payload_ty.hasRuntimeBitsIgnoreComptime(mod))4880 const is_non_null_id = blk: {
4462 try self.extractField(Type.bool, operand_id, 1)4881 if (is_pointer) {
4463 else4882 if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4464 // Optional representation is bool indicating whether the optional is set4883 const storage_class = spvStorageClass(operand_ty.ptrAddressSpace(mod));
4465 // Optionals with no payload are represented as an (indirect) bool, so convert4884 const bool_ptr_ty = try self.ptrType(Type.bool, storage_class);
4466 // it back to the direct bool here.4885 const tag_ptr_id = try self.accessChain(bool_ptr_ty, operand_id, &.{1});
4467 try self.convertToDirect(Type.bool, operand_id);4886 break :blk try self.load(Type.bool, tag_ptr_id, .{});
4887 }
4888
4889 break :blk try self.load(Type.bool, operand_id, .{});
4890 }
4891
4892 break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime(mod))
4893 try self.extractField(Type.bool, operand_id, 1)
4894 else
4895 // Optional representation is bool indicating whether the optional is set
4896 // Optionals with no payload are represented as an (indirect) bool, so convert
4897 // it back to the direct bool here.
4898 try self.convertToDirect(Type.bool, operand_id);
4899 };
44684900
4469 return switch (pred) {4901 return switch (pred) {
4470 .is_null => blk: {4902 .is_null => blk: {
...@@ -4535,6 +4967,32 @@ const DeclGen = struct {...@@ -4535,6 +4967,32 @@ const DeclGen = struct {
4535 return try self.extractField(payload_ty, operand_id, 0);4967 return try self.extractField(payload_ty, operand_id, 0);
4536 }4968 }
45374969
4970 fn airUnwrapOptionalPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4971 if (self.liveness.isUnused(inst)) return null;
4972
4973 const mod = self.module;
4974 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4975 const operand_id = try self.resolve(ty_op.operand);
4976 const operand_ty = self.typeOf(ty_op.operand);
4977 const optional_ty = operand_ty.childType(mod);
4978 const payload_ty = optional_ty.optionalChild(mod);
4979 const result_ty = self.typeOfIndex(inst);
4980 const result_ty_ref = try self.resolveType(result_ty, .direct);
4981
4982 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4983 // There is no payload, but we still need to return a valid pointer.
4984 // We can just return anything here, so just return a pointer to the operand.
4985 return try self.bitCast(result_ty, operand_ty, operand_id);
4986 }
4987
4988 if (optional_ty.optionalReprIsPayload(mod)) {
4989 // They are the same value.
4990 return try self.bitCast(result_ty, operand_ty, operand_id);
4991 }
4992
4993 return try self.accessChain(result_ty_ref, operand_id, &.{0});
4994 }
4995
4538 fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4996 fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4539 if (self.liveness.isUnused(inst)) return null;4997 if (self.liveness.isUnused(inst)) return null;
45404998
test/behavior/abs.zig+2-6
...@@ -7,7 +7,6 @@ test "@abs integers" {...@@ -7,7 +7,6 @@ test "@abs integers" {
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1110
12 try comptime testAbsIntegers();11 try comptime testAbsIntegers();
13 try testAbsIntegers();12 try testAbsIntegers();
...@@ -95,7 +94,6 @@ test "@abs floats" {...@@ -95,7 +94,6 @@ test "@abs floats" {
95 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO94 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
96 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO95 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO96 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;97 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
10098
101 try comptime testAbsFloats(f16);99 try comptime testAbsFloats(f16);
...@@ -105,9 +103,9 @@ test "@abs floats" {...@@ -105,9 +103,9 @@ test "@abs floats" {
105 try comptime testAbsFloats(f64);103 try comptime testAbsFloats(f64);
106 try testAbsFloats(f64);104 try testAbsFloats(f64);
107 try comptime testAbsFloats(f80);105 try comptime testAbsFloats(f80);
108 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f80);106 if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64) try testAbsFloats(f80);
109 try comptime testAbsFloats(f128);107 try comptime testAbsFloats(f128);
110 if (builtin.zig_backend != .stage2_wasm) try testAbsFloats(f128);108 if (builtin.zig_backend != .stage2_wasm and builtin.zig_backend != .stage2_spirv64) try testAbsFloats(f128);
111}109}
112110
113fn testAbsFloats(comptime T: type) !void {111fn testAbsFloats(comptime T: type) !void {
...@@ -155,7 +153,6 @@ test "@abs int vectors" {...@@ -155,7 +153,6 @@ test "@abs int vectors" {
155 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO154 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
159156
160 try comptime testAbsIntVectors(1);157 try comptime testAbsIntVectors(1);
161 try testAbsIntVectors(1);158 try testAbsIntVectors(1);
...@@ -224,7 +221,6 @@ test "@abs unsigned int vectors" {...@@ -224,7 +221,6 @@ test "@abs unsigned int vectors" {
224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
225 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO223 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
227 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
228224
229 try comptime testAbsUnsignedIntVectors(1);225 try comptime testAbsUnsignedIntVectors(1);
230 try testAbsUnsignedIntVectors(1);226 try testAbsUnsignedIntVectors(1);
test/behavior/align.zig+3-4
...@@ -18,7 +18,6 @@ test "global variable alignment" {...@@ -18,7 +18,6 @@ test "global variable alignment" {
18test "large alignment of local constant" {18test "large alignment of local constant" {
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky
2221
23 const x: f32 align(128) = 12.34;22 const x: f32 align(128) = 12.34;
24 try std.testing.expect(@intFromPtr(&x) % 128 == 0);23 try std.testing.expect(@intFromPtr(&x) % 128 == 0);
...@@ -27,7 +26,7 @@ test "large alignment of local constant" {...@@ -27,7 +26,7 @@ test "large alignment of local constant" {
27test "slicing array of length 1 can not assume runtime index is always zero" {26test "slicing array of length 1 can not assume runtime index is always zero" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky
3130
32 var runtime_index: usize = 1;31 var runtime_index: usize = 1;
33 _ = &runtime_index;32 _ = &runtime_index;
...@@ -512,7 +511,7 @@ test "struct field explicit alignment" {...@@ -512,7 +511,7 @@ test "struct field explicit alignment" {
512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO513 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;514 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky
516515
517 const S = struct {516 const S = struct {
518 const Node = struct {517 const Node = struct {
...@@ -581,7 +580,7 @@ test "comptime alloc alignment" {...@@ -581,7 +580,7 @@ test "comptime alloc alignment" {
581 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO580 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
582 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO582 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
584 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;583 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // flaky
585 if (builtin.zig_backend == .stage2_llvm and builtin.target.cpu.arch == .x86) {584 if (builtin.zig_backend == .stage2_llvm and builtin.target.cpu.arch == .x86) {
586 // https://github.com/ziglang/zig/issues/18034585 // https://github.com/ziglang/zig/issues/18034
587 return error.SkipZigTest;586 return error.SkipZigTest;
test/behavior/array.zig-2
...@@ -768,8 +768,6 @@ test "array init with no result pointer sets field result types" {...@@ -768,8 +768,6 @@ test "array init with no result pointer sets field result types" {
768}768}
769769
770test "runtime side-effects in comptime-known array init" {770test "runtime side-effects in comptime-known array init" {
771 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
772
773 var side_effects: u4 = 0;771 var side_effects: u4 = 0;
774 const init = [4]u4{772 const init = [4]u4{
775 blk: {773 blk: {
test/behavior/basic.zig+1
...@@ -1222,6 +1222,7 @@ test "integer compare" {...@@ -1222,6 +1222,7 @@ test "integer compare" {
12221222
1223test "reference to inferred local variable works as expected" {1223test "reference to inferred local variable works as expected" {
1224 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1224 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1225 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
12251226
1226 const Crasher = struct {1227 const Crasher = struct {
1227 lets_crash: u64 = 0,1228 lets_crash: u64 = 0,
test/behavior/bool.zig-2
...@@ -9,8 +9,6 @@ test "bool literals" {...@@ -9,8 +9,6 @@ test "bool literals" {
9}9}
1010
11test "cast bool to int" {11test "cast bool to int" {
12 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13
14 const t = true;12 const t = true;
15 const f = false;13 const f = false;
16 try expectEqual(@as(u32, 1), @intFromBool(t));14 try expectEqual(@as(u32, 1), @intFromBool(t));
test/behavior/builtin_functions_returning_void_or_noreturn.zig+1
...@@ -11,6 +11,7 @@ test {...@@ -11,6 +11,7 @@ test {
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1415
15 var val: u8 = undefined;16 var val: u8 = undefined;
16 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .Unordered));17 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .Unordered));
test/behavior/cast.zig+1-11
...@@ -605,7 +605,6 @@ test "@intCast on vector" {...@@ -605,7 +605,6 @@ test "@intCast on vector" {
605 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO605 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
606 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO606 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
607 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO607 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
608 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
609608
610 const S = struct {609 const S = struct {
611 fn doTheTest() !void {610 fn doTheTest() !void {
...@@ -760,6 +759,7 @@ test "peer type resolution: error union and error set" {...@@ -760,6 +759,7 @@ test "peer type resolution: error union and error set" {
760 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO759 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
761 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO760 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
762 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO761 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
762 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
763763
764 const a: error{Three} = undefined;764 const a: error{Three} = undefined;
765 const b: error{ One, Two }!u32 = undefined;765 const b: error{ One, Two }!u32 = undefined;
...@@ -1247,7 +1247,6 @@ test "implicit cast from *[N]T to ?[*]T" {...@@ -1247,7 +1247,6 @@ test "implicit cast from *[N]T to ?[*]T" {
1247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1248 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1249 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1249 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
12511250
1252 var x: ?[*]u16 = null;1251 var x: ?[*]u16 = null;
1253 var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };1252 var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
...@@ -1732,7 +1731,6 @@ test "peer type resolution: array with smaller child type and vector with larger...@@ -1732,7 +1731,6 @@ test "peer type resolution: array with smaller child type and vector with larger
1732 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1731 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1733 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1732 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1734 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1733 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1735 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
17361734
1737 var arr: [2]u8 = .{ 0, 1 };1735 var arr: [2]u8 = .{ 0, 1 };
1738 var vec: @Vector(2, u64) = .{ 2, 3 };1736 var vec: @Vector(2, u64) = .{ 2, 3 };
...@@ -2320,7 +2318,6 @@ test "@floatCast on vector" {...@@ -2320,7 +2318,6 @@ test "@floatCast on vector" {
2320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2318 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2321 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2323 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2324 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;2321 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
23252322
2326 const S = struct {2323 const S = struct {
...@@ -2341,7 +2338,6 @@ test "@ptrFromInt on vector" {...@@ -2341,7 +2338,6 @@ test "@ptrFromInt on vector" {
2341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2342 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2344 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
23452341
2346 const S = struct {2342 const S = struct {
2347 fn doTheTest() !void {2343 fn doTheTest() !void {
...@@ -2365,7 +2361,6 @@ test "@intFromPtr on vector" {...@@ -2365,7 +2361,6 @@ test "@intFromPtr on vector" {
2365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2366 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2368 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
23692364
2370 const S = struct {2365 const S = struct {
2371 fn doTheTest() !void {2366 fn doTheTest() !void {
...@@ -2389,7 +2384,6 @@ test "@floatFromInt on vector" {...@@ -2389,7 +2384,6 @@ test "@floatFromInt on vector" {
2389 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2384 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2390 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2385 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2391 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2386 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2392 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2393 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;2387 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
23942388
2395 const S = struct {2389 const S = struct {
...@@ -2410,7 +2404,6 @@ test "@intFromFloat on vector" {...@@ -2410,7 +2404,6 @@ test "@intFromFloat on vector" {
2410 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2411 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2412 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2413 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
24142407
2415 const S = struct {2408 const S = struct {
2416 fn doTheTest() !void {2409 fn doTheTest() !void {
...@@ -2430,7 +2423,6 @@ test "@intFromBool on vector" {...@@ -2430,7 +2423,6 @@ test "@intFromBool on vector" {
2430 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2433 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
24342426
2435 const S = struct {2427 const S = struct {
2436 fn doTheTest() !void {2428 fn doTheTest() !void {
...@@ -2468,7 +2460,6 @@ test "@as does not corrupt values with incompatible representations" {...@@ -2468,7 +2460,6 @@ test "@as does not corrupt values with incompatible representations" {
2468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2460 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2461 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2462 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2471 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2472 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;2463 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
24732464
2474 const x: f32 = @as(f16, blk: {2465 const x: f32 = @as(f16, blk: {
...@@ -2510,7 +2501,6 @@ test "@intCast vector of signed integer" {...@@ -2510,7 +2501,6 @@ test "@intCast vector of signed integer" {
2510 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2501 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2511 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2502 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2512 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2503 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2513 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
2514 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO2504 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2515 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO2505 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
25162506
test/behavior/destructure.zig+1
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
3const expect = std.testing.expect;4const expect = std.testing.expect;
45
test/behavior/duplicated_test_names.zig+2
...@@ -15,5 +15,7 @@ comptime {...@@ -15,5 +15,7 @@ comptime {
15test "thingy" {}15test "thingy" {}
1616
17test thingy {17test thingy {
18 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
19
18 if (thingy(1, 2) != 3) unreachable;20 if (thingy(1, 2) != 3) unreachable;
19}21}
test/behavior/eval.zig-1
...@@ -489,7 +489,6 @@ test "comptime bitwise operators" {...@@ -489,7 +489,6 @@ test "comptime bitwise operators" {
489489
490test "comptime shlWithOverflow" {490test "comptime shlWithOverflow" {
491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
493492
494 const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0];493 const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0];
495 var a = ~@as(u64, 0);494 var a = ~@as(u64, 0);
test/behavior/export_builtin.zig-3
...@@ -6,7 +6,6 @@ test "exporting enum type and value" {...@@ -6,7 +6,6 @@ test "exporting enum type and value" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
109
11 const S = struct {10 const S = struct {
12 const E = enum(c_int) { one, two };11 const E = enum(c_int) { one, two };
...@@ -22,7 +21,6 @@ test "exporting with internal linkage" {...@@ -22,7 +21,6 @@ test "exporting with internal linkage" {
22 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;23 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2624
27 const S = struct {25 const S = struct {
28 fn foo() callconv(.C) void {}26 fn foo() callconv(.C) void {}
...@@ -37,7 +35,6 @@ test "exporting using field access" {...@@ -37,7 +35,6 @@ test "exporting using field access" {
37 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;37 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
40 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
4138
42 const S = struct {39 const S = struct {
43 const Inner = struct {40 const Inner = struct {
test/behavior/export_keyword.zig+1
...@@ -23,6 +23,7 @@ const PackedUnion = packed union {...@@ -23,6 +23,7 @@ const PackedUnion = packed union {
2323
24test "packed struct, enum, union parameters in extern function" {24test "packed struct, enum, union parameters in extern function" {
25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2627
27 testPackedStuff(&(PackedStruct{28 testPackedStuff(&(PackedStruct{
28 .a = 1,29 .a = 1,
test/behavior/extern.zig+2
...@@ -5,6 +5,7 @@ const expect = std.testing.expect;...@@ -5,6 +5,7 @@ const expect = std.testing.expect;
5test "anyopaque extern symbol" {5test "anyopaque extern symbol" {
6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
89
9 const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });10 const a = @extern(*anyopaque, .{ .name = "a_mystery_symbol" });
10 const b: *i32 = @alignCast(@ptrCast(a));11 const b: *i32 = @alignCast(@ptrCast(a));
...@@ -17,6 +18,7 @@ test "function extern symbol" {...@@ -17,6 +18,7 @@ test "function extern symbol" {
17 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2022
21 const a = @extern(*const fn () callconv(.C) i32, .{ .name = "a_mystery_function" });23 const a = @extern(*const fn () callconv(.C) i32, .{ .name = "a_mystery_function" });
22 try expect(a() == 4567);24 try expect(a() == 4567);
test/behavior/floatop.zig-3
...@@ -969,7 +969,6 @@ test "@abs f16" {...@@ -969,7 +969,6 @@ test "@abs f16" {
969 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO969 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
970 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO970 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
971 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;971 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
972 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
973972
974 try testFabs(f16);973 try testFabs(f16);
975 try comptime testFabs(f16);974 try comptime testFabs(f16);
...@@ -979,7 +978,6 @@ test "@abs f32/f64" {...@@ -979,7 +978,6 @@ test "@abs f32/f64" {
979 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO978 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
981 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO980 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
982 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
983981
984 try testFabs(f32);982 try testFabs(f32);
985 try comptime testFabs(f32);983 try comptime testFabs(f32);
...@@ -1070,7 +1068,6 @@ fn testFabs(comptime T: type) !void {...@@ -1070,7 +1068,6 @@ fn testFabs(comptime T: type) !void {
1070test "@abs with vectors" {1068test "@abs with vectors" {
1071 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1072 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1070 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1073 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1074 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1071 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10751072
1076 try testFabsWithVectors();1073 try testFabsWithVectors();
test/behavior/for.zig+1
...@@ -456,6 +456,7 @@ test "inline for on tuple pointer" {...@@ -456,6 +456,7 @@ test "inline for on tuple pointer" {
456 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO456 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
459 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
459460
460 const S = struct { u32, u32, u32 };461 const S = struct { u32, u32, u32 };
461 var s: S = .{ 100, 200, 300 };462 var s: S = .{ 100, 200, 300 };
test/behavior/globals.zig-2
...@@ -8,7 +8,6 @@ test "store to global array" {...@@ -8,7 +8,6 @@ test "store to global array" {
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1211
13 try expect(pos[1] == 0.0);12 try expect(pos[1] == 0.0);
14 pos = [2]f32{ 0.0, 1.0 };13 pos = [2]f32{ 0.0, 1.0 };
...@@ -21,7 +20,6 @@ test "store to global vector" {...@@ -21,7 +20,6 @@ test "store to global vector" {
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2523
26 try expect(vpos[1] == 0.0);24 try expect(vpos[1] == 0.0);
27 vpos = @Vector(2, f32){ 0.0, 1.0 };25 vpos = @Vector(2, f32){ 0.0, 1.0 };
test/behavior/hasdecl.zig+5
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const expect = std.testing.expect;3const expect = std.testing.expect;
34
4const Foo = @import("hasdecl/foo.zig");5const Foo = @import("hasdecl/foo.zig");
...@@ -11,6 +12,8 @@ const Bar = struct {...@@ -11,6 +12,8 @@ const Bar = struct {
11};12};
1213
13test "@hasDecl" {14test "@hasDecl" {
15 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
16
14 try expect(@hasDecl(Foo, "public_thing"));17 try expect(@hasDecl(Foo, "public_thing"));
15 try expect(!@hasDecl(Foo, "private_thing"));18 try expect(!@hasDecl(Foo, "private_thing"));
16 try expect(!@hasDecl(Foo, "no_thing"));19 try expect(!@hasDecl(Foo, "no_thing"));
...@@ -21,6 +24,8 @@ test "@hasDecl" {...@@ -21,6 +24,8 @@ test "@hasDecl" {
21}24}
2225
23test "@hasDecl using a sliced string literal" {26test "@hasDecl using a sliced string literal" {
27 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
28
24 try expect(@hasDecl(@This(), "std") == true);29 try expect(@hasDecl(@This(), "std") == true);
25 try expect(@hasDecl(@This(), "std"[0..0]) == false);30 try expect(@hasDecl(@This(), "std"[0..0]) == false);
26 try expect(@hasDecl(@This(), "std"[0..1]) == false);31 try expect(@hasDecl(@This(), "std"[0..1]) == false);
test/behavior/import.zig+9
...@@ -1,17 +1,24 @@...@@ -1,17 +1,24 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const expect = std.testing.expect;3const expect = std.testing.expect;
3const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
4const a_namespace = @import("import/a_namespace.zig");5const a_namespace = @import("import/a_namespace.zig");
56
6test "call fn via namespace lookup" {7test "call fn via namespace lookup" {
8 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
9
7 try expect(@as(i32, 1234) == a_namespace.foo());10 try expect(@as(i32, 1234) == a_namespace.foo());
8}11}
912
10test "importing the same thing gives the same import" {13test "importing the same thing gives the same import" {
14 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
15
11 try expect(@import("std") == @import("std"));16 try expect(@import("std") == @import("std"));
12}17}
1318
14test "import in non-toplevel scope" {19test "import in non-toplevel scope" {
20 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
21
15 const S = struct {22 const S = struct {
16 usingnamespace @import("import/a_namespace.zig");23 usingnamespace @import("import/a_namespace.zig");
17 };24 };
...@@ -19,5 +26,7 @@ test "import in non-toplevel scope" {...@@ -19,5 +26,7 @@ test "import in non-toplevel scope" {
19}26}
2027
21test "import empty file" {28test "import empty file" {
29 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
30
22 _ = @import("import/empty.zig");31 _ = @import("import/empty.zig");
23}32}
test/behavior/int_div.zig+2
...@@ -6,6 +6,7 @@ test "integer division" {...@@ -6,6 +6,7 @@ test "integer division" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
910
10 try testDivision();11 try testDivision();
11 try comptime testDivision();12 try comptime testDivision();
...@@ -96,6 +97,7 @@ test "large integer division" {...@@ -96,6 +97,7 @@ test "large integer division" {
96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;97 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
99101
100 {102 {
101 var numerator: u256 = 99999999999999999997315645440;103 var numerator: u256 = 99999999999999999997315645440;
test/behavior/math.zig-10
...@@ -602,7 +602,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {...@@ -602,7 +602,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
602test "negation wrapping" {602test "negation wrapping" {
603 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO603 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
604 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO604 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
605 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
606605
607 try expectEqual(@as(u1, 1), negateWrap(u1, 1));606 try expectEqual(@as(u1, 1), negateWrap(u1, 1));
608}607}
...@@ -649,8 +648,6 @@ test "bit shift a u1" {...@@ -649,8 +648,6 @@ test "bit shift a u1" {
649}648}
650649
651test "truncating shift right" {650test "truncating shift right" {
652 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
653
654 try testShrTrunc(maxInt(u16));651 try testShrTrunc(maxInt(u16));
655 try comptime testShrTrunc(maxInt(u16));652 try comptime testShrTrunc(maxInt(u16));
656}653}
...@@ -772,7 +769,6 @@ test "@addWithOverflow" {...@@ -772,7 +769,6 @@ test "@addWithOverflow" {
772test "small int addition" {769test "small int addition" {
773 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO770 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
774 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO771 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
775 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
776772
777 var x: u2 = 0;773 var x: u2 = 0;
778 try expect(x == 0);774 try expect(x == 0);
...@@ -1330,8 +1326,6 @@ fn testShlTrunc(x: u16) !void {...@@ -1330,8 +1326,6 @@ fn testShlTrunc(x: u16) !void {
1330}1326}
13311327
1332test "exact shift left" {1328test "exact shift left" {
1333 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1334
1335 try testShlExact(0b00110101);1329 try testShlExact(0b00110101);
1336 try comptime testShlExact(0b00110101);1330 try comptime testShlExact(0b00110101);
13371331
...@@ -1343,8 +1337,6 @@ fn testShlExact(x: u8) !void {...@@ -1343,8 +1337,6 @@ fn testShlExact(x: u8) !void {
1343}1337}
13441338
1345test "exact shift right" {1339test "exact shift right" {
1346 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1347
1348 try testShrExact(0b10110100);1340 try testShrExact(0b10110100);
1349 try comptime testShrExact(0b10110100);1341 try comptime testShrExact(0b10110100);
1350}1342}
...@@ -1570,7 +1562,6 @@ test "vector integer addition" {...@@ -1570,7 +1562,6 @@ test "vector integer addition" {
1570 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1562 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1571 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1563 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1572 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1564 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1573 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
15741565
1575 const S = struct {1566 const S = struct {
1576 fn doTheTest() !void {1567 fn doTheTest() !void {
...@@ -1693,7 +1684,6 @@ test "absFloat" {...@@ -1693,7 +1684,6 @@ test "absFloat" {
1693 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1684 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1694 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1685 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1695 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1686 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1696 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
16971687
1698 try testAbsFloat();1688 try testAbsFloat();
1699 try comptime testAbsFloat();1689 try comptime testAbsFloat();
test/behavior/maximum_minimum.zig-5
...@@ -31,7 +31,6 @@ test "@max on vectors" {...@@ -31,7 +31,6 @@ test "@max on vectors" {
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_x86_64 and34 if (builtin.zig_backend == .stage2_x86_64 and
36 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;35 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
3736
...@@ -86,7 +85,6 @@ test "@min for vectors" {...@@ -86,7 +85,6 @@ test "@min for vectors" {
86 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO85 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO86 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
89 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
90 if (builtin.zig_backend == .stage2_x86_64 and88 if (builtin.zig_backend == .stage2_x86_64 and
91 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;89 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
9290
...@@ -199,7 +197,6 @@ test "@min/@max notices vector bounds" {...@@ -199,7 +197,6 @@ test "@min/@max notices vector bounds" {
199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
200 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO198 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO199 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;200 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
204201
205 var x: @Vector(2, u16) = .{ 140, 40 };202 var x: @Vector(2, u16) = .{ 140, 40 };
...@@ -253,7 +250,6 @@ test "@min/@max notices bounds from vector types" {...@@ -253,7 +250,6 @@ test "@min/@max notices bounds from vector types" {
253 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO252 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
257 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;253 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
258254
259 var x: @Vector(2, u16) = .{ 30, 67 };255 var x: @Vector(2, u16) = .{ 30, 67 };
...@@ -295,7 +291,6 @@ test "@min/@max notices bounds from vector types when element of comptime-known...@@ -295,7 +291,6 @@ test "@min/@max notices bounds from vector types when element of comptime-known
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO291 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO292 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO293 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
299 if (builtin.zig_backend == .stage2_x86_64 and294 if (builtin.zig_backend == .stage2_x86_64 and
300 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx)) return error.SkipZigTest;295 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx)) return error.SkipZigTest;
301296
test/behavior/muladd.zig-5
...@@ -10,7 +10,6 @@ test "@mulAdd" {...@@ -10,7 +10,6 @@ test "@mulAdd" {
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1413
15 try comptime testMulAdd();14 try comptime testMulAdd();
16 try testMulAdd();15 try testMulAdd();
...@@ -37,7 +36,6 @@ test "@mulAdd f16" {...@@ -37,7 +36,6 @@ test "@mulAdd f16" {
37 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO38 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;39 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
4240
43 try comptime testMulAdd16();41 try comptime testMulAdd16();
...@@ -111,7 +109,6 @@ test "vector f16" {...@@ -111,7 +109,6 @@ test "vector f16" {
111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
115112
116 try comptime vector16();113 try comptime vector16();
117 try vector16();114 try vector16();
...@@ -136,7 +133,6 @@ test "vector f32" {...@@ -136,7 +133,6 @@ test "vector f32" {
136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
140136
141 try comptime vector32();137 try comptime vector32();
142 try vector32();138 try vector32();
...@@ -161,7 +157,6 @@ test "vector f64" {...@@ -161,7 +157,6 @@ test "vector f64" {
161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
165160
166 try comptime vector64();161 try comptime vector64();
167 try vector64();162 try vector64();
test/behavior/namespace_depends_on_compile_var.zig+2
...@@ -3,6 +3,8 @@ const builtin = @import("builtin");...@@ -3,6 +3,8 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "namespace depends on compile var" {5test "namespace depends on compile var" {
6 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
7
6 if (some_namespace.a_bool) {8 if (some_namespace.a_bool) {
7 try expect(some_namespace.a_bool);9 try expect(some_namespace.a_bool);
8 } else {10 } else {
test/behavior/null.zig-2
...@@ -32,7 +32,6 @@ test "test maybe object and get a pointer to the inner value" {...@@ -32,7 +32,6 @@ test "test maybe object and get a pointer to the inner value" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
3635
37 var maybe_bool: ?bool = true;36 var maybe_bool: ?bool = true;
3837
...@@ -142,7 +141,6 @@ test "if var maybe pointer" {...@@ -142,7 +141,6 @@ test "if var maybe pointer" {
142 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;141 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
146144
147 try expect(shouldBeAPlus1(Particle{145 try expect(shouldBeAPlus1(Particle{
148 .a = 14,146 .a = 14,
test/behavior/optional.zig+1-3
...@@ -72,7 +72,6 @@ test "address of unwrap optional" {...@@ -72,7 +72,6 @@ test "address of unwrap optional" {
72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
7675
77 const S = struct {76 const S = struct {
78 const Foo = struct {77 const Foo = struct {
...@@ -341,7 +340,6 @@ test "optional pointer to zero bit optional payload" {...@@ -341,7 +340,6 @@ test "optional pointer to zero bit optional payload" {
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
344 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
345343
346 const B = struct {344 const B = struct {
347 fn foo(_: *@This()) void {}345 fn foo(_: *@This()) void {}
...@@ -453,6 +451,7 @@ test "Optional slice passed to function" {...@@ -453,6 +451,7 @@ test "Optional slice passed to function" {
453 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
454 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
455 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO453 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
454 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
456455
457 const S = struct {456 const S = struct {
458 fn foo(a: ?[]const u8) !void {457 fn foo(a: ?[]const u8) !void {
...@@ -518,7 +517,6 @@ test "copied optional doesn't alias source" {...@@ -518,7 +517,6 @@ test "copied optional doesn't alias source" {
518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO517 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
519 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO519 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
522520
523 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;521 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;
524522
test/behavior/pub_enum.zig+4
...@@ -3,6 +3,8 @@ const other = @import("pub_enum/other.zig");...@@ -3,6 +3,8 @@ const other = @import("pub_enum/other.zig");
3const expect = @import("std").testing.expect;3const expect = @import("std").testing.expect;
44
5test "pub enum" {5test "pub enum" {
6 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
7
6 try pubEnumTest(other.APubEnum.Two);8 try pubEnumTest(other.APubEnum.Two);
7}9}
8fn pubEnumTest(foo: other.APubEnum) !void {10fn pubEnumTest(foo: other.APubEnum) !void {
...@@ -10,5 +12,7 @@ fn pubEnumTest(foo: other.APubEnum) !void {...@@ -10,5 +12,7 @@ fn pubEnumTest(foo: other.APubEnum) !void {
10}12}
1113
12test "cast with imported symbol" {14test "cast with imported symbol" {
15 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
16
13 try expect(@as(other.size_t, 42) == 42);17 try expect(@as(other.size_t, 42) == 42);
14}18}
test/behavior/shuffle.zig-3
...@@ -8,7 +8,6 @@ test "@shuffle int" {...@@ -8,7 +8,6 @@ test "@shuffle int" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1211
13 const S = struct {12 const S = struct {
14 fn doTheTest() !void {13 fn doTheTest() !void {
...@@ -54,7 +53,6 @@ test "@shuffle bool 1" {...@@ -54,7 +53,6 @@ test "@shuffle bool 1" {
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
5856
59 const S = struct {57 const S = struct {
60 fn doTheTest() !void {58 fn doTheTest() !void {
...@@ -77,7 +75,6 @@ test "@shuffle bool 2" {...@@ -77,7 +75,6 @@ test "@shuffle bool 2" {
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
80 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
8178
82 if (builtin.zig_backend == .stage2_llvm) {79 if (builtin.zig_backend == .stage2_llvm) {
83 // https://github.com/ziglang/zig/issues/324680 // https://github.com/ziglang/zig/issues/3246
test/behavior/slice_sentinel_comptime.zig+2
...@@ -1,3 +1,5 @@...@@ -1,3 +1,5 @@
1const builtin = @import("builtin");
2
1test "comptime slice-sentinel in bounds (unterminated)" {3test "comptime slice-sentinel in bounds (unterminated)" {
2 // array4 // array
3 comptime {5 comptime {
test/behavior/struct.zig+2-2
...@@ -1744,8 +1744,6 @@ test "struct init with no result pointer sets field result types" {...@@ -1744,8 +1744,6 @@ test "struct init with no result pointer sets field result types" {
1744}1744}
17451745
1746test "runtime side-effects in comptime-known struct init" {1746test "runtime side-effects in comptime-known struct init" {
1747 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1748
1749 var side_effects: u4 = 0;1747 var side_effects: u4 = 0;
1750 const S = struct { a: u4, b: u4, c: u4, d: u4 };1748 const S = struct { a: u4, b: u4, c: u4, d: u4 };
1751 const init = S{1749 const init = S{
...@@ -2056,6 +2054,8 @@ test "struct field default value is a call" {...@@ -2056,6 +2054,8 @@ test "struct field default value is a call" {
2056}2054}
20572055
2058test "aggregate initializers should allow initializing comptime fields, verifying equality" {2056test "aggregate initializers should allow initializing comptime fields, verifying equality" {
2057 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2058
2059 var x: u32 = 15;2059 var x: u32 = 15;
2060 _ = &x;2060 _ = &x;
2061 const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });2061 const T = @TypeOf(.{ @as(i32, -1234), @as(u32, 5678), x });
test/behavior/switch_on_captured_error.zig+4
...@@ -5,6 +5,8 @@ const expectError = std.testing.expectError;...@@ -5,6 +5,8 @@ const expectError = std.testing.expectError;
5const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
66
7test "switch on error union catch capture" {7test "switch on error union catch capture" {
8 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
9
8 const S = struct {10 const S = struct {
9 const Error = error{ A, B, C };11 const Error = error{ A, B, C };
10 fn doTheTest() !void {12 fn doTheTest() !void {
...@@ -257,6 +259,8 @@ test "switch on error union catch capture" {...@@ -257,6 +259,8 @@ test "switch on error union catch capture" {
257}259}
258260
259test "switch on error union if else capture" {261test "switch on error union if else capture" {
262 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
263
260 const S = struct {264 const S = struct {
261 const Error = error{ A, B, C };265 const Error = error{ A, B, C };
262 fn doTheTest() !void {266 fn doTheTest() !void {
test/behavior/truncate.zig-1
...@@ -69,7 +69,6 @@ test "truncate on vectors" {...@@ -69,7 +69,6 @@ test "truncate on vectors" {
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
7372
74 const S = struct {73 const S = struct {
75 fn doTheTest() !void {74 fn doTheTest() !void {
test/behavior/tuple.zig-1
...@@ -483,7 +483,6 @@ test "empty tuple type" {...@@ -483,7 +483,6 @@ test "empty tuple type" {
483483
484test "tuple with comptime fields with non empty initializer" {484test "tuple with comptime fields with non empty initializer" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
487486
488 const a: struct { comptime comptime_int = 0 } = .{0};487 const a: struct { comptime comptime_int = 0 } = .{0};
489 _ = a;488 _ = a;
test/behavior/union.zig+2-1
...@@ -1119,6 +1119,7 @@ test "@unionInit on union with tag but no fields" {...@@ -1119,6 +1119,7 @@ test "@unionInit on union with tag but no fields" {
1119 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1119 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1121 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1121 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1122 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11221123
1123 const S = struct {1124 const S = struct {
1124 const Type = enum(u8) { no_op = 105 };1125 const Type = enum(u8) { no_op = 105 };
...@@ -2059,7 +2060,6 @@ test "store of comptime reinterpreted memory to packed union" {...@@ -2059,7 +2060,6 @@ test "store of comptime reinterpreted memory to packed union" {
20592060
2060test "union field is a pointer to an aligned version of itself" {2061test "union field is a pointer to an aligned version of itself" {
2061 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2062 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2062 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
20632063
2064 const E = union {2064 const E = union {
2065 next: *align(1) @This(),2065 next: *align(1) @This(),
...@@ -2181,6 +2181,7 @@ test "create union(enum) from other union(enum)" {...@@ -2181,6 +2181,7 @@ test "create union(enum) from other union(enum)" {
2181 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO2181 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
2182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2184 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
21842185
2185 const string = "hello world";2186 const string = "hello world";
2186 const TempRef = struct {2187 const TempRef = struct {
test/behavior/vector.zig-15
...@@ -179,7 +179,6 @@ test "array vector coercion - odd sizes" {...@@ -179,7 +179,6 @@ test "array vector coercion - odd sizes" {
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO181 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
183 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;182 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
184 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;183 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
185184
...@@ -219,7 +218,6 @@ test "array to vector with element type coercion" {...@@ -219,7 +218,6 @@ test "array to vector with element type coercion" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
223 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO221 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
224 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;222 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
225223
...@@ -261,7 +259,6 @@ test "tuple to vector" {...@@ -261,7 +259,6 @@ test "tuple to vector" {
261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO261 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
264 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
265262
266 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {263 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
267 // Regressed with LLVM 14:264 // Regressed with LLVM 14:
...@@ -329,7 +326,6 @@ test "vector @splat" {...@@ -329,7 +326,6 @@ test "vector @splat" {
329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO328 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
332 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
333329
334 if (builtin.zig_backend == .stage2_llvm and330 if (builtin.zig_backend == .stage2_llvm and
335 builtin.os.tag == .macos)331 builtin.os.tag == .macos)
...@@ -628,7 +624,6 @@ test "vector bitwise not operator" {...@@ -628,7 +624,6 @@ test "vector bitwise not operator" {
628 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
629 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
630 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
631 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
632627
633 const S = struct {628 const S = struct {
634 fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void {629 fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void {
...@@ -660,7 +655,6 @@ test "vector shift operators" {...@@ -660,7 +655,6 @@ test "vector shift operators" {
660 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO655 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
661 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO656 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
662 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO657 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
663 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
664658
665 const S = struct {659 const S = struct {
666 fn doTheTestShift(x: anytype, y: anytype) !void {660 fn doTheTestShift(x: anytype, y: anytype) !void {
...@@ -915,7 +909,6 @@ test "mask parameter of @shuffle is comptime scope" {...@@ -915,7 +909,6 @@ test "mask parameter of @shuffle is comptime scope" {
915 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO909 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
916 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO910 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
917 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO911 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
918 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
919912
920 const __v4hi = @Vector(4, i16);913 const __v4hi = @Vector(4, i16);
921 var v4_a = __v4hi{ 0, 0, 0, 0 };914 var v4_a = __v4hi{ 0, 0, 0, 0 };
...@@ -1067,7 +1060,6 @@ test "@addWithOverflow" {...@@ -1067,7 +1060,6 @@ test "@addWithOverflow" {
1067 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1068 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1061 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1069 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1062 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1070 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10711063
1072 const S = struct {1064 const S = struct {
1073 fn doTheTest() !void {1065 fn doTheTest() !void {
...@@ -1115,7 +1107,6 @@ test "@subWithOverflow" {...@@ -1115,7 +1107,6 @@ test "@subWithOverflow" {
1115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1108 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1118 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11191110
1120 const S = struct {1111 const S = struct {
1121 fn doTheTest() !void {1112 fn doTheTest() !void {
...@@ -1169,7 +1160,6 @@ test "@shlWithOverflow" {...@@ -1169,7 +1160,6 @@ test "@shlWithOverflow" {
1169 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1170 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1172 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
11731163
1174 const S = struct {1164 const S = struct {
1175 fn doTheTest() !void {1165 fn doTheTest() !void {
...@@ -1236,7 +1226,6 @@ test "byte vector initialized in inline function" {...@@ -1236,7 +1226,6 @@ test "byte vector initialized in inline function" {
1236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1226 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1227 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1228 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1239 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
12401229
1241 if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and1230 if (comptime builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .x86_64 and
1242 builtin.cpu.features.isEnabled(@intFromEnum(std.Target.x86.Feature.avx512f)))1231 builtin.cpu.features.isEnabled(@intFromEnum(std.Target.x86.Feature.avx512f)))
...@@ -1306,7 +1295,6 @@ test "@intCast to u0" {...@@ -1306,7 +1295,6 @@ test "@intCast to u0" {
1306 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1307 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1296 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1308 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1309 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13101298
1311 var zeros = @Vector(2, u32){ 0, 0 };1299 var zeros = @Vector(2, u32){ 0, 0 };
1312 _ = &zeros;1300 _ = &zeros;
...@@ -1331,7 +1319,6 @@ test "array operands to shuffle are coerced to vectors" {...@@ -1331,7 +1319,6 @@ test "array operands to shuffle are coerced to vectors" {
1331 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1319 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1332 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1320 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1334 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
13351322
1336 const mask = [5]i32{ -1, 0, 1, 2, 3 };1323 const mask = [5]i32{ -1, 0, 1, 2, 3 };
13371324
...@@ -1357,7 +1344,6 @@ test "store packed vector element" {...@@ -1357,7 +1344,6 @@ test "store packed vector element" {
1357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1344 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1358 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1359 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1346 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1360 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1361 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1347 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1362 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1348 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1363 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1349 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
...@@ -1454,7 +1440,6 @@ test "compare vectors with different element types" {...@@ -1454,7 +1440,6 @@ test "compare vectors with different element types" {
1454 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1440 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1455 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO1441 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1456 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1442 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1457 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
14581443
1459 var a: @Vector(2, u8) = .{ 1, 2 };1444 var a: @Vector(2, u8) = .{ 1, 2 };
1460 var b: @Vector(2, u9) = .{ 3, 0 };1445 var b: @Vector(2, u9) = .{ 3, 0 };
test/behavior/wrapping_arithmetic.zig+6
...@@ -5,6 +5,8 @@ const maxInt = std.math.maxInt;...@@ -5,6 +5,8 @@ const maxInt = std.math.maxInt;
5const expect = std.testing.expect;5const expect = std.testing.expect;
66
7test "wrapping add" {7test "wrapping add" {
8 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
9
8 const S = struct {10 const S = struct {
9 fn doTheTest() !void {11 fn doTheTest() !void {
10 try testWrapAdd(i8, -3, 10, 7);12 try testWrapAdd(i8, -3, 10, 7);
...@@ -40,6 +42,8 @@ test "wrapping add" {...@@ -40,6 +42,8 @@ test "wrapping add" {
40}42}
4143
42test "wrapping subtraction" {44test "wrapping subtraction" {
45 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
46
43 const S = struct {47 const S = struct {
44 fn doTheTest() !void {48 fn doTheTest() !void {
45 try testWrapSub(i8, -3, 10, -13);49 try testWrapSub(i8, -3, 10, -13);
...@@ -73,6 +77,8 @@ test "wrapping subtraction" {...@@ -73,6 +77,8 @@ test "wrapping subtraction" {
73}77}
7478
75test "wrapping multiplication" {79test "wrapping multiplication" {
80 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
81
76 // TODO: once #9660 has been solved, remove this line82 // TODO: once #9660 has been solved, remove this line
77 if (builtin.cpu.arch == .wasm32) return error.SkipZigTest;83 if (builtin.cpu.arch == .wasm32) return error.SkipZigTest;
7884