authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-01 14:21:04-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-01 14:21:04-07:00
log309aacfc8993ff4ec5914a7ee2c487eabbe00998
treefebc13c372a0fb6c4a237e065a7e00575046339a
parent8f14431bc883898aaf78cc985e2d90716187e882
parent073289d0dadfd1ea0088837563a109100b065ed3
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16284 from Snektron/spirv-internpool-fixes

SPIR-V InternPool aftermath damage control

9 files changed, 189 insertions(+), 101 deletions(-)

lib/std/builtin.zig+2-1
......@@ -741,7 +741,8 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
741741 builtin.zig_backend == .stage2_x86_64 or
742742 builtin.zig_backend == .stage2_x86 or
743743 builtin.zig_backend == .stage2_riscv64 or
744 builtin.zig_backend == .stage2_sparc64)
744 builtin.zig_backend == .stage2_sparc64 or
745 builtin.zig_backend == .stage2_spirv64)
745746 {
746747 while (true) {
747748 @breakpoint();
lib/std/testing.zig+50-44
......@@ -2,7 +2,6 @@ const std = @import("std.zig");
22const builtin = @import("builtin");
33
44const math = std.math;
5const print = std.debug.print;
65
76pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator;
87
......@@ -22,15 +21,22 @@ pub var base_allocator_instance = std.heap.FixedBufferAllocator.init("");
2221/// TODO https://github.com/ziglang/zig/issues/5738
2322pub var log_level = std.log.Level.warn;
2423
24fn print(comptime fmt: []const u8, args: anytype) void {
25 // Disable printing in tests for simple backends.
26 if (builtin.zig_backend == .stage2_spirv64) return;
27
28 std.debug.print(fmt, args);
29}
30
2531/// This function is intended to be used only in tests. It prints diagnostics to stderr
2632/// and then returns a test failure error when actual_error_union is not expected_error.
2733pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void {
2834 if (actual_error_union) |actual_payload| {
29 std.debug.print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload });
35 print("expected error.{s}, found {any}\n", .{ @errorName(expected_error), actual_payload });
3036 return error.TestUnexpectedError;
3137 } else |actual_error| {
3238 if (expected_error != actual_error) {
33 std.debug.print("expected error.{s}, found error.{s}\n", .{
39 print("expected error.{s}, found error.{s}\n", .{
3440 @errorName(expected_error),
3541 @errorName(actual_error),
3642 });
......@@ -58,7 +64,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
5864
5965 .Type => {
6066 if (actual != expected) {
61 std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
67 print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
6268 return error.TestExpectedEqual;
6369 }
6470 },
......@@ -74,7 +80,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
7480 .ErrorSet,
7581 => {
7682 if (actual != expected) {
77 std.debug.print("expected {}, found {}\n", .{ expected, actual });
83 print("expected {}, found {}\n", .{ expected, actual });
7884 return error.TestExpectedEqual;
7985 }
8086 },
......@@ -83,17 +89,17 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
8389 switch (pointer.size) {
8490 .One, .Many, .C => {
8591 if (actual != expected) {
86 std.debug.print("expected {*}, found {*}\n", .{ expected, actual });
92 print("expected {*}, found {*}\n", .{ expected, actual });
8793 return error.TestExpectedEqual;
8894 }
8995 },
9096 .Slice => {
9197 if (actual.ptr != expected.ptr) {
92 std.debug.print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr });
98 print("expected slice ptr {*}, found {*}\n", .{ expected.ptr, actual.ptr });
9399 return error.TestExpectedEqual;
94100 }
95101 if (actual.len != expected.len) {
96 std.debug.print("expected slice len {}, found {}\n", .{ expected.len, actual.len });
102 print("expected slice len {}, found {}\n", .{ expected.len, actual.len });
97103 return error.TestExpectedEqual;
98104 }
99105 },
......@@ -106,7 +112,7 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
106112 var i: usize = 0;
107113 while (i < info.len) : (i += 1) {
108114 if (!std.meta.eql(expected[i], actual[i])) {
109 std.debug.print("index {} incorrect. expected {}, found {}\n", .{
115 print("index {} incorrect. expected {}, found {}\n", .{
110116 i, expected[i], actual[i],
111117 });
112118 return error.TestExpectedEqual;
......@@ -151,12 +157,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
151157 if (actual) |actual_payload| {
152158 try expectEqual(expected_payload, actual_payload);
153159 } else {
154 std.debug.print("expected {any}, found null\n", .{expected_payload});
160 print("expected {any}, found null\n", .{expected_payload});
155161 return error.TestExpectedEqual;
156162 }
157163 } else {
158164 if (actual) |actual_payload| {
159 std.debug.print("expected null, found {any}\n", .{actual_payload});
165 print("expected null, found {any}\n", .{actual_payload});
160166 return error.TestExpectedEqual;
161167 }
162168 }
......@@ -167,12 +173,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void {
167173 if (actual) |actual_payload| {
168174 try expectEqual(expected_payload, actual_payload);
169175 } else |actual_err| {
170 std.debug.print("expected {any}, found {}\n", .{ expected_payload, actual_err });
176 print("expected {any}, found {}\n", .{ expected_payload, actual_err });
171177 return error.TestExpectedEqual;
172178 }
173179 } else |expected_err| {
174180 if (actual) |actual_payload| {
175 std.debug.print("expected {}, found {any}\n", .{ expected_err, actual_payload });
181 print("expected {}, found {any}\n", .{ expected_err, actual_payload });
176182 return error.TestExpectedEqual;
177183 } else |actual_err| {
178184 try expectEqual(expected_err, actual_err);
......@@ -219,7 +225,7 @@ pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance
219225
220226 switch (@typeInfo(T)) {
221227 .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) {
222 std.debug.print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected });
228 print("actual {}, not within absolute tolerance {} of expected {}\n", .{ actual, tolerance, expected });
223229 return error.TestExpectedApproxEqAbs;
224230 },
225231
......@@ -251,7 +257,7 @@ pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance
251257
252258 switch (@typeInfo(T)) {
253259 .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) {
254 std.debug.print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected });
260 print("actual {}, not within relative tolerance {} of expected {}\n", .{ actual, tolerance, expected });
255261 return error.TestExpectedApproxEqRel;
256262 },
257263
......@@ -294,7 +300,7 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
294300 break :diff_index if (expected.len == actual.len) return else shortest;
295301 };
296302
297 std.debug.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
303 print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
298304
299305 // TODO: Should this be configurable by the caller?
300306 const max_lines: usize = 16;
......@@ -329,12 +335,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
329335 // that is usually useful.
330336 const index_fmt = if (T == u8) "0x{X}" else "{}";
331337
332 std.debug.print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len });
338 print("\n============ expected this output: ============= len: {} (0x{X})\n\n", .{ expected.len, expected.len });
333339 if (window_start > 0) {
334340 if (T == u8) {
335 std.debug.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
341 print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
336342 } else {
337 std.debug.print("... truncated ...\n", .{});
343 print("... truncated ...\n", .{});
338344 }
339345 }
340346 differ.write(stderr.writer()) catch {};
......@@ -342,21 +348,21 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
342348 const end_offset = window_start + expected_window.len;
343349 const num_missing_items = expected.len - (window_start + expected_window.len);
344350 if (T == u8) {
345 std.debug.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
351 print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
346352 } else {
347 std.debug.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
353 print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
348354 }
349355 }
350356
351357 // now reverse expected/actual and print again
352358 differ.expected = actual_window;
353359 differ.actual = expected_window;
354 std.debug.print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len });
360 print("\n============= instead found this: ============== len: {} (0x{X})\n\n", .{ actual.len, actual.len });
355361 if (window_start > 0) {
356362 if (T == u8) {
357 std.debug.print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
363 print("... truncated, start index: " ++ index_fmt ++ " ...\n", .{window_start});
358364 } else {
359 std.debug.print("... truncated ...\n", .{});
365 print("... truncated ...\n", .{});
360366 }
361367 }
362368 differ.write(stderr.writer()) catch {};
......@@ -364,12 +370,12 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
364370 const end_offset = window_start + actual_window.len;
365371 const num_missing_items = actual.len - (window_start + actual_window.len);
366372 if (T == u8) {
367 std.debug.print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
373 print("... truncated, indexes [" ++ index_fmt ++ "..] not shown, remaining bytes: " ++ index_fmt ++ " ...\n", .{ end_offset, num_missing_items });
368374 } else {
369 std.debug.print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
375 print("... truncated, remaining items: " ++ index_fmt ++ " ...\n", .{num_missing_items});
370376 }
371377 }
372 std.debug.print("\n================================================\n\n", .{});
378 print("\n================================================\n\n", .{});
373379
374380 return error.TestExpectedEqual;
375381}
......@@ -493,12 +499,12 @@ pub fn expectEqualSentinel(comptime T: type, comptime sentinel: T, expected: [:s
493499 };
494500
495501 if (!std.meta.eql(sentinel, expected_value_sentinel)) {
496 std.debug.print("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel });
502 print("expectEqualSentinel: 'expected' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, expected_value_sentinel });
497503 return error.TestExpectedEqual;
498504 }
499505
500506 if (!std.meta.eql(sentinel, actual_value_sentinel)) {
501 std.debug.print("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel });
507 print("expectEqualSentinel: 'actual' sentinel in memory is different from its type sentinel. type sentinel {}, in memory sentinel {}\n", .{ sentinel, actual_value_sentinel });
502508 return error.TestExpectedEqual;
503509 }
504510}
......@@ -697,7 +703,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
697703
698704 .Type => {
699705 if (actual != expected) {
700 std.debug.print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
706 print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
701707 return error.TestExpectedEqual;
702708 }
703709 },
......@@ -713,7 +719,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
713719 .ErrorSet,
714720 => {
715721 if (actual != expected) {
716 std.debug.print("expected {}, found {}\n", .{ expected, actual });
722 print("expected {}, found {}\n", .{ expected, actual });
717723 return error.TestExpectedEqual;
718724 }
719725 },
......@@ -723,7 +729,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
723729 // We have no idea what is behind those pointers, so the best we can do is `==` check.
724730 .C, .Many => {
725731 if (actual != expected) {
726 std.debug.print("expected {*}, found {*}\n", .{ expected, actual });
732 print("expected {*}, found {*}\n", .{ expected, actual });
727733 return error.TestExpectedEqual;
728734 }
729735 },
......@@ -732,7 +738,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
732738 switch (@typeInfo(pointer.child)) {
733739 .Fn, .Opaque => {
734740 if (actual != expected) {
735 std.debug.print("expected {*}, found {*}\n", .{ expected, actual });
741 print("expected {*}, found {*}\n", .{ expected, actual });
736742 return error.TestExpectedEqual;
737743 }
738744 },
......@@ -741,13 +747,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
741747 },
742748 .Slice => {
743749 if (expected.len != actual.len) {
744 std.debug.print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
750 print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
745751 return error.TestExpectedEqual;
746752 }
747753 var i: usize = 0;
748754 while (i < expected.len) : (i += 1) {
749755 expectEqualDeep(expected[i], actual[i]) catch |e| {
750 std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{
756 print("index {d} incorrect. expected {any}, found {any}\n", .{
751757 i, expected[i], actual[i],
752758 });
753759 return e;
......@@ -759,13 +765,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
759765
760766 .Array => |_| {
761767 if (expected.len != actual.len) {
762 std.debug.print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
768 print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
763769 return error.TestExpectedEqual;
764770 }
765771 var i: usize = 0;
766772 while (i < expected.len) : (i += 1) {
767773 expectEqualDeep(expected[i], actual[i]) catch |e| {
768 std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{
774 print("index {d} incorrect. expected {any}, found {any}\n", .{
769775 i, expected[i], actual[i],
770776 });
771777 return e;
......@@ -775,13 +781,13 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
775781
776782 .Vector => |info| {
777783 if (info.len != @typeInfo(@TypeOf(actual)).Vector.len) {
778 std.debug.print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).Vector.len });
784 print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).Vector.len });
779785 return error.TestExpectedEqual;
780786 }
781787 var i: usize = 0;
782788 while (i < info.len) : (i += 1) {
783789 expectEqualDeep(expected[i], actual[i]) catch |e| {
784 std.debug.print("index {d} incorrect. expected {any}, found {any}\n", .{
790 print("index {d} incorrect. expected {any}, found {any}\n", .{
785791 i, expected[i], actual[i],
786792 });
787793 return e;
......@@ -792,7 +798,7 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
792798 .Struct => |structType| {
793799 inline for (structType.fields) |field| {
794800 expectEqualDeep(@field(expected, field.name), @field(actual, field.name)) catch |e| {
795 std.debug.print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) });
801 print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) });
796802 return e;
797803 };
798804 }
......@@ -823,12 +829,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
823829 if (actual) |actual_payload| {
824830 try expectEqualDeep(expected_payload, actual_payload);
825831 } else {
826 std.debug.print("expected {any}, found null\n", .{expected_payload});
832 print("expected {any}, found null\n", .{expected_payload});
827833 return error.TestExpectedEqual;
828834 }
829835 } else {
830836 if (actual) |actual_payload| {
831 std.debug.print("expected null, found {any}\n", .{actual_payload});
837 print("expected null, found {any}\n", .{actual_payload});
832838 return error.TestExpectedEqual;
833839 }
834840 }
......@@ -839,12 +845,12 @@ pub fn expectEqualDeep(expected: anytype, actual: @TypeOf(expected)) !void {
839845 if (actual) |actual_payload| {
840846 try expectEqualDeep(expected_payload, actual_payload);
841847 } else |actual_err| {
842 std.debug.print("expected {any}, found {any}\n", .{ expected_payload, actual_err });
848 print("expected {any}, found {any}\n", .{ expected_payload, actual_err });
843849 return error.TestExpectedEqual;
844850 }
845851 } else |expected_err| {
846852 if (actual) |actual_payload| {
847 std.debug.print("expected {any}, found {any}\n", .{ expected_err, actual_payload });
853 print("expected {any}, found {any}\n", .{ expected_err, actual_payload });
848854 return error.TestExpectedEqual;
849855 } else |actual_err| {
850856 try expectEqualDeep(expected_err, actual_err);
src/codegen/spirv.zig+124-56
......@@ -537,6 +537,12 @@ pub const DeclGen = struct {
537537
538538 fn addInt(self: *@This(), ty: Type, val: Value) !void {
539539 const mod = self.dg.module;
540 const len = ty.abiSize(mod);
541 if (val.isUndef(mod)) {
542 try self.addUndef(len);
543 return;
544 }
545
540546 const int_info = ty.intInfo(mod);
541547 const int_bits = switch (int_info.signedness) {
542548 .signed => @as(u64, @bitCast(val.toSignedInt(mod))),
......@@ -544,7 +550,6 @@ pub const DeclGen = struct {
544550 };
545551
546552 // TODO: Swap endianess if the compiler is big endian.
547 const len = ty.abiSize(mod);
548553 try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]);
549554 }
550555
......@@ -667,31 +672,41 @@ pub const DeclGen = struct {
667672 try self.addConstInt(u16, @as(u16, @intCast(int)));
668673 },
669674 .error_union => |error_union| {
675 const err_ty = switch (error_union.val) {
676 .err_name => ty.errorUnionSet(mod),
677 .payload => Type.err_int,
678 };
679 const err_val = switch (error_union.val) {
680 .err_name => |err_name| (try mod.intern(.{ .err = .{
681 .ty = ty.errorUnionSet(mod).toIntern(),
682 .name = err_name,
683 } })).toValue(),
684 .payload => try mod.intValue(Type.err_int, 0),
685 };
670686 const payload_ty = ty.errorUnionPayload(mod);
671 const is_pl = val.errorUnionIsPayload(mod);
672 const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0);
673
674687 const eu_layout = dg.errorUnionLayout(payload_ty);
675688 if (!eu_layout.payload_has_bits) {
676 return try self.lower(Type.anyerror, error_val);
689 // We use the error type directly as the type.
690 try self.lower(err_ty, err_val);
691 return;
677692 }
678693
679694 const payload_size = payload_ty.abiSize(mod);
680 const error_size = Type.anyerror.abiAlignment(mod);
695 const error_size = err_ty.abiSize(mod);
681696 const ty_size = ty.abiSize(mod);
682697 const padding = ty_size - payload_size - error_size;
683698
684699 const payload_val = switch (error_union.val) {
685 .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }),
700 .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
686701 .payload => |payload| payload,
687702 }.toValue();
688703
689704 if (eu_layout.error_first) {
690 try self.lower(Type.anyerror, error_val);
705 try self.lower(err_ty, err_val);
691706 try self.lower(payload_ty, payload_val);
692707 } else {
693708 try self.lower(payload_ty, payload_val);
694 try self.lower(Type.anyerror, error_val);
709 try self.lower(err_ty, err_val);
695710 }
696711
697712 try self.addUndef(padding);
......@@ -705,9 +720,14 @@ pub const DeclGen = struct {
705720 },
706721 .float => try self.addFloat(ty, val),
707722 .ptr => |ptr| {
723 const ptr_ty = switch (ptr.len) {
724 .none => ty,
725 else => ty.slicePtrFieldType(mod),
726 };
708727 switch (ptr.addr) {
709 .decl => |decl| try self.addDeclRef(ty, decl),
710 .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl),
728 .decl => |decl| try self.addDeclRef(ptr_ty, decl),
729 .mut_decl => |mut_decl| try self.addDeclRef(ptr_ty, mut_decl.decl),
730 .int => |int| try self.addInt(Type.usize, int.toValue()),
711731 else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}),
712732 }
713733 if (ptr.len != .none) {
......@@ -979,38 +999,84 @@ pub const DeclGen = struct {
979999 /// the constant is more complicated however, it needs to be lowered to an indirect constant, which
9801000 /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default.
9811001 /// This function should only be called during function code generation.
982 fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef {
1002 fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef {
9831003 const mod = self.module;
9841004 const target = self.getTarget();
9851005 const result_ty_ref = try self.resolveType(ty, repr);
9861006
987 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
1007 var val = arg_val;
1008 switch (mod.intern_pool.indexToKey(val.toIntern())) {
1009 .runtime_value => |rt| val = rt.val.toValue(),
1010 else => {},
1011 }
9881012
1013 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
9891014 if (val.isUndef(mod)) {
9901015 return self.spv.constUndef(result_ty_ref);
9911016 }
9921017
993 switch (ty.zigTypeTag(mod)) {
994 .Int => {
1018 switch (mod.intern_pool.indexToKey(val.toIntern())) {
1019 .int_type,
1020 .ptr_type,
1021 .array_type,
1022 .vector_type,
1023 .opt_type,
1024 .anyframe_type,
1025 .error_union_type,
1026 .simple_type,
1027 .struct_type,
1028 .anon_struct_type,
1029 .union_type,
1030 .opaque_type,
1031 .enum_type,
1032 .func_type,
1033 .error_set_type,
1034 .inferred_error_set_type,
1035 => unreachable, // types, not values
1036
1037 .undef => unreachable, // handled above
1038 .runtime_value => unreachable, // ???
1039
1040 .variable,
1041 .extern_func,
1042 .func,
1043 .enum_literal,
1044 .empty_enum_value,
1045 => unreachable, // non-runtime values
1046
1047 .simple_value => |simple_value| switch (simple_value) {
1048 .undefined,
1049 .void,
1050 .null,
1051 .empty_struct,
1052 .@"unreachable",
1053 .generic_poison,
1054 => unreachable, // non-runtime values
1055
1056 .false, .true => switch (repr) {
1057 .direct => return try self.spv.constBool(result_ty_ref, val.toBool()),
1058 .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())),
1059 },
1060 },
1061
1062 .int => {
9951063 if (ty.isSignedInt(mod)) {
9961064 return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod));
9971065 } else {
9981066 return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod));
9991067 }
10001068 },
1001 .Bool => switch (repr) {
1002 .direct => return try self.spv.constBool(result_ty_ref, val.toBool()),
1003 .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())),
1004 },
1005 .Float => return switch (ty.floatBits(target)) {
1069 .float => return switch (ty.floatBits(target)) {
10061070 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }),
10071071 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }),
10081072 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }),
10091073 80, 128 => unreachable, // TODO
10101074 else => unreachable,
10111075 },
1012 .ErrorSet => @panic("TODO"),
1013 .ErrorUnion => @panic("TODO"),
1076 .err => |err| {
1077 const value = try mod.getErrorValue(err.name);
1078 return try self.spv.constInt(result_ty_ref, value);
1079 },
10141080 // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra
10151081 // OpVariable that is not really required.
10161082 else => {
......@@ -1263,51 +1329,53 @@ pub const DeclGen = struct {
12631329 } });
12641330 },
12651331 .Struct => {
1266 const struct_ty = mod.typeToStruct(ty).?;
1267 const fields = struct_ty.fields.values();
1268
1269 if (ty.isSimpleTupleOrAnonStruct(mod)) {
1270 const member_types = try self.gpa.alloc(CacheRef, fields.len);
1271 defer self.gpa.free(member_types);
1332 const struct_ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1333 .anon_struct_type => |tuple| {
1334 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
1335 defer self.gpa.free(member_types);
12721336
1273 var member_index: usize = 0;
1274 for (fields) |field| {
1275 if (field.ty.ip_index != .unreachable_value or !field.ty.hasRuntimeBits(mod)) continue;
1337 var member_index: usize = 0;
1338 for (tuple.types, tuple.values) |field_ty, field_val| {
1339 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
12761340
1277 member_types[member_index] = try self.resolveType(field.ty, .indirect);
1278 member_index += 1;
1279 }
1341 member_types[member_index] = try self.resolveType(field_ty.toType(), .indirect);
1342 member_index += 1;
1343 }
12801344
1281 return try self.spv.resolve(.{ .struct_type = .{
1282 .member_types = member_types[0..member_index],
1283 } });
1284 }
1345 return try self.spv.resolve(.{ .struct_type = .{
1346 .member_types = member_types[0..member_index],
1347 } });
1348 },
1349 .struct_type => |struct_ty| struct_ty,
1350 else => unreachable,
1351 };
12851352
1286 if (struct_ty.layout == .Packed) {
1287 return try self.resolveType(struct_ty.backing_int_ty, .direct);
1353 const struct_obj = mod.structPtrUnwrap(struct_ty.index).?;
1354 if (struct_obj.layout == .Packed) {
1355 return try self.resolveType(struct_obj.backing_int_ty, .direct);
12881356 }
12891357
1290 const member_types = try self.gpa.alloc(CacheRef, fields.len);
1291 defer self.gpa.free(member_types);
1292
1293 const member_names = try self.gpa.alloc(CacheString, fields.len);
1294 defer self.gpa.free(member_names);
1358 var member_types = std.ArrayList(CacheRef).init(self.gpa);
1359 defer member_types.deinit();
12951360
1296 var member_index: usize = 0;
1297 for (fields, 0..) |field, i| {
1298 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;
1361 var member_names = std.ArrayList(CacheString).init(self.gpa);
1362 defer member_names.deinit();
12991363
1300 member_types[member_index] = try self.resolveType(field.ty, .indirect);
1301 member_names[member_index] = try self.spv.resolveString(mod.intern_pool.stringToSlice(struct_ty.fields.keys()[i]));
1302 member_index += 1;
1364 var it = struct_obj.runtimeFieldIterator(mod);
1365 while (it.next()) |field_and_index| {
1366 const field = field_and_index.field;
1367 const index = field_and_index.index;
1368 const field_name = mod.intern_pool.stringToSlice(struct_obj.fields.keys()[index]);
1369 try member_types.append(try self.resolveType(field.ty, .indirect));
1370 try member_names.append(try self.spv.resolveString(field_name));
13031371 }
13041372
1305 const name = mod.intern_pool.stringToSlice(try struct_ty.getFullyQualifiedName(self.module));
1373 const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module));
13061374
13071375 return try self.spv.resolve(.{ .struct_type = .{
13081376 .name = try self.spv.resolveString(name),
1309 .member_types = member_types[0..member_index],
1310 .member_names = member_names[0..member_index],
1377 .member_types = member_types.items,
1378 .member_names = member_names.items,
13111379 } });
13121380 },
13131381 .Optional => {
......@@ -2512,9 +2580,9 @@ pub const DeclGen = struct {
25122580 // just an element.
25132581 var elem_ptr_info = ptr_ty.ptrInfo(mod);
25142582 elem_ptr_info.flags.size = .One;
2515 const elem_ptr_ty = elem_ptr_info.child.toType();
2583 const elem_ptr_ty = try mod.intern_pool.get(mod.gpa, .{ .ptr_type = elem_ptr_info });
25162584
2517 return try self.load(elem_ptr_ty, elem_ptr_id);
2585 return try self.load(elem_ptr_ty.toType(), elem_ptr_id);
25182586 }
25192587
25202588 fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
test/behavior/c_char_signedness.zig+3
......@@ -1,10 +1,13 @@
11const std = @import("std");
2const builtin = @import("builtin");
23const expectEqual = std.testing.expectEqual;
34const c = @cImport({
45 @cInclude("limits.h");
56});
67
78test "c_char signedness" {
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10
811 try expectEqual(@as(c_char, c.CHAR_MIN), std.math.minInt(c_char));
912 try expectEqual(@as(c_char, c.CHAR_MAX), std.math.maxInt(c_char));
1013}
test/behavior/call.zig+2
......@@ -417,6 +417,8 @@ test "inline while with @call" {
417417}
418418
419419test "method call as parameter type" {
420 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
421
420422 const S = struct {
421423 fn foo(x: anytype, y: @TypeOf(x).Inner()) @TypeOf(y) {
422424 return y;
test/behavior/comptime_memory.zig+2
......@@ -433,6 +433,8 @@ test "dereference undefined pointer to zero-bit type" {
433433}
434434
435435test "type pun extern struct" {
436 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
437
436438 const S = extern struct { f: u8 };
437439 comptime var s = S{ .f = 123 };
438440 @as(*u8, @ptrCast(&s)).* = 72;
test/behavior/enum.zig+2
......@@ -1199,6 +1199,8 @@ test "enum tag from a local variable" {
11991199}
12001200
12011201test "auto-numbered enum with signed tag type" {
1202 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1203
12021204 const E = enum(i32) { a, b };
12031205
12041206 try std.testing.expectEqual(@as(i32, 0), @intFromEnum(E.a));
test/behavior/maximum_minimum.zig+2
......@@ -297,6 +297,8 @@ test "@min/@max notices bounds from vector types when element of comptime-known
297297}
298298
299299test "@min/@max of signed and unsigned runtime integers" {
300 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
301
300302 var x: i32 = -1;
301303 var y: u31 = 1;
302304
test/behavior/ptrfromint.zig+2
......@@ -33,6 +33,7 @@ test "@ptrFromInt creates null pointer" {
3333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3535 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
3637
3738 const ptr = @as(?*u32, @ptrFromInt(0));
3839 try expectEqual(@as(?*u32, null), ptr);
......@@ -42,6 +43,7 @@ test "@ptrFromInt creates allowzero zero pointer" {
4243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4344 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4445 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
4547
4648 const ptr = @as(*allowzero u32, @ptrFromInt(0));
4749 try expectEqual(@as(usize, 0), @intFromPtr(ptr));