mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
Merge pull request #16284 from Snektron/spirv-internpool-fixes
SPIR-V InternPool aftermath damage control
This commit is contained in:
commit
309aacfc89
@ -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,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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user