diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 99761b146d..bfb92952e2 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(); diff --git a/lib/std/testing.zig b/lib/std/testing.zig index bbb0905121..ca83870f1e 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); diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index e8cac568c6..eb697ea94e 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); - log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); + 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(); + 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); - 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 (tuple.types, tuple.values) |field_ty, field_val| { + if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue; - 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.toType(), .indirect); + member_index += 1; + } - 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], + } }); + }, + .struct_type => |struct_ty| struct_ty, + else => unreachable, + }; - return try self.spv.resolve(.{ .struct_type = .{ - .member_types = member_types[0..member_index], - } }); + 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); + var member_types = std.ArrayList(CacheRef).init(self.gpa); + defer member_types.deinit(); + + var member_names = std.ArrayList(CacheString).init(self.gpa); + defer member_names.deinit(); + + 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 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_index: usize = 0; - for (fields, 0..) |field, i| { - if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; - - 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; - } - - 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 { diff --git a/test/behavior/c_char_signedness.zig b/test/behavior/c_char_signedness.zig index 2484f9c5dc..6b0bfe4049 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 633f5e9c3f..c33c872347 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 9895be061d..639de0f5f2 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 ffb254f765..a472dc87a4 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 0844cdd282..926d94a2f8 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 72244aa7d1..2cf72936a1 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));