From 8eee3928626f9469dbd5ca15127b836e48553bd3 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 1 Jul 2023 14:27:12 +0200 Subject: [PATCH 1/4] spirv: fix up todos & errors from intern pool changes This replaces the implementation of constant() which one that is directly based on the intern pool rather than the Zig type tag too. --- src/codegen/spirv.zig | 188 ++++++++++++++++++++++++++++-------------- 1 file changed, 128 insertions(+), 60 deletions(-) diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index e8cac568c68d0cb1cb20751c4e329fd1161f4720..eb697ea94e98118ab43261cce265ee4e218d26c1 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -537,6 +537,12 @@ pub const DeclGen = struct { fn addInt(self: *@This(), ty: Type, val: Value) !void { const mod = self.dg.module; + const len = ty.abiSize(mod); + if (val.isUndef(mod)) { + try self.addUndef(len); + return; + } + const int_info = ty.intInfo(mod); const int_bits = switch (int_info.signedness) { .signed => @as(u64, @bitCast(val.toSignedInt(mod))), @@ -544,7 +550,6 @@ pub const DeclGen = struct { }; // TODO: Swap endianess if the compiler is big endian. - const len = ty.abiSize(mod); try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]); } @@ -667,31 +672,41 @@ pub const DeclGen = struct { try self.addConstInt(u16, @as(u16, @intCast(int))); }, .error_union => |error_union| { + const err_ty = switch (error_union.val) { + .err_name => ty.errorUnionSet(mod), + .payload => Type.err_int, + }; + const err_val = switch (error_union.val) { + .err_name => |err_name| (try mod.intern(.{ .err = .{ + .ty = ty.errorUnionSet(mod).toIntern(), + .name = err_name, + } })).toValue(), + .payload => try mod.intValue(Type.err_int, 0), + }; const payload_ty = ty.errorUnionPayload(mod); - const is_pl = val.errorUnionIsPayload(mod); - const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0); - const eu_layout = dg.errorUnionLayout(payload_ty); if (!eu_layout.payload_has_bits) { - return try self.lower(Type.anyerror, error_val); + // We use the error type directly as the type. + try self.lower(err_ty, err_val); + return; } const payload_size = payload_ty.abiSize(mod); - const error_size = Type.anyerror.abiAlignment(mod); + const error_size = err_ty.abiSize(mod); const ty_size = ty.abiSize(mod); const padding = ty_size - payload_size - error_size; const payload_val = switch (error_union.val) { - .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), + .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }), .payload => |payload| payload, }.toValue(); if (eu_layout.error_first) { - try self.lower(Type.anyerror, error_val); + try self.lower(err_ty, err_val); try self.lower(payload_ty, payload_val); } else { try self.lower(payload_ty, payload_val); - try self.lower(Type.anyerror, error_val); + try self.lower(err_ty, err_val); } try self.addUndef(padding); @@ -705,9 +720,14 @@ pub const DeclGen = struct { }, .float => try self.addFloat(ty, val), .ptr => |ptr| { + const ptr_ty = switch (ptr.len) { + .none => ty, + else => ty.slicePtrFieldType(mod), + }; switch (ptr.addr) { - .decl => |decl| try self.addDeclRef(ty, decl), - .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl), + .decl => |decl| try self.addDeclRef(ptr_ty, decl), + .mut_decl => |mut_decl| try self.addDeclRef(ptr_ty, mut_decl.decl), + .int => |int| try self.addInt(Type.usize, int.toValue()), else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), } if (ptr.len != .none) { @@ -979,38 +999,84 @@ pub const DeclGen = struct { /// the constant is more complicated however, it needs to be lowered to an indirect constant, which /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default. /// This function should only be called during function code generation. - fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef { + fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef { const mod = self.module; const target = self.getTarget(); const result_ty_ref = try self.resolveType(ty, repr); + var val = arg_val; + switch (mod.intern_pool.indexToKey(val.toIntern())) { + .runtime_value => |rt| val = rt.val.toValue(), + else => {}, + } + log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); - if (val.isUndef(mod)) { return self.spv.constUndef(result_ty_ref); } - switch (ty.zigTypeTag(mod)) { - .Int => { + switch (mod.intern_pool.indexToKey(val.toIntern())) { + .int_type, + .ptr_type, + .array_type, + .vector_type, + .opt_type, + .anyframe_type, + .error_union_type, + .simple_type, + .struct_type, + .anon_struct_type, + .union_type, + .opaque_type, + .enum_type, + .func_type, + .error_set_type, + .inferred_error_set_type, + => unreachable, // types, not values + + .undef => unreachable, // handled above + .runtime_value => unreachable, // ??? + + .variable, + .extern_func, + .func, + .enum_literal, + .empty_enum_value, + => unreachable, // non-runtime values + + .simple_value => |simple_value| switch (simple_value) { + .undefined, + .void, + .null, + .empty_struct, + .@"unreachable", + .generic_poison, + => unreachable, // non-runtime values + + .false, .true => switch (repr) { + .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), + .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())), + }, + }, + + .int => { if (ty.isSignedInt(mod)) { return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); } else { return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod)); } }, - .Bool => switch (repr) { - .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), - .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())), - }, - .Float => return switch (ty.floatBits(target)) { + .float => return switch (ty.floatBits(target)) { 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }), 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }), 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }), 80, 128 => unreachable, // TODO else => unreachable, }, - .ErrorSet => @panic("TODO"), - .ErrorUnion => @panic("TODO"), + .err => |err| { + const value = try mod.getErrorValue(err.name); + return try self.spv.constInt(result_ty_ref, value); + }, // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra // OpVariable that is not really required. else => { @@ -1263,51 +1329,53 @@ pub const DeclGen = struct { } }); }, .Struct => { - const struct_ty = mod.typeToStruct(ty).?; - const fields = struct_ty.fields.values(); - - if (ty.isSimpleTupleOrAnonStruct(mod)) { - const member_types = try self.gpa.alloc(CacheRef, fields.len); - defer self.gpa.free(member_types); - - var member_index: usize = 0; - for (fields) |field| { - if (field.ty.ip_index != .unreachable_value or !field.ty.hasRuntimeBits(mod)) continue; - - member_types[member_index] = try self.resolveType(field.ty, .indirect); - member_index += 1; - } - - return try self.spv.resolve(.{ .struct_type = .{ - .member_types = member_types[0..member_index], - } }); + const struct_ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) { + .anon_struct_type => |tuple| { + const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); + defer self.gpa.free(member_types); + + var member_index: usize = 0; + for (tuple.types, tuple.values) |field_ty, field_val| { + if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; + + member_types[member_index] = try self.resolveType(field_ty.toType(), .indirect); + member_index += 1; + } + + return try self.spv.resolve(.{ .struct_type = .{ + .member_types = member_types[0..member_index], + } }); + }, + .struct_type => |struct_ty| struct_ty, + else => unreachable, + }; + + const struct_obj = mod.structPtrUnwrap(struct_ty.index).?; + if (struct_obj.layout == .Packed) { + return try self.resolveType(struct_obj.backing_int_ty, .direct); } - if (struct_ty.layout == .Packed) { - return try self.resolveType(struct_ty.backing_int_ty, .direct); - } - - const member_types = try self.gpa.alloc(CacheRef, fields.len); - defer self.gpa.free(member_types); - - const member_names = try self.gpa.alloc(CacheString, fields.len); - defer self.gpa.free(member_names); + var member_types = std.ArrayList(CacheRef).init(self.gpa); + defer member_types.deinit(); - var member_index: usize = 0; - for (fields, 0..) |field, i| { - if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; + var member_names = std.ArrayList(CacheString).init(self.gpa); + defer member_names.deinit(); - member_types[member_index] = try self.resolveType(field.ty, .indirect); - member_names[member_index] = try self.spv.resolveString(mod.intern_pool.stringToSlice(struct_ty.fields.keys()[i])); - member_index += 1; + var it = struct_obj.runtimeFieldIterator(mod); + while (it.next()) |field_and_index| { + const field = field_and_index.field; + const index = field_and_index.index; + const field_name = mod.intern_pool.stringToSlice(struct_obj.fields.keys()[index]); + try member_types.append(try self.resolveType(field.ty, .indirect)); + try member_names.append(try self.spv.resolveString(field_name)); } - const name = mod.intern_pool.stringToSlice(try struct_ty.getFullyQualifiedName(self.module)); + const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module)); return try self.spv.resolve(.{ .struct_type = .{ .name = try self.spv.resolveString(name), - .member_types = member_types[0..member_index], - .member_names = member_names[0..member_index], + .member_types = member_types.items, + .member_names = member_names.items, } }); }, .Optional => { @@ -2512,9 +2580,9 @@ pub const DeclGen = struct { // just an element. var elem_ptr_info = ptr_ty.ptrInfo(mod); elem_ptr_info.flags.size = .One; - const elem_ptr_ty = elem_ptr_info.child.toType(); + const elem_ptr_ty = try mod.intern_pool.get(mod.gpa, .{ .ptr_type = elem_ptr_info }); - return try self.load(elem_ptr_ty, elem_ptr_id); + return try self.load(elem_ptr_ty.toType(), elem_ptr_id); } fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { -- 2.54.0 From 74f40ddd11451707a046f2a8b0807a656f81b51c Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 1 Jul 2023 14:27:57 +0200 Subject: [PATCH 2/4] spirv: enable simplified default panic handler SPIR-V cannot print, so we cannot yet use the fancy default panic handler. Instead we will just use the infinite loop one for now. --- lib/std/builtin.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 99761b146ddcb02e19861c9eb8092f981d014c1c..bfb92952e2450f142ae16b1443467cdf50fde136 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -741,7 +741,8 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_x86 or builtin.zig_backend == .stage2_riscv64 or - builtin.zig_backend == .stage2_sparc64) + builtin.zig_backend == .stage2_sparc64 or + builtin.zig_backend == .stage2_spirv64) { while (true) { @breakpoint(); -- 2.54.0 From aa398034eb1b2fd74e1815ae2e75ca1a3ca4a567 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 1 Jul 2023 14:29:11 +0200 Subject: [PATCH 3/4] testing: disable printing for targets that do not support it The SPIR-V cannot print the helpful error messages from the std.testing module. This commit overrides the default print function used here to one that only prints if the target supports it. For now, its only done for SPIR-V, but this function could be adapted to more targets that need it. --- lib/std/testing.zig | 94 ++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/lib/std/testing.zig b/lib/std/testing.zig index bbb090512130ff90c4dcdbaef24875183ceca1be..ca83870f1e1297741eab90513537ea80acf60788 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -2,7 +2,6 @@ const std = @import("std.zig"); const builtin = @import("builtin"); const math = std.math; -const print = std.debug.print; pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator; @@ -22,15 +21,22 @@ pub var base_allocator_instance = std.heap.FixedBufferAllocator.init(""); /// TODO https://github.com/ziglang/zig/issues/5738 pub var log_level = std.log.Level.warn; +fn print(comptime fmt: []const u8, args: anytype) void { + // Disable printing in tests for simple backends. + if (builtin.zig_backend == .stage2_spirv64) return; + + std.debug.print(fmt, args); +} + /// This function is intended to be used only in tests. It prints diagnostics to stderr /// and then returns a test failure error when actual_error_union is not expected_error. pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void { if (actual_error_union) |actual_payload| { - std.debug.print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload }); + print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload }); return error.TestUnexpectedError; } else |actual_error| { if (expected_error != actual_error) { - std.debug.print("expected error.{s}, found error.{s}\n", .{ + print("expected error.{s}, found error.{s}\n", .{ @errorName(expected_error), @errorName(actual_error), }); @@ -58,7 +64,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void { .Type => { if (actual != expected) { - std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); + print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); return error.TestExpectedEqual; } }, @@ -74,7 +80,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void { .ErrorSet, => { if (actual != expected) { - std.debug.print("expected {}, found {}\n", .{ expected, actual }); + print("expected {}, found {}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -83,17 +89,17 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void { switch (pointer.size) { .One, .Many, .C => { if (actual != expected) { - std.debug.print("expected {*}, found {*}\n", .{ expected, actual }); + print("expected {*}, found {*}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, .Slice => { if (actual.ptr != expected.ptr) { - std.debug.print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr }); + print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr }); return error.TestExpectedEqual; } if (actual.len != expected.len) { - std.debug.print("expected slice len {}, found {}\n", .{ expected.len, actual.len }); + print("expected slice len {}, found {}\n", .{ expected.len, actual.len }); return error.TestExpectedEqual; } }, @@ -106,7 +112,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void { var i: usize = 0; while (i < info.len) : (i += 1) { if (!std.meta.eql(expected[i], actual[i])) { - std.debug.print("index {} incorrect. expected {}, found {}\n", .{ + print("index {} incorrect. expected {}, found {}\n", .{ i, expected[i], actual[i], }); return error.TestExpectedEqual; @@ -151,12 +157,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void { if (actual) |actual_payload| { try expectEqual(expected_payload, actual_payload); } else { - std.debug.print("expected {any}, found null\n", .{expected_payload}); + print("expected {any}, found null\n", .{expected_payload}); return error.TestExpectedEqual; } } else { if (actual) |actual_payload| { - std.debug.print("expected null, found {any}\n", .{actual_payload}); + print("expected null, found {any}\n", .{actual_payload}); return error.TestExpectedEqual; } } @@ -167,12 +173,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void { if (actual) |actual_payload| { try expectEqual(expected_payload, actual_payload); } else |actual_err| { - std.debug.print("expected {any}, found {}\n", .{ expected_payload, actual_err }); + print("expected {any}, found {}\n", .{ expected_payload, actual_err }); return error.TestExpectedEqual; } } else |expected_err| { if (actual) |actual_payload| { - std.debug.print("expected {}, found {any}\n", .{ expected_err, actual_payload }); + print("expected {}, found {any}\n", .{ expected_err, actual_payload }); return error.TestExpectedEqual; } else |actual_err| { try expectEqual(expected_err, actual_err); @@ -219,7 +225,7 @@ pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance switch (@typeInfo(T)) { .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) { - std.debug.print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected }); + print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected }); return error.TestExpectedApproxEqAbs; }, @@ -251,7 +257,7 @@ pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance switch (@typeInfo(T)) { .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) { - std.debug.print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected }); + print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected }); return error.TestExpectedApproxEqRel; }, @@ -294,7 +300,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const break :diff_index if (expected.len == actual.len) return else shortest; }; - std.debug.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index }); + print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index }); // TODO: Should this be configurable by the caller? const max_lines: usize = 16; @@ -329,12 +335,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const // that is usually useful. const index_fmt = if (T == u8) "0x{X}" else "{}"; - std.debug.print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len }); + print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len }); if (window_start > 0) { if (T == u8) { - std.debug.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start}); + print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start}); } else { - std.debug.print("... truncated ...\n", .{}); + print("... truncated ...\n", .{}); } } differ.write(stderr.writer()) catch {}; @@ -342,21 +348,21 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const const end_offset = window_start + expected_window.len; const num_missing_items = expected.len - (window_start + expected_window.len); if (T == u8) { - std.debug.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items }); + print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items }); } else { - std.debug.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items}); + print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items}); } } // now reverse expected/actual and print again differ.expected = actual_window; differ.actual = expected_window; - std.debug.print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len }); + print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len }); if (window_start > 0) { if (T == u8) { - std.debug.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start}); + print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start}); } else { - std.debug.print("... truncated ...\n", .{}); + print("... truncated ...\n", .{}); } } differ.write(stderr.writer()) catch {}; @@ -364,12 +370,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const const end_offset = window_start + actual_window.len; const num_missing_items = actual.len - (window_start + actual_window.len); if (T == u8) { - std.debug.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items }); + print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items }); } else { - std.debug.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items}); + print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items}); } } - std.debug.print("\n================================================\n\n", .{}); + print("\n================================================\n\n", .{}); return error.TestExpectedEqual; } @@ -493,12 +499,12 @@ pub fn expectEqualSentinel(comptime T: type, comptime sentinel: T, expected: [:s }; if (!std.meta.eql(sentinel, expected_value_sentinel)) { - std.debug.print("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel }); + print("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel }); return error.TestExpectedEqual; } if (!std.meta.eql(sentinel, actual_value_sentinel)) { - std.debug.print("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel }); + print("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel }); return error.TestExpectedEqual; } } @@ -697,7 +703,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { .Type => { if (actual != expected) { - std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); + print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) }); return error.TestExpectedEqual; } }, @@ -713,7 +719,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { .ErrorSet, => { if (actual != expected) { - std.debug.print("expected {}, found {}\n", .{ expected, actual }); + print("expected {}, found {}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -723,7 +729,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { // We have no idea what is behind those pointers, so the best we can do is `==` check. .C, .Many => { if (actual != expected) { - std.debug.print("expected {*}, found {*}\n", .{ expected, actual }); + print("expected {*}, found {*}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -732,7 +738,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { switch (@typeInfo(pointer.child)) { .Fn, .Opaque => { if (actual != expected) { - std.debug.print("expected {*}, found {*}\n", .{ expected, actual }); + print("expected {*}, found {*}\n", .{ expected, actual }); return error.TestExpectedEqual; } }, @@ -741,13 +747,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { }, .Slice => { if (expected.len != actual.len) { - std.debug.print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); + print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); return error.TestExpectedEqual; } var i: usize = 0; while (i < expected.len) : (i += 1) { expectEqualDeep(expected[i], actual[i]) catch |e| { - std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{ + print("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], }); return e; @@ -759,13 +765,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { .Array => |_| { if (expected.len != actual.len) { - std.debug.print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); + print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); return error.TestExpectedEqual; } var i: usize = 0; while (i < expected.len) : (i += 1) { expectEqualDeep(expected[i], actual[i]) catch |e| { - std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{ + print("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], }); return e; @@ -775,13 +781,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { .Vector => |info| { if (info.len != @typeInfo(@TypeOf(actual)).Vector.len) { - std.debug.print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).Vector.len }); + print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).Vector.len }); return error.TestExpectedEqual; } var i: usize = 0; while (i < info.len) : (i += 1) { expectEqualDeep(expected[i], actual[i]) catch |e| { - std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{ + print("index {d} incorrect. expected {any}, found {any}\n", .{ i, expected[i], actual[i], }); return e; @@ -792,7 +798,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { .Struct => |structType| { inline for (structType.fields) |field| { expectEqualDeep(@field(expected, field.name), @field(actual, field.name)) catch |e| { - std.debug.print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) }); + print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) }); return e; }; } @@ -823,12 +829,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { if (actual) |actual_payload| { try expectEqualDeep(expected_payload, actual_payload); } else { - std.debug.print("expected {any}, found null\n", .{expected_payload}); + print("expected {any}, found null\n", .{expected_payload}); return error.TestExpectedEqual; } } else { if (actual) |actual_payload| { - std.debug.print("expected null, found {any}\n", .{actual_payload}); + print("expected null, found {any}\n", .{actual_payload}); return error.TestExpectedEqual; } } @@ -839,12 +845,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void { if (actual) |actual_payload| { try expectEqualDeep(expected_payload, actual_payload); } else |actual_err| { - std.debug.print("expected {any}, found {any}\n", .{ expected_payload, actual_err }); + print("expected {any}, found {any}\n", .{ expected_payload, actual_err }); return error.TestExpectedEqual; } } else |expected_err| { if (actual) |actual_payload| { - std.debug.print("expected {any}, found {any}\n", .{ expected_err, actual_payload }); + print("expected {any}, found {any}\n", .{ expected_err, actual_payload }); return error.TestExpectedEqual; } else |actual_err| { try expectEqualDeep(expected_err, actual_err); -- 2.54.0 From 073289d0dadfd1ea0088837563a109100b065ed3 Mon Sep 17 00:00:00 2001 From: Robin Voetter Date: Sat, 1 Jul 2023 14:30:32 +0200 Subject: [PATCH 4/4] spirv: disable new behavior tests that do not pass Some new behavior tests have recently been added, and not all of these pass with the SPIR-V backend. --- test/behavior/c_char_signedness.zig | 3 +++ test/behavior/call.zig | 2 ++ test/behavior/comptime_memory.zig | 2 ++ test/behavior/enum.zig | 2 ++ test/behavior/maximum_minimum.zig | 2 ++ test/behavior/ptrfromint.zig | 2 ++ 6 files changed, 13 insertions(+) diff --git a/test/behavior/c_char_signedness.zig b/test/behavior/c_char_signedness.zig index 2484f9c5dc452830d8f850d22558df6412bfbc0a..6b0bfe4049b2da56daa675368e5ec11c9ae5adbe 100644 --- a/test/behavior/c_char_signedness.zig +++ b/test/behavior/c_char_signedness.zig @@ -1,10 +1,13 @@ const std = @import("std"); +const builtin = @import("builtin"); const expectEqual = std.testing.expectEqual; const c = @cImport({ @cInclude("limits.h"); }); test "c_char signedness" { + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + try expectEqual(@as(c_char, c.CHAR_MIN), std.math.minInt(c_char)); try expectEqual(@as(c_char, c.CHAR_MAX), std.math.maxInt(c_char)); } diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 633f5e9c3ffe9f33138185fe8e37fbafeb6dfe8a..c33c872347c9e0e563fee8c24301dd008f7fdf28 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -417,6 +417,8 @@ test "inline while with @call" { } test "method call as parameter type" { + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + const S = struct { fn foo(x: anytype, y: @TypeOf(x).Inner()) @TypeOf(y) { return y; diff --git a/test/behavior/comptime_memory.zig b/test/behavior/comptime_memory.zig index 9895be061d4e8f19aea671d251d41190f102eb71..639de0f5f2b9aed1792f5bcf6b8fb20f10f558df 100644 --- a/test/behavior/comptime_memory.zig +++ b/test/behavior/comptime_memory.zig @@ -433,6 +433,8 @@ test "dereference undefined pointer to zero-bit type" { } test "type pun extern struct" { + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + const S = extern struct { f: u8 }; comptime var s = S{ .f = 123 }; @as(*u8, @ptrCast(&s)).* = 72; diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index ffb254f765cf7ae9ee6b3d9ef77b3b51d0dbca48..a472dc87a400592feaeff9c3fcb8defd3fc70797 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1199,6 +1199,8 @@ test "enum tag from a local variable" { } test "auto-numbered enum with signed tag type" { + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + const E = enum(i32) { a, b }; try std.testing.expectEqual(@as(i32, 0), @intFromEnum(E.a)); diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index 0844cdd28220bf3448fc2c321cf9ae5e8d7f84c5..926d94a2f8f255af4930e6265fc852423e0c6e2e 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -297,6 +297,8 @@ test "@min/@max notices bounds from vector types when element of comptime-known } test "@min/@max of signed and unsigned runtime integers" { + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + var x: i32 = -1; var y: u31 = 1; diff --git a/test/behavior/ptrfromint.zig b/test/behavior/ptrfromint.zig index 72244aa7d122178eabb8624a52bc6f0176565d64..2cf72936a12c028c9e6633d5bfc8bafaac3df92e 100644 --- a/test/behavior/ptrfromint.zig +++ b/test/behavior/ptrfromint.zig @@ -33,6 +33,7 @@ test "@ptrFromInt creates null pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const ptr = @as(?*u32, @ptrFromInt(0)); try expectEqual(@as(?*u32, null), ptr); @@ -42,6 +43,7 @@ test "@ptrFromInt creates allowzero zero pointer" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const ptr = @as(*allowzero u32, @ptrFromInt(0)); try expectEqual(@as(usize, 0), @intFromPtr(ptr)); -- 2.54.0